A node is one VM in a cluster. Every cluster has exactly one primary; additional nodes are async read replicas.

Add a replica

POST /database/node/add
Authorization: Bearer <token>
Content-Type: application/json

{
  "cluster_id": <id>,
  "image_id": 1,
  "instance_type": "m1a.xlarge",
  "subnet_id": 1,
  "zone_id": 1,
  "allocate_public_ipv4": false,
  "security_group_ids": [12]
}

Required: cluster_id, image_id, instance_type, subnet_id, zone_id.

The new node is provisioned, joins the cluster as a replica, and starts streaming from the primary. Adding nodes is online — no downtime on the primary.

Replicas can be a different instance type than the primary if you want — pick whatever matches your read workload.

Restart one node

POST /database/node/restart
Authorization: Bearer <token>
Content-Type: application/json

{ "node_id": <id> }

Restarting the primary triggers a failover to one of the replicas — clients see a short reconnect window. Restarting a replica is invisible to writers but causes that replica’s connections to drop.

Terminate one node

POST /database/node/terminate
Authorization: Bearer <token>
Content-Type: application/json

{ "node_id": <id> }

Removes the node from the cluster. The cluster keeps running with the remaining nodes; the removed node’s storage is released.

You can’t terminate the last node — terminate the cluster itself with cluster/terminate instead.

Read traffic

The cluster hostname resolves to the primary. To read from replicas, use the per-node hostnames returned in database/list, or use a connection pooler like PgBouncer / pgpool-II that knows about streaming replication.

Required permissions

ActionPermission
Adddatabase:node:add
Restartdatabase:node:restart
Terminatedatabase:node:terminate

Resource scoping: exc:database:node/<id>. See the Policies guide.