To build against new Base features without running infrastructure, use the hosted Vibenet instead.
Choose a Devnet
Use the Docker devnet to test node behavior or anything that depends on L1. Use the snapshot devnet to test your app against the contracts and liquidity it will meet on Base Mainnet.
Prerequisites
Both devnets need:- A clone of base/base. Run every command from its root.
just1.51.0or newer- Foundry (
cast) to send transactions jq
Docker Devnet
The Docker devnet runs a complete Base stack: an L1 (Reth + Lighthouse), a Base sequencer, two RPC nodes, and a batcher. It also runs a shadow batcher and shadow validator used to test the Rust batcher. It also needs Docker with Compose v2 and Buildx. The first build compiles the Rust services, so allocate generous memory to Docker.Start the Devnet
Terminal
Check that blocks are advancing:
Terminal
Send a Test Transaction
The devnet prefunds the standard Foundry/Anvil test accounts, listed inetc/docker/devnet-env. Send ETH through the sequencer:
Terminal
status 1 confirms the sequencer included the transaction. To run the built-in L1 and L2 checks instead, use just devnet checks.
Endpoints
Ports are set in
etc/docker/devnet-env. In just devnet up mode, 7545 is one of three conductor-managed sequencers. After a leader change, transactions sent to 7545 can stay pending; send through the RPC node at 8545, which forwards to the current leader.
Hardfork Activation
The devnet schedules Azul at L2 block 20, Beryl at 21, Cobalt at 22, and Denim at 25, so a fresh devnet crosses each activation within its first few blocks. Before Denim, the devnet produces a block every 2 seconds. At Denim, the sequencer switches to 200ms blocks.
To move an activation, set
L2_BASE_DENIM_BLOCK (or the matching L2_BASE_<HARDFORK>_BLOCK variable) before up or up-single. Set it to an empty value to leave that hardfork unscheduled.
Common Commands
Run
just devnet with no arguments for the full list.
Snapshot Devnet
The snapshot devnet downloads a Base node snapshot and continues it as a private local chain. Onebase dev process runs an execution node and a sequencer that produces 200ms blocks on top of the snapshot head. Deployed contracts, balances, and storage are exactly what they were on Base Mainnet at that block. There is no L1: the chain does not derive from L1, bridge, or advance safe and finalized heads.
It also needs:
- The Rust toolchain from the repo’s
rust-toolchain.toml(install rustup), Go, a C/C++ compiler, libclang, OpenSSL development headers,pkg-config, CMake, andprotoc. Thejustrecipes buildbasefrom your checkout; Docker is not required. - At least 1.5 TB of free disk for a Base Mainnet snapshot, which uses about 1.4 TB once unpacked, preferably on a fast NVMe drive. The workflow has been tested on Linux.
Download a Snapshot
Terminal
--print-plan-json.
If the download is interrupted, rerun the same command to resume; verified archives are reused. Add --manifest-url <url> to pin a specific snapshot. Never rerun a download into a directory that has already produced development blocks.
To use Base Sepolia, keep BASE_CHAIN unset for the download and pass --chain:
Terminal
Run the Devnet
Terminal
BASE_CHAIN=sepolia. The command builds base, prints the RPC endpoints and the snapshot head, and runs in the foreground.
On the first run, the node rebuilds the transaction and history indexes the snapshot does not include. RPC answers within seconds, but no blocks are produced until the rebuild finishes, which took about 22 minutes for a Base Mainnet snapshot in testing. Later runs start sequencing within seconds.
Both endpoints serve the standard
eth_*, debug_*, and trace_* methods, so Foundry, viem, and Hardhat work by pointing them at the HTTP URL. Change the ports with --http.port and --ws.port. The endpoints listen only on loopback and are unauthenticated; keep them private, because anyone who can reach them can act as any account.
Check that blocks are advancing:
Terminal
Impersonate Accounts
The snapshot devnet adds one RPC method,dev_impersonateTransaction, that runs a transaction as any account without its private key. Use it to fund accounts, move tokens from existing holders, and call owner-only or admin-only functions.
The method returns a transaction hash. The request runs as a deposit transaction: it skips signature, nonce, and fee checks, and pays no fees. Signature checks inside contracts, such as
ecrecover, EIP-1271, or permit, still apply. To test fees and transaction admission, send signed transactions instead.
The snapshot devnet keeps the snapshot’s chain ID,
8453 for Base Mainnet. Act as real accounts with dev_impersonateTransaction, and sign only with throwaway keys like the one below.Fund a New Account
Generate a throwaway key and mint it 1 ETH:Terminal
Terminal
0x7e, an effectiveGasPrice of zero, and from set to the impersonated account. Each request increments that account’s nonce. The account can now send normal signed transactions:
Terminal
Act as a Token Holder
Pick any account that holds WETH on Base Mainnet, such as one you find on a block explorer, and check its balance:Terminal
Terminal
Call an Owner-Only Function
Setfrom to the account the contract authorizes. For a contract with an owner() function:
Terminal
setValue(uint256) with the function you want to call. The same request from any other account is included with status 0.
Deploy a Contract as an Account
Omitto and pass the init code as input. This example deploys a contract that returns 42:
Terminal
Terminal
Confirm Inclusion
A returned hash means the request is queued, not mined. It is included in the next block with enough gas, usually within about 200ms. Pollcast receipt until it returns.
- Do not resubmit while waiting. Every request is a new transaction, so a repeated request runs again.
- Reverts are still included. A call that reverts or runs out of gas is included with
status 0. Any minted ETH is kept. - Pending requests are held in memory. Requests not yet included are lost if the process stops.
Block Timing
The snapshot devnet produces a block every 200ms. Block header timestamps have whole-second resolution, so about five consecutive blocks share a timestamp. Contracts that count blocks see time pass 10 times faster than on a 2-second chain; contracts that compareblock.timestamp see normal time. Heavy disk or CPU load can delay blocks.
Learn More
The base/base repo is the source of truth for both devnets:base devreference: snapshot devnet download retention, restarts, timing, anddev_impersonateTransactionlimits- Devnet README: Docker devnet topology, batcher setup, the Anvil + Nitro proving variant, and upgrade-signal testing
etc/docker/Justfile: every Docker devnet command- Testing guide: system tests against the Docker devnet (
just devnet tests) - Standalone proving guide: run the prover stack, which the Docker devnet does not include. ZK proving against a local devnet requires disabling Beryl and Cobalt.