ChainLaunch Pro Feature
One-shot testnet provisioning requires ChainLaunch Pro. Learn more about Pro features.
The testnet API spins up a fully-functional Hyperledger Fabric or Hyperledger Besu network in a single API call — keys, organizations, peers/orderers/validators, channels, and genesis block all generated and started for you. Use it for local development, demos, integration tests, and CI fixtures. It's not for production.
For production-grade networks, use the network builder UI or Network Templates — those give you control over crypto material, MSP definitions, channel policies, and node configuration. The testnet API trades that control for one-command convenience.
What you get
| Platform | Topology |
|---|---|
| Besu | N validator nodes (≥ 4) with QBFT consensus, shared genesis with optional initial balances, Docker or systemd mode |
| Fabric | Configurable peer orgs and orderer orgs, configurable peer/orderer counts per org, configurable channels, etcdraft or SmartBFT consensus |
Each testnet creates:
- One key per node, generated in parallel under the configured key provider.
- One Organization per peer org and orderer org (Fabric).
- One Network row + genesis block.
- N Node rows, started immediately.
- Channels (Fabric only) joined by every peer.
You get back the network ID and the node IDs. The whole thing typically takes 30–90 seconds for a 4-node Besu network or a 2-org Fabric network.
Permissions
Testnet endpoints require network:create + node:create (granted to ADMIN and OPERATOR by default). See RBAC.
Quickstart — Besu
chainlaunch testnet besu \
--name besu-dev \
--nodes 4 \
--prefix validator \
--mode docker \
--version 25.5.0 \
--provider-id 1 \
--initial-balance "0x627306090abaB3A6e1400e9345bC60c78a8BEf57=0x3635c9adc5dea00000" \
--initial-balance "0xf17f52151EbEF6C7334FAD080c5704D77216b732=0x3635c9adc5dea00000"CLI output (plain text — the CLI streams progress and prints the network ID):
Creating 4 validator keys...
Creating key for node validator-besu-dev-1...
Key created: ID 101
...
Besu network created: ID 12
Creating 4 Besu nodes...
Creating Besu node validator-besu-dev-1 with key ID 101...
Node created ID: 201
...
Besu testnet created successfully! Network ID: 12
Equivalent REST API response (POST /testnets/besu), useful for automation:
{
"network_id": 12,
"node_ids": [101, 102, 103, 104],
"message": "Besu testnet 'besu-dev' created with 4 validators"
}The four validators come up running QBFT, the genesis block prefunds the addresses you listed, and you can immediately point web3.js / ethers / hardhat at the JSON-RPC endpoint of any node.
Fields
| Field | Required | Default | Notes |
|---|---|---|---|
name |
yes | — | Used as the network name and the key/node prefix |
nodes |
yes | — | Minimum 4 for QBFT (3f+1, f=1) |
prefix |
no | besu |
Prefix applied to validator node names |
mode |
yes | — | docker or service (systemd) |
version |
no | 25.5.0 |
Besu version |
provider_id |
no | 1 |
Key provider — see Key Management |
initial_balances |
no | empty | Map of address → wei for genesis prefunding |
Quickstart — Fabric
chainlaunch testnet fabric \
--name fabric-dev \
--mode docker \
--org Org1 \
--peerOrgs Org1,Org2 \
--ordererOrgs OrdererOrg \
--peerCounts Org1=2,Org2=2 \
--ordererCounts OrdererOrg=3CLI output (plain text):
Fabric testnet created successfully! Network ID: 13
Peer joined network 13 successfully. Network ID: 201, Status: joined
Peer joined network 13 successfully. Network ID: 202, Status: joined
...
Orderer joined network 13 successfully. Network ID: 205, Status: joined
...
Equivalent REST API response (POST /testnets/fabric), useful for automation:
{
"network_id": 13,
"node_ids": [201, 202, 203, 204, 205, 206, 207],
"message": "Fabric testnet 'fabric-dev' created with 2 peer orgs, 1 orderer org, 1 channel"
}You get four peers (two per org) and three orderers in the orderer org, all joined to a brand-new network with its own genesis block. Channels and chaincode are created in follow-up steps -- see Chaincode CI/CD with the CLI.
`--channels` is currently unused by the CLI
The --channels flag is accepted by chainlaunch testnet fabric but the runner does not wire it through to network creation today. Use POST /testnets/fabric with a channels field in the JSON body if you need channels provisioned at testnet creation time, or create channels separately via the network builder after provisioning.
Fields
| Field | Required | Default | Notes |
|---|---|---|---|
name |
yes | — | Network name |
mode |
yes | — | docker or service |
peer_orgs |
yes | — | List of peer org names; one Organization is created per entry |
orderer_orgs |
yes | — | List of orderer org names |
peer_counts |
yes | — | Map of orgName → count. Each peer org needs an entry. |
orderer_counts |
yes | — | Map of orgName → count. Each orderer org needs an entry. Total must be ≥ 3 orderers for consenters. |
channels |
no | ["mychannel"] if omitted |
Channels to create. All peers join all channels. REST-only: not wired through --channels on the CLI today. |
consensus_type |
no | etcdraft |
etcdraft or smartbft. REST-only: the CLI does not expose this. |
Lifecycle
POST /testnets/{platform}
→ ChainLaunch creates keys, orgs, network, nodes
→ Returns 201 with networkId + nodeIds
# Treat the resulting network like any other ChainLaunch network from here:
GET /networks/{networkId}
GET /nodes/{nodeId}
POST /networks/{networkId}/chaincodes (Fabric)
DELETE /networks/{networkId} (tears down everything)
The testnet API is provisioning-only — it has no special teardown. Delete the network the same way you'd delete any other.
CLI
# Besu
chainlaunch testnet besu \
--name besu-dev --nodes 4 --mode docker
# Fabric (note: CLI uses camelCase flag names — different from the JSON API)
chainlaunch testnet fabric \
--name fabric-dev --mode docker \
--org Org1 \
--peerOrgs Org1,Org2 \
--ordererOrgs OrdererOrg \
--peerCounts Org1=2,Org2=2 \
--ordererCounts OrdererOrg=3
# Channels are not yet wired through the CLI — create them after provisioning
# or call POST /testnets/fabric directly with a `channels` field.Common patterns
CI fixture
Spin up a fresh network for every test job and tear it down afterwards. ChainLaunch handles the cleanup atomically:
# .github/workflows/integration.yml
- name: Provision testnet
run: |
# The CLI prints plain-text status, so call the REST endpoint when you
# need a parseable response. (At least 3 orderers are required by the
# CLI runner; the REST endpoint enforces the same consenter floor.)
RESP=$(curl -fsS -u "$CHAINLAUNCH_USER:$CHAINLAUNCH_PASSWORD" \
-H 'Content-Type: application/json' \
-d '{"name":"ci-fabric","mode":"docker","peer_orgs":["Org1","Org2"],"orderer_orgs":["OrdererOrg"],"peer_counts":{"Org1":1,"Org2":1},"orderer_counts":{"OrdererOrg":3},"channels":["mychannel"]}' \
"$CHAINLAUNCH_API_URL/testnets/fabric")
NETWORK_ID=$(echo "$RESP" | jq .network_id)
echo "NETWORK_ID=$NETWORK_ID" >> $GITHUB_ENV
- name: Run integration tests
run: pytest tests/integration
- name: Teardown
if: always()
run: |
# Network deletion via the CLI is not yet wrapped — use the API.
curl -sX DELETE -u "$CHAINLAUNCH_USER:$CHAINLAUNCH_PASSWORD" \
"$CHAINLAUNCH_API_URL/networks/fabric/$NETWORK_ID"Demo environment
A lightweight network for sales demos. Default the prefix so all containers are easy to spot in docker ps:
chainlaunch testnet besu --name demo --prefix demo --nodes 4 --mode dockerDevelopment against a stable testnet
For longer-lived shared dev networks, provision once and don't tear down. Treat the testnet output as an ordinary network — every other ChainLaunch feature (backups, monitoring, RBAC, audit) applies.
Limits
- Besu testnets require ≥ 4 nodes (QBFT 3f+1 with f=1). The API rejects fewer.
- Fabric peer orgs that aren't listed in
peer_counts(or with count 0) cause the request to fail. - The same key provider is used for every node. To split keys across providers, build the network the long way via Network Templates.
- All nodes in one testnet land on the same host (
mode=dockerruns all containers on the ChainLaunch host;mode=serviceruns all systemd units on the host). For multi-host testnets, use Pro Sharing to pair multiple ChainLaunch instances and share network metadata. - The genesis block is generated once at provisioning. To change parameters later, you have to recreate the network.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
besu testnet requires at least 4 nodes for QBFT consensus |
nodes < 4 |
Bump to 4 or more |
| Some node IDs returned but their containers aren't running | Port exhaustion on the host | Check docker ps, free up ports, redeploy |
peer_counts must include all peer_orgs |
Mismatch between peer_orgs array and peer_counts map |
Make sure every org name in peer_orgs is a key in peer_counts |
| Slow startup (>2min) | Image pull on first run | Subsequent runs reuse cached images |
| Channel doesn't appear after provisioning | etcdraft hadn't elected a leader yet | Wait 10–15 seconds and retry; or check orderer logs |
| Initial balances missing | Address case-sensitive issue | Use checksum-cased Ethereum addresses |
When NOT to use the testnet API
- Production networks. Hand-build via the UI or Network Templates so you control crypto material and policies.
- Multi-host networks. The testnet runs everything on one ChainLaunch host. Pair instances via Pro Sharing for distributed deployments.
- Custom MSP definitions. The testnet uses ChainLaunch defaults; if you need fine-grained MSP policies, build it manually.
- Existing-org reuse. The testnet API creates fresh organizations every time. To deploy a new network using existing keys/orgs, use the regular network builder.
Next steps
- Network Templates — repeatable network blueprints with full control.
- Multi-Org Fabric Network — production-grade multi-org consortium walkthrough.
- Pro Sharing — link two testnets across hosts for distributed dev.
- CLI Reference — full
chainlaunch testnetflag reference.