Skip to main content
Version: 0.16 (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 optional block explorer, faucet, monitoring, and trace services, so you can develop against a working environment without wiring the network services manually.

The Compose model lives in docker-compose.yml and uses profiles for optional explorer, faucet, 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 faucet, Midenscan explorer, Tempo, Grafana, and network monitor services with Compose profiles:

docker compose \
-f "${COMPOSE_APPLICATION}" \
--profile faucet \
--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
Faucet frontendhttp://faucet.localhosthttp://localhost:8081
Faucet APIhttp://faucet.localhost/apihttp://localhost:8000
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 Miden Note Transport service exchanges private notes between clients. Enable its optional profile explicitly:

docker compose --profile note-transport up -d

Its browser-facing gRPC-Web endpoint is http://ntl.localhost; native gRPC clients can use localhost:57292. Notes are persisted in the note-transport-data volume.

The pinned Gateway FM image currently supports only linux/amd64. Compose selects that platform explicitly, allowing Docker to run it through emulation on ARM hosts. To use a compatible native build instead, set both MIDEN_NOTE_TRANSPORT_IMAGE and MIDEN_NOTE_TRANSPORT_PLATFORM.

Faucet

The faucet is maintained in the separate 0xMiden/faucet repository and can lag behind the node's protocol version. It is therefore excluded from the default stack. Enable its profile explicitly:

docker compose --profile faucet build faucet
docker compose --profile faucet up -d

For a repository checkout, the first run builds the exact upstream commit pinned in compose/faucet.yml. Node releases publish an image built from the same pin, so the published Compose application can pull it without requiring a source build.

On its first successful start, the service imports the native MIDEN faucet account created at genesis and stores its client state in the faucet-data volume. Later starts reuse that state. The API is available at http://faucet.localhost/api and the frontend at http://faucet.localhost.

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

Genesis Config Override

By default, the local network bootstraps from the bundled genesis Compose config in compose/bootstrap.yml. It contains the public signing keys for the three validator services. Their corresponding private keys are insecure defaults defined in compose/validator.yml and must never be used outside local development.

To replace it, create a Compose override file:

genesis.override.yml
configs:
genesis: !override
file: /absolute/path/to/genesis.toml

Use that override with either the repository model or a published application:

make local-network-up COMPOSE_OVERRIDE_FILE=/absolute/path/to/genesis.override.yml

docker compose \
-f oci://ghcr.io/0xmiden/miden-local-network:vX.Y.Z \
-f /absolute/path/to/genesis.override.yml \
up -d

The custom configuration is mounted into the bootstrap validator as /genesis.toml and passed to miden-validator genesis --config. Its validators list must contain the public keys corresponding to the three validator private keys. Override those private keys with MIDEN_VALIDATOR_1_SIGNING_KEY, MIDEN_VALIDATOR_2_SIGNING_KEY, and MIDEN_VALIDATOR_3_SIGNING_KEY.

This only affects validator bootstrap. If the local network has already been bootstrapped, delete the existing local chain data before starting with a different genesis configuration:

make local-network-delete

Storage Key Setup

The Compose bootstrap service runs the two-of-three storage key ceremony and validates each validator's output before starting the network. This can take several minutes. 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 rpc.Api/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.