Skip to main content
← Back to Blog
Security & DevOps6 min read

Deploying LLM Infrastructure: Fly.io vs Railway vs Vercel

Serverless function timeouts and cold starts are the wrong shape for streaming, stateful MCP servers. What each platform actually gives you for that workload.

A Vercel function on the Pro plan has a maximum duration of 300 seconds by default, and 800 seconds is the documented ceiling on higher tiers (Vercel function limits). That number is fine for an API route and it is the wrong shape for an MCP server, which holds a connection open for as long as the client session lasts and keeps state in the process while it does. The mismatch is not about how generous the limit is. It is that the platform's billing and scheduling model assumes a request that starts, finishes, and frees the box.

Start from the workload and the platform choice mostly falls out. An MCP server has four properties that matter:

  • Long-lived connections. SSE or a streamable HTTP session that stays open across many tool calls.
  • Streaming responses measured in minutes, not milliseconds.
  • In-process state: session registries, capability negotiation results, warm DB pools.
  • Latency-sensitive database access, several round trips per tool call.

A Next.js marketing site and dashboard has none of these. It wants a CDN, image optimization, and preview deployments. These are two different workloads and there is no rule saying they have to live on the same platform.

The axes that actually differentiate

Max duration and connection lifetime

Serverless platforms cap execution time because a function occupies a slot. Fly and Railway run processes; a connection lives until one side closes it or the platform's proxy idle timeout fires, and idle timeouts on a streaming connection are avoidable with keepalive frames. If your protocol needs a socket open for twenty minutes, this axis decides the question on its own and the rest of the comparison is detail.

Cold starts

A cold start on a REST endpoint costs one user 400ms once. A cold start on a stateful server costs you the state. Every in-memory session registry, every warm connection pool, every negotiated capability set is gone, and the client that reconnects has to redo the handshake. Fly's machines can scale to zero and cold start fast, which is genuinely good for bursty work and still means the process restarted. Railway's default of an always-on service sidesteps the problem by paying for idle, which is the honest trade: you are buying process continuity with money.

Region placement relative to your database

This is the axis people underweight, and it dominates. Put the compute in iad1 and the Postgres primary in eu-central and every query pays 80 to 100ms of round trip. A tool call that does five sequential queries, which is not an unusual number once you are doing auth, tenancy lookup, vector search, and a write, spends half a second on geography before any work happens.

# same region as Postgres
5 queries x ~2ms RTT   = 10ms

# different continent from Postgres
5 queries x ~90ms RTT  = 450ms   # 45x, and none of it is your code

No platform's own cold-start or routing advantage is worth 440ms. So the first question is not "which platform is fastest," it is "can I place compute in the same region as my database." All three can, if you configure it deliberately. The failure is almost always a default region that nobody changed.

The corollary bites hardest on globally distributed compute. Fly's pitch is placing instances near users, and that is a real win for read-mostly or edge-cacheable work. For a write-heavy single-primary Postgres app, an instance in Sydney talking to a primary in Virginia is slower for that user than a Virginia instance would have been. Global placement helps when data is local too, and hurts when it is not.

WebSocket and SSE support

Fly and Railway both proxy WebSocket and SSE without ceremony. On Vercel, SSE from a Node function works but is still bounded by the function duration limit, and the edge runtime has a different set of constraints (no persistent state, restricted Node APIs) that rule out most of what a Fastify MCP server does. This is a capability boundary, not a quality judgment.

Pricing shape

Serverless bills roughly by request-duration, so an idle service costs nearly nothing and a busy one scales linearly. Persistent platforms bill for allocated resources whether or not traffic arrives. For a service with steady low-to-moderate traffic, the persistent model is usually cheaper and always more predictable. For a service that gets ten requests a day, serverless wins on cost by a wide margin. Check egress separately, since it is where surprise bills come from on every platform.

Monorepo build fit

With pnpm workspaces, the question is whether the platform can build a shared package before the app that imports it, and whether it can skip deploys when nothing in the relevant path changed. Vercel has the most mature story here, including native monorepo detection and per-project root directories. Fly expects you to own a Dockerfile, which is more work up front and completely unambiguous afterward. Railway sits in between with per-service root directories and watch paths. Owning the Dockerfile has an underrated benefit: local docker compose up reproduces production, which matters a lot for a self-hostable product.

What each is genuinely good at

Vercel is the best place to run a Next.js frontend and it is not close. Preview deployments per branch, ISR, image optimization, and edge caching are deeply integrated in a way the others do not attempt. Use it for the web app. Do not use it for a stateful streaming process.

Fly.io is the right answer when geography is part of the product: persistent VMs you can place in specific regions, real volumes, private networking between apps, and scale-to-zero when you want it. The cost is that you are operating something closer to infrastructure, and you should want that only if placement or hardware control is buying you something.

Railway is the shortest path to a boring always-on service. Push to a branch, get a long-running process with a managed Postgres next to it and a monorepo config that takes a few minutes. It is less configurable than Fly and it is not trying to be a CDN. For a single-region stateful server where the deploy story should be uninteresting, that is the correct set of trade-offs.

Pick by execution model first (does the process need to outlive the request?), then by database proximity, then by pricing. Developer experience is the tiebreaker, not the criterion.

The split most LLM products end up at is frontend on a serverless/CDN platform and inference or protocol servers on a persistent one, because those are two workloads with opposite requirements. That is where Unimatrix landed: the Fastify MCP server runs as a long-lived process on Railway in the same region as its Neon Postgres, and the same image runs under Docker for self-hosting. Deployment specifics are in the MCP docs.

Your AI remembers everything. Everywhere.

Unimatrix gives you a shared, durable memory layer across Claude Desktop, Cursor, ChatGPT, and Gemini. Setup in 2 minutes. Free and paid plans available.

Looking for developer resources?

Browse our catalog of 500+ tested AI prompt profiles covering DevOps, data modeling, agent behaviors, and API wrappers. Have a prompt to share? Submit your own for review by our librarian to be featured. Completely free, no registration required. Browse prompt libraries →

Keep reading