Skip to main content
Platforms

Railway

Run the Rivet control plane on Railway.

Requirements

Steps

Deploy a template

Two templates are published. Both provision the control plane and a PostgreSQL database.

RivetRivet Starter
Blank templateComplete example
Control plane and PostgreSQLControl plane, PostgreSQL, and a chat app built with actors
Manual setup from hereRuns immediately

To build it by hand instead, create a project, add a PostgreSQL database, then add a Docker Image service using rivetdev/engine:latest with RIVET__POSTGRES__URL=${{Postgres.DATABASE_URL}}.

The Railway template repository is a useful starting point for your own application.

Find the admin token

The templates generate one. It is under the Variables tab as RIVET__AUTH__ADMIN_TOKEN.

Set the draining period

Railway kills the old deploy 0 seconds after SIGTERM by default, so in-flight requests are dropped and state flushes are interrupted on every single deploy. Rivet drains cleanly on SIGTERM, but only if it is given time.

Under Settings → Deploy, set Draining seconds to 60. It can also be set with drainingSeconds in config-as-code, or the RAILWAY_DEPLOYMENT_DRAINING_SECONDS service variable. See Railway’s deployment teardown docs.

Verify

Open your service URL with /ui appended and log in with the admin token.

Create the runner config

A runner config declares a pool that workers connect to. Without one the control plane refuses every worker, so create it before deploying any:

curl -X PUT "https://<your-service>.up.railway.app/runner-configs/default?namespace=default" \
  -H "Authorization: Bearer $RIVET_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"datacenters":{"default":{"normal":{}}}}'

Use normal for long-lived workers. See Runner configs.

Signal handling

If your start command is a wrapper (npm start, yarn start, a shell script), the wrapper becomes PID 1, swallows SIGTERM, and the drain never happens no matter what you set the draining period to.

  • Invoke the binary directly, for example node dist/index.js.
  • Or run dumb-init or tini as PID 1 in your Dockerfile.

WebSocket timeouts

Railway’s HTTP proxy supports WebSockets. If you add your own reverse proxy inside the service, raise its idle and read timeouts to 3600. See Ports.

Scaling past one instance

Both templates provision a single control plane service on PostgreSQL, which is a fine starting point. Before raising the replica count, add NATS for pub/sub so replicas coordinate. See Storage.

Railway has no CPU-target autoscaler, so replica count is a number you set rather than one that moves with load. Pick it for peak traffic, and use Kubernetes or AWS ECS if you need it to scale on its own.

Next steps