Toast
ContributorDecisions

ADR-003: Deployment Platform - Railway

ADR-003: Deployment Platform - Railway

Status

Accepted

Context

We needed a deployment platform for this development infrastructure spike with specific requirements:

Must-Have Requirements

  1. Preview deployments per PR - Every pull request needs a running instance for review
  2. Database per preview - Each PR environment needs its own PostgreSQL database
  3. Automatic cleanup - When PRs close/merge, both app and database should be deleted
  4. Fast iteration - Deploy times under 5 minutes
  5. Simple setup - Minimal configuration and maintenance overhead

Nice-to-Have

  • PostgreSQL (not MySQL) - Matches our production database choice
  • Built-in GitHub integration
  • Reasonable cost for development/spike work
  • Good developer experience (CLI, dashboard, logs)

Options Considered

1. Railway

Approach: Single platform providing both compute and PostgreSQL.

Pros:

  • Native PR environments with automatic provisioning
  • PostgreSQL included as first-class service
  • Single platform = single bill, single dashboard
  • Built-in GitHub integration handles deployments
  • Variable interpolation connects app to database automatically
  • Automatic cleanup when PRs close

Cons:

  • Relatively new platform (less battle-tested than AWS/GCP)
  • Vendor lock-in for deployment configuration
  • Less flexibility than self-managed infrastructure
  • railway.json only supports single-service config (multi-service requires manual setup)

2. Neon + Fly.io

Approach: Neon for serverless PostgreSQL with branching, Fly.io for compute.

Pros:

  • Neon's database branching is excellent for PR previews
  • Fly.io has fast, global edge deployment
  • Both are developer-focused with good DX
  • Neon's free tier is generous

Cons:

  • Two platforms to manage, configure, and debug
  • Need custom GitHub Actions workflow to coordinate
  • More moving parts for the spike phase
  • Fly.io requires buildpacks or Dockerfile optimization for fast deploys

3. Neon + Vercel

Approach: Neon for database, Vercel for serverless functions.

Pros:

  • Vercel's preview deployments are best-in-class
  • Neon integration is well-documented
  • Excellent for Next.js/frontend projects

Cons:

  • Vercel serverless functions have cold start overhead
  • Not ideal for long-running Hono API server
  • Would push us toward serverless architecture prematurely
  • Pricing can escalate with API traffic

4. PlanetScale + Render

Approach: PlanetScale for MySQL with branching, Render for compute.

Pros:

  • PlanetScale has excellent database branching
  • Render has straightforward PR previews
  • Both have good developer experience

Cons:

  • PlanetScale is MySQL, not PostgreSQL
  • PlanetScale removed free tier (cost consideration for spike)
  • Two platforms to coordinate
  • Would need to switch databases for production

5. Render (App + PostgreSQL)

Approach: Single platform like Railway.

Pros:

  • Similar integrated experience to Railway
  • PostgreSQL included
  • Preview environments available

Cons:

  • Preview databases require manual configuration
  • Less mature PR environment automation than Railway
  • Slower build times in our testing

Decision

Use Railway for the spike.

Rationale

  1. Simplicity wins for spikes - Railway's integrated approach means one platform, one configuration, one place to debug. This is appropriate for proving out architecture, not building production infrastructure.

  2. Native PR environments solve the hard problem - The combination of automatic preview creation, database provisioning, and cleanup is exactly what we need. Building this ourselves would take significant time.

  3. PostgreSQL alignment - We chose PostgreSQL for the database layer (see ADR-002). Railway provides PostgreSQL natively without needing a separate service.

  4. Good enough, not perfect - Railway's limitations (single-service config, less flexibility) are acceptable trade-offs for the spike phase. We're optimizing for learning speed, not production readiness.

Consequences

Positive

  • Fast setup - Production environment running in under an hour
  • Zero preview workflow maintenance - Railway handles PR environments automatically
  • Single source of truth - One dashboard for apps, databases, logs, and deployments
  • Simple environment variables - ${{Postgres.DATABASE_URL}} interpolation connects services

Negative

  • Multi-service config is manual - railway.json only configures one service; adding PostgreSQL requires dashboard/CLI setup. Documented in docs/railway-setup.md.
  • Platform dependency - Deployment configuration is Railway-specific. Moving to another platform requires migration work.
  • Less control - Can't customize infrastructure as deeply as AWS/GCP

Risks and Mitigations

RiskMitigation
Railway pricing changesStandard Dockerfile means we can migrate to any container platform
Railway outages affect developmentLocal Docker Compose setup works independently
Feature limitations discoveredRe-evaluate at production planning phase

Production Considerations

Railway is appropriate for this spike, but production deployment may warrant re-evaluation:

  • Scale requirements - Railway handles moderate scale; very high traffic might need dedicated infrastructure
  • Compliance needs - Evaluate data residency, SOC2, etc. based on actual requirements
  • Cost at scale - Compare Railway pricing vs self-managed at projected production load
  • Multi-region - Railway supports multiple regions but evaluate latency requirements

These concerns are explicitly out of scope for the spike phase.

References

On this page