Railway Is My Go-To Infrastructure. Here's Why I Recommend It to Enterprise Clients

By , Senior Full-Stack EngineerUpdated 14 min read

I've deployed production applications on AWS, Azure, Vercel, and Heroku. I have opinions about all of them. But for the past several years, every new project I start goes to Railway.

I currently run several production projects on Railway: AccessHawk (AI accessibility scanner), SereneReader (real-time RSS reader), SPConnector (automated packing slip printing), MyPetDay (pet care tracking), and this portfolio site.

The thing that changed everything for me: Railway deploys containers by default, not serverless functions. That one decision means background workers, WebSockets, EventStreams, persistent connections, and long-running processes just work. No workarounds. Combined with config-as-code, built-in databases, and a team that ships real features weekly, Railway cut my go-to-live time from days to minutes.

Here's the full case, with real config from my production projects.

Non-serverless by default: the feature nobody talks about

This is what I bring up first with enterprise clients. Railway runs your code in containers. Your process starts, stays running, and handles requests for as long as the service is deployed. No cold starts. No execution time limits. No ephemeral state.

Vercel, by contrast, deploys server-side code as serverless functions largely powered by AWS Lambda (with Edge Functions running on V8 isolates as an alternative). They've built significant custom infrastructure on top of Lambda, including a Rust-based runtime and their Fluid Compute model, but the execution model is still fundamentally ephemeral. On the Pro plan, functions default to a 5-minute cap and can be configured up to 800 seconds (with a 30-minute extended maximum in beta). No persistent processes. No background workers. No WebSocket servers. No BullMQ queue consumers.

This matters as soon as your application does anything beyond request-response. AccessHawk depends on long-running background workers that process jobs from Redis queues. SereneReader uses BullMQ workers for RSS feed processing and Server-Sent Events for real-time updates. SPConnector needs persistent API polling. All impossible on Vercel without bolting on external services like Inngest or Trigger.dev (or Vercel's own Workflows product, which trades a persistent process for durable step functions).

AccessHawk: Playwright workers that run for minutes

AccessHawk scans websites for WCAG accessibility violations using Playwright and Chromium. A single scan can take several minutes: launch a headless browser, navigate pages, run Lighthouse audits, analyze results with LLMs. This is a BullMQ worker that pulls jobs from Redis and runs continuously.

Here's the actual railway.toml for the AccessHawk worker:

[build]
builder = "DOCKERFILE"
dockerfilePath = "docker/worker.Dockerfile"
watchPatterns = ["packages/worker/**", "packages/shared/**", "docker/worker.Dockerfile"]

[deploy]
startCommand = "node dist/index.js"
restartPolicyType = "ON_FAILURE"
restartPolicyMaxRetries = 3

There's no healthcheckPath because this worker is not an HTTP service. It pulls jobs from a queue and runs indefinitely. Railway just runs it. The worker uses a custom Dockerfile because it needs Playwright, Chromium, system fonts, and Sharp for image processing. Those dependencies alone would blow past a standard serverless function's 250MB bundle limit (Vercel's large-functions option raises that, but the persistent-worker problem remains).

Config-as-code: your infrastructure lives in git

Every Railway project I maintain has a railway.toml checked into version control. Build commands, start commands, health checks, restart policies, watch patterns, zero-downtime settings. All versioned alongside the application code. Config defined in code overrides dashboard values, so what's in the repo is what runs in production.

Here's the config for SereneReader, which uses the most deployment features:

[build]
builder = "RAILPACK"
buildCommand = "pnpm install --frozen-lockfile && pnpm run build:railway"
watchPatterns = ["app/**", "server/**", "types/**", "public/**", "nuxt.config.ts", "package.json", "tailwind.config.ts"]

[deploy]
startCommand = "node .output/server/index.mjs"
healthcheckPath = "/api/health"
healthcheckTimeout = 120
restartPolicyType = "ON_FAILURE"
restartPolicyMaxRetries = 3
overlapSeconds = 30
drainingSeconds = 10

The overlapSeconds and drainingSeconds settings give me zero-downtime deployments. The new version starts, gets 30 seconds to warm up alongside the old version, then the old version gets a SIGTERM and 10 seconds to drain active connections. No dropped requests.

Compare this to Vercel's vercel.json, which handles routing, headers, and function configuration but not infrastructure. Or to AWS, where your deployment config is spread across CloudFormation templates, task definitions, security groups, IAM roles, and load balancer configurations.

Railway also supports environment-specific overrides in the same file. You can define different settings for PR environments, staging, and production:

[deploy]
startCommand = "node server.js"
healthcheckPath = "/api/health"

[environments.pr.deploy]
startCommand = "node server.js"
healthcheckPath = "/api/health"
healthcheckTimeout = 60

Monorepo support that actually works

AccessHawk is a pnpm workspace monorepo with Turborepo. It has three Railway services (web, worker, orchestrator) deployed from the same repository. Each service gets its own railway.toml with targeted build commands and watch patterns.

Here's the pattern I use for every monorepo web service:

[build]
builder = "RAILPACK"
buildCommand = "pnpm install --frozen-lockfile && pnpm --filter @accesshawk/shared build && pnpm --filter @accesshawk/web build"
watchPatterns = ["packages/web/**", "packages/shared/**"]

[deploy]
startCommand = "node packages/web/.output/server/index.mjs"
healthcheckPath = "/api/health"
healthcheckTimeout = 120
restartPolicyType = "ON_FAILURE"
restartPolicyMaxRetries = 3

The watchPatterns matter more than you'd think. When I push a change to packages/worker/, only the worker service rebuilds. The web and orchestrator services skip the deploy entirely. Fewer wasted build minutes, no unnecessary downtime.

The build command compiles the shared package before the service build (pnpm --filter @accesshawk/shared build && pnpm --filter @accesshawk/web build), so types and utilities are ready. This pattern is reusable for any monorepo on Railway.

Built-in databases and services

Railway has one-click deployment of PostgreSQL, MySQL, MongoDB, and Redis. These run as co-located services in the same project, connected via Wireguard-encrypted private networking. One provider, one bill, one set of connection strings.

AccessHawk uses MongoDB + Redis within its Railway project. The Redis instance powers BullMQ job queues, and services communicate over Railway's private network using .railway.internal DNS. Zero firewall configuration needed.

They also launched S3-compatible object storage in late 2025 at $0.015/GB-month with free egress. I use it for Playwright screenshot storage in AccessHawk.

Vercel went the other direction. They launched Vercel Postgres and Vercel KV (Redis), then sunset both. You now use marketplace integrations like Neon, Supabase, or Upstash, each with its own billing, latency overhead, and connection management.

Go-to-live time: minutes, not days

My portfolio site went from code to production URL in under 10 minutes. Connect the GitHub repo, Railway auto-detects the framework, builds, deploys. Add a custom domain, SSL certificate auto-provisions. Done.

Here's the entire railway.toml for this portfolio site:

[build]
builder = "RAILPACK"
buildCommand = "pnpm install --frozen-lockfile && pnpm build"

[deploy]
startCommand = "node server.js"
healthcheckPath = "/api/health"
healthcheckTimeout = 120

Five lines of config that actually matter. On AWS, deploying the same application to ECS means configuring a cluster, task definition, service, load balancer, target group, security groups, IAM roles, and Route 53 records. Even with AWS ECS Express Mode, you still need IAM configuration and ECR container registry setup.

Azure is the same story. AKS deployments need Resource Group management, Azure Container Registry, RBAC with Azure AD, and multi-step configuration. Even Azure App Service, the simplest option, has more configuration than Railway's entire setup.

For enterprise clients, this changes the conversation. Instead of "how long to set up infrastructure," it's "how long to build the feature." My portfolio site went from repository to production in a single afternoon including the domain setup.

A platform that ships weekly

Railway publishes a changelog every Friday. Not marketing fluff, actual features. I subscribe to these emails and regularly find things I've been wanting.

Some recent ones that made a real difference for me:

  • Deploy-less Horizontal Scaling (Feb 2026) - Scale replicas without triggering a full redeploy. New replicas use the existing image.
  • Focused PR Environments (Jan 2026) - Railway now analyzes which services a PR actually touches and only deploys those. In a monorepo with three services, most PRs only spin up one.
  • Architecture View (Jan 2026) - Visual topology of your services, databases, and connections. Useful when onboarding someone to a complex project.
  • DB Metrics and Network Flows (Jan 2026) - Database performance metrics and network traffic visualization.
  • Zero-Downtime Volume Resizing (Jan 2026) - Resize persistent storage without interrupting your service.
  • S3-Compatible Object Storage (2025) - $0.015/GB-month with free egress.
  • Railpack Builder (2025) - Replaced Nixpacks as the default builder. Faster builds, covers 11 languages.
  • HTTP Service Metrics (2025) - Request rates, latency percentiles, error rates per service.
  • 2FA Enforcement and Enterprise SSO (2025) - The security features enterprise clients always ask about.

For context: Railway is about 40 people. They raised $100M in January 2026, moved to co-located bare-metal data centers in 2025, and have over 2.25 million developers on the platform. That kind of output from a team that size is unusual.

Features that matter for enterprise clients

When I bring up Railway with enterprise clients, I get the same questions every time: security, compliance, operational maturity. Here's what I point them to:

  • SOC 2 Type II certified - Not just a point-in-time audit. Type II means sustained security practices over time.
  • HIPAA BAAs available - Healthcare compliance. I've had clients in regulated industries ask about this specifically.
  • Sealed environment variables - Once set, values can't be read back from the dashboard. Only injected during deployment. This one gets a lot of nods in security reviews.
  • Static outbound IPs - Fixed IPs for firewall allowlisting and third-party API integrations that need known source IPs.
  • Private networking - Wireguard-encrypted service-to-service communication. Zero-config service discovery. No manual firewall rules.
  • PR environments - Automatic preview deployments on pull requests. QA tests in isolated environments that mirror production.
  • Audit logs - Enterprise-tier activity tracking.
  • Replica scaling - Up to 42 replicas per service on Pro (up to 1,000 vCPU and 1 TB RAM per service), with multi-region distribution across 4 regions (US West, US East, EU West, Southeast Asia).
  • RBAC and team management - Granular access control with restricted environments and deployer roles.

The Pro tier at $20/month per seat (each seat includes $20 in usage credits) covers most of this. Enterprise adds SSO, audit logs, and dedicated VMs. (All Railway prices in this post are accurate as of February 2026 — confirm current rates on railway.com.)

The Vercel comparison: where serverless falls short

I want to be fair here: Vercel is good at what it does. If your application is a Next.js frontend with API routes that return quickly, Vercel's developer experience is hard to beat. But the serverless-only model has real limits.

Railway's pricing is simpler: CPU time, memory, storage, egress. A typical Next.js app runs $8-15/month. My portfolio site costs a few dollars a month. The dashboard shows real-time usage, so I always know where I stand.

When a project needs both a web frontend and background processing, Railway lets me put everything in one project with private networking between services. On Vercel, I'd need Vercel for the frontend plus a separate provider for workers, plus another for databases, plus another for queues. That's a lot of moving parts.

A few of my Railway projects at a glance

Here's how each project uses Railway:

AccessHawk (3 services)

  • Web: Nuxt 4 SSR frontend + API (Railpack builder)
  • Worker: BullMQ job processor with Playwright + Chromium (Dockerfile builder)
  • Orchestrator: Admin dashboard + worker autoscaler using Railway API
  • Infrastructure: MongoDB, Redis, S3-compatible storage, all co-located
  • The worker runs Playwright scans that take minutes per job. This would be impossible on serverless.

SereneReader (1 service)

  • Service: Nuxt 4 SSR with BullMQ background job processing and Server-Sent Events for real-time updates
  • Infrastructure: MongoDB, Redis
  • RSS feed processing via BullMQ workers and SSE for live updates require persistent connections that serverless can't sustain.

SPConnector (1 service + workers)

  • Service: Node.js backend with background PrintNode polling
  • Infrastructure: Persistent connections to Shippo and PrintNode APIs
  • Long-running API polling that would timeout on serverless.

MyPetDay (1 service)

  • Service: Nuxt 4 SSR with zero-downtime deploys (overlapSeconds + drainingSeconds)
  • Infrastructure: MongoDB, S3-compatible storage
  • Most detailed railway.toml of all my projects, with graceful zero-downtime deployment config.

Portfolio (1 service)

  • Service: Vue 3 + Express SSR. Five-line railway.toml. Simplest possible config.
  • Railway works just as well for a simple portfolio site as it does for a monorepo with three services.

Getting started

If you want to try Railway, here's the fastest path from zero to production:

  1. Sign up: Create an account at railway.com. No credit card required for the free tier.
  2. Connect GitHub: Link your repository. Railway auto-detects your framework.
  3. Add a railway.toml (optional): Start minimal. Builder, build command, start command, health check.
  4. Set environment variables: Add secrets in the Railway dashboard. Use sealed variables for production secrets.
  5. Deploy: Push to your main branch. Railway builds and deploys automatically.
  6. Add a custom domain: Point your DNS, Railway provisions the SSL certificate.
  7. Add databases if needed: One-click Postgres, MongoDB, or Redis in the same project.

For monorepos, create a separate Railway service for each package and add targeted watchPatterns to each railway.toml. Use pnpm --filter in build commands to scope builds to the relevant package.

# Minimal railway.toml for a Nuxt/Next.js app
[build]
builder = "RAILPACK"
buildCommand = "pnpm install --frozen-lockfile && pnpm build"

[deploy]
startCommand = "node .output/server/index.mjs"
healthcheckPath = "/api/health"
healthcheckTimeout = 120
restartPolicyType = "ON_FAILURE"
restartPolicyMaxRetries = 3

Conclusion

Railway got out of my way. I stopped spending time on load balancers and IAM policies and started spending it on features. The container-first approach means I don't architect around serverless limitations. Config-as-code means my infrastructure is reviewable and version-controlled like the rest of my code.

For enterprise clients, it checks the boxes: SOC 2 Type II, HIPAA BAAs, sealed variables, private networking, multi-region scaling. The Pro tier at $20/month per seat covers nearly everything, and usage-based pricing keeps costs predictable.

What gives me the most confidence is the pace. ~40 people, meaningful releases weekly, $100M in funding, 2.25M+ developers. This isn't slowing down.

If you want to try it, sign up at railway.com. The free tier gives you $1 in monthly resources, no credit card required. You can have something running in about 10 minutes.

Contact

Drop me a line. I read everything and reply within a day.

Required fields are marked “(required)”.