diff --git a/Cargo.lock b/Cargo.lock
index 97bdc9351357acb86101e2f466e4269ba07443d7..7eb88c85bc8ef9865c26ee29aeda6d2049878fbc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4353,7 +4353,6 @@ dependencies = [
  "futures",
  "hex-literal",
  "impl-trait-for-tuples",
- "lazy_static",
  "log",
  "pallet-message-queue",
  "parity-scale-codec",
@@ -6210,7 +6209,6 @@ dependencies = [
  "gethostname",
  "handlebars",
  "itertools 0.11.0",
- "lazy_static",
  "linked-hash-map",
  "log",
  "parity-scale-codec",
@@ -10119,7 +10117,6 @@ dependencies = [
  "kitchensink-runtime",
  "kvdb",
  "kvdb-rocksdb",
- "lazy_static",
  "log",
  "node-primitives",
  "node-testing",
@@ -14104,7 +14101,6 @@ dependencies = [
  "futures",
  "futures-timer",
  "indexmap 2.2.3",
- "lazy_static",
  "parity-scale-codec",
  "polkadot-erasure-coding",
  "polkadot-node-network-protocol",
@@ -14148,7 +14144,6 @@ dependencies = [
  "async-trait",
  "futures",
  "futures-timer",
- "lazy_static",
  "parking_lot 0.12.3",
  "polkadot-node-network-protocol",
  "polkadot-node-subsystem",
@@ -14696,7 +14691,6 @@ dependencies = [
 name = "polkadot-node-jaeger"
 version = "7.0.0"
 dependencies = [
- "lazy_static",
  "log",
  "mick-jaeger",
  "parity-scale-codec",
@@ -14863,7 +14857,6 @@ dependencies = [
  "kvdb",
  "kvdb-memorydb",
  "kvdb-shared-tests",
- "lazy_static",
  "log",
  "parity-db",
  "parity-scale-codec",
@@ -19432,7 +19425,6 @@ dependencies = [
  "futures-timer",
  "hyper 0.14.29",
  "hyper-rustls 0.24.2",
- "lazy_static",
  "log",
  "num_cpus",
  "once_cell",
@@ -19815,7 +19807,6 @@ dependencies = [
  "console",
  "criterion",
  "is-terminal",
- "lazy_static",
  "libc",
  "log",
  "parity-scale-codec",
@@ -19904,7 +19895,6 @@ dependencies = [
  "async-channel 1.9.0",
  "futures",
  "futures-timer",
- "lazy_static",
  "log",
  "parking_lot 0.12.3",
  "prometheus",
@@ -21752,7 +21742,6 @@ name = "sp-consensus-beefy"
 version = "13.0.0"
 dependencies = [
  "array-bytes",
- "lazy_static",
  "parity-scale-codec",
  "scale-info",
  "serde",
@@ -21838,7 +21827,6 @@ dependencies = [
  "impl-serde",
  "itertools 0.11.0",
  "k256",
- "lazy_static",
  "libsecp256k1",
  "log",
  "merlin",
@@ -22014,7 +22002,6 @@ dependencies = [
 name = "sp-core-fuzz"
 version = "0.0.0"
 dependencies = [
- "lazy_static",
  "libfuzzer-sys",
  "regex",
  "sp-core 28.0.0",
@@ -22494,7 +22481,6 @@ name = "sp-panic-handler"
 version = "13.0.0"
 dependencies = [
  "backtrace",
- "lazy_static",
  "regex",
 ]
 
@@ -23086,7 +23072,6 @@ dependencies = [
  "array-bytes",
  "criterion",
  "hash-db",
- "lazy_static",
  "memory-db",
  "nohash-hasher",
  "parity-scale-codec",
@@ -27020,7 +27005,6 @@ dependencies = [
  "frame-support",
  "frame-system",
  "impl-trait-for-tuples",
- "lazy_static",
  "log",
  "pallet-balances",
  "pallet-message-queue",
@@ -27270,7 +27254,6 @@ name = "zombienet-backchannel"
 version = "1.0.0"
 dependencies = [
  "futures-util",
- "lazy_static",
  "parity-scale-codec",
  "reqwest 0.11.20",
  "serde",
diff --git a/Cargo.toml b/Cargo.toml
index a30b5b57d3618ea4fbd1863bdf9e927628c3dc72..155cd2cf5ba706b4ecb449541f9769bfb63fa6d3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -826,7 +826,6 @@ kvdb-memorydb = { version = "0.13.0" }
 kvdb-rocksdb = { version = "0.19.0" }
 kvdb-shared-tests = { version = "0.11.0" }
 landlock = { version = "0.3.0" }
-lazy_static = { version = "1.5.0" }
 libc = { version = "0.2.155" }
 libfuzzer-sys = { version = "0.4" }
 libp2p = { version = "0.52.4" }
diff --git a/cumulus/pallets/parachain-system/Cargo.toml b/cumulus/pallets/parachain-system/Cargo.toml
index 30a232f01b3e5ca82eab239626e2255a683972ee..66429625d5bfe6fd51ce795a21d59ffbdb2d0bd8 100644
--- a/cumulus/pallets/parachain-system/Cargo.toml
+++ b/cumulus/pallets/parachain-system/Cargo.toml
@@ -49,7 +49,6 @@ cumulus-primitives-proof-size-hostfunction = { workspace = true }
 [dev-dependencies]
 assert_matches = { workspace = true }
 hex-literal = { workspace = true, default-features = true }
-lazy_static = { workspace = true }
 trie-standardmap = { workspace = true }
 rand = { workspace = true, default-features = true }
 futures = { workspace = true }
diff --git a/cumulus/pallets/parachain-system/src/tests.rs b/cumulus/pallets/parachain-system/src/tests.rs
index 548231966e420f2c8a00642042657257e20f085d..23223627ebca2cf7bc197459bff9391edc7d4fd3 100755
--- a/cumulus/pallets/parachain-system/src/tests.rs
+++ b/cumulus/pallets/parachain-system/src/tests.rs
@@ -754,12 +754,8 @@ fn message_queue_chain() {
 #[test]
 #[cfg(not(feature = "runtime-benchmarks"))]
 fn receive_dmp() {
-	lazy_static::lazy_static! {
-		static ref MSG: InboundDownwardMessage = InboundDownwardMessage {
-			sent_at: 1,
-			msg: b"down".to_vec(),
-		};
-	}
+	static MSG: std::sync::LazyLock<InboundDownwardMessage> =
+		std::sync::LazyLock::new(|| InboundDownwardMessage { sent_at: 1, msg: b"down".to_vec() });
 
 	BlockTests::new()
 		.with_relay_sproof_builder(|_, relay_block_num, sproof| match relay_block_num {
@@ -771,14 +767,14 @@ fn receive_dmp() {
 		})
 		.with_inherent_data(|_, relay_block_num, data| match relay_block_num {
 			1 => {
-				data.downward_messages.push(MSG.clone());
+				data.downward_messages.push((*MSG).clone());
 			},
 			_ => unreachable!(),
 		})
 		.add(1, || {
 			HANDLED_DMP_MESSAGES.with(|m| {
 				let mut m = m.borrow_mut();
-				assert_eq!(&*m, &[(MSG.msg.clone())]);
+				assert_eq!(&*m, &[MSG.msg.clone()]);
 				m.clear();
 			});
 		});
diff --git a/cumulus/xcm/xcm-emulator/Cargo.toml b/cumulus/xcm/xcm-emulator/Cargo.toml
index 6924f11292d674978f6721a59ff53b7acc55da39..8598481fae7670a2b57e4e52b418753501827717 100644
--- a/cumulus/xcm/xcm-emulator/Cargo.toml
+++ b/cumulus/xcm/xcm-emulator/Cargo.toml
@@ -13,7 +13,6 @@ workspace = true
 codec = { workspace = true, default-features = true }
 paste = { workspace = true, default-features = true }
 log = { workspace = true }
-lazy_static = { workspace = true }
 impl-trait-for-tuples = { workspace = true }
 array-bytes = { workspace = true }
 
diff --git a/cumulus/xcm/xcm-emulator/src/lib.rs b/cumulus/xcm/xcm-emulator/src/lib.rs
index d393d4537734f90f871e0b2ea3204487deb8b674..bb2945dc267db568e44cdca2d525a47ca062c6cc 100644
--- a/cumulus/xcm/xcm-emulator/src/lib.rs
+++ b/cumulus/xcm/xcm-emulator/src/lib.rs
@@ -18,12 +18,16 @@ extern crate alloc;
 
 pub use array_bytes;
 pub use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};
-pub use lazy_static::lazy_static;
 pub use log;
 pub use paste;
 pub use std::{
-	any::type_name, collections::HashMap, error::Error, fmt, marker::PhantomData, ops::Deref,
-	sync::Mutex,
+	any::type_name,
+	collections::HashMap,
+	error::Error,
+	fmt,
+	marker::PhantomData,
+	ops::Deref,
+	sync::{LazyLock, Mutex},
 };
 
 // Substrate
@@ -443,10 +447,8 @@ macro_rules! __impl_test_ext_for_relay_chain {
 				= $crate::RefCell::new($crate::TestExternalities::new($genesis));
 		}
 
-		$crate::lazy_static! {
-			pub static ref $global_ext: $crate::Mutex<$crate::RefCell<$crate::HashMap<String, $crate::TestExternalities>>>
-				= $crate::Mutex::new($crate::RefCell::new($crate::HashMap::new()));
-		}
+		pub static $global_ext: $crate::LazyLock<$crate::Mutex<$crate::RefCell<$crate::HashMap<String, $crate::TestExternalities>>>>
+			= $crate::LazyLock::new(|| $crate::Mutex::new($crate::RefCell::new($crate::HashMap::new())));
 
 		impl<$network: $crate::Network> $crate::TestExt for $name<$network> {
 			fn build_new_ext(storage: $crate::Storage) -> $crate::TestExternalities {
@@ -478,10 +480,10 @@ macro_rules! __impl_test_ext_for_relay_chain {
 					v.take()
 				});
 
-				// Get TestExternality from lazy_static
+				// Get TestExternality from LazyLock
 				let global_ext_guard = $global_ext.lock().unwrap();
 
-				// Replace TestExternality in lazy_static by TestExternality from thread_local
+				// Replace TestExternality in LazyLock by TestExternality from thread_local
 				global_ext_guard.deref().borrow_mut().insert(id.to_string(), local_ext);
 			}
 
@@ -490,10 +492,10 @@ macro_rules! __impl_test_ext_for_relay_chain {
 
 				let mut global_ext_unlocked = false;
 
-				// Keep the mutex unlocked until TesExternality from lazy_static
+				// Keep the mutex unlocked until TesExternality from LazyLock
 				// has been updated
 				while !global_ext_unlocked {
-					// Get TesExternality from lazy_static
+					// Get TesExternality from LazyLock
 					let global_ext_result = $global_ext.try_lock();
 
 					if let Ok(global_ext_guard) = global_ext_result {
@@ -506,10 +508,10 @@ macro_rules! __impl_test_ext_for_relay_chain {
 					}
 				}
 
-				// Now that we know that lazy_static TestExt has been updated, we lock its mutex
+				// Now that we know that TestExt has been updated, we lock its mutex
 				let mut global_ext_guard = $global_ext.lock().unwrap();
 
-				// and set TesExternality from lazy_static into TesExternality for local_thread
+				// and set TesExternality from LazyLock into TesExternality for local_thread
 				let global_ext = global_ext_guard.deref();
 
 				$local_ext.with(|v| {
@@ -744,10 +746,8 @@ macro_rules! __impl_test_ext_for_parachain {
 				= $crate::RefCell::new($crate::TestExternalities::new($genesis));
 		}
 
-		$crate::lazy_static! {
-			pub static ref $global_ext: $crate::Mutex<$crate::RefCell<$crate::HashMap<String, $crate::TestExternalities>>>
-				= $crate::Mutex::new($crate::RefCell::new($crate::HashMap::new()));
-		}
+		pub static $global_ext: $crate::LazyLock<$crate::Mutex<$crate::RefCell<$crate::HashMap<String, $crate::TestExternalities>>>>
+			= $crate::LazyLock::new(|| $crate::Mutex::new($crate::RefCell::new($crate::HashMap::new())));
 
 		impl<$network: $crate::Network> $crate::TestExt for $name<$network> {
 			fn build_new_ext(storage: $crate::Storage) -> $crate::TestExternalities {
@@ -777,10 +777,10 @@ macro_rules! __impl_test_ext_for_parachain {
 					v.take()
 				});
 
-				// Get TestExternality from lazy_static
+				// Get TestExternality from LazyLock
 				let global_ext_guard = $global_ext.lock().unwrap();
 
-				// Replace TestExternality in lazy_static by TestExternality from thread_local
+				// Replace TestExternality in LazyLock by TestExternality from thread_local
 				global_ext_guard.deref().borrow_mut().insert(id.to_string(), local_ext);
 			}
 
@@ -789,10 +789,10 @@ macro_rules! __impl_test_ext_for_parachain {
 
 				let mut global_ext_unlocked = false;
 
-				// Keep the mutex unlocked until TesExternality from lazy_static
+				// Keep the mutex unlocked until TesExternality from LazyLock
 				// has been updated
 				while !global_ext_unlocked {
-					// Get TesExternality from lazy_static
+					// Get TesExternality from LazyLock
 					let global_ext_result = $global_ext.try_lock();
 
 					if let Ok(global_ext_guard) = global_ext_result {
@@ -805,10 +805,10 @@ macro_rules! __impl_test_ext_for_parachain {
 					}
 				}
 
-				// Now that we know that lazy_static TestExt has been updated, we lock its mutex
+				// Now that we know that TestExt has been updated, we lock its mutex
 				let mut global_ext_guard = $global_ext.lock().unwrap();
 
-				// and set TesExternality from lazy_static into TesExternality for local_thread
+				// and set TesExternality from LazyLock into TesExternality for local_thread
 				let global_ext = global_ext_guard.deref();
 
 				$local_ext.with(|v| {
diff --git a/polkadot/node/jaeger/Cargo.toml b/polkadot/node/jaeger/Cargo.toml
index 90a6c80e3d0bd3ab2567933bf94d89b7a00dc1e9..8615041bdaffedd83ebf8d77624eda107f31e253 100644
--- a/polkadot/node/jaeger/Cargo.toml
+++ b/polkadot/node/jaeger/Cargo.toml
@@ -11,7 +11,6 @@ workspace = true
 
 [dependencies]
 mick-jaeger = { workspace = true }
-lazy_static = { workspace = true }
 parking_lot = { workspace = true, default-features = true }
 polkadot-primitives = { workspace = true, default-features = true }
 polkadot-node-primitives = { workspace = true, default-features = true }
diff --git a/polkadot/node/jaeger/src/lib.rs b/polkadot/node/jaeger/src/lib.rs
index 7de4586068166f28a1d69d1787d2a960d298cf92..2ce5b8b6eb6d30ae69c789394b38bd9eb0ee5d63 100644
--- a/polkadot/node/jaeger/src/lib.rs
+++ b/polkadot/node/jaeger/src/lib.rs
@@ -61,11 +61,12 @@ use self::spans::TraceIdentifier;
 use sp_core::traits::SpawnNamed;
 
 use parking_lot::RwLock;
-use std::{result, sync::Arc};
+use std::{
+	result,
+	sync::{Arc, LazyLock},
+};
 
-lazy_static::lazy_static! {
-	static ref INSTANCE: RwLock<Jaeger> = RwLock::new(Jaeger::None);
-}
+static INSTANCE: LazyLock<RwLock<Jaeger>> = LazyLock::new(|| RwLock::new(Jaeger::None));
 
 /// Stateful convenience wrapper around [`mick_jaeger`].
 pub enum Jaeger {
diff --git a/polkadot/node/network/dispute-distribution/Cargo.toml b/polkadot/node/network/dispute-distribution/Cargo.toml
index ccf1b5daad7c3b7f3dd7d5525cb619781c01bce8..b4dcafe09eb60f9991af206d7c826d559f32d00a 100644
--- a/polkadot/node/network/dispute-distribution/Cargo.toml
+++ b/polkadot/node/network/dispute-distribution/Cargo.toml
@@ -38,5 +38,4 @@ sp-tracing = { workspace = true, default-features = true }
 sc-keystore = { workspace = true, default-features = true }
 futures-timer = { workspace = true }
 assert_matches = { workspace = true }
-lazy_static = { workspace = true }
 polkadot-primitives-test-helpers = { workspace = true }
diff --git a/polkadot/node/network/dispute-distribution/src/tests/mock.rs b/polkadot/node/network/dispute-distribution/src/tests/mock.rs
index ccc050233e8408d09e8cbe6261a44e682939d4b9..baa857e2eb6878a5342ef4f01b5d2aa8e3c8e777 100644
--- a/polkadot/node/network/dispute-distribution/src/tests/mock.rs
+++ b/polkadot/node/network/dispute-distribution/src/tests/mock.rs
@@ -19,12 +19,11 @@
 
 use std::{
 	collections::{HashMap, HashSet},
-	sync::Arc,
+	sync::{Arc, LazyLock},
 	time::Instant,
 };
 
 use async_trait::async_trait;
-use lazy_static::lazy_static;
 
 use polkadot_node_network_protocol::{authority_discovery::AuthorityDiscovery, PeerId};
 use sc_keystore::LocalKeystore;
@@ -60,64 +59,60 @@ pub const ALICE_INDEX: ValidatorIndex = ValidatorIndex(1);
 pub const BOB_INDEX: ValidatorIndex = ValidatorIndex(2);
 pub const CHARLIE_INDEX: ValidatorIndex = ValidatorIndex(3);
 
-lazy_static! {
-
 /// Mocked `AuthorityDiscovery` service.
-pub static ref MOCK_AUTHORITY_DISCOVERY: MockAuthorityDiscovery = MockAuthorityDiscovery::new();
+pub static MOCK_AUTHORITY_DISCOVERY: LazyLock<MockAuthorityDiscovery> =
+	LazyLock::new(|| MockAuthorityDiscovery::new());
 // Creating an innocent looking `SessionInfo` is really expensive in a debug build. Around
 // 700ms on my machine, We therefore cache those keys here:
-pub static ref MOCK_VALIDATORS_DISCOVERY_KEYS: HashMap<Sr25519Keyring, AuthorityDiscoveryId> =
-	MOCK_VALIDATORS
-	.iter()
-	.chain(MOCK_AUTHORITIES_NEXT_SESSION.iter())
-	.map(|v| (*v, v.public().into()))
-	.collect()
-;
-pub static ref FERDIE_DISCOVERY_KEY: AuthorityDiscoveryId =
-	MOCK_VALIDATORS_DISCOVERY_KEYS.get(&Sr25519Keyring::Ferdie).unwrap().clone();
-
-pub static ref MOCK_SESSION_INFO: SessionInfo =
-	SessionInfo {
-		validators: MOCK_VALIDATORS.iter().take(4).map(|k| k.public().into()).collect(),
-		discovery_keys: MOCK_VALIDATORS
+pub static MOCK_VALIDATORS_DISCOVERY_KEYS: LazyLock<HashMap<Sr25519Keyring, AuthorityDiscoveryId>> =
+	LazyLock::new(|| {
+		MOCK_VALIDATORS
 			.iter()
-			.map(|k| MOCK_VALIDATORS_DISCOVERY_KEYS.get(&k).unwrap().clone())
-			.collect(),
-		assignment_keys: vec![],
-		validator_groups: Default::default(),
-		n_cores: 0,
-		zeroth_delay_tranche_width: 0,
-		relay_vrf_modulo_samples: 0,
-		n_delay_tranches: 0,
-		no_show_slots: 0,
-		needed_approvals: 0,
-		active_validator_indices: vec![],
-		dispute_period: 6,
-		random_seed: [0u8; 32],
-	};
+			.chain(MOCK_AUTHORITIES_NEXT_SESSION.iter())
+			.map(|v| (*v, v.public().into()))
+			.collect()
+	});
+pub static FERDIE_DISCOVERY_KEY: LazyLock<AuthorityDiscoveryId> =
+	LazyLock::new(|| MOCK_VALIDATORS_DISCOVERY_KEYS.get(&Sr25519Keyring::Ferdie).unwrap().clone());
+
+pub static MOCK_SESSION_INFO: LazyLock<SessionInfo> = LazyLock::new(|| SessionInfo {
+	validators: MOCK_VALIDATORS.iter().take(4).map(|k| k.public().into()).collect(),
+	discovery_keys: MOCK_VALIDATORS
+		.iter()
+		.map(|k| MOCK_VALIDATORS_DISCOVERY_KEYS.get(&k).unwrap().clone())
+		.collect(),
+	assignment_keys: vec![],
+	validator_groups: Default::default(),
+	n_cores: 0,
+	zeroth_delay_tranche_width: 0,
+	relay_vrf_modulo_samples: 0,
+	n_delay_tranches: 0,
+	no_show_slots: 0,
+	needed_approvals: 0,
+	active_validator_indices: vec![],
+	dispute_period: 6,
+	random_seed: [0u8; 32],
+});
 
 /// `SessionInfo` for the second session. (No more validators, but two more authorities.
-pub static ref MOCK_NEXT_SESSION_INFO: SessionInfo =
-	SessionInfo {
-		discovery_keys:
-			MOCK_AUTHORITIES_NEXT_SESSION
-				.iter()
-				.map(|k| MOCK_VALIDATORS_DISCOVERY_KEYS.get(&k).unwrap().clone())
-				.collect(),
-		validators: Default::default(),
-		assignment_keys: vec![],
-		validator_groups: Default::default(),
-		n_cores: 0,
-		zeroth_delay_tranche_width: 0,
-		relay_vrf_modulo_samples: 0,
-		n_delay_tranches: 0,
-		no_show_slots: 0,
-		needed_approvals: 0,
-		active_validator_indices: vec![],
-		dispute_period: 6,
-		random_seed: [0u8; 32],
-	};
-}
+pub static MOCK_NEXT_SESSION_INFO: LazyLock<SessionInfo> = LazyLock::new(|| SessionInfo {
+	discovery_keys: MOCK_AUTHORITIES_NEXT_SESSION
+		.iter()
+		.map(|k| MOCK_VALIDATORS_DISCOVERY_KEYS.get(&k).unwrap().clone())
+		.collect(),
+	validators: Default::default(),
+	assignment_keys: vec![],
+	validator_groups: Default::default(),
+	n_cores: 0,
+	zeroth_delay_tranche_width: 0,
+	relay_vrf_modulo_samples: 0,
+	n_delay_tranches: 0,
+	no_show_slots: 0,
+	needed_approvals: 0,
+	active_validator_indices: vec![],
+	dispute_period: 6,
+	random_seed: [0u8; 32],
+});
 
 pub fn make_candidate_receipt(relay_parent: Hash) -> CandidateReceipt {
 	CandidateReceipt {
diff --git a/polkadot/node/network/gossip-support/Cargo.toml b/polkadot/node/network/gossip-support/Cargo.toml
index 83fdc7e26191e6b2568a9733b163a0f0239f6709..c8c19e5de070fdb981a484f78d5349161fd6d71c 100644
--- a/polkadot/node/network/gossip-support/Cargo.toml
+++ b/polkadot/node/network/gossip-support/Cargo.toml
@@ -39,5 +39,4 @@ polkadot-node-subsystem-test-helpers = { workspace = true }
 assert_matches = { workspace = true }
 async-trait = { workspace = true }
 parking_lot = { workspace = true, default-features = true }
-lazy_static = { workspace = true }
 quickcheck = { workspace = true, default-features = true }
diff --git a/polkadot/node/network/gossip-support/src/tests.rs b/polkadot/node/network/gossip-support/src/tests.rs
index 09622254f523e5605f8b203645819b2ea176dcfd..399f29db67da8c029cab8b151eff220e03398b68 100644
--- a/polkadot/node/network/gossip-support/src/tests.rs
+++ b/polkadot/node/network/gossip-support/src/tests.rs
@@ -16,12 +16,11 @@
 
 //! Unit tests for Gossip Support Subsystem.
 
-use std::{collections::HashSet, time::Duration};
+use std::{collections::HashSet, sync::LazyLock, time::Duration};
 
 use assert_matches::assert_matches;
 use async_trait::async_trait;
 use futures::{executor, future, Future};
-use lazy_static::lazy_static;
 use quickcheck::quickcheck;
 use rand::seq::SliceRandom as _;
 
@@ -56,39 +55,29 @@ const AUTHORITY_KEYRINGS: &[Sr25519Keyring] = &[
 	Sr25519Keyring::Ferdie,
 ];
 
-lazy_static! {
-	static ref AUTHORITIES: Vec<AuthorityDiscoveryId> =
-		AUTHORITY_KEYRINGS.iter().map(|k| k.public().into()).collect();
+static AUTHORITIES: LazyLock<Vec<AuthorityDiscoveryId>> =
+	LazyLock::new(|| AUTHORITY_KEYRINGS.iter().map(|k| k.public().into()).collect());
 
-	static ref AUTHORITIES_WITHOUT_US: Vec<AuthorityDiscoveryId> = {
-		let mut a = AUTHORITIES.clone();
-		a.pop(); // remove FERDIE.
-		a
-	};
-
-	static ref PAST_PRESENT_FUTURE_AUTHORITIES: Vec<AuthorityDiscoveryId> = {
-		(0..50)
-			.map(|_| AuthorityDiscoveryPair::generate().0.public())
-			.chain(AUTHORITIES.clone())
-			.collect()
-	};
+static AUTHORITIES_WITHOUT_US: LazyLock<Vec<AuthorityDiscoveryId>> = LazyLock::new(|| {
+	let mut a = AUTHORITIES.clone();
+	a.pop(); // remove FERDIE.
+	a
+});
 
-	// [2 6]
-	// [4 5]
-	// [1 3]
-	// [0  ]
+static PAST_PRESENT_FUTURE_AUTHORITIES: LazyLock<Vec<AuthorityDiscoveryId>> = LazyLock::new(|| {
+	(0..50)
+		.map(|_| AuthorityDiscoveryPair::generate().0.public())
+		.chain(AUTHORITIES.clone())
+		.collect()
+});
 
-	static ref EXPECTED_SHUFFLING: Vec<usize> = vec![6, 4, 0, 5, 2, 3, 1];
+static EXPECTED_SHUFFLING: LazyLock<Vec<usize>> = LazyLock::new(|| vec![6, 4, 0, 5, 2, 3, 1]);
 
-	static ref ROW_NEIGHBORS: Vec<ValidatorIndex> = vec![
-		ValidatorIndex::from(2),
-	];
+static ROW_NEIGHBORS: LazyLock<Vec<ValidatorIndex>> =
+	LazyLock::new(|| vec![ValidatorIndex::from(2)]);
 
-	static ref COLUMN_NEIGHBORS: Vec<ValidatorIndex> = vec![
-		ValidatorIndex::from(3),
-		ValidatorIndex::from(5),
-	];
-}
+static COLUMN_NEIGHBORS: LazyLock<Vec<ValidatorIndex>> =
+	LazyLock::new(|| vec![ValidatorIndex::from(3), ValidatorIndex::from(5)]);
 
 type VirtualOverseer =
 	polkadot_node_subsystem_test_helpers::TestSubsystemContextHandle<GossipSupportMessage>;
diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs
index 5b6bcdaa9d7ae3ab8c6fb70a831c8931379ef184..99d3a3e515b82e9a89127aa62817638ec2991877 100644
--- a/polkadot/node/primitives/src/lib.rs
+++ b/polkadot/node/primitives/src/lib.rs
@@ -105,7 +105,7 @@ pub const MAX_FINALITY_LAG: u32 = 500;
 /// Type of a session window size.
 ///
 /// We are not using `NonZeroU32` here because `expect` and `unwrap` are not yet const, so global
-/// constants of `SessionWindowSize` would require `lazy_static` in that case.
+/// constants of `SessionWindowSize` would require `LazyLock` in that case.
 ///
 /// See: <https://github.com/rust-lang/rust/issues/67441>
 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
diff --git a/polkadot/node/subsystem-util/Cargo.toml b/polkadot/node/subsystem-util/Cargo.toml
index a7157d1b5b7f46627665fb96d97f28c95fb105ec..3bd3892ba605cd1aae41cc14e484dba9ad939c2c 100644
--- a/polkadot/node/subsystem-util/Cargo.toml
+++ b/polkadot/node/subsystem-util/Cargo.toml
@@ -48,7 +48,6 @@ assert_matches = { workspace = true }
 futures = { features = ["thread-pool"], workspace = true }
 log = { workspace = true, default-features = true }
 polkadot-node-subsystem-test-helpers = { workspace = true }
-lazy_static = { workspace = true }
 polkadot-primitives-test-helpers = { workspace = true }
 kvdb-shared-tests = { workspace = true }
 tempfile = { workspace = true }
diff --git a/polkadot/node/zombienet-backchannel/Cargo.toml b/polkadot/node/zombienet-backchannel/Cargo.toml
index a9bf1f5ef093a905de7ca96c515a5a1b2c9cd17b..56c49a1ec305e17e949c71104bd659bdb5c379a6 100644
--- a/polkadot/node/zombienet-backchannel/Cargo.toml
+++ b/polkadot/node/zombienet-backchannel/Cargo.toml
@@ -16,7 +16,6 @@ tokio = { features = ["macros", "net", "rt-multi-thread", "sync"], workspace = t
 url = { workspace = true }
 tokio-tungstenite = { workspace = true }
 futures-util = { workspace = true, default-features = true }
-lazy_static = { workspace = true }
 codec = { features = ["derive"], workspace = true, default-features = true }
 reqwest = { features = ["rustls-tls"], workspace = true }
 thiserror = { workspace = true }
diff --git a/polkadot/node/zombienet-backchannel/src/lib.rs b/polkadot/node/zombienet-backchannel/src/lib.rs
index 9068b03399ca5180ec17a03669be3ea25fc3c5db..080dcf1c2b75dce91b9fd38af59fadfbd7dc63bb 100644
--- a/polkadot/node/zombienet-backchannel/src/lib.rs
+++ b/polkadot/node/zombienet-backchannel/src/lib.rs
@@ -21,7 +21,6 @@
 
 use codec;
 use futures_util::{SinkExt, StreamExt};
-use lazy_static::lazy_static;
 use serde::{Deserialize, Serialize};
 use std::{env, sync::Mutex};
 use tokio::sync::broadcast;
@@ -30,9 +29,7 @@ use tokio_tungstenite::{connect_async, tungstenite::protocol::Message};
 mod errors;
 use errors::BackchannelError;
 
-lazy_static! {
-	pub static ref ZOMBIENET_BACKCHANNEL: Mutex<Option<ZombienetBackchannel>> = Mutex::new(None);
-}
+pub static ZOMBIENET_BACKCHANNEL: Mutex<Option<ZombienetBackchannel>> = Mutex::new(None);
 
 #[derive(Debug)]
 pub struct ZombienetBackchannel {
diff --git a/prdoc/pr_5716.prdoc b/prdoc/pr_5716.prdoc
new file mode 100644
index 0000000000000000000000000000000000000000..a986662337295d7f1350422efb8c705cb59b6b1c
--- /dev/null
+++ b/prdoc/pr_5716.prdoc
@@ -0,0 +1,37 @@
+# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
+# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
+
+title: Replace `lazy_static` with `LazyLock`
+
+doc:
+  - audience: Node Dev
+    description: |
+      Replace all lazy_static usages with LazyLock from the Rust standard library. This will bring us less dependencies. 
+
+crates:
+  - name: sp-core
+    bump: patch
+  - name: sp-panic-handler
+    bump: patch
+  - name: sp-trie
+    bump: patch
+  - name: sc-utils
+    bump: major
+  - name: cumulus-pallet-parachain-system
+    bump: patch
+  - name: sp-consensus-beefy
+    bump: patch
+  - name: polkadot-node-primitives
+    bump: patch
+  - name: polkadot-node-jaeger
+    bump: patch
+  - name: frame-benchmarking-cli
+    bump: major
+  - name: sc-offchain
+    bump: patch
+  - name: polkadot-dispute-distribution
+    bump: patch
+  - name: polkadot-gossip-support
+    bump: patch
+  - name: xcm-emulator
+    bump: patch  
diff --git a/substrate/bin/node/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml
index 88ea908abc23a9f270268c6c7911837c2547256b..8c6556da682c109545b8004d2b346018344f7b3b 100644
--- a/substrate/bin/node/bench/Cargo.toml
+++ b/substrate/bin/node/bench/Cargo.toml
@@ -40,7 +40,6 @@ hash-db = { workspace = true, default-features = true }
 tempfile = { workspace = true }
 fs_extra = { workspace = true }
 rand = { features = ["small_rng"], workspace = true, default-features = true }
-lazy_static = { workspace = true }
 parity-db = { workspace = true }
 sc-transaction-pool = { workspace = true, default-features = true }
 sc-transaction-pool-api = { workspace = true, default-features = true }
diff --git a/substrate/bin/node/bench/src/trie.rs b/substrate/bin/node/bench/src/trie.rs
index 09ab405c03b23baed9217e50e8fb19e50fb18baf..402a186767eeb3203c045c89a58bc3bc27311b26 100644
--- a/substrate/bin/node/bench/src/trie.rs
+++ b/substrate/bin/node/bench/src/trie.rs
@@ -20,11 +20,14 @@
 
 use hash_db::Prefix;
 use kvdb::KeyValueDB;
-use lazy_static::lazy_static;
 use rand::Rng;
 use sp_state_machine::Backend as _;
 use sp_trie::{trie_types::TrieDBMutBuilderV1, TrieMut as _};
-use std::{borrow::Cow, collections::HashMap, sync::Arc};
+use std::{
+	borrow::Cow,
+	collections::HashMap,
+	sync::{Arc, LazyLock},
+};
 
 use node_primitives::Hash;
 
@@ -57,10 +60,8 @@ pub enum DatabaseSize {
 	Huge,
 }
 
-lazy_static! {
-	static ref KUSAMA_STATE_DISTRIBUTION: SizePool =
-		SizePool::from_histogram(crate::state_sizes::KUSAMA_STATE_DISTRIBUTION);
-}
+static KUSAMA_STATE_DISTRIBUTION: LazyLock<SizePool> =
+	LazyLock::new(|| SizePool::from_histogram(crate::state_sizes::KUSAMA_STATE_DISTRIBUTION));
 
 impl DatabaseSize {
 	/// Should be multiple of SAMPLE_SIZE!
diff --git a/substrate/client/offchain/Cargo.toml b/substrate/client/offchain/Cargo.toml
index 4b5b04cca627be105506ff63f7a81df8cbe45f9b..bbbe7018d1060e5e87ed94dca9b1afabab978cc9 100644
--- a/substrate/client/offchain/Cargo.toml
+++ b/substrate/client/offchain/Cargo.toml
@@ -22,7 +22,10 @@ codec = { features = ["derive"], workspace = true, default-features = true }
 fnv = { workspace = true }
 futures = { workspace = true }
 futures-timer = { workspace = true }
-hyperv14 = { features = ["http2", "stream"], workspace = true, default-features = true }
+hyperv14 = { features = [
+	"http2",
+	"stream",
+], workspace = true, default-features = true }
 hyper-rustls = { features = ["http2"], workspace = true }
 num_cpus = { workspace = true }
 once_cell = { workspace = true }
@@ -46,7 +49,6 @@ log = { workspace = true, default-features = true }
 
 [dev-dependencies]
 async-trait = { workspace = true }
-lazy_static = { workspace = true }
 tokio = { workspace = true, default-features = true }
 sc-block-builder = { workspace = true, default-features = true }
 sc-client-db = { default-features = true, workspace = true }
diff --git a/substrate/client/offchain/src/api/http.rs b/substrate/client/offchain/src/api/http.rs
index fda5728b0d03e5dd2445d7f88f85c6987f5bf399..73407b1359d772cb28071fa0ba2f6e35b8b47f00 100644
--- a/substrate/client/offchain/src/api/http.rs
+++ b/substrate/client/offchain/src/api/http.rs
@@ -763,14 +763,12 @@ mod tests {
 	use crate::api::timestamp;
 	use core::convert::Infallible;
 	use futures::{future, StreamExt};
-	use lazy_static::lazy_static;
 	use sp_core::offchain::{Duration, Externalities, HttpError, HttpRequestId, HttpRequestStatus};
+	use std::sync::LazyLock;
 
-	// Using lazy_static to avoid spawning lots of different SharedClients,
+	// Using LazyLock to avoid spawning lots of different SharedClients,
 	// as spawning a SharedClient is CPU-intensive and opens lots of fds.
-	lazy_static! {
-		static ref SHARED_CLIENT: SharedClient = SharedClient::new();
-	}
+	static SHARED_CLIENT: LazyLock<SharedClient> = LazyLock::new(|| SharedClient::new());
 
 	// Returns an `HttpApi` whose worker is ran in the background, and a `SocketAddr` to an HTTP
 	// server that runs in the background as well.
diff --git a/substrate/client/tracing/Cargo.toml b/substrate/client/tracing/Cargo.toml
index 09571610a3a60a8bc0e01bac83b1d9c4ee0e7d03..b8f5e40caf83b5c04d5823bb9ecefa0aa9b10bee 100644
--- a/substrate/client/tracing/Cargo.toml
+++ b/substrate/client/tracing/Cargo.toml
@@ -20,7 +20,6 @@ console = { workspace = true }
 is-terminal = { workspace = true }
 chrono = { workspace = true }
 codec = { workspace = true, default-features = true }
-lazy_static = { workspace = true }
 libc = { workspace = true }
 log = { workspace = true, default-features = true }
 parking_lot = { workspace = true, default-features = true }
@@ -29,7 +28,10 @@ serde = { workspace = true, default-features = true }
 thiserror = { workspace = true }
 tracing = { workspace = true, default-features = true }
 tracing-log = { workspace = true }
-tracing-subscriber = { workspace = true, features = ["env-filter", "parking_lot"] }
+tracing-subscriber = { workspace = true, features = [
+	"env-filter",
+	"parking_lot",
+] }
 sc-client-api = { workspace = true, default-features = true }
 sc-tracing-proc-macro = { workspace = true, default-features = true }
 sp-api = { workspace = true, default-features = true }
diff --git a/substrate/client/utils/Cargo.toml b/substrate/client/utils/Cargo.toml
index 6c3a2228952efa292fa101ceff94b2b17cc6a3fe..485261058d5902f115bef06307de69124259b163 100644
--- a/substrate/client/utils/Cargo.toml
+++ b/substrate/client/utils/Cargo.toml
@@ -16,7 +16,6 @@ workspace = true
 async-channel = { workspace = true }
 futures = { workspace = true }
 futures-timer = { workspace = true }
-lazy_static = { workspace = true }
 log = { workspace = true, default-features = true }
 parking_lot = { workspace = true, default-features = true }
 prometheus = { workspace = true }
diff --git a/substrate/client/utils/src/metrics.rs b/substrate/client/utils/src/metrics.rs
index 308e90cb25379d62fe02f1878a664ff44377c9df..9b6e1e47039e76c55fa1f7bde80bc64da206c7dc 100644
--- a/substrate/client/utils/src/metrics.rs
+++ b/substrate/client/utils/src/metrics.rs
@@ -18,42 +18,49 @@
 
 //! Metering primitives and globals
 
-use lazy_static::lazy_static;
 use prometheus::{
 	core::{AtomicU64, GenericCounter, GenericGauge},
 	Error as PrometheusError, Registry,
 };
+use std::sync::LazyLock;
 
 use prometheus::{
 	core::{GenericCounterVec, GenericGaugeVec},
 	Opts,
 };
 
-lazy_static! {
-	pub static ref TOKIO_THREADS_TOTAL: GenericCounter<AtomicU64> =
-		GenericCounter::new("substrate_tokio_threads_total", "Total number of threads created")
-			.expect("Creating of statics doesn't fail. qed");
-	pub static ref TOKIO_THREADS_ALIVE: GenericGauge<AtomicU64> =
-		GenericGauge::new("substrate_tokio_threads_alive", "Number of threads alive right now")
-			.expect("Creating of statics doesn't fail. qed");
-}
+pub static TOKIO_THREADS_TOTAL: LazyLock<GenericCounter<AtomicU64>> = LazyLock::new(|| {
+	GenericCounter::new("substrate_tokio_threads_total", "Total number of threads created")
+		.expect("Creating of statics doesn't fail. qed")
+});
 
-lazy_static! {
-	pub static ref UNBOUNDED_CHANNELS_COUNTER: GenericCounterVec<AtomicU64> = GenericCounterVec::new(
-		Opts::new(
-			"substrate_unbounded_channel_len",
-			"Items sent/received/dropped on each mpsc::unbounded instance"
-		),
-		&["entity", "action"], // name of channel, send|received|dropped
-	).expect("Creating of statics doesn't fail. qed");
-	pub static ref UNBOUNDED_CHANNELS_SIZE: GenericGaugeVec<AtomicU64> = GenericGaugeVec::new(
+pub static TOKIO_THREADS_ALIVE: LazyLock<GenericGauge<AtomicU64>> = LazyLock::new(|| {
+	GenericGauge::new("substrate_tokio_threads_alive", "Number of threads alive right now")
+		.expect("Creating of statics doesn't fail. qed")
+});
+
+pub static UNBOUNDED_CHANNELS_COUNTER: LazyLock<GenericCounterVec<AtomicU64>> =
+	LazyLock::new(|| {
+		GenericCounterVec::new(
+			Opts::new(
+				"substrate_unbounded_channel_len",
+				"Items sent/received/dropped on each mpsc::unbounded instance",
+			),
+			&["entity", "action"], // name of channel, send|received|dropped
+		)
+		.expect("Creating of statics doesn't fail. qed")
+	});
+
+pub static UNBOUNDED_CHANNELS_SIZE: LazyLock<GenericGaugeVec<AtomicU64>> = LazyLock::new(|| {
+	GenericGaugeVec::new(
 		Opts::new(
 			"substrate_unbounded_channel_size",
 			"Size (number of messages to be processed) of each mpsc::unbounded instance",
 		),
 		&["entity"], // name of channel
-	).expect("Creating of statics doesn't fail. qed");
-}
+	)
+	.expect("Creating of statics doesn't fail. qed")
+});
 
 pub static SENT_LABEL: &'static str = "send";
 pub static RECEIVED_LABEL: &'static str = "received";
diff --git a/substrate/primitives/consensus/beefy/Cargo.toml b/substrate/primitives/consensus/beefy/Cargo.toml
index 57ddab9a70ceacb430cdcf65fd2af1cfbc05ec77..13d80683c853da5db00efe896161158a2a06041a 100644
--- a/substrate/primitives/consensus/beefy/Cargo.toml
+++ b/substrate/primitives/consensus/beefy/Cargo.toml
@@ -28,7 +28,6 @@ sp-runtime = { workspace = true }
 sp-keystore = { workspace = true }
 sp-weights = { workspace = true }
 strum = { features = ["derive"], workspace = true }
-lazy_static = { optional = true, workspace = true }
 
 [dev-dependencies]
 array-bytes = { workspace = true, default-features = true }
@@ -38,7 +37,6 @@ w3f-bls = { features = ["std"], workspace = true, default-features = true }
 default = ["std"]
 std = [
 	"codec/std",
-	"dep:lazy_static",
 	"scale-info/std",
 	"serde/std",
 	"sp-api/std",
diff --git a/substrate/primitives/consensus/beefy/src/test_utils.rs b/substrate/primitives/consensus/beefy/src/test_utils.rs
index bd335ede489380541fe1b2c166d58f59e2a88614..4460bcefd45f92ad263e10128091a721e44080c1 100644
--- a/substrate/primitives/consensus/beefy/src/test_utils.rs
+++ b/substrate/primitives/consensus/beefy/src/test_utils.rs
@@ -26,7 +26,7 @@ use sp_core::{ecdsa, Pair};
 use sp_runtime::traits::{BlockNumber, Hash, Header as HeaderT};
 
 use codec::Encode;
-use std::{collections::HashMap, marker::PhantomData};
+use std::{collections::HashMap, marker::PhantomData, sync::LazyLock};
 use strum::IntoEnumIterator;
 
 /// Set of test accounts using [`crate::ecdsa_crypto`] types.
@@ -111,12 +111,15 @@ where
 	}
 }
 
-lazy_static::lazy_static! {
-	static ref PRIVATE_KEYS: HashMap<Keyring<ecdsa_crypto::AuthorityId>, ecdsa_crypto::Pair> =
-		Keyring::iter().map(|i| (i.clone(), i.pair())).collect();
-	static ref PUBLIC_KEYS: HashMap<Keyring<ecdsa_crypto::AuthorityId>, ecdsa_crypto::Public> =
-		PRIVATE_KEYS.iter().map(|(name, pair)| (name.clone(), sp_application_crypto::Pair::public(pair))).collect();
-}
+static PRIVATE_KEYS: LazyLock<HashMap<Keyring<ecdsa_crypto::AuthorityId>, ecdsa_crypto::Pair>> =
+	LazyLock::new(|| Keyring::iter().map(|i| (i.clone(), i.pair())).collect());
+static PUBLIC_KEYS: LazyLock<HashMap<Keyring<ecdsa_crypto::AuthorityId>, ecdsa_crypto::Public>> =
+	LazyLock::new(|| {
+		PRIVATE_KEYS
+			.iter()
+			.map(|(name, pair)| (name.clone(), sp_application_crypto::Pair::public(pair)))
+			.collect()
+	});
 
 impl From<Keyring<ecdsa_crypto::AuthorityId>> for ecdsa_crypto::Pair {
 	fn from(k: Keyring<ecdsa_crypto::AuthorityId>) -> Self {
diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml
index 51cbfa3bdfbe24210ee7d2805f52f928e73df54a..f6bc17bccacaf48354ad43dcd327c2577a35ad66 100644
--- a/substrate/primitives/core/Cargo.toml
+++ b/substrate/primitives/core/Cargo.toml
@@ -26,10 +26,14 @@ impl-serde = { optional = true, workspace = true }
 hash-db = { workspace = true }
 hash256-std-hasher = { workspace = true }
 bs58 = { optional = true, workspace = true }
-rand = { features = ["small_rng"], optional = true, workspace = true, default-features = true }
+rand = { features = [
+	"small_rng",
+], optional = true, workspace = true, default-features = true }
 substrate-bip39 = { workspace = true }
 # personal fork here as workaround for: https://github.com/rust-bitcoin/rust-bip39/pull/64
-bip39 = { package = "parity-bip39", version = "2.0.1", default-features = false, features = ["alloc"] }
+bip39 = { package = "parity-bip39", version = "2.0.1", default-features = false, features = [
+	"alloc",
+] }
 zeroize = { workspace = true }
 secrecy = { features = ["alloc"], workspace = true }
 parking_lot = { optional = true, workspace = true, default-features = true }
@@ -58,17 +62,21 @@ sp-runtime-interface = { workspace = true }
 # k256 crate, better portability, intended to be used in substrate-runtimes (no-std)
 k256 = { features = ["alloc", "ecdsa"], workspace = true }
 # secp256k1 crate, better performance, intended to be used on host side (std)
-secp256k1 = { features = ["alloc", "recovery"], optional = true, workspace = true }
+secp256k1 = { features = [
+	"alloc",
+	"recovery",
+], optional = true, workspace = true }
 
 # bls crypto
 w3f-bls = { optional = true, workspace = true }
 # bandersnatch crypto
-bandersnatch_vrfs = { git = "https://github.com/w3f/ring-vrf", rev = "0fef826", default-features = false, features = ["substrate-curves"], optional = true }
+bandersnatch_vrfs = { git = "https://github.com/w3f/ring-vrf", rev = "0fef826", default-features = false, features = [
+	"substrate-curves",
+], optional = true }
 
 [dev-dependencies]
 criterion = { workspace = true, default-features = true }
 serde_json = { workspace = true, default-features = true }
-lazy_static = { workspace = true }
 regex = { workspace = true }
 
 [[bench]]
diff --git a/substrate/primitives/core/fuzz/Cargo.toml b/substrate/primitives/core/fuzz/Cargo.toml
index 46dfe8d483b7468b06d3dccb5494e6c6ec8cefe0..b6ef395adf9ac9a9a2a44cb1aa208eb736049fe8 100644
--- a/substrate/primitives/core/fuzz/Cargo.toml
+++ b/substrate/primitives/core/fuzz/Cargo.toml
@@ -11,7 +11,6 @@ workspace = true
 cargo-fuzz = true
 
 [dependencies]
-lazy_static = { workspace = true }
 libfuzzer-sys = { workspace = true }
 regex = { workspace = true }
 
diff --git a/substrate/primitives/core/fuzz/fuzz_targets/fuzz_address_uri.rs b/substrate/primitives/core/fuzz/fuzz_targets/fuzz_address_uri.rs
index e2d9e2fc8b0822ae9d984683cdaaf71a97bd7c2e..ac84faf2d8986e47c713cf445ed11cf6b93480ea 100644
--- a/substrate/primitives/core/fuzz/fuzz_targets/fuzz_address_uri.rs
+++ b/substrate/primitives/core/fuzz/fuzz_targets/fuzz_address_uri.rs
@@ -24,11 +24,12 @@ extern crate sp_core;
 use libfuzzer_sys::fuzz_target;
 use regex::Regex;
 use sp_core::crypto::AddressUri;
+use std::sync::LazyLock;
 
-lazy_static::lazy_static! {
-	static ref SECRET_PHRASE_REGEX: Regex = Regex::new(r"^(?P<phrase>[a-zA-Z0-9 ]+)?(?P<path>(//?[^/]+)*)(///(?P<password>.*))?$")
-		.expect("constructed from known-good static value; qed");
-}
+static SECRET_PHRASE_REGEX: LazyLock<Regex> = LazyLock::new(|| {
+	Regex::new(r"^(?P<phrase>[a-zA-Z0-9 ]+)?(?P<path>(//?[^/]+)*)(///(?P<password>.*))?$")
+		.expect("constructed from known-good static value; qed")
+});
 
 fuzz_target!(|input: &str| {
 	let regex_result = SECRET_PHRASE_REGEX.captures(input);
diff --git a/substrate/primitives/core/src/address_uri.rs b/substrate/primitives/core/src/address_uri.rs
index bbe31b7553bd2b2304384934bdf9ee1928d63aa1..4877250cf3acd619b5ddee15768bdff83501cf56 100644
--- a/substrate/primitives/core/src/address_uri.rs
+++ b/substrate/primitives/core/src/address_uri.rs
@@ -196,11 +196,12 @@ impl<'a> AddressUri<'a> {
 mod tests {
 	use super::*;
 	use regex::Regex;
+	use std::sync::LazyLock;
 
-	lazy_static::lazy_static! {
-		static ref SECRET_PHRASE_REGEX: Regex = Regex::new(r"^(?P<phrase>[a-zA-Z0-9 ]+)?(?P<path>(//?[^/]+)*)(///(?P<password>.*))?$")
-			.expect("constructed from known-good static value; qed");
-	}
+	static SECRET_PHRASE_REGEX: LazyLock<Regex> = LazyLock::new(|| {
+		Regex::new(r"^(?P<phrase>[a-zA-Z0-9 ]+)?(?P<path>(//?[^/]+)*)(///(?P<password>.*))?$")
+			.expect("constructed from known-good static value; qed")
+	});
 
 	fn check_with_regex(input: &str) {
 		let regex_result = SECRET_PHRASE_REGEX.captures(input);
diff --git a/substrate/primitives/panic-handler/Cargo.toml b/substrate/primitives/panic-handler/Cargo.toml
index 395e788eb244e9a9ae3114bc04d35f184c2f7f3a..012fe08f7cd533416bd46f31bb06c45122b51ba6 100644
--- a/substrate/primitives/panic-handler/Cargo.toml
+++ b/substrate/primitives/panic-handler/Cargo.toml
@@ -18,5 +18,4 @@ targets = ["x86_64-unknown-linux-gnu"]
 
 [dependencies]
 backtrace = { workspace = true }
-lazy_static = { workspace = true }
 regex = { workspace = true }
diff --git a/substrate/primitives/panic-handler/src/lib.rs b/substrate/primitives/panic-handler/src/lib.rs
index e2a9bfa195a6672d13c472b115b3ca4ed4348325..c4a7eb8dc67c7cf8e4defcb5f60746a16d04cc40 100644
--- a/substrate/primitives/panic-handler/src/lib.rs
+++ b/substrate/primitives/panic-handler/src/lib.rs
@@ -31,6 +31,7 @@ use std::{
 	io::{self, Write},
 	marker::PhantomData,
 	panic::{self, PanicInfo},
+	sync::LazyLock,
 	thread,
 };
 
@@ -128,8 +129,9 @@ impl Drop for AbortGuard {
 
 // NOTE: When making any changes here make sure to also change this function in `sc-tracing`.
 fn strip_control_codes(input: &str) -> std::borrow::Cow<str> {
-	lazy_static::lazy_static! {
-		static ref RE: Regex = Regex::new(r#"(?x)
+	static RE: LazyLock<Regex> = LazyLock::new(|| {
+		Regex::new(
+			r#"(?x)
 			\x1b\[[^m]+m|        # VT100 escape codes
 			[
 			  \x00-\x09\x0B-\x1F # ASCII control codes / Unicode C0 control codes, except \n
@@ -138,8 +140,10 @@ fn strip_control_codes(input: &str) -> std::borrow::Cow<str> {
 			  \u{202A}-\u{202E}  # Unicode left-to-right / right-to-left control characters
 			  \u{2066}-\u{2069}  # Same as above
 			]
-		"#).expect("regex parsing doesn't fail; qed");
-	}
+		"#,
+		)
+		.expect("regex parsing doesn't fail; qed")
+	});
 
 	RE.replace_all(input, "")
 }
diff --git a/substrate/primitives/trie/Cargo.toml b/substrate/primitives/trie/Cargo.toml
index a28f29b01581380bd9435ec075db9e0970ce043e..7f27bb097290e06cee472a3ddfbfff5eb0783c09 100644
--- a/substrate/primitives/trie/Cargo.toml
+++ b/substrate/primitives/trie/Cargo.toml
@@ -24,7 +24,6 @@ harness = false
 ahash = { optional = true, workspace = true }
 codec = { workspace = true }
 hash-db = { workspace = true }
-lazy_static = { optional = true, workspace = true }
 memory-db = { workspace = true }
 nohash-hasher = { optional = true, workspace = true }
 parking_lot = { optional = true, workspace = true, default-features = true }
@@ -51,7 +50,6 @@ std = [
 	"ahash",
 	"codec/std",
 	"hash-db/std",
-	"lazy_static",
 	"memory-db/std",
 	"nohash-hasher",
 	"parking_lot",
diff --git a/substrate/primitives/trie/src/cache/shared_cache.rs b/substrate/primitives/trie/src/cache/shared_cache.rs
index e3ba94a2af7c1c9a4565169c85d6bb6053107a11..7f6da80fe95f13a2a828ba994d1bca1ffe445675 100644
--- a/substrate/primitives/trie/src/cache/shared_cache.rs
+++ b/substrate/primitives/trie/src/cache/shared_cache.rs
@@ -25,17 +25,15 @@ use schnellru::LruMap;
 use std::{
 	collections::{hash_map::Entry as SetEntry, HashMap},
 	hash::{BuildHasher, Hasher as _},
-	sync::Arc,
+	sync::{Arc, LazyLock},
 };
 use trie_db::{node::NodeOwned, CachedValue};
 
-lazy_static::lazy_static! {
-	static ref RANDOM_STATE: ahash::RandomState = {
-		use rand::Rng;
-		let mut rng = rand::thread_rng();
-		ahash::RandomState::generate_with(rng.gen(), rng.gen(), rng.gen(), rng.gen())
-	};
-}
+static RANDOM_STATE: LazyLock<ahash::RandomState> = LazyLock::new(|| {
+	use rand::Rng;
+	let mut rng = rand::thread_rng();
+	ahash::RandomState::generate_with(rng.gen(), rng.gen(), rng.gen(), rng.gen())
+});
 
 pub struct SharedNodeCacheLimiter {
 	/// The maximum size (in bytes) the cache can hold inline.
diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml
index 4e88e3360e3914a78d0bd8b71b8b55ab8bd22f8f..ee5522f5bc0466a46b7c17a150c9ceece3b46c91 100644
--- a/substrate/utils/frame/benchmarking-cli/Cargo.toml
+++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml
@@ -24,7 +24,6 @@ comfy-table = { workspace = true }
 handlebars = { workspace = true }
 Inflector = { workspace = true }
 itertools = { workspace = true }
-lazy_static = { workspace = true }
 linked-hash-map = { workspace = true }
 log = { workspace = true, default-features = true }
 rand = { features = ["small_rng"], workspace = true, default-features = true }
diff --git a/substrate/utils/frame/benchmarking-cli/src/machine/hardware.rs b/substrate/utils/frame/benchmarking-cli/src/machine/hardware.rs
index ee1d490b854790087953865fee76da76db221d5c..f542eb60520ed063e51f7226ab367f61cba44668 100644
--- a/substrate/utils/frame/benchmarking-cli/src/machine/hardware.rs
+++ b/substrate/utils/frame/benchmarking-cli/src/machine/hardware.rs
@@ -17,19 +17,17 @@
 
 //! Contains types to define hardware requirements.
 
-use lazy_static::lazy_static;
 use sc_sysinfo::Requirements;
+use std::sync::LazyLock;
 
-lazy_static! {
-	/// The hardware requirements as measured on reference hardware.
-	///
-	/// These values are provided by Parity, however it is possible
-	/// to use your own requirements if you are running a custom chain.
-	pub static ref SUBSTRATE_REFERENCE_HARDWARE: Requirements = {
-		let raw = include_bytes!("reference_hardware.json").as_slice();
-		serde_json::from_slice(raw).expect("Hardcoded data is known good; qed")
-	};
-}
+/// The hardware requirements as measured on reference hardware.
+///
+/// These values are provided by Parity, however it is possible
+/// to use your own requirements if you are running a custom chain.
+pub static SUBSTRATE_REFERENCE_HARDWARE: LazyLock<Requirements> = LazyLock::new(|| {
+	let raw = include_bytes!("reference_hardware.json").as_slice();
+	serde_json::from_slice(raw).expect("Hardcoded data is known good; qed")
+});
 
 #[cfg(test)]
 mod tests {