diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml
index 0793c31dbb87c01f95abd93f624453b03b9128dd..8ec3660307d42772298e07004c51f77d71e00c33 100644
--- a/.github/workflows/checks.yml
+++ b/.github/workflows/checks.yml
@@ -32,8 +32,8 @@ jobs:
       - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7
       - name: script
         run: |
-          forklift cargo clippy --all-targets --locked --workspace --quiet
-          forklift cargo clippy --all-targets --all-features --locked --workspace --quiet
+          cargo clippy --all-targets --locked --workspace --quiet
+          cargo clippy --all-targets --all-features --locked --workspace --quiet
   check-try-runtime:
     runs-on: ${{ needs.preflight.outputs.RUNNER }}
     needs: [preflight]
diff --git a/.github/workflows/misc-sync-templates.yml b/.github/workflows/misc-sync-templates.yml
index b5db0538569b06fb5c47e6c10eadbb85118d82db..7ff0705fe249aa9899add3baad1b148091b432ff 100644
--- a/.github/workflows/misc-sync-templates.yml
+++ b/.github/workflows/misc-sync-templates.yml
@@ -83,6 +83,12 @@ jobs:
           homepage = "https://paritytech.github.io/polkadot-sdk/"
 
           [workspace]
+          EOF
+
+          [ ${{ matrix.template }} != "solochain" ] && echo "# Leave out the node compilation from regular template usage." \
+            && echo "\"default-members\" = [\"pallets/template\", \"runtime\"]" >> Cargo.toml
+          [ ${{ matrix.template }} == "solochain" ] && echo "# The node isn't yet replaceable by Omni Node."
+          cat << EOF >> Cargo.toml
           members = [
               "node",
               "pallets/template",
diff --git a/Cargo.lock b/Cargo.lock
index 520b088f913cd72477d9d6a673e3a1ff54e37377..14ce58be7faa3b31b1b6385179e973ee4c95d5c6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3077,6 +3077,32 @@ version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
 
+[[package]]
+name = "cmd_lib"
+version = "1.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "371c15a3c178d0117091bd84414545309ca979555b1aad573ef591ad58818d41"
+dependencies = [
+ "cmd_lib_macros",
+ "env_logger 0.10.1",
+ "faccess",
+ "lazy_static",
+ "log",
+ "os_pipe",
+]
+
+[[package]]
+name = "cmd_lib_macros"
+version = "1.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb844bd05be34d91eb67101329aeba9d3337094c04fd8507d821db7ebb488eaf"
+dependencies = [
+ "proc-macro-error2",
+ "proc-macro2 1.0.86",
+ "quote 1.0.37",
+ "syn 2.0.82",
+]
+
 [[package]]
 name = "coarsetime"
 version = "0.1.23"
@@ -5389,18 +5415,18 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
 
 [[package]]
 name = "docify"
-version = "0.2.8"
+version = "0.2.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43a2f138ad521dc4a2ced1a4576148a6a610b4c5923933b062a263130a6802ce"
+checksum = "a772b62b1837c8f060432ddcc10b17aae1453ef17617a99bc07789252d2a5896"
 dependencies = [
  "docify_macros",
 ]
 
 [[package]]
 name = "docify_macros"
-version = "0.2.8"
+version = "0.2.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a081e51fb188742f5a7a1164ad752121abcb22874b21e2c3b0dd040c515fdad"
+checksum = "60e6be249b0a462a14784a99b19bf35a667bb5e09de611738bb7362fa4c95ff7"
 dependencies = [
  "common-path",
  "derive-syn-parse",
@@ -5899,6 +5925,17 @@ dependencies = [
  "once_cell",
 ]
 
+[[package]]
+name = "faccess"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59ae66425802d6a903e268ae1a08b8c38ba143520f227a205edf4e9c7e3e26d5"
+dependencies = [
+ "bitflags 1.3.2",
+ "libc",
+ "winapi",
+]
+
 [[package]]
 name = "fallible-iterator"
 version = "0.2.0"
@@ -10733,6 +10770,16 @@ dependencies = [
  "num-traits",
 ]
 
+[[package]]
+name = "os_pipe"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982"
+dependencies = [
+ "libc",
+ "windows-sys 0.59.0",
+]
+
 [[package]]
 name = "os_str_bytes"
 version = "6.5.1"
@@ -16771,6 +16818,28 @@ dependencies = [
  "version_check",
 ]
 
+[[package]]
+name = "proc-macro-error-attr2"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
+dependencies = [
+ "proc-macro2 1.0.86",
+ "quote 1.0.37",
+]
+
+[[package]]
+name = "proc-macro-error2"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
+dependencies = [
+ "proc-macro-error-attr2",
+ "proc-macro2 1.0.86",
+ "quote 1.0.37",
+ "syn 2.0.82",
+]
+
 [[package]]
 name = "proc-macro-hack"
 version = "0.5.20+deprecated"
@@ -23493,6 +23562,8 @@ name = "staging-chain-spec-builder"
 version = "1.6.1"
 dependencies = [
  "clap 4.5.13",
+ "cmd_lib",
+ "docify",
  "log",
  "sc-chain-spec",
  "serde",
@@ -26744,7 +26815,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
 dependencies = [
  "windows-core 0.52.0",
- "windows-targets 0.52.0",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -26762,7 +26833,7 @@ version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
 dependencies = [
- "windows-targets 0.52.0",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -26789,7 +26860,16 @@ version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows-targets 0.52.0",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -26824,17 +26904,18 @@ dependencies = [
 
 [[package]]
 name = "windows-targets"
-version = "0.52.0"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
 dependencies = [
- "windows_aarch64_gnullvm 0.52.0",
- "windows_aarch64_msvc 0.52.0",
- "windows_i686_gnu 0.52.0",
- "windows_i686_msvc 0.52.0",
- "windows_x86_64_gnu 0.52.0",
- "windows_x86_64_gnullvm 0.52.0",
- "windows_x86_64_msvc 0.52.0",
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
 ]
 
 [[package]]
@@ -26851,9 +26932,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.52.0"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
 
 [[package]]
 name = "windows_aarch64_msvc"
@@ -26869,9 +26950,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.52.0"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
 
 [[package]]
 name = "windows_i686_gnu"
@@ -26887,9 +26968,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.52.0"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
 
 [[package]]
 name = "windows_i686_msvc"
@@ -26905,9 +26992,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.52.0"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
 
 [[package]]
 name = "windows_x86_64_gnu"
@@ -26923,9 +27010,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.52.0"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
@@ -26941,9 +27028,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.52.0"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
 
 [[package]]
 name = "windows_x86_64_msvc"
@@ -26959,9 +27046,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.52.0"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
 name = "winnow"
diff --git a/Cargo.toml b/Cargo.toml
index e451529431ba74f0938eccd19f1522b2000799cf..f3042a8a3bdfa41a72951388553d28766a927744 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -556,7 +556,13 @@ default-members = [
 [workspace.lints.rust]
 suspicious_double_ref_op = { level = "allow", priority = 2 }
 # `substrate_runtime` is a common `cfg` condition name used in the repo.
-unexpected_cfgs = { level = "warn", check-cfg = ['cfg(build_opt_level, values("3"))', 'cfg(build_profile, values("debug", "release"))', 'cfg(enable_alloc_error_handler)', 'cfg(fuzzing)', 'cfg(substrate_runtime)'] }
+unexpected_cfgs = { level = "warn", check-cfg = [
+	'cfg(build_opt_level, values("3"))',
+	'cfg(build_profile, values("debug", "release"))',
+	'cfg(enable_alloc_error_handler)',
+	'cfg(fuzzing)',
+	'cfg(substrate_runtime)',
+] }
 
 [workspace.lints.clippy]
 all = { level = "allow", priority = 0 }
@@ -677,6 +683,7 @@ cid = { version = "0.9.0" }
 clap = { version = "4.5.13" }
 clap-num = { version = "1.0.2" }
 clap_complete = { version = "4.5.13" }
+cmd_lib = { version = "1.9.5" }
 coarsetime = { version = "0.1.22" }
 codec = { version = "3.6.12", default-features = false, package = "parity-scale-codec" }
 collectives-westend-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend" }
@@ -735,7 +742,7 @@ derive_more = { version = "0.99.17", default-features = false }
 digest = { version = "0.10.3", default-features = false }
 directories = { version = "5.0.1" }
 dlmalloc = { version = "0.2.4" }
-docify = { version = "0.2.8" }
+docify = { version = "0.2.9" }
 dyn-clonable = { version = "0.9.0" }
 dyn-clone = { version = "1.0.16" }
 ed25519-dalek = { version = "2.1", default-features = false }
@@ -1087,7 +1094,9 @@ polkavm-derive = "0.9.1"
 polkavm-linker = "0.9.2"
 portpicker = { version = "0.1.1" }
 pretty_assertions = { version = "1.3.0" }
-primitive-types = { version = "0.13.1", default-features = false, features = ["num-traits"] }
+primitive-types = { version = "0.13.1", default-features = false, features = [
+	"num-traits",
+] }
 proc-macro-crate = { version = "3.0.0" }
 proc-macro-warning = { version = "1.0.0", default-features = false }
 proc-macro2 = { version = "1.0.86" }
diff --git a/cumulus/polkadot-omni-node/README.md b/cumulus/polkadot-omni-node/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..d87b3b63c4071668a933d4ec28756dbfab43e08f
--- /dev/null
+++ b/cumulus/polkadot-omni-node/README.md
@@ -0,0 +1,65 @@
+# Polkadot Omni Node
+
+This is a white labeled implementation based on [`polkadot-omni-node-lib`](https://crates.io/crates/polkadot-omni-node-lib).
+It can be used to start a parachain node from a provided chain spec file. It is only compatible with runtimes that use block
+number `u32` and `Aura` consensus.
+
+## Installation
+
+Download & expose it via `PATH`:
+
+```bash
+# Download and set it on PATH.
+wget https://github.com/paritytech/polkadot-sdk/releases/download/<stable_release_tag>/polkadot-omni-node
+chmod +x polkadot-omni-node
+export PATH="$PATH:`pwd`"
+```
+
+Compile & install via `cargo`:
+
+```bash
+# Assuming ~/.cargo/bin is on the PATH
+cargo install polkadot-omni-node
+```
+
+## Usage
+
+A basic example for an Omni Node run starts from a runtime which implements the [`sp_genesis_builder::GenesisBuilder`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html).
+The interface mandates the runtime to expose a [`named-preset`](https://docs.rs/staging-chain-spec-builder/latest/staging_chain_spec_builder/#generate-chain-spec-using-runtime-provided-genesis-config-preset).
+
+### 1. Install chain-spec-builder
+
+**Note**: `chain-spec-builder` binary is published on [`crates.io`](https://crates.io) under
+[`staging-chain-spec-builder`](https://crates.io/crates/staging-chain-spec-builder) due to a name conflict.
+Install it with `cargo` like bellow :
+
+```bash
+cargo install staging-chain-spec-builder
+```
+
+### 2. Generate a chain spec
+
+Omni Node expects for the chain spec to contain parachains related fields like `relay_chain` and `para_id`.
+These fields can be introduced by running [`staging-chain-spec-builder`](https://crates.io/crates/staging-chain-spec-builder)
+with additional flags:
+
+```bash
+chain-spec-builder create --relay-chain <relay_chain_id> --para-id <id> -r <runtime.wasm> named-preset <preset_name>
+```
+
+### 3. Run Omni Node
+
+And now with the generated chain spec we can start Omni Node like so:
+
+```bash
+polkadot-omni-node --chain <chain_spec.json>
+```
+
+## Useful links
+
+* [`Omni Node Polkadot SDK Docs`](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/omni_node/index.html)
+* [`Chain Spec Genesis Reference Docs`](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/chain_spec_genesis/index.html)
+* [`polkadot-parachain-bin`](https://crates.io/crates/polkadot-parachain-bin)
+* [`polkadot-sdk-parachain-template`](https://github.com/paritytech/polkadot-sdk-parachain-template)
+* [`frame-omni-bencher`](https://crates.io/crates/frame-omni-bencher)
+* [`staging-chain-spec-builder`](https://crates.io/crates/staging-chain-spec-builder)
diff --git a/cumulus/polkadot-omni-node/lib/README.md b/cumulus/polkadot-omni-node/lib/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..5789a35a101693a3edfdce6c634aba6ba20eee5c
--- /dev/null
+++ b/cumulus/polkadot-omni-node/lib/README.md
@@ -0,0 +1,26 @@
+# Polkadot Omni Node Library
+
+Helper library that can be used to run a parachain node.
+
+## Overview
+
+This library can be used to run a parachain node while also customizing the chain specs
+that are supported by default by the `--chain-spec` argument of the node's `CLI`
+and the parameters of the runtime that is associated with each of these chain specs.
+
+## API
+
+The library exposes the possibility to provide a [`RunConfig`]. Through this structure
+2 optional configurations can be provided:
+- a chain spec loader (an implementation of [`chain_spec::LoadSpec`]): this can be used for
+  providing the chain specs that are supported by default by the `--chain-spec` argument of the
+  node's `CLI` and the actual chain config associated with each one.
+- a runtime resolver (an implementation of [`runtime::RuntimeResolver`]): this can be used for
+  providing the parameters of the runtime that is associated with each of the chain specs
+
+Apart from this, a [`CliConfig`] can also be provided, that can be used to customize some
+user-facing binary author, support url, etc.
+
+## Examples
+
+For an example, see the [`polkadot-parachain-bin`](https://crates.io/crates/polkadot-parachain-bin) crate.
diff --git a/cumulus/polkadot-omni-node/lib/src/lib.rs b/cumulus/polkadot-omni-node/lib/src/lib.rs
index 3f01f42111444342ef85e68996570df34e30a649..ccc1b542b253dd9e002baf3f62f23a6dc3b32f02 100644
--- a/cumulus/polkadot-omni-node/lib/src/lib.rs
+++ b/cumulus/polkadot-omni-node/lib/src/lib.rs
@@ -14,40 +14,7 @@
 // You should have received a copy of the GNU General Public License
 // along with Cumulus.  If not, see <http://www.gnu.org/licenses/>.
 
-//! # Polkadot Omni Node Library
-//!
-//! Helper library that can be used to run a parachain node.
-//!
-//! ## Overview
-//!
-//! This library can be used to run a parachain node while also customizing the chain specs
-//! that are supported by default by the `--chain-spec` argument of the node's `CLI`
-//! and the parameters of the runtime that is associated with each of these chain specs.
-//!
-//! ## API
-//!
-//! The library exposes the possibility to provide a [`RunConfig`]. Through this structure
-//! 2 optional configurations can be provided:
-//! - a chain spec loader (an implementation of [`chain_spec::LoadSpec`]): this can be used for
-//!   providing the chain specs that are supported by default by the `--chain-spec` argument of the
-//!   node's `CLI` and the actual chain config associated with each one.
-//! - a runtime resolver (an implementation of [`runtime::RuntimeResolver`]): this can be used for
-//!   providing the parameters of the runtime that is associated with each of the chain specs
-//!
-//! Apart from this, a [`CliConfig`] can also be provided, that can be used to customize some
-//! user-facing binary author, support url, etc.
-//!
-//! ## Examples
-//!
-//! For an example, see the [`polkadot-parachain-bin`](https://crates.io/crates/polkadot-parachain-bin) crate.
-//!
-//! ## Binary
-//!
-//! It can be used to start a parachain node from a provided chain spec file.
-//! It is only compatible with runtimes that use block number `u32` and `Aura` consensus.
-//!
-//! Example: `polkadot-omni-node --chain <chain_spec.json>`
-
+#![doc = include_str!("../README.md")]
 #![deny(missing_docs)]
 
 pub mod cli;
diff --git a/prdoc/pr_5954.prdoc b/prdoc/pr_5954.prdoc
new file mode 100644
index 0000000000000000000000000000000000000000..2c9efcce7a6a1e7432e18e01c034479a5080b18a
--- /dev/null
+++ b/prdoc/pr_5954.prdoc
@@ -0,0 +1,19 @@
+# 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: "templates: make node compilation optional"
+
+doc:
+  - audience: [Node Dev, Runtime Dev]
+    description: |
+      Node compilation for minimal and parachain templates is made optional, not part of the
+      templates `default-members` list. At the same time, we introduce OmniNode as alternative
+      to run the templates.
+
+crates:
+  - name: polkadot-omni-node
+    bump: patch
+  - name: polkadot-omni-node-lib
+    bump: patch
+  - name: staging-chain-spec-builder
+    bump: patch
diff --git a/substrate/bin/utils/chain-spec-builder/Cargo.toml b/substrate/bin/utils/chain-spec-builder/Cargo.toml
index f2fe8cb7e166c7b5f8a70e73582be0c9c173e2a1..b71e935a918f2e52a5a8324b011ec6891c68a510 100644
--- a/substrate/bin/utils/chain-spec-builder/Cargo.toml
+++ b/substrate/bin/utils/chain-spec-builder/Cargo.toml
@@ -21,15 +21,28 @@ path = "bin/main.rs"
 name = "chain-spec-builder"
 
 [lib]
-crate-type = ["rlib"]
+# Docs tests are not needed since the code samples that would be executed
+# are exercised already in the context of unit/integration tests, by virtue
+# of using a combination of encapsulation in functions + `docify::export`.
+# This is a practice we should use for new code samples if any.
+doctest = false
 
 [dependencies]
 clap = { features = ["derive"], workspace = true }
+docify = { workspace = true }
 log = { workspace = true, default-features = true }
-sc-chain-spec = { features = ["clap"], workspace = true, default-features = true }
+sc-chain-spec = { features = [
+	"clap",
+], workspace = true, default-features = true }
 serde_json = { workspace = true, default-features = true }
 serde = { workspace = true, default-features = true }
 sp-tracing = { workspace = true, default-features = true }
 
 [dev-dependencies]
 substrate-test-runtime = { workspace = true }
+cmd_lib = { workspace = true }
+docify = { workspace = true }
+
+[features]
+# `cargo build --feature=generate-readme` updates the `README.md` file.
+generate-readme = []
diff --git a/substrate/bin/utils/chain-spec-builder/README.docify.md b/substrate/bin/utils/chain-spec-builder/README.docify.md
new file mode 100644
index 0000000000000000000000000000000000000000..bb4db4c666e055779ca4dcd9b2b754df565f9b59
--- /dev/null
+++ b/substrate/bin/utils/chain-spec-builder/README.docify.md
@@ -0,0 +1,102 @@
+# Chain Spec Builder
+
+Substrate's chain spec builder utility.
+
+A chain-spec is short for `chain-specification`. See the [`sc-chain-spec`](https://crates.io/docs.rs/sc-chain-spec/latest/sc_chain_spec)
+for more information.
+
+_Note:_ this binary is a more flexible alternative to the `build-spec` subcommand, contained in typical Substrate-based nodes.
+This particular binary is capable of interacting with [`sp-genesis-builder`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/index.html)
+implementation of any provided runtime allowing to build chain-spec JSON files.
+
+See [`ChainSpecBuilderCmd`](https://docs.rs/staging-chain-spec-builder/6.0.0/staging_chain_spec_builder/enum.ChainSpecBuilderCmd.html)
+for a list of available commands.
+
+## Installation
+
+```bash
+cargo install staging-chain-spec-builder
+```
+
+_Note:_ `chain-spec-builder` binary is published on [crates.io](https://crates.io) under
+[`staging-chain-spec-builder`](https://crates.io/crates/staging-chain-spec-builder) due to a name conflict.
+
+## Usage
+
+Please note that below usage is backed by integration tests. The commands' examples are wrapped
+around by the `bash!(...)` macro calls.
+
+### Generate chains-spec using default config from runtime
+
+Query the default genesis config from the provided runtime WASM blob and use it in the chain spec.
+
+<!-- docify::embed!("tests/test.rs", cmd_create_default) -->
+
+_Note:_ [`GenesisBuilder::get_preset`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset)
+runtime function is called.
+
+### Display the runtime's default `GenesisConfig`
+
+<!-- docify::embed!("tests/test.rs", cmd_display_default_preset) -->
+
+_Note:_ [`GenesisBuilder::get_preset`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset)
+runtime function is called.
+
+### Display the `GenesisConfig` preset with given name
+
+<!-- docify::embed!("tests/test.rs", cmd_display_preset)-->
+
+_Note:_ [`GenesisBuilder::get_preset`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset)
+runtime function is called.
+
+### List the names of `GenesisConfig` presets provided by runtime
+
+<!-- docify::embed!("tests/test.rs", cmd_list_presets)-->
+
+_Note:_ [`GenesisBuilder::preset_names`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.preset_names)
+runtime function is called.
+
+### Generate chain spec using runtime provided genesis config preset
+
+Patch the runtime's default genesis config with the named preset provided by the runtime and generate the plain
+version of chain spec:
+
+<!-- docify::embed!("tests/test.rs", cmd_create_with_named_preset)-->
+
+_Note:_ [`GenesisBuilder::get_preset`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset)
+runtime functions are called.
+
+### Generate raw storage chain spec using genesis config patch
+
+Patch the runtime's default genesis config with provided `patch.json` and generate raw
+storage (`-s`) version of chain spec:
+
+<!-- docify::embed!("tests/test.rs", cmd_create_with_patch_raw)-->
+
+_Note:_ [`GenesisBuilder::get_preset`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset)
+and
+[`GenesisBuilder::build_state`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.build_state)
+runtime functions are called.
+
+### Generate raw storage chain spec using full genesis config
+
+Build the chain spec using provided full genesis config json file. No defaults will be used:
+
+<!-- docify::embed!("tests/test.rs", cmd_create_full_raw)-->
+
+_Note_: [`GenesisBuilder::build_state`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.build_state)
+runtime function is called.
+
+### Generate human readable chain spec using provided genesis config patch
+
+<!-- docify::embed!("tests/test.rs", cmd_create_with_patch_plain)-->
+
+### Generate human readable chain spec using provided full genesis config
+
+<!-- docify::embed!("tests/test.rs", cmd_create_full_plain)-->
+
+### Extra tools
+
+The `chain-spec-builder` provides also some extra utilities: [`VerifyCmd`](https://docs.rs/staging-chain-spec-builder/latest/staging_chain_spec_builder/struct.VerifyCmd.html),
+[`ConvertToRawCmd`](https://docs.rs/staging-chain-spec-builder/latest/staging_chain_spec_builder/struct.ConvertToRawCmd.html),
+[`UpdateCodeCmd`](https://docs.rs/staging-chain-spec-builder/latest/staging_chain_spec_builder/struct.UpdateCodeCmd.html).
diff --git a/substrate/bin/utils/chain-spec-builder/README.md b/substrate/bin/utils/chain-spec-builder/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..e03c710ce1b3627da21b083fdac7871980085fde
--- /dev/null
+++ b/substrate/bin/utils/chain-spec-builder/README.md
@@ -0,0 +1,140 @@
+# Chain Spec Builder
+
+Substrate's chain spec builder utility.
+
+A chain-spec is short for `chain-specification`. See the [`sc-chain-spec`](https://crates.io/docs.rs/sc-chain-spec/latest/sc_chain_spec)
+for more information.
+
+_Note:_ this binary is a more flexible alternative to the `build-spec` subcommand, contained in typical Substrate-based nodes.
+This particular binary is capable of interacting with [`sp-genesis-builder`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/index.html)
+implementation of any provided runtime allowing to build chain-spec JSON files.
+
+See [`ChainSpecBuilderCmd`](https://docs.rs/staging-chain-spec-builder/6.0.0/staging_chain_spec_builder/enum.ChainSpecBuilderCmd.html)
+for a list of available commands.
+
+## Installation
+
+```bash
+cargo install staging-chain-spec-builder
+```
+
+_Note:_ `chain-spec-builder` binary is published on [crates.io](https://crates.io) under
+[`staging-chain-spec-builder`](https://crates.io/crates/staging-chain-spec-builder) due to a name conflict.
+
+## Usage
+
+Please note that below usage is backed by integration tests. The commands' examples are wrapped
+around by the `bash!(...)` macro calls.
+
+### Generate chains-spec using default config from runtime
+
+Query the default genesis config from the provided runtime WASM blob and use it in the chain spec.
+
+```rust,ignore
+bash!(
+	chain-spec-builder -c "/dev/stdout" create -r $runtime_path default
+)
+```
+
+_Note:_ [`GenesisBuilder::get_preset`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset)
+runtime function is called.
+
+### Display the runtime's default `GenesisConfig`
+
+```rust,ignore
+bash!(
+	chain-spec-builder display-preset -r $runtime_path
+)
+```
+
+_Note:_ [`GenesisBuilder::get_preset`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset)
+runtime function is called.
+
+### Display the `GenesisConfig` preset with given name
+
+```rust,ignore
+fn cmd_display_preset(runtime_path: &str) -> String {
+	bash!(
+		chain-spec-builder display-preset -r $runtime_path -p "staging"
+	)
+}
+```
+
+_Note:_ [`GenesisBuilder::get_preset`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset)
+runtime function is called.
+
+### List the names of `GenesisConfig` presets provided by runtime
+
+```rust,ignore
+bash!(
+	chain-spec-builder list-presets -r $runtime_path
+)
+```
+
+_Note:_ [`GenesisBuilder::preset_names`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.preset_names)
+runtime function is called.
+
+### Generate chain spec using runtime provided genesis config preset
+
+Patch the runtime's default genesis config with the named preset provided by the runtime and generate the plain
+version of chain spec:
+
+```rust,ignore
+bash!(
+	chain-spec-builder -c "/dev/stdout" create --relay-chain "dev" --para-id 1000 -r $runtime_path named-preset "staging"
+)
+```
+
+_Note:_ [`GenesisBuilder::get_preset`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset)
+runtime functions are called.
+
+### Generate raw storage chain spec using genesis config patch
+
+Patch the runtime's default genesis config with provided `patch.json` and generate raw
+storage (`-s`) version of chain spec:
+
+```rust,ignore
+bash!(
+	chain-spec-builder -c "/dev/stdout" create -s -r $runtime_path patch "tests/input/patch.json"
+)
+```
+
+_Note:_ [`GenesisBuilder::get_preset`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset)
+and
+[`GenesisBuilder::build_state`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.build_state)
+runtime functions are called.
+
+### Generate raw storage chain spec using full genesis config
+
+Build the chain spec using provided full genesis config json file. No defaults will be used:
+
+```rust,ignore
+bash!(
+	chain-spec-builder -c "/dev/stdout" create -s -r $runtime_path full "tests/input/full.json"
+)
+```
+
+_Note_: [`GenesisBuilder::build_state`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.build_state)
+runtime function is called.
+
+### Generate human readable chain spec using provided genesis config patch
+
+```rust,ignore
+bash!(
+	chain-spec-builder -c "/dev/stdout" create -r $runtime_path patch "tests/input/patch.json"
+)
+```
+
+### Generate human readable chain spec using provided full genesis config
+
+```rust,ignore
+bash!(
+	chain-spec-builder -c "/dev/stdout" create -r $runtime_path full "tests/input/full.json"
+)
+```
+
+### Extra tools
+
+The `chain-spec-builder` provides also some extra utilities: [`VerifyCmd`](https://docs.rs/staging-chain-spec-builder/latest/staging_chain_spec_builder/struct.VerifyCmd.html),
+[`ConvertToRawCmd`](https://docs.rs/staging-chain-spec-builder/latest/staging_chain_spec_builder/struct.ConvertToRawCmd.html),
+[`UpdateCodeCmd`](https://docs.rs/staging-chain-spec-builder/latest/staging_chain_spec_builder/struct.UpdateCodeCmd.html).
diff --git a/substrate/bin/utils/chain-spec-builder/src/lib.rs b/substrate/bin/utils/chain-spec-builder/src/lib.rs
index 629edcf685685d73312fefe1a967a8585465cfaf..98ff480b8cebab0c58948771de37795b8957cb16 100644
--- a/substrate/bin/utils/chain-spec-builder/src/lib.rs
+++ b/substrate/bin/utils/chain-spec-builder/src/lib.rs
@@ -15,107 +15,9 @@
 
 // You should have received a copy of the GNU General Public License
 // along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-//! Substrate's chain spec builder utility.
-//!
-//! A chain-spec is short for `chain-configuration`. See the [`sc-chain-spec`] for more information.
-//!
-//! Note that this binary is analogous to the `build-spec` subcommand, contained in typical
-//! substrate-based nodes. This particular binary is capable of interacting with
-//! [`sp-genesis-builder`] implementation of any provided runtime allowing to build chain-spec JSON
-//! files.
-//!
-//! See [`ChainSpecBuilderCmd`] for a list of available commands.
-//!
-//! ## Typical use-cases.
-//! ##### Generate chains-spec using default config from runtime.
-//!
-//!	Query the default genesis config from the provided `runtime.wasm` and use it in the chain
-//! spec.
-//!	```bash
-//! chain-spec-builder create -r runtime.wasm default
-//! ```
-//! 
-//! _Note:_ [`GenesisBuilder::get_preset`][sp-genesis-builder-get-preset] runtime function is
-//! called.
-//!
-//!
-//! ##### Display the runtime's default `GenesisConfig`
-//!
-//! Displays the content of the runtime's default `GenesisConfig`
-//! ```bash
-//! chain-spec-builder display-preset -r runtime.wasm
-//! ```
-//! 
-//! _Note:_ [`GenesisBuilder::get_preset`][sp-genesis-builder-get-preset] runtime function is called.
-//!
-//! ##### Display the `GenesisConfig` preset with given name
-//!
-//! Displays the content of the `GenesisConfig` preset for given name
-//! ```bash
-//! chain-spec-builder display-preset -r runtime.wasm -p "staging"
-//! ```
-//! 
-//! _Note:_ [`GenesisBuilder::get_preset`][sp-genesis-builder-get-preset] runtime function is called.
-//!
-//! ##### List the names of `GenesisConfig` presets provided by runtime.
-//!
-//! Displays the names of the presets of `GenesisConfigs` provided by runtime.
-//! ```bash
-//! chain-spec-builder list-presets -r runtime.wasm
-//! ```
-//! 
-//! _Note:_ [`GenesisBuilder::preset_names`][sp-genesis-builder-list] runtime function is called.
-//!
-//! ##### Generate chain spec using runtime provided genesis config preset.
-//!
-//! Patch the runtime's default genesis config with the named preset provided by the runtime and generate the plain
-//! version of chain spec:
-//! ```bash
-//! chain-spec-builder create -r runtime.wasm named-preset "staging"
-//! ```
-//! 
-//! _Note:_ [`GenesisBuilder::get_preset`][sp-genesis-builder-get-preset] and [`GenesisBuilder::build_state`][sp-genesis-builder-build] runtime functions are called.
-//!
-//! ##### Generate raw storage chain spec using genesis config patch.
-//!
-//! Patch the runtime's default genesis config with provided `patch.json` and generate raw
-//! storage (`-s`) version of chain spec:
-//! ```bash
-//! chain-spec-builder create -s -r runtime.wasm patch patch.json
-//! ```
-//! 
-//! _Note:_ [`GenesisBuilder::build_state`][sp-genesis-builder-build] runtime function is called.
-//!
-//! ##### Generate raw storage chain spec using full genesis config.
-//!
-//! Build the chain spec using provided full genesis config json file. No defaults will be used:
-//! ```bash
-//! chain-spec-builder create -s -r runtime.wasm full full-genesis-config.json
-//! ```
-//! 
-//! _Note_: [`GenesisBuilder::build_state`][sp-genesis-builder-build] runtime function is called.
-//!
-//! ##### Generate human readable chain spec using provided genesis config patch.
-//! ```bash
-//! chain-spec-builder create -r runtime.wasm patch patch.json
-//! ```
-//! 
-//! ##### Generate human readable chain spec using provided full genesis config.
-//! ```bash
-//! chain-spec-builder create -r runtime.wasm full full-genesis-config.json
-//! ```
-//! 
-//! ##### Extra tools.
-//! The `chain-spec-builder` provides also some extra utilities: [`VerifyCmd`], [`ConvertToRawCmd`],
-//! [`UpdateCodeCmd`].
-//!
-//! [`sc-chain-spec`]: ../sc_chain_spec/index.html
-//! [`node-cli`]: ../node_cli/index.html
-//! [`sp-genesis-builder`]: ../sp_genesis_builder/index.html
-//! [sp-genesis-builder-build]: ../sp_genesis_builder/trait.GenesisBuilder.html#method.build_state
-//! [sp-genesis-builder-list]: ../sp_genesis_builder/trait.GenesisBuilder.html#method.preset_names
-//! [sp-genesis-builder-get-preset]: ../sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset
+#![doc = include_str!("../README.md")]
+#[cfg(feature = "generate-readme")]
+docify::compile_markdown!("README.docify.md", "README.md");
 
 use clap::{Parser, Subcommand};
 use sc_chain_spec::{
diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/create_with_full.json b/substrate/bin/utils/chain-spec-builder/tests/expected/create_with_full.json
index 6d127b6c0aca09fce0924291b5a5615b302b443f..10071670179abe09e4ee431d2b5538f2eacc860d 100644
--- a/substrate/bin/utils/chain-spec-builder/tests/expected/create_with_full.json
+++ b/substrate/bin/utils/chain-spec-builder/tests/expected/create_with_full.json
@@ -16,9 +16,18 @@
       "config": {
         "babe": {
           "authorities": [
-            "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
-            "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL",
-            "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b"
+            [
+              "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
+              1
+            ],
+            [
+              "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL",
+              1
+            ],
+            [
+              "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b",
+              1
+            ]
           ],
           "epochConfig": {
             "allowed_slots": "PrimaryAndSecondaryVRFSlots",
diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_default.json b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_default.json
new file mode 100644
index 0000000000000000000000000000000000000000..203b6716cb26883a31ff3c90500f0d0d810dc78f
--- /dev/null
+++ b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_default.json
@@ -0,0 +1,36 @@
+{
+  "name": "Custom",
+  "id": "custom",
+  "chainType": "Live",
+  "bootNodes": [],
+  "telemetryEndpoints": null,
+  "protocolId": null,
+  "properties": {
+    "tokenDecimals": 12,
+    "tokenSymbol": "UNIT"
+  },
+  "codeSubstitutes": {},
+  "genesis": {
+    "runtimeGenesis": {
+      "config": {
+        "babe": {
+          "authorities": [],
+          "epochConfig": {
+            "allowed_slots": "PrimaryAndSecondaryVRFSlots",
+            "c": [
+              1,
+              4
+            ]
+          }
+        },
+        "balances": {
+          "balances": []
+        },
+        "substrateTest": {
+          "authorities": []
+        },
+        "system": {}
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_full_plain.json b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_full_plain.json
new file mode 100644
index 0000000000000000000000000000000000000000..26868c3241a192c7b9b2b257ef5b6ae962839e70
--- /dev/null
+++ b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_full_plain.json
@@ -0,0 +1,66 @@
+{
+  "name": "Custom",
+  "id": "custom",
+  "chainType": "Live",
+  "bootNodes": [],
+  "telemetryEndpoints": null,
+  "protocolId": null,
+  "properties": {
+    "tokenDecimals": 12,
+    "tokenSymbol": "UNIT"
+  },
+  "codeSubstitutes": {},
+  "genesis": {
+    "runtimeGenesis": {
+      "config": {
+        "babe": {
+          "authorities": [
+            [
+              "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
+              1
+            ],
+            [
+              "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL",
+              1
+            ],
+            [
+              "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b",
+              1
+            ]
+          ],
+          "epochConfig": {
+            "allowed_slots": "PrimaryAndSecondaryVRFSlots",
+            "c": [
+              2,
+              4
+            ]
+          }
+        },
+        "balances": {
+          "balances": [
+            [
+              "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
+              2000000000000000
+            ],
+            [
+              "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y",
+              2000000000000000
+            ],
+            [
+              "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b",
+              5000000000000000
+            ]
+          ]
+        },
+        "substrateTest": {
+          "authorities": [
+            "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
+            "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL",
+            "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b"
+          ]
+        },
+        "system": {}
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_full_raw.json b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_full_raw.json
new file mode 100644
index 0000000000000000000000000000000000000000..523a266fc439269936a2cbfe2abbfab28095440f
--- /dev/null
+++ b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_full_raw.json
@@ -0,0 +1,39 @@
+{
+  "name": "Custom",
+  "id": "custom",
+  "chainType": "Live",
+  "bootNodes": [],
+  "telemetryEndpoints": null,
+  "protocolId": null,
+  "properties": {
+    "tokenDecimals": 12,
+    "tokenSymbol": "UNIT"
+  },
+  "codeSubstitutes": {},
+  "genesis": {
+    "raw": {
+      "top": {
+        "0x00771836bebdd29870ff246d305c578c4e7b9012096b41c4eb3aaf947f6ea429": "0x0000",
+        "0x00771836bebdd29870ff246d305c578c5e0621c4869aa60c02be9adcc98a0d1d": "0x0cd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d1cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c186e1bafbb1430668c95d89b77217a402a74f64c3e103137b69e95e4b6e06b1e",
+        "0x1cb6f36e027abb2091cfb5110ab5087f4e7b9012096b41c4eb3aaf947f6ea429": "0x0000",
+        "0x1cb6f36e027abb2091cfb5110ab5087f5e0621c4869aa60c02be9adcc98a0d1d": "0x0cd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01000000000000001cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c0100000000000000186e1bafbb1430668c95d89b77217a402a74f64c3e103137b69e95e4b6e06b1e0100000000000000",
+        "0x1cb6f36e027abb2091cfb5110ab5087f66e8f035c8adbe7f1547b43c51e6f8a4": "0x00000000",
+        "0x1cb6f36e027abb2091cfb5110ab5087faacf00b9b41fda7a9268821c2a2b3e4c": "0x0cd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01000000000000001cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c0100000000000000186e1bafbb1430668c95d89b77217a402a74f64c3e103137b69e95e4b6e06b1e0100000000000000",
+        "0x1cb6f36e027abb2091cfb5110ab5087fdc6b171b77304263c292cc3ea5ed31ef": "0x0200000000000000040000000000000002",
+        "0x26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429": "0x0000",
+        "0x26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710": "0x01",
+        "0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc": "0x4545454545454545454545454545454545454545454545454545454545454545",
+        "0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746bb1bdbcacd6ac9340000000000000000": "0x4545454545454545454545454545454545454545454545454545454545454545",
+        "0x26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439": "0x01",
+        "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da92c2a60ec6dd16cd8ab911865ecf7555b186e1bafbb1430668c95d89b77217a402a74f64c3e103137b69e95e4b6e06b1e": "0x00000000000000000000000001000000000000000080e03779c311000000000000000000000000000000000000000000000000000000000000000080",
+        "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94f9aea1afa791265fae359272badc1cf8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48": "0x000000000000000000000000010000000000000000008d49fd1a07000000000000000000000000000000000000000000000000000000000000000080",
+        "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9b0edae20838083f2cde1c4080db8cf8090b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22": "0x000000000000000000000000010000000000000000008d49fd1a07000000000000000000000000000000000000000000000000000000000000000080",
+        "0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0x0000",
+        "0x3a65787472696e7369635f696e646578": "0x00000000",
+        "0xc2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429": "0x0100",
+        "0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80": "0x0080faca73f91f00"
+      },
+      "childrenDefault": {}
+    }
+  }
+}
diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_with_named_preset_staging.json b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_with_named_preset_staging.json
new file mode 100644
index 0000000000000000000000000000000000000000..5cf51554b2cba8d9456f31a20159addc9f9983e5
--- /dev/null
+++ b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_with_named_preset_staging.json
@@ -0,0 +1,39 @@
+{
+  "bootNodes": [],
+  "chainType": "Live",
+  "codeSubstitutes": {},
+  "genesis": {
+    "runtimeGenesis": {
+      "patch": {
+        "balances": {
+          "balances": [
+            [
+              "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
+              1000000000000000
+            ],
+            [
+              "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y",
+              1000000000000000
+            ]
+          ]
+        },
+        "substrateTest": {
+          "authorities": [
+            "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
+            "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL"
+          ]
+        }
+      }
+    }
+  },
+  "id": "custom",
+  "name": "Custom",
+  "para_id": 1000,
+  "properties": {
+    "tokenDecimals": 12,
+    "tokenSymbol": "UNIT"
+  },
+  "protocolId": null,
+  "relay_chain": "dev",
+  "telemetryEndpoints": null
+}
\ No newline at end of file
diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_with_patch_plain.json b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_with_patch_plain.json
new file mode 100644
index 0000000000000000000000000000000000000000..b243534c0d61f5f63959065b450cc1870631272a
--- /dev/null
+++ b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_with_patch_plain.json
@@ -0,0 +1,42 @@
+{
+  "name": "Custom",
+  "id": "custom",
+  "chainType": "Live",
+  "bootNodes": [],
+  "telemetryEndpoints": null,
+  "protocolId": null,
+  "properties": {
+    "tokenDecimals": 12,
+    "tokenSymbol": "UNIT"
+  },
+  "codeSubstitutes": {},
+  "genesis": {
+    "runtimeGenesis": {
+      "patch": {
+        "balances": {
+          "balances": [
+            [
+              "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
+              1000000000000000
+            ],
+            [
+              "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y",
+              1000000000000000
+            ],
+            [
+              "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b",
+              5000000000000000
+            ]
+          ]
+        },
+        "substrateTest": {
+          "authorities": [
+            "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
+            "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL",
+            "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b"
+          ]
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_with_patch_raw.json b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_with_patch_raw.json
new file mode 100644
index 0000000000000000000000000000000000000000..c4ac1cbe8ea197c125a88ccbfefa8b3fda06644e
--- /dev/null
+++ b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_with_patch_raw.json
@@ -0,0 +1,37 @@
+{
+  "name": "Custom",
+  "id": "custom",
+  "chainType": "Live",
+  "bootNodes": [],
+  "telemetryEndpoints": null,
+  "protocolId": null,
+  "properties": {
+    "tokenDecimals": 12,
+    "tokenSymbol": "UNIT"
+  },
+  "codeSubstitutes": {},
+  "genesis": {
+    "raw": {
+      "top": {
+        "0x00771836bebdd29870ff246d305c578c4e7b9012096b41c4eb3aaf947f6ea429": "0x0000",
+        "0x00771836bebdd29870ff246d305c578c5e0621c4869aa60c02be9adcc98a0d1d": "0x0cd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d1cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c186e1bafbb1430668c95d89b77217a402a74f64c3e103137b69e95e4b6e06b1e",
+        "0x1cb6f36e027abb2091cfb5110ab5087f4e7b9012096b41c4eb3aaf947f6ea429": "0x0000",
+        "0x1cb6f36e027abb2091cfb5110ab5087f66e8f035c8adbe7f1547b43c51e6f8a4": "0x00000000",
+        "0x1cb6f36e027abb2091cfb5110ab5087fdc6b171b77304263c292cc3ea5ed31ef": "0x0100000000000000040000000000000002",
+        "0x26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429": "0x0000",
+        "0x26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710": "0x01",
+        "0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc": "0x4545454545454545454545454545454545454545454545454545454545454545",
+        "0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746bb1bdbcacd6ac9340000000000000000": "0x4545454545454545454545454545454545454545454545454545454545454545",
+        "0x26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439": "0x01",
+        "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da92c2a60ec6dd16cd8ab911865ecf7555b186e1bafbb1430668c95d89b77217a402a74f64c3e103137b69e95e4b6e06b1e": "0x00000000000000000000000001000000000000000080e03779c311000000000000000000000000000000000000000000000000000000000000000080",
+        "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94f9aea1afa791265fae359272badc1cf8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48": "0x00000000000000000000000001000000000000000080c6a47e8d03000000000000000000000000000000000000000000000000000000000000000080",
+        "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9b0edae20838083f2cde1c4080db8cf8090b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22": "0x00000000000000000000000001000000000000000080c6a47e8d03000000000000000000000000000000000000000000000000000000000000000080",
+        "0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0x0000",
+        "0x3a65787472696e7369635f696e646578": "0x00000000",
+        "0xc2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429": "0x0100",
+        "0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80": "0x00806d8176de1800"
+      },
+      "childrenDefault": {}
+    }
+  }
+}
diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/doc/display_preset.json b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/display_preset.json
new file mode 100644
index 0000000000000000000000000000000000000000..6aa6799af771d197636dea3b3add454150cc2c4c
--- /dev/null
+++ b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/display_preset.json
@@ -0,0 +1 @@
+{"babe":{"authorities":[],"epochConfig":{"allowed_slots":"PrimaryAndSecondaryVRFSlots","c":[1,4]}},"balances":{"balances":[]},"substrateTest":{"authorities":[]},"system":{}}
diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/doc/display_preset_staging.json b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/display_preset_staging.json
new file mode 100644
index 0000000000000000000000000000000000000000..b0c8e40c23a9796a1206206da456e2c660154697
--- /dev/null
+++ b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/display_preset_staging.json
@@ -0,0 +1 @@
+{"balances":{"balances":[["5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",1000000000000000],["5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y",1000000000000000]]},"substrateTest":{"authorities":["5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY","5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL"]}}
diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/doc/list_presets.json b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/list_presets.json
new file mode 100644
index 0000000000000000000000000000000000000000..882462391888962cea1bf2cb527b2e45a62101a9
--- /dev/null
+++ b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/list_presets.json
@@ -0,0 +1 @@
+{"presets":["foobar","staging"]}
diff --git a/substrate/bin/utils/chain-spec-builder/tests/input/full.json b/substrate/bin/utils/chain-spec-builder/tests/input/full.json
index f05e3505a2bb662042483c32aa6210fc74ba3124..e34aede52cbe5dc8a2e1d9b474354532519e6ecf 100644
--- a/substrate/bin/utils/chain-spec-builder/tests/input/full.json
+++ b/substrate/bin/utils/chain-spec-builder/tests/input/full.json
@@ -1,9 +1,9 @@
 {
   "babe": {
     "authorities": [
-      "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
-      "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL",
-      "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b"
+      ["5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", 1],
+      ["5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", 1],
+      ["5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b", 1]
     ],
     "epochConfig": {
       "allowed_slots": "PrimaryAndSecondaryVRFSlots",
diff --git a/substrate/bin/utils/chain-spec-builder/tests/test.rs b/substrate/bin/utils/chain-spec-builder/tests/test.rs
index f553f05f20a049aecaab7e06d86e01d3685a326e..5ac687d75fd4454e1e2452e0b001bc435279efd9 100644
--- a/substrate/bin/utils/chain-spec-builder/tests/test.rs
+++ b/substrate/bin/utils/chain-spec-builder/tests/test.rs
@@ -19,7 +19,10 @@
 use std::fs::File;
 
 use clap::Parser;
+
+use cmd_lib::spawn_with_output;
 use sc_chain_spec::update_code_in_json_chain_spec;
+use serde_json::{from_reader, from_str, Value};
 use staging_chain_spec_builder::ChainSpecBuilder;
 
 // note: the runtime path will not be read, runtime code will be set directly, to avoid hassle with
@@ -28,6 +31,44 @@ const DUMMY_PATH: &str = "fake-runtime-path";
 
 const OUTPUT_FILE: &str = "/tmp/chain_spec_builder.test_output_file.json";
 
+// Used for running commands visually pleasing in doc tests.
+macro_rules! bash(
+	( chain-spec-builder $($a:tt)* ) => {{
+		let bin_path = env!("CARGO_BIN_EXE_chain-spec-builder");
+		spawn_with_output!(
+			$bin_path $($a)*
+		)
+		.expect("a process running. qed")
+		.wait_with_output()
+		.expect("to get output. qed.")
+	}}
+);
+
+// Used specifically in docs tests.
+fn doc_assert(output: String, expected_output_path: &str, remove_code: bool) {
+	let expected: Value =
+		from_reader(File::open(expected_output_path).unwrap()).expect("a valid JSON. qed.");
+	let output = if remove_code {
+		let mut output: Value = from_str(output.as_str()).expect("a valid JSON. qed.");
+		// Remove code sections gracefully for both `plain` & `raw`.
+		output
+			.get_mut("genesis")
+			.and_then(|inner| inner.get_mut("runtimeGenesis"))
+			.and_then(|inner| inner.as_object_mut())
+			.and_then(|inner| inner.remove("code"));
+		output
+			.get_mut("genesis")
+			.and_then(|inner| inner.get_mut("raw"))
+			.and_then(|inner| inner.get_mut("top"))
+			.and_then(|inner| inner.as_object_mut())
+			.and_then(|inner| inner.remove("0x3a636f6465"));
+		output
+	} else {
+		from_str::<Value>(output.as_str()).expect("a valid JSON. qed.")
+	};
+	assert_eq!(output, expected);
+}
+
 /// Asserts that the JSON in output file matches the JSON in expected file.
 ///
 /// This helper function reads the JSON content from the file at `OUTPUT_FILE + suffix` path. If the
@@ -192,3 +233,165 @@ fn test_add_code_substitute() {
 	builder.run().unwrap();
 	assert_output_eq_expected(true, SUFFIX, "tests/expected/add_code_substitute.json");
 }
+
+#[docify::export_content]
+fn cmd_create_default(runtime_path: &str) -> String {
+	bash!(
+		chain-spec-builder -c "/dev/stdout" create -r $runtime_path default
+	)
+}
+
+#[test]
+fn create_default() {
+	doc_assert(
+		cmd_create_default(
+			substrate_test_runtime::WASM_BINARY_PATH.expect("to be a valid path. qed"),
+		),
+		"tests/expected/doc/create_default.json",
+		true,
+	);
+}
+
+#[docify::export_content]
+fn cmd_display_default_preset(runtime_path: &str) -> String {
+	bash!(
+		chain-spec-builder display-preset -r $runtime_path
+	)
+}
+
+#[test]
+fn display_default_preset() {
+	doc_assert(
+		cmd_display_default_preset(
+			substrate_test_runtime::WASM_BINARY_PATH.expect("to be a valid path. qed."),
+		),
+		"tests/expected/doc/display_preset.json",
+		false,
+	);
+}
+
+#[docify::export]
+fn cmd_display_preset(runtime_path: &str) -> String {
+	bash!(
+		chain-spec-builder display-preset -r $runtime_path -p "staging"
+	)
+}
+
+#[test]
+fn display_preset() {
+	doc_assert(
+		cmd_display_preset(
+			substrate_test_runtime::WASM_BINARY_PATH.expect("to be a valid path. qed"),
+		),
+		"tests/expected/doc/display_preset_staging.json",
+		false,
+	);
+}
+
+#[docify::export_content]
+fn cmd_list_presets(runtime_path: &str) -> String {
+	bash!(
+		chain-spec-builder list-presets -r $runtime_path
+	)
+}
+
+#[test]
+fn list_presets() {
+	doc_assert(
+		cmd_list_presets(
+			substrate_test_runtime::WASM_BINARY_PATH.expect("to be a valid path. qed"),
+		),
+		"tests/expected/doc/list_presets.json",
+		false,
+	);
+}
+
+#[docify::export_content]
+fn cmd_create_with_named_preset(runtime_path: &str) -> String {
+	bash!(
+		chain-spec-builder -c "/dev/stdout" create --relay-chain "dev" --para-id 1000 -r $runtime_path named-preset "staging"
+	)
+}
+
+#[test]
+fn create_with_named_preset() {
+	doc_assert(
+		cmd_create_with_named_preset(
+			substrate_test_runtime::WASM_BINARY_PATH.expect("to be a valid path. qed"),
+		),
+		"tests/expected/doc/create_with_named_preset_staging.json",
+		true,
+	)
+}
+
+#[docify::export_content]
+fn cmd_create_with_patch_raw(runtime_path: &str) -> String {
+	bash!(
+		chain-spec-builder -c "/dev/stdout" create -s -r $runtime_path patch "tests/input/patch.json"
+	)
+}
+
+#[test]
+fn create_with_patch_raw() {
+	doc_assert(
+		cmd_create_with_patch_raw(
+			substrate_test_runtime::WASM_BINARY_PATH.expect("to be a valid path. qed"),
+		),
+		"tests/expected/doc/create_with_patch_raw.json",
+		true,
+	);
+}
+
+#[docify::export_content]
+fn cmd_create_with_patch_plain(runtime_path: &str) -> String {
+	bash!(
+		chain-spec-builder -c "/dev/stdout" create -r $runtime_path patch "tests/input/patch.json"
+	)
+}
+
+#[test]
+fn create_with_patch_plain() {
+	doc_assert(
+		cmd_create_with_patch_plain(
+			substrate_test_runtime::WASM_BINARY_PATH.expect("to be a valid path. qed"),
+		),
+		"tests/expected/doc/create_with_patch_plain.json",
+		true,
+	);
+}
+
+#[docify::export_content]
+fn cmd_create_full_plain(runtime_path: &str) -> String {
+	bash!(
+		chain-spec-builder -c "/dev/stdout" create -r $runtime_path full "tests/input/full.json"
+	)
+}
+
+#[test]
+fn create_full_plain() {
+	doc_assert(
+		cmd_create_full_plain(
+			substrate_test_runtime::WASM_BINARY_PATH.expect("to be a valid path. qed"),
+		),
+		"tests/expected/doc/create_full_plain.json",
+		true,
+	);
+}
+
+#[docify::export_content]
+fn cmd_create_full_raw(runtime_path: &str) -> String {
+	bash!(
+		chain-spec-builder -c "/dev/stdout" create -s -r $runtime_path full "tests/input/full.json"
+	)
+}
+
+#[test]
+fn create_full_raw() {
+	doc_assert(
+		cmd_create_full_raw(
+			substrate_test_runtime::WASM_BINARY_PATH.expect("to be a valid path. qed"),
+		),
+		"tests/expected/doc/create_full_raw.json",
+		true,
+	);
+}
diff --git a/substrate/utils/wasm-builder/src/builder.rs b/substrate/utils/wasm-builder/src/builder.rs
index eb761a103d62ecd680747584e077de5025f9955b..a40aafe1d8127d5c250d729ce07ceac210f27757 100644
--- a/substrate/utils/wasm-builder/src/builder.rs
+++ b/substrate/utils/wasm-builder/src/builder.rs
@@ -303,7 +303,8 @@ fn provide_dummy_wasm_binary_if_not_exist(file_path: &Path) {
 	if !file_path.exists() {
 		crate::write_file_if_changed(
 			file_path,
-			"pub const WASM_BINARY: Option<&[u8]> = None;\
+			"pub const WASM_BINARY_PATH: Option<&str> = None;\
+			 pub const WASM_BINARY: Option<&[u8]> = None;\
 			 pub const WASM_BINARY_BLOATY: Option<&[u8]> = None;",
 		);
 	}
@@ -378,9 +379,11 @@ fn build_project(
 		file_name,
 		format!(
 			r#"
+				pub const WASM_BINARY_PATH: Option<&str> = Some("{wasm_binary_path}");
 				pub const WASM_BINARY: Option<&[u8]> = Some(include_bytes!("{wasm_binary}"));
 				pub const WASM_BINARY_BLOATY: Option<&[u8]> = Some(include_bytes!("{wasm_binary_bloaty}"));
 			"#,
+			wasm_binary_path = wasm_binary,
 			wasm_binary = wasm_binary,
 			wasm_binary_bloaty = wasm_binary_bloaty,
 		),
diff --git a/substrate/utils/wasm-builder/src/lib.rs b/substrate/utils/wasm-builder/src/lib.rs
index e3f2ff5cd733498a01e3d92b9f731d7247c9761f..420ecd63e1dcc2b799d44bc984528346321f9a4b 100644
--- a/substrate/utils/wasm-builder/src/lib.rs
+++ b/substrate/utils/wasm-builder/src/lib.rs
@@ -48,6 +48,8 @@
 //! This will include the generated Wasm binary as two constants `WASM_BINARY` and
 //! `WASM_BINARY_BLOATY`. The former is a compact Wasm binary and the latter is the Wasm binary as
 //! being generated by the compiler. Both variables have `Option<&'static [u8]>` as type.
+//! Additionally it will create the `WASM_BINARY_PATH` which is the path to the WASM blob on the
+//! filesystem.
 //!
 //! ### Feature
 //!
diff --git a/templates/minimal/Dockerfile b/templates/minimal/Dockerfile
index 0c59192208fe66961613f7adaec16284078b9d9f..422f7f726a7e47345d3bc0f3d56dbabc7669ff27 100644
--- a/templates/minimal/Dockerfile
+++ b/templates/minimal/Dockerfile
@@ -4,7 +4,7 @@ WORKDIR /polkadot
 COPY . /polkadot
 
 RUN cargo fetch
-RUN cargo build --locked --release
+RUN cargo build --workspace --locked --release
 
 FROM docker.io/parity/base-bin:latest
 
diff --git a/templates/minimal/README.md b/templates/minimal/README.md
index fe1317a033c7dab4c50aa552ee2a8e14e49d882a..cf43d71d884993c51ba1265ef49d445d4866d1ec 100644
--- a/templates/minimal/README.md
+++ b/templates/minimal/README.md
@@ -11,30 +11,54 @@
 
 </div>
 
-* 🤏 This template is a minimal (in terms of complexity and the number of components)
+## Table of Contents
+
+- [Intro](#intro)
+
+- [Template Structure](#template-structure)
+
+- [Getting Started](#getting-started)
+
+- [Starting a Minimal Template Chain](#starting-a-minimal-template-chain)
+
+  - [Omni Node](#omni-node)
+  - [Minimal Template Node](#minimal-template-node)
+  - [Zombienet with Omni Node](#zombienet-with-omni-node)
+  - [Zombienet with Minimal Template Node](#zombienet-with-minimal-template-node)
+  - [Connect with the Polkadot-JS Apps Front-End](#connect-with-the-polkadot-js-apps-front-end)
+  - [Takeaways](#takeaways)
+
+- [Contributing](#contributing)
+
+- [Getting Help](#getting-help)
+
+## Intro
+
+- 🤏 This template is a minimal (in terms of complexity and the number of components)
 template for building a blockchain node.
 
-* 🔧 Its runtime is configured with a single custom pallet as a starting point, and a handful of ready-made pallets
+- 🔧 Its runtime is configured with a single custom pallet as a starting point, and a handful of ready-made pallets
 such as a [Balances pallet](https://paritytech.github.io/polkadot-sdk/master/pallet_balances/index.html).
 
-* 👤 The template has no consensus configured - it is best for experimenting with a single node network.
+- 👤 The template has no consensus configured - it is best for experimenting with a single node network.
 
 ## Template Structure
 
 A Polkadot SDK based project such as this one consists of:
 
-* 💿 a [Node](./node/README.md) - the binary application.
-* 🧮 the [Runtime](./runtime/README.md) - the core logic of the blockchain.
-* 🎨 the [Pallets](./pallets/README.md) - from which the runtime is constructed.
+- 🧮 the [Runtime](./runtime/README.md) - the core logic of the blockchain.
+- 🎨 the [Pallets](./pallets/README.md) - from which the runtime is constructed.
+- 💿 a [Node](./node/README.md) - the binary application (which is not part of the cargo default-members list and is not
+compiled unless building the entire workspace).
 
 ## Getting Started
 
-* 🦀 The template is using the Rust language.
+- 🦀 The template is using the Rust language.
 
-* 👉 Check the
+- 👉 Check the
 [Rust installation instructions](https://www.rust-lang.org/tools/install) for your system.
 
-* 🛠️ Depending on your operating system and Rust version, there might be additional
+- 🛠️ Depending on your operating system and Rust version, there might be additional
 packages required to compile this template - please take note of the Rust compiler output.
 
 Fetch minimal template code:
@@ -45,65 +69,152 @@ git clone https://github.com/paritytech/polkadot-sdk-minimal-template.git minima
 cd minimal-template
 ```
 
-### Build
+## Starting a Minimal Template Chain
+
+### Omni Node
+
+[Omni Node](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/omni_node/index.html) can
+be used to run the minimal template's runtime. `polkadot-omni-node` binary crate usage is described at a high-level
+[on crates.io](https://crates.io/crates/polkadot-omni-node).
+
+#### Install `polkadot-omni-node`
+
+Please see installation section on [crates.io/omni-node](https://crates.io/crates/polkadot-omni-node).
+
+#### Build `minimal-template-runtime`
+
+```sh
+cargo build -p minimal-template-runtime --release
+```
+
+#### Install `staging-chain-spec-builder`
 
-🔨 Use the following command to build the node without launching it:
+Please see the installation section at [`crates.io/staging-chain-spec-builder`](https://crates.io/crates/staging-chain-spec-builder).
+
+#### Use chain-spec-builder to generate the chain_spec.json file
 
 ```sh
-cargo build --release
+chain-spec-builder create --relay-chain "dev" --para-id 1000 --runtime \
+    target/release/wbuild/minimal-template-runtime/minimal_template_runtime.wasm named-preset development
 ```
 
-🐳 Alternatively, build the docker image:
+**Note**: the `relay-chain` and `para-id` flags are extra bits of information required to
+configure the node for the case of representing a parachain that is connected to a relay chain.
+They are not relevant to minimal template business logic, but they are mandatory information for
+Omni Node, nonetheless.
+
+#### Run Omni Node
+
+Start Omni Node with manual seal (3 seconds block times), minimal template runtime based
+chain spec. We'll use `--tmp` flag to start the node with its configurations stored in a
+temporary directory, which will be deleted at the end of the process.
+
+```sh
+polkadot-omni-node --chain <path/to/chain_spec.json> --dev-block-time 3000 --tmp
+```
+
+### Minimal Template Node
+
+#### Build both node & runtime
+
+```sh
+cargo build --workspace --release
+```
+
+🐳 Alternatively, build the docker image which builds all the workspace members,
+and has as entry point the node binary:
 
 ```sh
 docker build . -t polkadot-sdk-minimal-template
 ```
 
-### Single-Node Development Chain
+#### Start the `minimal-template-node`
 
-👤 The following command starts a single-node development chain:
+The `minimal-template-node` has dependency on the `minimal-template-runtime`. It will use
+the `minimal_template_runtime::WASM_BINARY` constant (which holds the WASM blob as a byte
+array) for chain spec building, while starting. This is in contrast to Omni Node which doesn't
+depend on a specific runtime, but asks for the chain spec at startup.
 
 ```sh
-./target/release/minimal-template-node --dev
+<target/release/path/to/minimal-template-node> --tmp --consensus manual-seal-3000
+# or via docker
+docker run --rm polkadot-sdk-minimal-template
+```
+
+### Zombienet with Omni Node
+
+#### Install `zombienet`
+
+We can install `zombienet` as described [here](https://paritytech.github.io/zombienet/install.html#installation),
+and `zombienet-omni-node.toml` contains the network specification we want to start.
+
+#### Update `zombienet-omni-node.toml` with a valid chain spec path
+
+Before starting the network with zombienet we must update the network specification
+with a valid chain spec path. If we need to generate one, we can look up at the previous
+section for chain spec creation [here](#use-chain-spec-builder-to-generate-the-chain_specjson-file).
 
-# docker version:
-docker run --rm polkadot-sdk-minimal-template --dev
+Then make the changes in the network specification like so:
+
+```toml
+# ...
+chain = "dev"
+chain_spec_path = "<TO BE UPDATED WITH A VALID PATH>"
+default_args = ["--dev-block-time 3000"]
+# ..
+```
+
+#### Start the network
+
+```sh
+zombienet --provider native spawn zombienet-omni-node.toml
 ```
 
-Development chains:
+### Zombienet with `minimal-template-node`
 
-* 🧹 Do not persist the state.
-* 💰 Are pre-configured with a genesis state that includes several pre-funded development accounts.
-* 🧑‍⚖️ One development account (`ALICE`) is used as `sudo` accounts.
+For this one we just need to have `zombienet` installed and run:
+
+```sh
+zombienet --provider native spawn zombienet-multi-node.toml
+```
 
 ### Connect with the Polkadot-JS Apps Front-End
 
-* 🌐 You can interact with your local node using the
+- 🌐 You can interact with your local node using the
 hosted version of the [Polkadot/Substrate
 Portal](https://polkadot.js.org/apps/#/explorer?rpc=ws://localhost:9944).
 
-* 🪐 A hosted version is also
+- 🪐 A hosted version is also
 available on [IPFS](https://dotapps.io/).
 
-* 🧑‍🔧 You can also find the source code and instructions for hosting your own instance in the
+- 🧑‍🔧 You can also find the source code and instructions for hosting your own instance in the
 [`polkadot-js/apps`](https://github.com/polkadot-js/apps) repository.
 
+### Takeaways
+
+Previously minimal template's development chains:
+
+- ❌ Started in a multi-node setup will produce forks because minimal lacks consensus.
+- 🧹 Do not persist the state.
+- 💰 Are pre-configured with a genesis state that includes several pre-funded development accounts.
+- 🧑‍⚖️ One development account (`ALICE`) is used as `sudo` accounts.
+
 ## Contributing
 
-* 🔄 This template is automatically updated after releases in the main [Polkadot SDK monorepo](https://github.com/paritytech/polkadot-sdk).
+- 🔄 This template is automatically updated after releases in the main [Polkadot SDK monorepo](https://github.com/paritytech/polkadot-sdk).
 
-* ➡️ Any pull requests should be directed to this [source](https://github.com/paritytech/polkadot-sdk/tree/master/templates/minimal).
+- ➡️ Any pull requests should be directed to this [source](https://github.com/paritytech/polkadot-sdk/tree/master/templates/minimal).
 
-* 😇 Please refer to the monorepo's
+- 😇 Please refer to the monorepo's
 [contribution guidelines](https://github.com/paritytech/polkadot-sdk/blob/master/docs/contributor/CONTRIBUTING.md) and
 [Code of Conduct](https://github.com/paritytech/polkadot-sdk/blob/master/docs/contributor/CODE_OF_CONDUCT.md).
 
 ## Getting Help
 
-* 🧑‍🏫 To learn about Polkadot in general, [Polkadot.network](https://polkadot.network/) website is a good starting point.
+- 🧑‍🏫 To learn about Polkadot in general, [Polkadot.network](https://polkadot.network/) website is a good starting point.
 
-* 🧑‍🔧 For technical introduction, [here](https://github.com/paritytech/polkadot-sdk#-documentation) are
+- 🧑‍🔧 For technical introduction, [here](https://github.com/paritytech/polkadot-sdk#-documentation) are
 the Polkadot SDK documentation resources.
 
-* 👥 Additionally, there are [GitHub issues](https://github.com/paritytech/polkadot-sdk/issues) and
+- 👥 Additionally, there are [GitHub issues](https://github.com/paritytech/polkadot-sdk/issues) and
 [Substrate StackExchange](https://substrate.stackexchange.com/).
diff --git a/templates/minimal/node/src/cli.rs b/templates/minimal/node/src/cli.rs
index 54107df75a3630d818df881d600e4ce18f886286..f349f8c8da0490fea81275e75f32e12d8b4481fe 100644
--- a/templates/minimal/node/src/cli.rs
+++ b/templates/minimal/node/src/cli.rs
@@ -21,6 +21,7 @@ use polkadot_sdk::{sc_cli::RunCmd, *};
 pub enum Consensus {
 	ManualSeal(u64),
 	InstantSeal,
+	None,
 }
 
 impl std::str::FromStr for Consensus {
@@ -31,6 +32,8 @@ impl std::str::FromStr for Consensus {
 			Consensus::InstantSeal
 		} else if let Some(block_time) = s.strip_prefix("manual-seal-") {
 			Consensus::ManualSeal(block_time.parse().map_err(|_| "invalid block time")?)
+		} else if s.to_lowercase() == "none" {
+			Consensus::None
 		} else {
 			return Err("incorrect consensus identifier".into());
 		})
diff --git a/templates/minimal/node/src/service.rs b/templates/minimal/node/src/service.rs
index 169993e2e93ae0eea7ca8ca38aef7a5690e2d082..f9a9d1e0f3cfe9aba3dc380acbd514f76b9bb4e1 100644
--- a/templates/minimal/node/src/service.rs
+++ b/templates/minimal/node/src/service.rs
@@ -273,6 +273,7 @@ pub fn new_full<Network: sc_network::NetworkBackend<Block, <Block as BlockT>::Ha
 				authorship_future,
 			);
 		},
+		_ => {},
 	}
 
 	network_starter.start_network();
diff --git a/templates/minimal/zombienet-omni-node.toml b/templates/minimal/zombienet-omni-node.toml
new file mode 100644
index 0000000000000000000000000000000000000000..33b0fceba68c9257a6f5094f252e1830d0fc15e5
--- /dev/null
+++ b/templates/minimal/zombienet-omni-node.toml
@@ -0,0 +1,9 @@
+[relaychain]
+default_command = "polkadot-omni-node"
+chain = "dev"
+chain_spec_path = "<path/to/chain_spec.json>"
+default_args = ["--dev-block-time 3000"]
+
+[[relaychain.nodes]]
+name = "alice"
+ws_port = 9944
diff --git a/templates/minimal/zombienet.toml b/templates/minimal/zombienet.toml
new file mode 100644
index 0000000000000000000000000000000000000000..89df054bf6526ba9e535cef297f9938e613d2f05
--- /dev/null
+++ b/templates/minimal/zombienet.toml
@@ -0,0 +1,30 @@
+# The setup bellow allows only one node to produce
+# blocks and the rest will follow.
+
+[relaychain]
+chain = "dev"
+default_command = "minimal-template-node"
+
+[[relaychain.nodes]]
+name = "alice"
+args = ["--consensus manual-seal-3000"]
+validator = true
+ws_port = 9944
+
+[[relaychain.nodes]]
+name = "bob"
+args = ["--consensus None"]
+validator = true
+ws_port = 9955
+
+[[relaychain.nodes]]
+name = "charlie"
+args = ["--consensus None"]
+validator = true
+ws_port = 9966
+
+[[relaychain.nodes]]
+name = "dave"
+args = ["--consensus None"]
+validator = true
+ws_port = 9977
diff --git a/templates/parachain/Dockerfile b/templates/parachain/Dockerfile
index 72a8f19fe79ae0ff870f19e90206c9aa7a4309fb..da1353d5fb9c84fec84a3d020a40b7bd17a1c381 100644
--- a/templates/parachain/Dockerfile
+++ b/templates/parachain/Dockerfile
@@ -4,7 +4,7 @@ WORKDIR /polkadot
 COPY . /polkadot
 
 RUN cargo fetch
-RUN cargo build --locked --release
+RUN cargo build --workspace --locked --release
 
 FROM docker.io/parity/base-bin:latest
 
diff --git a/templates/parachain/README.md b/templates/parachain/README.md
index 3de85cbeb4dc77a386fc702f645c0bb4e7ffb96d..65a6979041f2b230cea1afc7017a3050fa3fdd1b 100644
--- a/templates/parachain/README.md
+++ b/templates/parachain/README.md
@@ -11,32 +11,55 @@
 
 </div>
 
-* ⏫ This template provides a starting point to build a [parachain](https://wiki.polkadot.network/docs/learn-parachains).
+## Table of Contents
 
-* ☁️ It is based on the
+- [Intro](#intro)
+
+- [Template Structure](#template-structure)
+
+- [Getting Started](#getting-started)
+
+- [Starting a Development Chain](#starting-a-development-chain)
+
+  - [Omni Node](#omni-node-prerequisites)
+  - [Zombienet setup with Omni Node](#zombienet-setup-with-omni-node)
+  - [Parachain Template Node](#parachain-template-node)
+  - [Connect with the Polkadot-JS Apps Front-End](#connect-with-the-polkadot-js-apps-front-end)
+  - [Takeaways](#takeaways)
+
+- [Contributing](#contributing)
+- [Getting Help](#getting-help)
+
+## Intro
+
+- ⏫ This template provides a starting point to build a [parachain](https://wiki.polkadot.network/docs/learn-parachains).
+
+- ☁️ It is based on the
 [Cumulus](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/cumulus/index.html) framework.
 
-* 🔧 Its runtime is configured with a single custom pallet as a starting point, and a handful of ready-made pallets
+- 🔧 Its runtime is configured with a single custom pallet as a starting point, and a handful of ready-made pallets
 such as a [Balances pallet](https://paritytech.github.io/polkadot-sdk/master/pallet_balances/index.html).
 
-* 👉 Learn more about parachains [here](https://wiki.polkadot.network/docs/learn-parachains)
+- 👉 Learn more about parachains [here](https://wiki.polkadot.network/docs/learn-parachains)
 
 ## Template Structure
 
 A Polkadot SDK based project such as this one consists of:
 
-* 💿 a [Node](./node/README.md) - the binary application.
-* 🧮 the [Runtime](./runtime/README.md) - the core logic of the parachain.
-* 🎨 the [Pallets](./pallets/README.md) - from which the runtime is constructed.
+- 🧮 the [Runtime](./runtime/README.md) - the core logic of the parachain.
+- 🎨 the [Pallets](./pallets/README.md) - from which the runtime is constructed.
+- 💿 a [Node](./node/README.md) - the binary application, not part of the project default-members list and not compiled unless
+building the project with `--workspace` flag, which builds all workspace members, and is an alternative to
+[Omni Node](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/omni_node/index.html).
 
 ## Getting Started
 
-* 🦀 The template is using the Rust language.
+- 🦀 The template is using the Rust language.
 
-* 👉 Check the
+- 👉 Check the
 [Rust installation instructions](https://www.rust-lang.org/tools/install) for your system.
 
-* 🛠️ Depending on your operating system and Rust version, there might be additional
+- 🛠️ Depending on your operating system and Rust version, there might be additional
 packages required to compile this template - please take note of the Rust compiler output.
 
 Fetch parachain template code:
@@ -47,90 +70,149 @@ git clone https://github.com/paritytech/polkadot-sdk-parachain-template.git para
 cd parachain-template
 ```
 
-### Build
+## Starting a Development Chain
+
+### Omni Node Prerequisites
 
-🔨 Use the following command to build the node without launching it:
+[Omni Node](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/omni_node/index.html) can
+be used to run the parachain template's runtime. `polkadot-omni-node` binary crate usage is described at a high-level
+[on crates.io](https://crates.io/crates/polkadot-omni-node).
+
+#### Install `polkadot-omni-node`
+
+Please see the installation section at [`crates.io/omni-node`](https://crates.io/crates/polkadot-omni-node).
+
+#### Build `parachain-template-runtime`
 
 ```sh
 cargo build --release
 ```
 
-🐳 Alternatively, build the docker image:
+#### Install `staging-chain-spec-builder`
+
+Please see the installation section at [`crates.io/staging-chain-spec-builder`](https://crates.io/crates/staging-chain-spec-builder).
+
+#### Use `chain-spec-builder` to generate the `chain_spec.json` file
 
 ```sh
-docker build . -t polkadot-sdk-parachain-template
+chain-spec-builder create --relay-chain "rococo-local" --para-id 1000 --runtime \
+    target/release/wbuild/parachain-template-runtime/parachain_template_runtime.wasm named-preset development
 ```
 
-### Local Development Chain
+**Note**: the `relay-chain` and `para-id` flags are mandatory information required by
+Omni Node, and for parachain template case the value for `para-id` must be set to `1000`, since this
+is also the value injected through [ParachainInfo](https://docs.rs/staging-parachain-info/0.17.0/staging_parachain_info/)
+pallet into the `parachain-template-runtime`'s storage. The `relay-chain` value is set in accordance
+with the relay chain ID where this instantiation of parachain-template will connect to.
 
-🧟 This project uses [Zombienet](https://github.com/paritytech/zombienet) to orchestrate the relaychain and parachain nodes.
-You can grab a [released binary](https://github.com/paritytech/zombienet/releases/latest) or use an [npm version](https://www.npmjs.com/package/@zombienet/cli).
+#### Run Omni Node
 
-This template produces a parachain node.
-You can install it in your environment by running:
+Start Omni Node with the generated chain spec. We'll start it development mode (without a relay chain config),
+with a temporary directory for configuration (given `--tmp`), and block production set to create a block with
+every second.
+
+```bash
+polkadot-omni-node --chain <path/to/chain_spec.json> --tmp --dev-block-time 1000
 
-```sh
-cargo install --path node
 ```
 
-You still need a relaychain node - you can download the `polkadot`
-(and the accompanying `polkadot-prepare-worker` and `polkadot-execute-worker`)
-binaries from [Polkadot SDK releases](https://github.com/paritytech/polkadot-sdk/releases/latest).
+However, such a setup is not close to what would run in production, and for that we need to setup a local
+relay chain network that will help with the block finalization. In this guide we'll setup a local relay chain
+as well. We'll not do it manually, by starting one node at a time, but we'll use [zombienet](https://paritytech.github.io/zombienet/intro.html).
+
+Follow through the next section for more details on how to do it.
 
-In addition to the installed parachain node, make sure to bring
-`zombienet`, `polkadot`, `polkadot-prepare-worker`, and `polkadot-execute-worker`
-into `PATH`, for example:
+### Zombienet setup with Omni Node
+
+Assuming we continue from the last step of the previous section, we have a chain spec and we need to setup a relay chain.
+We can install `zombienet` as described [here](https://paritytech.github.io/zombienet/install.html#installation), and
+`zombienet-omni-node.toml` contains the network specification we want to start.
+
+#### Relay chain prerequisites
+
+Download the `polkadot` (and the accompanying `polkadot-prepare-worker` and `polkadot-execute-worker`) binaries from
+[Polkadot SDK releases](https://github.com/paritytech/polkadot-sdk/releases). Then expose them on `PATH` like so:
 
 ```sh
-export PATH="<path-to-binaries>:$PATH"
+export PATH="$PATH:<path/to/binaries>"
 ```
 
-This way, we can conveniently use them in the following steps.
+#### Update `zombienet-omni-node.toml` with a valid chain spec path
+
+```toml
+# ...
+[[parachains]]
+id = 1000
+chain_spec_path = "<TO BE UPDATED WITH A VALID PATH>"
+# ...
+```
 
-👥 The following command starts a local development chain, with a single relay chain node and a single parachain collator:
+#### Start the network
 
 ```sh
-zombienet --provider native spawn ./zombienet.toml
+zombienet --provider native spawn zombienet-omni-node.toml
+```
+
+### Parachain Template Node
+
+As mentioned in the `Template Structure` section, the `node` crate is optionally compiled and it is an alternative
+to `Omni Node`. Similarly, it requires setting up a relay chain, and we'll use `zombienet` once more.
+
+#### Install the `parachain-template-node`
 
-# Alternatively, the npm version:
-npx --yes @zombienet/cli --provider native spawn ./zombienet.toml
+```sh
+cargo install --path node
 ```
 
-Development chains:
+#### Setup and start the network
+
+For setup, please consider the instructions for `zombienet` installation [here](https://paritytech.github.io/zombienet/install.html#installation)
+and [relay chain prerequisites](#relay-chain-prerequisites).
 
-* 🧹 Do not persist the state.
-* 💰 Are preconfigured with a genesis state that includes several prefunded development accounts.
-* 🧑‍⚖️ Development accounts are used as validators, collators, and `sudo` accounts.
+We're left just with starting the network:
+
+```sh
+zombienet --provider native spawn zombienet.toml
+```
 
 ### Connect with the Polkadot-JS Apps Front-End
 
-* 🌐 You can interact with your local node using the
+- 🌐 You can interact with your local node using the
 hosted version of the Polkadot/Substrate Portal:
 [relay chain](https://polkadot.js.org/apps/#/explorer?rpc=ws://localhost:9944)
 and [parachain](https://polkadot.js.org/apps/#/explorer?rpc=ws://localhost:9988).
 
-* 🪐 A hosted version is also
+- 🪐 A hosted version is also
 available on [IPFS](https://dotapps.io/).
 
-* 🧑‍🔧 You can also find the source code and instructions for hosting your own instance in the
+- 🧑‍🔧 You can also find the source code and instructions for hosting your own instance in the
 [`polkadot-js/apps`](https://github.com/polkadot-js/apps) repository.
 
+### Takeaways
+
+Development parachains:
+
+- 🔗 Connect to relay chains, and we showcased how to connect to a local one.
+- 🧹 Do not persist the state.
+- 💰 Are preconfigured with a genesis state that includes several prefunded development accounts.
+- 🧑‍⚖️ Development accounts are used as validators, collators, and `sudo` accounts.
+
 ## Contributing
 
-* 🔄 This template is automatically updated after releases in the main [Polkadot SDK monorepo](https://github.com/paritytech/polkadot-sdk).
+- 🔄 This template is automatically updated after releases in the main [Polkadot SDK monorepo](https://github.com/paritytech/polkadot-sdk).
 
-* ➡️ Any pull requests should be directed to this [source](https://github.com/paritytech/polkadot-sdk/tree/master/templates/parachain).
+- ➡️ Any pull requests should be directed to this [source](https://github.com/paritytech/polkadot-sdk/tree/master/templates/parachain).
 
-* 😇 Please refer to the monorepo's
+- 😇 Please refer to the monorepo's
 [contribution guidelines](https://github.com/paritytech/polkadot-sdk/blob/master/docs/contributor/CONTRIBUTING.md) and
 [Code of Conduct](https://github.com/paritytech/polkadot-sdk/blob/master/docs/contributor/CODE_OF_CONDUCT.md).
 
 ## Getting Help
 
-* 🧑‍🏫 To learn about Polkadot in general, [Polkadot.network](https://polkadot.network/) website is a good starting point.
+- 🧑‍🏫 To learn about Polkadot in general, [Polkadot.network](https://polkadot.network/) website is a good starting point.
 
-* 🧑‍🔧 For technical introduction, [here](https://github.com/paritytech/polkadot-sdk#-documentation) are
+- 🧑‍🔧 For technical introduction, [here](https://github.com/paritytech/polkadot-sdk#-documentation) are
 the Polkadot SDK documentation resources.
 
-* 👥 Additionally, there are [GitHub issues](https://github.com/paritytech/polkadot-sdk/issues) and
+- 👥 Additionally, there are [GitHub issues](https://github.com/paritytech/polkadot-sdk/issues) and
 [Substrate StackExchange](https://substrate.stackexchange.com/).
diff --git a/templates/parachain/runtime/src/genesis_config_presets.rs b/templates/parachain/runtime/src/genesis_config_presets.rs
index 394bde0be77000d7d06675401eff5ec06a97c36f..9091db357005bfd2fced9d272ac48c2486023d16 100644
--- a/templates/parachain/runtime/src/genesis_config_presets.rs
+++ b/templates/parachain/runtime/src/genesis_config_presets.rs
@@ -15,6 +15,8 @@ use sp_keyring::Sr25519Keyring;
 
 /// The default XCM version to set in genesis config.
 const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION;
+/// Parachain id used for gensis config presets of parachain template.
+const PARACHAIN_ID: u32 = 1000;
 
 /// Generate the session keys from individual elements.
 ///
@@ -76,9 +78,7 @@ fn local_testnet_genesis() -> Value {
 		],
 		Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(),
 		Sr25519Keyring::Alice.to_account_id(),
-		// TODO: this is super opaque, how should one know they should configure this? add to
-		// README!
-		1000.into(),
+		PARACHAIN_ID.into(),
 	)
 }
 
@@ -91,7 +91,7 @@ fn development_config_genesis() -> Value {
 		],
 		Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(),
 		Sr25519Keyring::Alice.to_account_id(),
-		1000.into(),
+		PARACHAIN_ID.into(),
 	)
 }
 
diff --git a/templates/parachain/zombienet-omni-node.toml b/templates/parachain/zombienet-omni-node.toml
new file mode 100644
index 0000000000000000000000000000000000000000..29e99cfcd493113c3ee643c3cffb08e2fce498a9
--- /dev/null
+++ b/templates/parachain/zombienet-omni-node.toml
@@ -0,0 +1,22 @@
+[relaychain]
+default_command = "polkadot"
+chain = "rococo-local"
+
+[[relaychain.nodes]]
+name = "alice"
+validator = true
+ws_port = 9944
+
+[[relaychain.nodes]]
+name = "bob"
+validator = true
+ws_port = 9955
+
+[[parachains]]
+id = 1000
+chain_spec_path = "<path/to/chain_spec.json>"
+
+[parachains.collator]
+name = "charlie"
+ws_port = 9988
+command = "polkadot-omni-node"
diff --git a/templates/zombienet/tests/smoke.rs b/templates/zombienet/tests/smoke.rs
index ba5f42142f31e2fa60fc4baa2b85f7737e60752e..c0c9646d4e9c978e82158446c19f90a6dd1f49e3 100644
--- a/templates/zombienet/tests/smoke.rs
+++ b/templates/zombienet/tests/smoke.rs
@@ -7,28 +7,74 @@
 //! `cargo build --package minimal-template-node --release`
 //! `export PATH=<path-to-polkadot-sdk-repo>/target/release:$PATH
 //!
-//! The you can run the test with
-//! `cargo test -p template-zombienet-tests`
+//! There are also some tests related to omni node which run basaed on pre-generated chain specs,
+//! so to be able to run them you would need to generate the right chain spec (just minimal and
+//! parachain tests supported for now).
+//!
+//! You can run the following command to generate a minimal chainspec, once the runtime wasm file is
+//! compiled:
+//!`chain-spec-builder create --relay-chain <relay_chain_id> --para-id 1000 -r \
+//!     <path_to_template_wasm_file> named-preset development`
+//!
+//! Once the files are generated, you must export an environment variable called
+//! `CHAIN_SPECS_DIR` which should point to the absolute path of the directory
+//! that holds the generated chain specs. The chain specs file names should be
+//! `minimal_chain_spec.json` for minimal and `parachain_chain_spec.json` for parachain
+//! templates.
+//!
+//! To start all tests here we should run:
+//! `cargo test -p template-zombienet-tests --features zombienet`
 
 #[cfg(feature = "zombienet")]
 mod smoke {
+	use std::path::PathBuf;
+
 	use anyhow::anyhow;
 	use zombienet_sdk::{NetworkConfig, NetworkConfigBuilder, NetworkConfigExt};
 
-	pub fn get_config(cmd: &str, para_cmd: Option<&str>) -> Result<NetworkConfig, anyhow::Error> {
-		let chain = if cmd == "polkadot" { "rococo-local" } else { "dev" };
+	const CHAIN_SPECS_DIR_PATH: &str = "CHAIN_SPECS_DIR";
+	const PARACHAIN_ID: u32 = 1000;
+
+	#[inline]
+	fn expect_env_var(var_name: &str) -> String {
+		std::env::var(var_name)
+			.unwrap_or_else(|_| panic!("{CHAIN_SPECS_DIR_PATH} environment variable is set. qed."))
+	}
+
+	#[derive(Default)]
+	struct NetworkSpec {
+		relaychain_cmd: &'static str,
+		relaychain_spec_path: Option<PathBuf>,
+		// TODO: update the type to something like Option<Vec<Arg>> after
+		// `zombienet-sdk` exposes `shared::types::Arg`.
+		relaychain_cmd_args: Option<Vec<(&'static str, &'static str)>>,
+		para_cmd: Option<&'static str>,
+		para_cmd_args: Option<Vec<(&'static str, &'static str)>>,
+	}
+
+	fn get_config(network_spec: NetworkSpec) -> Result<NetworkConfig, anyhow::Error> {
+		let chain = if network_spec.relaychain_cmd == "polkadot" { "rococo-local" } else { "dev" };
 		let config = NetworkConfigBuilder::new().with_relaychain(|r| {
-			r.with_chain(chain)
-				.with_default_command(cmd)
-				.with_node(|node| node.with_name("alice"))
+			let mut r = r.with_chain(chain).with_default_command(network_spec.relaychain_cmd);
+			if let Some(path) = network_spec.relaychain_spec_path {
+				r = r.with_chain_spec_path(path);
+			}
+
+			if let Some(args) = network_spec.relaychain_cmd_args {
+				r = r.with_default_args(args.into_iter().map(|arg| arg.into()).collect());
+			}
+
+			r.with_node(|node| node.with_name("alice"))
 				.with_node(|node| node.with_name("bob"))
 		});
 
-		let config = if let Some(para_cmd) = para_cmd {
+		let config = if let Some(para_cmd) = network_spec.para_cmd {
 			config.with_parachain(|p| {
-				p.with_id(1000)
-					.with_default_command(para_cmd)
-					.with_collator(|n| n.with_name("collator"))
+				let mut p = p.with_id(PARACHAIN_ID).with_default_command(para_cmd);
+				if let Some(args) = network_spec.para_cmd_args {
+					p = p.with_default_args(args.into_iter().map(|arg| arg.into()).collect());
+				}
+				p.with_collator(|n| n.with_name("collator"))
 			})
 		} else {
 			config
@@ -46,14 +92,18 @@ mod smoke {
 			env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"),
 		);
 
-		let config = get_config("polkadot", Some("parachain-template-node"))?;
+		let config = get_config(NetworkSpec {
+			relaychain_cmd: "polkadot",
+			para_cmd: Some("parachain-template-node"),
+			..Default::default()
+		})?;
 
 		let network = config.spawn_native().await?;
 
 		// wait 6 blocks of the para
 		let collator = network.get_node("collator")?;
 		assert!(collator
-			.wait_metric("block_height{status=\"best\"}", |b| b > 5_f64)
+			.wait_metric("block_height{status=\"finalized\"}", |b| b > 5_f64)
 			.await
 			.is_ok());
 
@@ -66,13 +116,19 @@ mod smoke {
 			env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"),
 		);
 
-		let config = get_config("solochain-template-node", None)?;
+		let config = get_config(NetworkSpec {
+			relaychain_cmd: "solochain-template-node",
+			..Default::default()
+		})?;
 
 		let network = config.spawn_native().await?;
 
 		// wait 6 blocks
 		let alice = network.get_node("alice")?;
-		assert!(alice.wait_metric("block_height{status=\"best\"}", |b| b > 5_f64).await.is_ok());
+		assert!(alice
+			.wait_metric("block_height{status=\"finalized\"}", |b| b > 5_f64)
+			.await
+			.is_ok());
 
 		Ok(())
 	}
@@ -83,13 +139,73 @@ mod smoke {
 			env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"),
 		);
 
-		let config = get_config("minimal-template-node", None)?;
+		let config = get_config(NetworkSpec {
+			relaychain_cmd: "minimal-template-node",
+			..Default::default()
+		})?;
+
+		let network = config.spawn_native().await?;
+
+		// wait 6 blocks
+		let alice = network.get_node("alice")?;
+		assert!(alice
+			.wait_metric("block_height{status=\"finalized\"}", |b| b > 5_f64)
+			.await
+			.is_ok());
+
+		Ok(())
+	}
+
+	#[tokio::test(flavor = "multi_thread")]
+	async fn omni_node_with_minimal_runtime_block_production_test() -> Result<(), anyhow::Error> {
+		let _ = env_logger::try_init_from_env(
+			env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"),
+		);
 
+		let chain_spec_path = expect_env_var(CHAIN_SPECS_DIR_PATH) + "/minimal_chain_spec.json";
+		let config = get_config(NetworkSpec {
+			relaychain_cmd: "polkadot-omni-node",
+			relaychain_cmd_args: Some(vec![("--dev-block-time", "1000")]),
+			relaychain_spec_path: Some(chain_spec_path.into()),
+			..Default::default()
+		})?;
 		let network = config.spawn_native().await?;
 
 		// wait 6 blocks
 		let alice = network.get_node("alice")?;
-		assert!(alice.wait_metric("block_height{status=\"best\"}", |b| b > 5_f64).await.is_ok());
+		assert!(alice
+			.wait_metric("block_height{status=\"finalized\"}", |b| b > 5_f64)
+			.await
+			.is_ok());
+
+		Ok(())
+	}
+
+	#[tokio::test(flavor = "multi_thread")]
+	async fn omni_node_with_parachain_runtime_block_production_test() -> Result<(), anyhow::Error> {
+		let _ = env_logger::try_init_from_env(
+			env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"),
+		);
+
+		let chain_spec_path = expect_env_var(CHAIN_SPECS_DIR_PATH) + "/parachain_chain_spec.json";
+
+		let config = get_config(NetworkSpec {
+			relaychain_cmd: "polkadot",
+			para_cmd: Some("polkadot-omni-node"),
+			// Leaking the `String` to be able to use it below as a static str,
+			// required by the `FromStr` implementation for zombienet-configuration
+			// `Arg` type, which is not exposed yet through `zombienet-sdk`.
+			para_cmd_args: Some(vec![("--chain", chain_spec_path.leak())]),
+			..Default::default()
+		})?;
+		let network = config.spawn_native().await?;
+
+		// wait 6 blocks
+		let alice = network.get_node("collator")?;
+		assert!(alice
+			.wait_metric("block_height{status=\"finalized\"}", |b| b > 5_f64)
+			.await
+			.is_ok());
 
 		Ok(())
 	}