diff --git a/substrate/.cargo/config.toml b/substrate/.cargo/config.toml
index 5355758f7a4fab279a0b78f13224fa691725c363..66b28b3485d86be96ee2d246e3108650ccff1961 100644
--- a/substrate/.cargo/config.toml
+++ b/substrate/.cargo/config.toml
@@ -18,14 +18,15 @@ rustflags = [
   "-Aclippy::borrowed-box",              # Reasonable to fix this one
   "-Aclippy::too-many-arguments",        # (Turning this on would lead to)
   "-Aclippy::unnecessary_cast",          # Types may change
-  "-Aclippy::identity-op",               # One case where we do 0 + 
+  "-Aclippy::identity-op",               # One case where we do 0 +
   "-Aclippy::useless_conversion",        # Types may change
   "-Aclippy::unit_arg",                  # styalistic.
   "-Aclippy::option-map-unit-fn",        # styalistic
-  "-Aclippy::bind_instead_of_map",       # styalistic 
+  "-Aclippy::bind_instead_of_map",       # styalistic
   "-Aclippy::erasing_op",                # E.g. 0 * DOLLARS
   "-Aclippy::eq_op",                     # In tests we test equality.
   "-Aclippy::while_immutable_condition", # false positives
   "-Aclippy::needless_option_as_deref",  # false positives
   "-Aclippy::derivable_impls",           # false positives
+  "-Aclippy::stable_sort_primitive",     # prefer stable sort
 ]
diff --git a/substrate/bin/node/bench/src/core.rs b/substrate/bin/node/bench/src/core.rs
index 3b3060a888349fac91303e137909383c5ce944e6..b6ad3ecd800680b2a4f3d2504a682154035a24ce 100644
--- a/substrate/bin/node/bench/src/core.rs
+++ b/substrate/bin/node/bench/src/core.rs
@@ -132,7 +132,7 @@ pub fn run_benchmark(benchmark: Box<dyn BenchmarkDescription>, mode: Mode) -> Be
 		durations.push(duration.as_nanos());
 	}
 
-	durations.sort_unstable();
+	durations.sort();
 
 	let raw_average = (durations.iter().sum::<u128>() / (durations.len() as u128)) as u64;
 	let average = (durations.iter().skip(10).take(30).sum::<u128>() / 30) as u64;
diff --git a/substrate/client/rpc-servers/src/lib.rs b/substrate/client/rpc-servers/src/lib.rs
index 0e2aca0dcc82976290d81e091d43d3a66548a629..7eb825e169bfaa697100ea6341f6ff90cf357eb8 100644
--- a/substrate/client/rpc-servers/src/lib.rs
+++ b/substrate/client/rpc-servers/src/lib.rs
@@ -198,7 +198,7 @@ fn format_allowed_hosts(addrs: &[SocketAddr]) -> Vec<String> {
 
 fn build_rpc_api<M: Send + Sync + 'static>(mut rpc_api: RpcModule<M>) -> RpcModule<M> {
 	let mut available_methods = rpc_api.method_names().collect::<Vec<_>>();
-	available_methods.sort_unstable();
+	available_methods.sort();
 
 	rpc_api
 		.register_method("rpc_methods", move |_, _| {
diff --git a/substrate/frame/benchmarking/src/analysis.rs b/substrate/frame/benchmarking/src/analysis.rs
index 9ba2ea657bab09cb88bec4c0936308a613df6260..a736cdc20318276da9e473895f422866edfa455c 100644
--- a/substrate/frame/benchmarking/src/analysis.rs
+++ b/substrate/frame/benchmarking/src/analysis.rs
@@ -181,7 +181,7 @@ impl Analysis {
 			})
 			.collect();
 
-		values.sort_unstable();
+		values.sort();
 		let mid = values.len() / 2;
 
 		Some(Self {
@@ -311,7 +311,7 @@ impl Analysis {
 		}
 
 		for (_, rs) in results.iter_mut() {
-			rs.sort_unstable();
+			rs.sort();
 			let ql = rs.len() / 4;
 			*rs = rs[ql..rs.len() - ql].to_vec();
 		}
diff --git a/substrate/frame/contracts/src/wasm/runtime.rs b/substrate/frame/contracts/src/wasm/runtime.rs
index 329649299407110080775a29b3621e49980c73fb..6d7e6bcf69e5fbc7ea5b194dad37fb1567372ff6 100644
--- a/substrate/frame/contracts/src/wasm/runtime.rs
+++ b/substrate/frame/contracts/src/wasm/runtime.rs
@@ -1976,11 +1976,7 @@ pub mod env {
 		data_len: u32,
 	) -> Result<(), TrapReason> {
 		fn has_duplicates<T: Ord>(items: &mut Vec<T>) -> bool {
-			// # Warning
-			//
-			// Unstable sorts are non-deterministic across architectures. The usage here is OK
-			// because we are rejecting duplicates which removes the non determinism.
-			items.sort_unstable();
+			items.sort();
 			// Find any two consecutive equal elements.
 			items.windows(2).any(|w| match &w {
 				&[a, b] => a == b,
diff --git a/substrate/frame/election-provider-multi-phase/src/mock.rs b/substrate/frame/election-provider-multi-phase/src/mock.rs
index 6a638c8d2a2e1c9e6eb9360675aec8ddad3bae24..e04e0bf474caf18cabfcd54bc6995a95804a8712 100644
--- a/substrate/frame/election-provider-multi-phase/src/mock.rs
+++ b/substrate/frame/election-provider-multi-phase/src/mock.rs
@@ -155,7 +155,7 @@ pub fn trim_helpers() -> TrimHelpers {
 		seq_phragmen(desired_targets as usize, targets.clone(), voters.clone(), None).unwrap();
 
 	// sort by decreasing order of stake
-	assignments.sort_unstable_by_key(|assignment| {
+	assignments.sort_by_key(|assignment| {
 		std::cmp::Reverse(stakes.get(&assignment.who).cloned().unwrap_or_default())
 	});
 
diff --git a/substrate/frame/examples/basic/src/benchmarking.rs b/substrate/frame/examples/basic/src/benchmarking.rs
index 4d1659af46460101d6d6398994359d24ac8f23c0..87d65a0bfa5b63429c2c09bf43411bf434a3e800 100644
--- a/substrate/frame/examples/basic/src/benchmarking.rs
+++ b/substrate/frame/examples/basic/src/benchmarking.rs
@@ -63,7 +63,7 @@ benchmarks! {
 		}
 	}: {
 		// The benchmark execution phase could also be a closure with custom code
-		m.sort_unstable();
+		m.sort();
 	}
 
 	// This line generates test cases for benchmarking, and could be run by:
diff --git a/substrate/primitives/npos-elections/fuzzer/src/common.rs b/substrate/primitives/npos-elections/fuzzer/src/common.rs
index e5853f28c49290b540e7bbea9ab79cf1a157ffaa..ad9bd43f9bce0a2324e27492f52bd1a3b3ffcea4 100644
--- a/substrate/primitives/npos-elections/fuzzer/src/common.rs
+++ b/substrate/primitives/npos-elections/fuzzer/src/common.rs
@@ -80,7 +80,7 @@ pub fn generate_random_npos_inputs(
 		}
 		candidates.push(id);
 	}
-	candidates.sort_unstable();
+	candidates.sort();
 	candidates.dedup();
 	assert_eq!(candidates.len(), candidate_count);
 
@@ -99,11 +99,11 @@ pub fn generate_random_npos_inputs(
 
 		let mut chosen_candidates = Vec::with_capacity(n_candidates_chosen);
 		chosen_candidates.extend(candidates.choose_multiple(&mut rng, n_candidates_chosen));
-		chosen_candidates.sort_unstable();
+		chosen_candidates.sort();
 		voters.push((id, vote_weight, chosen_candidates));
 	}
 
-	voters.sort_unstable();
+	voters.sort();
 	voters.dedup_by_key(|(id, _weight, _chosen_candidates)| *id);
 	assert_eq!(voters.len(), voter_count);
 
diff --git a/substrate/utils/frame/benchmarking-cli/src/shared/stats.rs b/substrate/utils/frame/benchmarking-cli/src/shared/stats.rs
index 3234d5f2f94f7db8420812a23eee419bdab0a8c5..ffae4a17724f883176454484b544f9ea49cf97af 100644
--- a/substrate/utils/frame/benchmarking-cli/src/shared/stats.rs
+++ b/substrate/utils/frame/benchmarking-cli/src/shared/stats.rs
@@ -112,7 +112,7 @@ impl Stats {
 	/// Returns the specified percentile for the given data.
 	/// This is best effort since it ignores the interpolation case.
 	fn percentile(mut xs: Vec<u64>, p: f64) -> u64 {
-		xs.sort_unstable();
+		xs.sort();
 		let index = (xs.len() as f64 * p).ceil() as usize - 1;
 		xs[index.clamp(0, xs.len() - 1)]
 	}