Skip to content

Deploy to Railway

Supabase stays as-is (Postgres, Auth, Storage). Railway hosts the API, the static frontend, and this documentation site.

Service Root directory Config
API server server/railway.toml
Frontend repo root railway.toml
Docs docs docs/railway.toml

The API is self-contained: catalog seed data lives in server/src/lib/catalog/ (no dependency on frontend src/). Railway can build with Root Directory = server.


  1. New service → GitHub repo → set Root Directory to server
  2. Variables (from server/.env.example):
Variable Notes
DATABASE_URL Supabase transaction pooler (port 6543)
DIRECT_URL Supabase session pooler (port 5432)
SUPABASE_URL
SUPABASE_SERVICE_ROLE_KEY
OPENAI_API_KEY Required for card creator chat
CORS_ORIGIN Public frontend URL, e.g. https://worker24-web.up.railway.app
CREATOR_IMAGE_BUCKET Optional, e.g. creator-images
AVATAR_IMAGE_BUCKET Optional, e.g. avatars
DEMO_USER_PASSWORD Optional

PORT is set by Railway automatically.

  1. Deploy → copy the public API URL (e.g. https://worker24-api.up.railway.app)

Build runs prisma generate + tsc. Start runs prisma migrate deploy then the server.

Health check: GET /health


  1. New service → same repo → Root Directory = / (repo root)
  2. Variables (must be present before build — Vite bakes them in):
Variable Example
VITE_USE_MOCK_DATA false
VITE_API_URL https://worker24-api.up.railway.app
VITE_SUPABASE_URL https://xxx.supabase.co
VITE_SUPABASE_ANON_KEY anon key
  1. Deploy → copy the public frontend URL
  2. Go back to the API service and set CORS_ORIGIN to that frontend URL (redeploy API if needed)

  1. New service → same repo → set Root Directory to docs
  2. No secrets required for a static docs build
  3. Deploy → public URL (e.g. https://worker24-docs.up.railway.app)

Build runs npm install && npm run build (Astro/Starlight → dist/).
Start serves the static site with serve on $PORT.

Optional: point a custom domain like docs.yourdomain.com at this service, then set site in docs/astro.config.mjs to that URL.

Local preview:

Terminal window
cd docs && npm run dev
# http://localhost:4321

Or from the repo root: npm run docs:dev


Terminal window
# Terminal 1 — API
cd server && npm run dev
# Terminal 2 — frontend (or from repo root)
npm run dev

Root .env:

Terminal window
VITE_API_URL=/api
VITE_USE_MOCK_DATA=false
VITE_SUPABASE_URL=...
VITE_SUPABASE_ANON_KEY=...

server/.env — database and server secrets as before.

Local CORS always allows http://localhost:5173 — no CORS_ORIGIN needed locally.


  • GET https://<api>/health{ "ok": true }
  • Frontend loads, catalog fetches cards
  • Account menu shows Sign in when logged out
  • Login / sign-up works
  • Card creator chat streams responses
  • Avatar upload works (Supabase avatars bucket + AVATAR_IMAGE_BUCKET)
  • Docs site loads at the Docs service URL

Sign in missingVITE_USE_MOCK_DATA must be false and VITE_API_URL must point to the live API URL (rebuild frontend after changing).

CORS errorsCORS_ORIGIN on the API must exactly match the frontend origin (scheme + host, no trailing slash).

DB connection errors — use Supabase pooler URLs from server/.env.example, not the direct db.*.supabase.co host.

Stale frontend env — Railway rebuilds are required after changing any VITE_* variable.

Docs build fails / wrong app built — Docs service Root Directory must be docs, otherwise Railway may build the Vite frontend instead.