ChainLaunch Pro Feature
Node groups are the FabricX orchestration primitive. They require ChainLaunch Pro. Learn more about Pro features.
A Node Group is the parent record for a multi-process FabricX role. Where a Hyperledger Fabric peer is one container, a FabricX orderer is four containers (router, batcher, consenter, assembler) and a FabricX committer is five (sidecar, coordinator, validator, verifier, query). Operating those processes one-by-one is error-prone — node groups bundle them into a single unit you can init, start, stop, and back up atomically.
If you're running classic Fabric (peer/orderer/CA) or Besu, you don't need node groups. They're specifically a FabricX feature.
Group types
| Group type | Children | Use |
|---|---|---|
FABRICX_ORDERER_GROUP |
router, batcher, consenter, assembler | The four-process FabricX orderer party. Each port is allocated at init time. |
FABRICX_COMMITTER |
sidecar, coordinator, validator, verifier, query | The five-process FabricX committer party. Children are added one at a time so each can have its own MSP identity. |
Lifecycle
Create → Init (orderer only) → Start → ... → Stop → Delete
- Create — register the group row with platform/MSP/party metadata.
- Init (orderer only) — generate crypto, write on-disk config, persist
deployment_config, and create the four child role rows. Idempotent: fails if already initialized. - Start / Stop / Restart — fan out the action to every child in canonical role order (router → batcher → consenter → assembler for orderers; sidecar → coordinator → validator → verifier → query for committers).
- Delete — removes the group and all children. Use only after Stop.
For the committer, there's no init step. Add children one at a time via POST /api/v1/nodes with fabricXCommitter.nodeGroupId pointing at the parent group; each child carries its own MSP signing identity.
Permissions
All node-group endpoints require node:create, node:update, or node:delete as appropriate (mapped from RBAC roles ADMIN/OPERATOR). See RBAC.
Walkthrough — provision a FabricX orderer party
TOKEN="..."
BASE="https://chainlaunch.example.com/api/v1"
# 1. Create the group
GROUP=$(curl -sX POST "$BASE/node-groups" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "orderer-party-1",
"platform": "FABRICX",
"groupType": "FABRICX_ORDERER_GROUP",
"mspId": "OrdererMSP",
"organizationId": 1,
"partyId": 1,
"version": "v1.0.0",
"externalIp": "10.0.0.10",
"domainNames": ["orderer1.example.com"]
}')
GROUP_ID=$(echo "$GROUP" | jq .id)
# 2. Init — allocate ports for the four children
curl -sX POST "$BASE/node-groups/$GROUP_ID/init" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"routerPort": 7050,
"batcherPort": 7051,
"consenterPort": 7052,
"assemblerPort": 7053,
"consenterType": "smartbft"
}'
# 3. Start all four containers
curl -sX POST "$BASE/node-groups/$GROUP_ID/start" -H "Authorization: Bearer $TOKEN"
# 4. Inspect children (in canonical order)
curl -s "$BASE/node-groups/$GROUP_ID/children" -H "Authorization: Bearer $TOKEN" | jqExpected children listing:
[
{"role": "router", "nodeId": 101, "status": "RUNNING", "port": 7050},
{"role": "batcher", "nodeId": 102, "status": "RUNNING", "port": 7051},
{"role": "consenter", "nodeId": 103, "status": "RUNNING", "port": 7052},
{"role": "assembler", "nodeId": 104, "status": "RUNNING", "port": 7053}
]Walkthrough — provision a FabricX committer party
# 1. Create the group (no init step)
GROUP=$(curl -sX POST "$BASE/node-groups" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"name": "committer-org1",
"platform": "FABRICX",
"groupType": "FABRICX_COMMITTER",
"mspId": "Org1MSP",
"organizationId": 2,
"partyId": 2,
"version": "v1.0.0",
"externalIp": "10.0.0.20"
}')
GROUP_ID=$(echo "$GROUP" | jq .id)
# 2. Add each child individually (each gets its own MSP identity)
for ROLE in sidecar coordinator validator verifier query; do
curl -sX POST "$BASE/nodes" \
-H "Authorization: Bearer $TOKEN" \
-d "{
\"name\": \"committer-org1-$ROLE\",
\"platform\": \"FABRICX\",
\"nodeType\": \"FABRICX_$(echo $ROLE | tr a-z A-Z)\",
\"fabricXCommitter\": {
\"nodeGroupId\": $GROUP_ID,
\"role\": \"$ROLE\"
}
}"
done
# 3. Optionally attach a managed Postgres for the committer's state
SVC=$(curl -sX POST "$BASE/node-groups/$GROUP_ID/services/postgres" \
-d '{"name":"committer-pg","db":"committer","user":"committer","password":"...","hostPort":15432}')
# 4. Start the whole group
curl -sX POST "$BASE/node-groups/$GROUP_ID/start" -H "Authorization: Bearer $TOKEN"Children start in canonical order: sidecar → coordinator → validator → verifier → query. Stop runs in reverse.
Attaching services
Committers usually need an external PostgreSQL for their state store. There are two attach modes:
| Mode | Endpoint | When to use |
|---|---|---|
| Create-and-attach | POST /node-groups/{id}/services/postgres |
Greenfield: ChainLaunch creates the Postgres container and points the group at it |
| Attach existing | PUT /node-groups/{id}/postgres-service with serviceId |
You already have a Postgres elsewhere, just register the pointer |
| Detach | DELETE /node-groups/{id}/postgres-service |
Clears the pointer. The underlying service is not stopped — use POST /services/{id}/stop separately. |
Only FABRICX_COMMITTER groups accept Postgres services. Orderers don't need one.
Endpoint reference
| Method | Path | Purpose |
|---|---|---|
| GET | /api/v1/node-groups?limit=&offset= |
List groups |
| POST | /api/v1/node-groups |
Create group |
| GET | /api/v1/node-groups/{id} |
Get group |
| DELETE | /api/v1/node-groups/{id} |
Delete group + children |
| POST | /api/v1/node-groups/{id}/init |
(Orderer only) provision crypto + child rows |
| POST | /api/v1/node-groups/{id}/start |
Start every child in canonical order |
| POST | /api/v1/node-groups/{id}/stop |
Stop every child in reverse order |
| POST | /api/v1/node-groups/{id}/restart |
Stop then Start |
| GET | /api/v1/node-groups/{id}/children |
List children in canonical order |
| GET | /api/v1/node-groups/{id}/services |
List attached services |
| POST | /api/v1/node-groups/{id}/services/postgres |
Provision and attach Postgres |
| PUT | /api/v1/node-groups/{id}/postgres-service |
Attach existing service by id |
| DELETE | /api/v1/node-groups/{id}/postgres-service |
Clear pointer (no stop) |
CLI
The chainlaunch CLI mirrors these endpoints:
chainlaunch node-groups create \
--name orderer-party-1 \
--platform FABRICX \
--group-type FABRICX_ORDERER_GROUP \
--msp-id OrdererMSP \
--party-id 1
chainlaunch node-groups init <id> \
--router-port 7050 --batcher-port 7051 \
--consenter-port 7052 --assembler-port 7053
chainlaunch node-groups start <id>
chainlaunch node-groups listSee chainlaunch CLI reference for the full surface.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
init is only supported for FABRICX_ORDERER_GROUP |
You called init on a committer | Committers don't init — add children one at a time via POST /nodes |
init returns "already initialized" |
Re-running init on a group that has crypto | Delete the group and recreate, or skip init |
Group starts but one child stays in STARTING |
Port collision with another container | Check docker ps; pick free ports and re-init or recreate |
Group has 4 children but /children returns them in surprising order |
None — ChainLaunch enforces canonical role order | This is intentional; start/stop honor the same order |
| Cannot attach Postgres to an orderer | By design — orderers don't use Postgres | Attach Postgres only to FABRICX_COMMITTER groups |
| Group delete fails with "not stopped" | Children are still running | Stop the group first, then delete |
Children appear under /nodes but not under /node-groups/{id}/children |
The child's nodeGroupId field is unset |
Re-create the child with fabricXCommitter.nodeGroupId set |
How node groups relate to nodes
A node group is a parent record. Each child is a real node in the nodes table with node_group_id pointing back at the parent. That means:
- Children show up in
GET /api/v1/nodeslike any other node. - Children inherit the group's MSP identity, party id, and external IP.
- Per-child config (port, role, log level) lives on the child row.
- Backups and monitoring scrape children individually but tag them with the group label.
When in doubt, treat the group as the deployment unit and the children as the observation unit.
Next steps
- FabricX Overview — what FabricX is and why it has multi-process parties.
- FabricX Quickstart — provision a 4-party FabricX network end-to-end.
- FabricX Architecture — the role each child container plays.
- Backups — back up a whole node group atomically.
- RBAC & Permissions — who can manage groups.