ADR 003: Railway + Vercel Split Deployment
2026-07-13 status: Superseded for staging + production by ADR-038 (prod cutover #701 closed 2026-06-15). Railway remains canonical for dev only (deliberate choice, #1233). This ADR's Decision/Consequences sections below describe the pre-cutover state and are now historical for staging/prod; see ADR-038 for the current posture and
docs/ops/deploy.mdfor the live hosting table.
Date: 2026-04-22 Status: Accepted โ SUPERSEDED for staging/prod 2026-07-13 by ADR-038. Frontend-on-Vercel decision is unaffected. Dev remains on Railway.
Contextโ
The platform has three services that need to be deployed and operated:
api/โ NestJS backend (needs persistent connections, WebSocket, DB access)agent/โ Python FastAPI (GPU-optional, longer cold starts acceptable)frontend/โ Next.js (SSR + static assets, benefits from CDN edge)
Options evaluated:
- AWS ECS/EKS โ full control, high operational overhead, expensive for early stage
- Render โ simpler than AWS, limited WebSocket support, no persistent volumes on cheap tiers
- Fly.io โ good for edge, no managed Postgres/Redis, more config overhead
- Railway โ managed Postgres + Redis, simple deploy from
railway.toml, WebSocket support, persistent volumes - Vercel โ CDN-first, excellent for Next.js, no support for long-running Python or Node processes
Decisionโ
Railway for all backend services (api, agent, Postgres, Redis) + Vercel for the Next.js frontend.
As of 2026-06-03 this is the dev + prod posture; staging has cut over to ECS Fargate (#1303, building on #1101). See the ECS clarification addendum below and ADR-028.
The split is deliberate:
- Vercel's edge CDN gives the frontend global performance and zero-config Next.js deployment
- Railway handles everything that needs persistent connections, a database, or WebSocket support
All backend services are in one Railway project (humanwork), deployed independently via railway up --service <name>. Railway manages:
- Postgres 16 (with pgvector plugin) โ
humanwork-postgres - Redis 7 โ
humanwork-redis - API service โ
humanwork-api - Agent service โ
humanwork-agent
CI/CD is via GitHub Actions: test โ build โ railway up per service โ vercel --prod for frontend โ smoke test.
Consequencesโ
Benefits:
- Railway's managed Postgres eliminates DB operations overhead (backups, failover, pgvector extension installation via init script)
railway.tomlper service makes deploy config explicit and version-controlled- Railway keeps last 5 deployments โ rollback is one CLI command
- Vercel's CDN handles frontend scaling automatically; no capacity planning needed
- One Railway project = one billing line, simple cost visibility
Trade-offs:
- Railway is US-West region only currently. Multi-region (PRD target: Asia-Pacific edge) requires migration to AWS or Railway's planned multi-region support. Folded into the ECS Fargate cutover (#701) โ see addendum.
- Railway has ~2 minute cold starts for the agent service (Python dependency install). Mitigated by keeping the service always-on (no scale-to-zero).
- Split deployment means two sets of deploy credentials (Railway token + Vercel token) in GitHub Actions secrets.
Addendaโ
2026-06-01 โ Env-driven DB pool sizing (#917, closes #450)โ
DB pool sizing (DATABASE_POOL_MAX, DATABASE_POOL_MIN, DATABASE_POOL_IDLE_TIMEOUT_MS) is now env-driven on the API service. This was previously a hard-coded constant that did not match Railway's PgBouncer/pooler invariants and could exhaust pooled connections under multi-pod scale (see ADR-018). Defaults are tuned for Railway's transaction-pooler mode; non-Railway deploys (local docker, ephemeral CI) override via .env.
ECS clarificationโ
The "AWS ECS/EKS" line in the options table above was decision-time context only โ Railway is canonical for backend services as of this ADR. As of 2026-06-01, that has begun to shift: Railway hosts production today; staging is being migrated to ECS Fargate (#1101 Terraform + GHA, #1303 staging boot, #1314 composite ecs-deploy action, #1327 api-deploy/agent-deploy on composite). The infra/terraform/, agent/deploy/ecs.deferred/, and docs/ops/ecs-prod-deployment-spec.md artifacts reflect the in-flight migration. A formal supersession ADR will land once prod also cuts over.
Region note: Production is currently deployed to Railway US-West. For Asian mid-market launch, latency from HK/Singapore is acceptable at MVP scale (~150-200ms RTT). AWS AP-Southeast deployment was previously tracked as BLK-037 and is now folded into the ECS Fargate cutover above.
2026-07-13 โ Formal supersession (ADR-038)โ
Prod cutover (#701) closed 2026-06-15. ADR-038 is the formal supersession promised above โ staging and production are now AWS ECS Fargate + RDS Proxy, canonically. Railway is retained for dev only, a deliberate choice (#1233), not a lagging migration. See ADR-038 for the full decision record and docs/ops/deploy.md for the live per-environment hosting table.