Skip to content
Deploy

Overview

Four deployables, three platforms, and which of them ship on a push.

Four deployables, three platforms, and only one of them ships when you push. That asymmetry is the single most common way to deploy nothing while believing you deployed something.

What goes where#

You changedDeploys toAutomatic on push to main
web/Vercelyes
server/Railwayno — manual, always
src/ (control plane)Railway, its own serviceno — manual
infra/ (media plane)a rented VMno — a runbook

Order#

  1. The media plane first. Everything else needs a LIVEKIT_URL to point at, and until one exists the control plane mints tokens nothing can use.
  2. The control plane. Give it the key pair from step 1 and UDK_SECRET.
  3. The API and the web app. They need the control plane's URL, and they need to agree with it about UDK_SECRET.
  4. The worker, beside the media plane.

The one Railway setting that is not optional#

Every service carries a healthcheck, and a repository without a deploy block is worse than one with a slow probe — with no healthcheck, the platform goes green the instant the container starts, which means traffic reaches an app that cannot answer yet.

"deploy": {
  "healthcheckPath": "/health",
  "healthcheckTimeout": 300,
  "restartPolicyType": "ON_FAILURE",
  "restartPolicyMaxRetries": 10,
  "overlapSeconds": 20,
  "drainingSeconds": 15
}

healthcheckTimeout must clear the worst-case cold boot, not the warm one. 120 seconds was tried and failed a perfectly correct deploy.

A probe hardcoded to 200 is not a shortcut past this. There is one probe and it is a traffic gate: an always-healthy endpoint tells the platform to cut the edge over to a container that cannot answer, and removes the only signal that would ever restart a wedged process. Keep the probe honest and make readiness fast.

A deploy reported SUCCESS is not yet reachable#

Zero-downtime rollover holds the old container until the new one drains, and the window is minutes — measured at 5m15s and 5m55s from SUCCESS to the first 200. During it the domain accepts TCP and returns nothing, which reads exactly like an outage and is not one.

Do not roll back, do not redeploy, and do not go hunting. drainingSeconds and overlapSeconds above are what shorten it.

Verifying, without waiting blind#

/health is not a readiness signal for a new deploy: the old instance keeps answering it perfectly while the new one builds, so a health poll reports success about code that is not running yet.

Confirm a field only the new code emits, or ask the platform which revision is live. Health and status

Up nextThe media plane