Learn / Local Development

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.

Running a Production Node?

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.

Best for:
  • 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.

Best for:
  • 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.

Best for:
  • 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:

NodeRPC PortP2P PortRole
Alice994430334Validator + Sudo
Bob994530335Validator

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 list
FAST_BLOCKS

Set 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:

FeatureEnvironmentPurpose
pow-faucetDevEnables the PoW faucet RPC to mint test TAO without sudo
fast-runtimeDevReduces tempo/epoch lengths for faster testing cycles
metadata-hashProductionEmbeds a hash of the metadata for runtime verification
runtime-benchmarksDevEnables pallet benchmarking for weight calculation
try-runtimeDevEnables 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-ipv4

Manual 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:

ValueStateAuthorityNotes
devTemporary (wiped on restart)Alice (sudo)Single node, instant genesis
localPersistent (state saved to disk)Alice + BobTwo-node local testnet
test_finneyPersistentConnects to public testnet
finneyPersistentConnects to mainnet
devnetPersistentConnects 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
Subnet Registration Cost

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):

NameSeedRole
Alice//AliceAuthority + Sudo
Bob//BobPre-funded
Charlie//CharliePre-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
Underlying Chain Calls

Each btcli command submits an extrinsic to the chain: subnet createregister_network, subnet registerburned_register, weight setset_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 | jq

Clone 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
Sync Time

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:

FlagDefaultDescription
--outputDirectory to write the cloned state database
--sync-timeout-sec7200Maximum seconds to wait for the initial state sync (default 2 hours)
--aliceoffInject Alice as a pre-funded account with sudo privileges in the cloned state
--boboffInject Bob as a pre-funded account in the cloned state
--charlieoffInject Charlie as a pre-funded account in the cloned state

Next Steps