# http/serve-cluster
Start a cluster of N worker runtimes, each binding the same port with
`SO_REUSEPORT` for kernel-level accept load-balancing. Each worker
loads the app file independently (which calls `http/serve` itself).
## Syntax
[http/serve-cluster port app-path ?n-workers ?opts]
## Parameters
- `port` — TCP port to bind (number)
- `app-path` — app file each worker loads (string)
- `n-workers` — optional, defaults to `os/cpu-count` (number)
- `opts` — optional map:
- `:app-name` — name used for the cache file basename (defaults to
app-path basename)
- `:watch-dirs` — vector of extra directories the parent watches for
reloads (the app file's directory is always watched)
## Returns
Cluster info map: `%{ :port :app-name :app-path :worker-count :workers :generation }`.
## Example
# driver.dft [http/serve-cluster 3000 "app.dft"] [vwait]
# Explicit worker count and watch dirs [http/serve-cluster 3000 "app.dft" 8 %{ :app-name "api" :watch-dirs @{"packages/help/manual" "www/pages"} }] [vwait]
## Notes
- The parent runtime owns the file watcher and the cluster control
stdlib functions. It must call `[vwait]` to stay alive.
- Each worker is a fully isolated runtime (own VM, heap, event loop,
OS thread). Workers do not share mutable state — use a WAL SQLite
cache, the `config/*` registry, or `pub/sub` for cross-worker state.
- In cluster-worker mode, `[vwait]` is a no-op in the worker (the loop
thread services the event loop) and `[http/serve]` automatically
sets `SO_REUSEPORT`.
## See Also
`http/serve`, `http/cluster-metrics`, `http/cluster-status`,
`http/cluster-reload`, `http/cluster-stop`