Architecture decision ADR-006

Use Railway as Primary Cloud Platform Managed via Terraform

Accepted · 2026-05-10

Historical decision text is preserved. Accepted describes the decision, not deployment of every capability discussed. Consult the Architecture and Infrastructure tabs for the verified running system.

Date: 2026-05-10
Status: Accepted (amended 2026-05-20 — see "Amendment" below)
Deciders: Daniel Meza


Amendment (2026-05-20)

The original problem statement called for "separate staging and production environments." Per ADR-011 (Trunk-Based Development with Single Environment), the current release uses only a production environment tied to the single main branch. The Railway platform choice is unchanged; only the environment count has shrunk. The architecture remains compatible with re-introducing staging and develop environments if integration risk later justifies the cost.


Context and Problem Statement

Urza's Wallet needs a cloud platform to host its web app, API service, ingestion cron job, PostgreSQL database, and (eventually) Redis cache. The platform must:

The NerdWallet reference architecture recommends AWS EKS (Kubernetes) for production-grade deployments, with Terraform for IaC. The question is whether this recommendation applies to a Phase 1 product on a small team, or whether a platform-as-a-service (PaaS) provides a better tradeoff at this stage.


Decision Drivers


Considered Options

  1. Railway (PaaS) — Deploy all services as Railway projects. Use Railway managed PostgreSQL. Use Terraform Railway provider for IaC.
  2. AWS (ECS + RDS + CloudFront) — Deploy containers to ECS Fargate, use RDS for PostgreSQL, CloudFront for CDN. Terraform with AWS provider.
  3. Fly.io — Container-focused PaaS with built-in PostgreSQL (Fly Postgres), global edge deployment, Terraform support.
  4. Render — PaaS with managed PostgreSQL, preview environments, Terraform support.
  5. Vercel + Supabase — Vercel for Next.js hosting (first-class), Supabase for PostgreSQL + Auth.
  6. Google Cloud Run + Cloud SQL — Serverless containers + managed PostgreSQL. Terraform with Google provider.

Decision Outcome

Option 1: Railway as the primary platform is adopted, managed via Terraform using the terraform-provider-railway.

Why Railway wins on the low-ops + managed services combination:

Terraform module strategy:

The terraform-provider-railway is used to manage:

The terraform-provider-github manages:

The infra/terraform/shared/ module manages:

Terraform state backend: Terraform Cloud free tier (up to 500 resources, 1 concurrent run). Alternatively, a Cloudflare R2 bucket used as an S3-compatible backend with DynamoDB-compatible state locking via a third-party solution. Terraform Cloud is simpler for a small team.

Portability safeguards:


Positive Consequences

Negative Consequences / Trade-offs


Pros and Cons of the Options

Option Ops Overhead Managed PostgreSQL Preview Envs IaC Support Cost at Phase 1
Railway (chosen) Very Low Yes (auto-inject) Yes (native) Yes (community Terraform) ~$20–40/month
AWS (ECS + RDS) High Yes (RDS) Manual setup Yes (mature Terraform) ~$150–300/month + DevOps time
Fly.io Low Yes (Fly Postgres) Yes Yes (Terraform) ~$20–50/month
Render Low Yes Yes Yes (Terraform) ~$20–50/month
Vercel + Supabase Very low Yes (Supabase) Yes (Vercel) Partial ~$20–40/month
GCP Cloud Run + Cloud SQL Medium Yes Manual setup Yes (Terraform) ~$30–80/month

Fly.io and Render were close alternatives. Fly.io has better geographic distribution (Railway is primarily US-East and EU-West), which could be beneficial if Costa Rican users experience latency. However, Railway's GitHub integration and Terraform provider are more mature for this use case, and latency from Costa Rica to US-East is acceptable (~70–100 ms round-trip) for an SSG/ISR-heavy site.

Vercel + Supabase was considered for its zero-configuration Next.js hosting. However, using Supabase only for PostgreSQL while Clerk handles auth would be a mixed provider setup that provides no benefit. Additionally, Vercel has per-seat pricing for team features and does not offer a managed cron job service, which would require an additional provider for the Data Ingestion Service.


References