Local Development
Run a local Subtensor chain to test transactions, experiment with subnets, and iterate quickly — without spending real TAO or waiting for testnet confirmations.
This guide covers local development setups. For running a public-facing node on mainnet or testnet, see the Node Operations guide.
Choose Your Setup
There are three ways to run a local Subtensor chain, each with different tradeoffs. Pick the one that best fits your workflow.
Docker Localnet
Pre-built Docker images with Alice and Bob validators ready to go. No Rust toolchain required. The fastest way to get a local network running.
- • Quick setup and teardown
- • CI/CD integration
- • Getting started fast
Source Build
Build from the Subtensor source with dev-specific features like the PoW faucet and fast runtime. Required when modifying the node itself.
- • Node development and hacking
- • Custom dev features
- • Full control over binary
Clone State
Fork real mainnet or testnet state into a local chain. Test against production data without touching live funds or subnets.
- • Testing against real state
- • Debugging production issues
- • Migration dry runs
Docker Localnet
The Subtensor repository ships a docker-compose.yml that spins up a two-node localnet
(Alice and Bob) in minutes. No Rust compilation required.
# Clone the repository
git clone https://github.com/opentensor/subtensor.git
cd subtensor
# Build and start the localnet (Alice + Bob validators)
docker compose -f docker-compose.localnet.yml build
docker compose -f docker-compose.localnet.yml up -d
# Follow logs
docker compose -f docker-compose.localnet.yml logs -f Default ports exposed on localhost:
| Node | RPC Port | P2P Port | Role |
|---|---|---|---|
| Alice | 9944 | 30334 | Validator + Sudo |
| Bob | 9945 | 30335 | Validator |
Connect with btcli
Point btcli at your local Alice node using the --subtensor.network flag:
btcli --subtensor.network ws://127.0.0.1:9944 wallet listSet the FAST_BLOCKS=1 environment variable before starting the compose stack to enable faster block times.
This speeds up tempo-based operations like subnet registration and weight setting during
development.
Verify Connection
# Verify local node connection
curl -s -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"system_health","params":[],"id":1}' \
http://127.0.0.1:9944 | jq You should see isSyncing: false and peers: 1 (Alice and Bob are peered with each other).
Source Build for Dev
Building from source lets you enable dev-specific Cargo features that are not included in
production builds. The most important for local development is pow-faucet, which lets you mint test TAO via a proof-of-work
faucet.
See the Node Operations guide for full prerequisites (Rust toolchain, build-essential, clang, protobuf-compiler).
# Clone and build with dev features
git clone https://github.com/opentensor/subtensor.git
cd subtensor
# Build with pow-faucet enabled (release profile for speed)
cargo build -p node-subtensor --release --features=pow-faucet
# Binary location
./target/release/node-subtensor Available build features:
| Feature | Environment | Purpose |
|---|---|---|
pow-faucet | Dev | Enables the PoW faucet RPC to mint test TAO without sudo |
fast-runtime | Dev | Reduces tempo/epoch lengths for faster testing cycles |
metadata-hash | Production | Embeds a hash of the metadata for runtime verification |
runtime-benchmarks | Dev | Enables pallet benchmarking for weight calculation |
try-runtime | Dev | Enables runtime migration testing against live state snapshots |
Running in Dev Mode
Once you have a dev binary, start it with --chain dev and a sealing mode. Dev
mode starts a single-node chain with Alice as both the authority and sudo account. All
state is temporary and wiped on restart (unless you set a --base-path).
Instant Seal (Recommended)
A new block is produced immediately when a transaction is submitted. Best for interactive development — you see results right away.
./target/release/node-subtensor \
--chain dev \
--sealing instant \
--rpc-external \
--rpc-cors all \
--allow-private-ipv4Manual Seal
Blocks are only produced when you explicitly request one via the engine_createBlock RPC call. Useful for testing exact block boundaries.
./target/release/node-subtensor \
--chain dev \
--sealing manual \
--rpc-external \
--rpc-cors all \
--allow-private-ipv4--chain options:
| Value | State | Authority | Notes |
|---|---|---|---|
dev | Temporary (wiped on restart) | Alice (sudo) | Single node, instant genesis |
local | Persistent (state saved to disk) | Alice + Bob | Two-node local testnet |
test_finney | Persistent | — | Connects to public testnet |
finney | Persistent | — | Connects to mainnet |
devnet | Persistent | — | Connects to development network |
Getting Test TAO
On a local dev chain built with --features=pow-faucet, you can mint test TAO into any wallet using the faucet. The faucet requires a small proof-of-work to prevent spam.
# Mint TAO into your owner wallet
btcli --subtensor.network ws://127.0.0.1:9944 wallet faucet \
--wallet.name owner \
--max-allowed-attempts 50
# Mint TAO into your validator wallet
btcli --subtensor.network ws://127.0.0.1:9944 wallet faucet \
--wallet.name validator \
--max-allowed-attempts 50 Creating a subnet requires approximately 1,000 TAO . Run the faucet multiple times to accumulate enough test balance before attempting subnet registration.
Pre-funded dev accounts (available on --chain dev and local without
the faucet):
| Name | Seed | Role |
|---|---|---|
| Alice | //Alice | Authority + Sudo |
| Bob | //Bob | Pre-funded |
| Charlie | //Charlie | Pre-funded |
Testing Transactions
With a local chain running and test TAO in your wallets, you can test the full subnet lifecycle end-to-end using btcli. Each btcli command maps to an underlying chain call — see the linked reference docs.
# Create a subnet (costs ~1000 TAO)
btcli --subtensor.network ws://127.0.0.1:9944 subnet create \
--wallet.name owner
# Register a neuron on subnet 1
btcli --subtensor.network ws://127.0.0.1:9944 subnet register \
--wallet.name validator \
--wallet.hotkey default \
--netuid 1
# List registered neurons
btcli --subtensor.network ws://127.0.0.1:9944 subnet list
# Set weights (once you have at least 2 neurons)
btcli --subtensor.network ws://127.0.0.1:9944 weight set \
--wallet.name validator \
--wallet.hotkey default \
--netuid 1 Each btcli command submits an extrinsic to the chain: subnet create → register_network, subnet register → burned_register, weight set → set_weights. See the Reference Docs for full call details.
Verify via RPC
After creating a subnet, verify it exists by querying the node directly:
# Verify subnet creation via RPC
curl -s -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"subtensor_getSubnetInfo","params":[1],"id":1}' \
http://127.0.0.1:9944 | jqClone State
The clone-state subcommand syncs state from a live network (mainnet or testnet)
into a local database, then starts a local chain using that state. This lets you test against
real production data without touching live funds.
# Clone state from mainnet into a local chain
./target/release/node-subtensor clone-state \
--chain finney \
--output /var/lib/subtensor-clone \
--alice State cloning can take up to 2 hours depending on network conditions and the size of
the chain state. The default sync timeout is 7,200 seconds (2 hours). Add --history-backfill skip to skip historical gap-backfill during sync for faster completion.
Key clone-state flags:
| Flag | Default | Description |
|---|---|---|
--output | — | Directory to write the cloned state database |
--sync-timeout-sec | 7200 | Maximum seconds to wait for the initial state sync (default 2 hours) |
--alice | off | Inject Alice as a pre-funded account with sudo privileges in the cloned state |
--bob | off | Inject Bob as a pre-funded account in the cloned state |
--charlie | off | Inject Charlie as a pre-funded account in the cloned state |