diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock
index 5affebc76fdeb5c3f33fd2f47769fa53e9c61662..5584971260cd132b222e773f24de4538cb29cb9e 100644
--- a/substrate/Cargo.lock
+++ b/substrate/Cargo.lock
@@ -2848,6 +2848,7 @@ dependencies = [
  "Inflector",
  "cfg-expr",
  "derive-syn-parse",
+ "expander",
  "frame-support-procedural-tools",
  "itertools",
  "macro_magic",
diff --git a/substrate/frame/support/procedural/Cargo.toml b/substrate/frame/support/procedural/Cargo.toml
index a2823463c5d6772471e9e4e00c55bf60b18808cc..f8c6b9393f08de7a00fff53c71ac899ef7f2ea0d 100644
--- a/substrate/frame/support/procedural/Cargo.toml
+++ b/substrate/frame/support/procedural/Cargo.toml
@@ -25,6 +25,7 @@ syn = { version = "2.0.16", features = ["full"] }
 frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" }
 proc-macro-warning = { version = "0.4.1", default-features = false }
 macro_magic = { version = "0.3.5", features = ["proc_support"] }
+expander = "2.0.0"
 
 [features]
 default = ["std"]
diff --git a/substrate/frame/support/procedural/src/construct_runtime/mod.rs b/substrate/frame/support/procedural/src/construct_runtime/mod.rs
index 958a10e7242dc7a5c29e874cf0aa31ea7d902273..9879a65d684a69439ff7e3676e89be93df08a069 100644
--- a/substrate/frame/support/procedural/src/construct_runtime/mod.rs
+++ b/substrate/frame/support/procedural/src/construct_runtime/mod.rs
@@ -178,7 +178,15 @@ pub fn construct_runtime(input: TokenStream) -> TokenStream {
 				.and_then(|_| construct_runtime_final_expansion(explicit_decl)),
 	};
 
-	res.unwrap_or_else(|e| e.to_compile_error()).into()
+	let res = res.unwrap_or_else(|e| e.to_compile_error());
+
+	let res = expander::Expander::new("construct_runtime")
+		.dry(std::env::var("FRAME_EXPAND").is_err())
+		.verbose(true)
+		.write_to_out_dir(res)
+		.expect("Does not fail because of IO in OUT_DIR; qed");
+
+	res.into()
 }
 
 /// When some pallet have implicit parts definition then the macro will expand into a macro call to