MainSDK
Search⌘K
How-to

Run one instance per core

Run one instance of your server per core with cluster.run, restart without dropping a request and stop cleanly on SIGTERM.

Building for 0.4

Status Status is where the work is: Planned (in a milestone, not started), Building (tickets in progress), Preview (usable, may change), then the stability it ships at.

Stability The promise an interface ships with.

  • Stable Follows semantic versioning; breaking changes need a new major, 12 months of overlap and a codemod.
  • Beta Usable in production; may change before it becomes stable.
  • Experimental May change or go away; needs an explicit opt-in in main.yaml.
Stability levels
Updated 2026-10-28

You will start your server once per core on one shared port, roll a restart through the instances and let the primary stop them through the drain. It takes about 10 minutes and needs no account.

You need

  • A long-running Node server that listens on a port. Serverless, edge and Deno run one process.
  • For limits and broadcasts that count once per host: runtime.store.driver: local (the default).

1. Declare the cluster

main.yaml
cluster:
  processes: auto
  start-timeout: 30s
health:
  shutdown: { deadline: 25s }

2. Start through cluster.run

start.ts
import { cluster } from "mainsdk";

declare function startServer(): Promise<void>;   // your own server entry, such as the one that calls listen()

await cluster.run(startServer);

The primary forks the instances and serves nothing. Each instance runs your server, and the primary routes connections only to instances that listen. In mainsdk dev and on serverless it runs one process and logs MAIN-WORKER-0014.

3. Roll a restart

Send SIGHUP to the primary, or call cluster.restart({ reason: "deploy" }). Each slot gets a new instance, waits until it is ready, then shuts the old one down through the drain. A new instance that is not ready in time stops the roll with MAIN-WORKER-0013 and the old instances keep serving.

4. Stop

SIGTERM to the primary starts the normal drain in every instance. The primary waits for health.shutdown.deadline plus 2 seconds, then ends what is left, and exits 0 only if every instance exited 0. An instance that crashes is respawned after the backoff (MAIN-WORKER-0011); a slot that crashes crashes times in window stops (MAIN-WORKER-0012).

Check it worked

  • Requests show several process ids, never the primary's.
  • cluster.snapshot() lists every instance as ready.
  • A restart replaces every pid and no request fails.

Was this page helpful?

↑↓ moveEnter openEsc close

Not decided yet