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
- Preview deployments per PR - Every pull request needs a running instance for review
- Database per preview - Each PR environment needs its own PostgreSQL database
- Automatic cleanup - When PRs close/merge, both app and database should be deleted
- Fast iteration - Deploy times under 5 minutes
- 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.jsononly 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
-
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.
-
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.
-
PostgreSQL alignment - We chose PostgreSQL for the database layer (see ADR-002). Railway provides PostgreSQL natively without needing a separate service.
-
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.jsononly configures one service; adding PostgreSQL requires dashboard/CLI setup. Documented indocs/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
| Risk | Mitigation |
|---|---|
| Railway pricing changes | Standard Dockerfile means we can migrate to any container platform |
| Railway outages affect development | Local Docker Compose setup works independently |
| Feature limitations discovered | Re-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.