Skip to main content
Version: Next (unstable)

Local Network Development

Use this guide to start a disposable Miden network for local development and testing. The provided Docker Compose setup includes a sequencer, three validators, a transaction prover, a network transaction builder, and a funding service. Optional services provide a block explorer, monitoring, and traces.

The Compose model lives in docker-compose.yml and uses profiles for optional explorer, telemetry, and monitoring services. The guide uses make targets as shorthand for the underlying Docker image builds and Docker Compose commands; check the Makefile when you need the exact command.

This is not a production deployment guide and it is not the path for independent full node runners on an existing network.

Prerequisites​

  • Git
  • Docker with Docker Compose support
  • make

Check Out a Version​

Prefer a release tag when testing against released artifacts. Use a branch when developing against the current repository state.

git clone https://github.com/0xMiden/node.git
cd node
git checkout <release-tag-or-branch>

Run a Published Version​

New releases are also published as Compose applications in the GitHub container registry. With Docker Compose 2.34.0 or later, start the core local network directly from the release artifact:

RELEASE_TAG=vX.Y.Z
COMPOSE_APPLICATION=oci://ghcr.io/0xmiden/miden-local-network:${RELEASE_TAG}

docker compose -f "${COMPOSE_APPLICATION}" up -d
docker compose -f "${COMPOSE_APPLICATION}" logs -f
docker compose -f "${COMPOSE_APPLICATION}" down -v

The application includes an OpenTelemetry Collector that receives traces from the Miden services. Enable the optional Midenscan explorer, Tempo, Grafana, and network monitor services with Compose profiles:

docker compose \
-f "${COMPOSE_APPLICATION}" \
--profile explorer \
--profile telemetry \
--profile monitor \
up -d

When the telemetry profile is enabled, the collector forwards traces to Tempo. To send a copy to another OTLP/gRPC endpoint, set OTEL_EXPORTER_OTLP_ENDPOINT; this works with or without the telemetry profile:

OTEL_EXPORTER_OTLP_ENDPOINT=https://collector.example.com:4317 \
docker compose -f "${COMPOSE_APPLICATION}" up -d

The genesis configuration can be replaced with the same Compose override used for a repository checkout.

Local Network Commands​

Build the images after checkout or whenever you need fresh local images. The Makefile targets enable the telemetry and monitor profiles. The local network stores data in the node-data Docker volume; local-network-down keeps that data, while local-network-delete removes it.

# Build the Docker images used by the local network.
make local-network-build

# Optionally build for a specific Docker platform.
make local-network-build DOCKER_PLATFORM=linux/arm64

# Start the local network.
make local-network-up

# Follow container logs.
#
# Logs are useful for startup checks; use Tempo traces for request-level debugging.
make local-network-logs

# Stop the local network, preserving the local chain data volume.
make local-network-down

# Stop the local network and delete the local chain data volume.
make local-network-delete

After make local-network-delete, run make local-network-up to bootstrap a fresh local chain.

Exposed Endpoints​

The bundled Caddy router listens on port 80 and routes .localhost host names to services on the Compose network. Names under .localhost resolve to the local loopback address, so they require no hosts-file or external DNS changes. Port 80 must be available on the host.

Existing direct ports remain available for native gRPC clients, automation, and compatibility:

ServiceRouted URLDirect address
RPC API (gRPC-Web)http://rpc.localhostlocalhost:57291 for native gRPC
Transaction proverhttp://prover.localhostNot published directly
Note transporthttp://ntl.localhostlocalhost:57292 for native gRPC
Funding servicehttp://funding.localhosthttp://localhost:50401
Block explorerhttp://explorer.localhosthttp://localhost:8080
Explorer GraphQLhttp://explorer.localhost/graphqlhttp://localhost:8199/graphql
Grafanahttp://grafana.localhosthttp://localhost:3000
Network monitorhttp://monitor.localhosthttp://localhost:3001
Tempo HTTP APIhttp://tempo.localhosthttp://localhost:3200
Tempo OTLP gRPCNot routedlocalhost:4317

Block Explorer​

Enable the explorer profile to run the Gateway FM Midenscan frontend, backend, indexer, database, and database migration:

docker compose --profile explorer up -d

The indexer reads from the local sequencer and persists its state in the explorer-data volume. The frontend is available at http://explorer.localhost, with its GraphQL API at http://explorer.localhost/graphql. These third-party components are intended for local development and are not part of the Miden node implementation.

Note Transport​

The workspace miden-note-transport service exchanges private notes between clients. Enable its optional profile:

docker compose --profile note-transport up -d

Its browser-facing gRPC-Web endpoint is http://ntl.localhost. Native gRPC clients can use localhost:57292. Compose initializes the database on first use and persists notes in the note-transport-data volume. The service limits stored note data to 1 GiB. Set MIDEN_NOTE_TRANSPORT_IMAGE to select a different workspace image.

Funding​

The funding service distributes the USDCx held by the distributor account. Use its HTTP API at http://funding.localhost. See the funding service guide for the request format.

The faucet service is disabled. The local network does not mint additional USDCx.

Monitoring and Traces​

The bundled OpenTelemetry Collector receives traces from the local network. With the telemetry profile enabled, it forwards traces to Tempo. Grafana is preconfigured with Tempo as a data source, so use http://grafana.localhost to inspect traces when a request fails, stalls, or behaves differently than expected.

Container logs are still useful for startup failures and quick checks, but traces usually provide a better view of how a request moved through the local network.

The network monitor at http://monitor.localhost provides a compact health view for the running local network.

Prover Override​

The default stack spins up an internal prover instance which means proving will happen locally. This can be overridden to use an external prover by setting MIDEN_REMOTE_PROVER_URL when starting the stack. The URL must be reachable from inside the Compose network.

MIDEN_REMOTE_PROVER_URL=http://<prover-host>:50051 make local-network-up

Additional Genesis Accounts​

To include additional accounts, create a TOML file with [[wallet]], [[fungible_faucet]], or [[account]] entries. Mount it through a Compose override:

accounts.override.yml
services:
bootstrap-validator:
configs:
- source: additional-accounts
target: /accounts.toml
environment:
MIDEN_VALIDATOR_GENESIS_ACCOUNTS_CONFIG: /accounts.toml
configs:
additional-accounts:
file: /absolute/path/to/accounts.toml
make local-network-up COMPOSE_OVERRIDE_FILE=/absolute/path/to/accounts.override.yml

Delete the existing local chain with make local-network-delete before changing its genesis accounts.

Storage Key Setup​

The Compose bootstrap service runs three concurrent dkg participate processes for a two-of-three storage key ceremony. They use the configured local validator signing keys and connect directly over loopback UDP inside the bootstrap container, which has no external network access. The ceremony does not need KMS, a relay, or public Iroh services.

Bootstrap generates the persistent endpoint identities before genesis and keeps them under /data/validators/endpoints in the node-data volume. Each participant writes its own /data/validators/<n>/storage-key.bundle. Bootstrap marks the validators ready only after all three participants confirm completion. A failed ceremony stops bootstrap; delete the local network data before starting a new ceremony.

The ceremony can take several minutes and has a five-minute timeout. For a faster local start, set MIDEN_VALIDATOR_USE_STORAGE_KEY_FIXTURE=true to use the committed insecure fixture instead. The fixture is public test data and must never be used outside local development.

Check the RPC API​

The RPC server exposes gRPC reflection. With grpcurl installed, a basic status check looks like:

grpcurl -plaintext localhost:57291 miden.node.v1.NodeService/Status

Note the -plaintext flag, the local network does not use TLS.

Use the gRPC API section for the public RPC surface and streaming endpoints.