The Full SaaS Deployment Guide: Vercel + Railway Without Surprise Bills
A complete deployment playbook: frontend on Vercel, API on Railway, billing caps set, and the mistakes that cause $1,000 surprise bills.
Table of contents8 sections
- 01The $1,100 Bill That Wasn’t Even Mine
- 02The One Rule: Split the Frontend From the Backend
- 03Frontend on Vercel (and Nowhere Else)
- 04The Backend Belongs on Railway
- 05Wiring the Two Together
- 06Setting the Guardrails (a.k.a. Not Going Broke in Your Sleep)
- 07The Mistakes That Cause Surprise Bills
- 08The Bottom Line
The $1,100 Bill That Wasn’t Even Mine
It was late 2023. I was deep in Bitly-clone territory building Clickly, and I was in one of those indie-hacker Discord servers at 1 AM where everyone pretends they’re closer to ramen-profitable than they actually are. Someone dropped a screenshot. It was a Vercel invoice. $1,143.
He hadn’t launched anything big. He had a small Next.js app, a single API route that called an external service, and one afternoon a scraper found that route and hammered it a few million times. Serverless does exactly what you tell it: it scales. It scaled him right into a four-figure bill for a product with, I think, eleven users.
I remember closing my laptop and just sitting there. Because that was my exact nightmare. I’m the guy who wouldn’t pay $20 for a Vercel plan while making $0 — you think I could survive an eleven-hundred-dollar surprise? That night I stopped thinking about deployment as “where do I put my code” and started thinking about it as “how do I make sure a stranger with a script can never bankrupt me in my sleep.”
This guide is the answer I landed on. It isn’t a tier list — I already ranked every platform I’ve touched — and it’s deliberately the opposite of the enterprise route: if you were tempted to run your own Kubernetes cluster, read that first, then come back here for the version that doesn’t eat your month. This is the architecture: where each piece goes, how they talk to each other, and the two or three guardrails that turn deployment from a liability into a thing that quietly hums in the background. Frontend on Vercel, backend on Railway, caps set, done.
The One Rule: Split the Frontend From the Backend
If you remember nothing else, remember this: your frontend and your backend want completely different billing models, so put them in completely different places.
Here’s the why. Vercel is serverless-first. That’s genuinely magical for a website — a marketing page, a dashboard shell, an Astro content site. Traffic arrives in bursts, Vercel spins functions up and down, and 99% of the time it’s fast and cheap and you never think about it. Serverless is perfect for the frontend, because frontends are spiky and mostly idle.
But the moment you have work that runs constantly or predictably a lot — a cron job checking endpoints every five minutes, an API route hit on every user action, a webhook receiver, a background worker chewing through a queue — serverless billing turns against you. You pay per invocation, per GB-hour of memory, per second of compute, and those numbers only ever climb. There’s no ceiling by default. That’s the trap my Discord friend fell into.
A flat-fee server is the opposite. You rent a small box for a predictable monthly price, and whether it handles a hundred requests or a hundred thousand, the bill doesn’t move. Twenty thousand API calls every five minutes? On Vercel that’s a heart attack. On a small Railway box it’s a Tuesday.
So the rule writes itself:
- Spiky, public, mostly-idle work → Vercel (frontend, marketing pages, light API routes).
- Constant, heavy, or predictable work → a flat-fee box (your real API, crons, workers, webhooks).
Everything below is just the mechanics of doing that cleanly.
Frontend on Vercel (and Nowhere Else)
For the frontend, don’t overthink it. If you’re on Next.js or Astro, deploy on Vercel and ship. They own Next.js; deployment there is as close to magic as this industry gets. Connect your GitHub repo, push to main, and you’re live with a global CDN, automatic HTTPS, and preview deployments on every pull request. I’ve tried to be clever and host frontends elsewhere. I always come crawling back.
Two things to get right, though.
The commercial-use trap. Vercel’s free Hobby plan is glorious — 100 GB of data transfer, a million edge requests, and a million function invocations a month, all free. But per Vercel’s own terms, Hobby is for non-commercial, personal use only. The second your project is a real business — you’re charging money, it’s a registered thing — you’re supposed to be on Pro at $20 a month per user. Plenty of founders quietly run a commercial SaaS on Hobby and don’t find out they’re offside until something goes sideways. Budget the $20. It’s the one legitimately unavoidable line, and I made peace with it in what it actually costs to run a SaaS.
Keep the heavy logic off it. Even on Pro, that $20 only includes $20 of usage. A single runaway function can blow through it fast. So Vercel hosts your pages and your light stuff — auth callbacks, form submissions, the occasional API route. The workloads that run all day long don’t live here. Which brings us to the other box.
The Backend Belongs on Railway
When I need something running 24/7 for a price I can predict, Railway is where it goes. The dashboard is genuinely delightful — I’ve watched non-technical friends deploy a Postgres database and a backend service on it without me holding their hand.
Here’s the current pricing, because it changed and people keep quoting the old version. Railway’s Hobby plan is $5 a month, and that $5 is a usage credit, not just a flat subscription on top. You’re billed by the minute for CPU, memory, egress, and volume storage. If your actual resource usage for the month comes in under $5, you just pay the $5. If it comes in at $8, you pay $8. For a small always-on API — the kind that hammers a few thousand endpoints on a schedule — you’re realistically sitting right around that $5 floor. The point is the bill is bounded by your actual compute, not by how many times a stranger poked your endpoint.
This is where your real API goes. Your cron jobs. Your webhook receivers. That one function that would’ve been called ten million times a month and eaten 70% of your Vercel bill — I’ve watched exactly that happen — lives here now, for a flat handful of dollars.
When Railway isn’t enough
Railway covers the vast majority of what a broke solopreneur needs. But it does run out of road in two places:
- You need multi-region, or you live in the terminal. Reach for Fly.io. It’s CLI-first — type
fly launchand your app scatters across the globe. Fair warning: the old free tier is gone for new accounts (you get a short trial, then pay-as-you-go), but the cheapest always-on machine still runs around $2–5 a month. I love Fly, I just don’t reach for it first. - You want a “real server” feel. Koyeb used to be my pick here — a flat monthly instance with dirt-cheap custom domains. Heads up, though: Koyeb was acquired by Mistral AI in early 2026, and new signups no longer get the free Starter tier — the entry point is now a $29/month Pro plan. That quietly reprices it out of “broke solopreneur” territory for a fresh account, so I can’t recommend it the way I used to. Railway and Fly are the safer bets today.
For the full ranked list — including DigitalOcean, Northflank, and the ones I’d never touch again — that’s the deployment tier list. This post is about wiring, so let’s wire.
Wiring the Two Together
This is the part tutorials skip, and it’s honestly the only fiddly bit. You’ve got a frontend on Vercel and an API on Railway. How do they talk?
The request flow
Picture it as a straight line. The user’s browser loads your site from Vercel. When they do something that needs real backend work — pull their analytics, kick off a job, hit the database hard — the frontend makes an HTTP call to your Railway service’s public URL. Railway does the heavy lifting, talks to your Neon Postgres, and hands the result back. Vercel stays cheap because it’s just serving pages and proxying the occasional call; Railway stays cheap because it’s a flat-fee box that doesn’t care how busy it is.
The three things you actually have to configure
1. Environment variables, in two places. Railway gives your backend a public domain (something like your-api.up.railway.app, or a custom domain you attach). Put that URL in your Vercel project as an env var — NEXT_PUBLIC_API_URL or similar — so the frontend knows where to call. Your secrets (database URL, third-party API keys) live on Railway, not Vercel, because that’s where the code using them actually runs. Don’t paste your Neon connection string into Vercel if Vercel never touches the database.
2. CORS, or you’ll lose an evening. Your backend has to explicitly allow requests coming from your Vercel domain. This is the single most common thing that makes people think the whole setup is broken — the frontend calls the backend, the browser blocks it, the console screams about CORS, and you spiral. Set your backend to allow your production domain (and your *.vercel.app preview domains too, if you want previews to work against the live API). Ten minutes of config saves you a night of confusion.
3. Keep the database on Neon, not on the platform. Both Vercel and Railway will happily sell you a database. Don’t. Run your Postgres on Neon — it’s free until you have real load, it separates storage from compute so an idle database costs almost nothing, and it doesn’t lock you to either host. The day you move your backend off Railway, your data doesn’t have to move with it. (I went down the entire database rabbit hole — Timescale, ClickHouse, per-user SQLite — in the advanced database guide, but the short answer is: Neon, and stop thinking about it.)
That’s the whole wiring job. Frontend URL knows the backend URL, backend allows the frontend origin, database sits neutral in the middle. Three settings.
Setting the Guardrails (a.k.a. Not Going Broke in Your Sleep)
Now the part this post is named after. The split protects you from predictable cost. Guardrails protect you from the unpredictable — the scraper, the bug, the infinite loop, the spike you weren’t ready for.
Vercel Spend Management. Turn it on. Today. This is the feature that would’ve saved my Discord friend his $1,143. You set a dollar amount for the billing cycle, and when your metered usage crosses it, Vercel can pause your production deployments automatically — and as of their recent update, pausing production by default is the standard behavior. You can also wire it to send an alert or hit a webhook first, if you’d rather get a text than go dark.
Two things to know going in, so it never surprises you:
- It’s not instant. Vercel checks your spend every few minutes, so a project can keep serving traffic and accruing a little usage for several minutes after you cross the line. It’s a circuit breaker, not a laser trip-wire. Set the cap a little below your real pain threshold.
- You resume manually. Once a project pauses, it stays paused until you turn it back on — per project, from the dashboard or the API. Raising the cap doesn’t auto-unpause anything. That’s a feature: it forces you to look at why you blew the cap before you re-open the floodgates.
Railway mostly polices itself. Because Railway bills by actual consumption on a small box, a runaway bill is far harder there — there’s a physical ceiling to how much a tiny instance can do. Still, switch on usage alerts so you get a nudge if consumption climbs, and size your instance sanely. The flat-fee box is the guardrail; you just don’t want to accidentally provision a giant one.
Move the one hot function off Vercel entirely. This is the highest-leverage move there is. Go look at your usage breakdown and find the single endpoint that gets called the most. There’s almost always one function eating the majority of your invocations. Move that one to your Railway box, or to an edge function on Bunny, and leave the light stuff on Vercel. I’ve seen this single change cut a function bill by 80%.
The Mistakes That Cause Surprise Bills
Every horror-story invoice I’ve seen traces back to one of these. None of them are exotic. They’re all just “nobody set the guardrail.”
- No spend cap set. The default on most platforms is no limit. If you do exactly one thing from this post, set the cap.
- Cron jobs on serverless. A job that runs every minute is 43,200 invocations a month — for one schedule. Put recurring work on the flat-fee box.
- One popular endpoint left on Vercel. The ten-million-calls function. Find it, move it.
- Running a commercial app on the free Hobby plan. Less a bill risk than a terms risk — but it’s the kind of thing that bites right when you’re finally getting traction and can least afford the disruption.
- Serving big files through your app. A 5 MB video or a chunky JSON blob pushed straight through Vercel functions is pure egress cost. Put a CDN in front — Bunny costs a dollar a month and eats that egress for you.
- Leaving image optimization cranked wide open. Vercel’s image transformations are metered too. Lovely feature, quietly billable at volume.
Notice the pattern? Every one of these is predictable and preventable. Surprise bills aren’t bad luck. They’re a guardrail you didn’t set.
The Bottom Line
Deployment in 2026 is not hard. That’s the thing I wish someone had shouted at me in that Discord server at 1 AM. The tools are magic, the free tiers are generous, and you can have a real product live in an afternoon. The only genuine risk left is the bill — and the bill is entirely a configuration problem, not a fate.
So here’s the whole thing on one hand: frontend on Vercel, backend on Railway, database on Neon, spend cap switched on, hot function moved off serverless. That’s a stack that carries you from your first user to your first thousand without ever ambushing you. It cost me a scared night watching someone else’s invoice to learn it, and a few of my own scars to trust it. You get it for free.
Once it’s humming, forget about it. Deployment should be the 1% of your work that never crosses your mind again — because the other 99% is building something people want, and then the actual war, which is getting anyone to use it. If you’re wiring this whole stack together on a shoestring for the first time, start from the broke solopreneur’s survival guide and come back here for the plumbing.
This is the Broken Engineer Guide — I set the billing cap, split the workloads, and slept fine, then went and failed at distribution instead. Learn the deployment part. It’s the easy 1%. Go build something.
