ChainLaunch

Pro Feature

Node Groups

Node groups are the FabricX orchestration primitive. They require ChainLaunch Pro. Learn more about Pro features.

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" | jq

Expected 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 list

See 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/nodes like 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