Vercel vs Fly.io for Full-Stack Apps: Honest Cost and Cold-Start Test
You pick Vercel because it deploys in 30 seconds and your Next.js app just works. Then you hit a sustained-traffic week, your serverless functions spin up from cold on every burst, and your bill quadruples. Or you go with Fly.io because you want a persistent process and global edge machines, and you spend a day debugging flyctl config before your first deploy succeeds.
Both platforms are genuinely good. The choice depends on your workload shape, your tolerance for ops work, and what "cheap" actually means for your usage pattern. This article walks through a concrete test with a full-stack app to help you decide.
What You'll Learn
- How Vercel and Fly.io price their compute differently, and when each gets expensive
- Measured cold-start latency under real conditions for serverless functions and Fly.io Machines
- Developer experience trade-offs: deployment speed, configuration complexity, and debugging
- Which platform fits which workload archetype (static-heavy, API-heavy, long-running background jobs)
- Common billing and architecture mistakes to avoid on each platform
How the Test Was Set Up
The test app is a Next.js 14 frontend backed by a Node.js/Express API. The frontend fetches data from three API routes on every page load: one lightweight read, one database query (PostgreSQL on Supabase), and one call to an external service. Traffic is simulated using k6 with a ramp pattern: idle for 5 minutes, then 50 virtual users for 10 minutes, then idle again for another 5 minutes. The idle-to-burst transition is where cold starts bite.
On Vercel, the API routes run as serverless functions on the Hobby plan (upgraded to Pro for the billing comparison). On Fly.io, the same Express server runs inside a Docker container on a shared-cpu-1x machine with 256 MB RAM, with auto_stop_machines = true and min_machines_running = 0 to simulate comparable cold-start conditions. All regions tested are US East.
This is not a lab benchmark. It reflects the kind of workload a small SaaS or internal tool actually generates.
Vercel: Strengths, Limits, and Real Pricing
Vercel's core value proposition is zero-configuration deployment for frontend frameworks, especially Next.js. Push to main, and your app is live β including preview deployments for every pull request. For teams moving fast, that workflow is genuinely hard to beat.
What you get on the free Hobby plan
The Hobby plan covers personal projects with 100 GB of bandwidth, 6,000 serverless function execution minutes per month, and deployments from Git. Edge Functions and the CDN are included. For a low-traffic side project, you will likely never hit a limit.
Where costs climb on Pro
The Pro plan starts at $20/month per seat and includes a generous baseline, but the pricing model charges per unit beyond those baselines. Serverless function execution time is billed by GB-second. If you have a function that allocates 1 GB of memory and runs for 500 ms, that's 0.5 GB-seconds. At scale, this adds up faster than you expect β especially if you default to the maximum memory allocation out of habit.
The practical ceiling people run into most often: function duration limits. Hobby plan functions time out at 10 seconds. Pro raises that to 60 seconds for standard regions and up to 300 seconds for specific regions on the Fluid Compute tier. If you have any long-running processing job (PDF generation, data export, media transcoding), Vercel will either timeout your function or push you toward a paid edge tier.
Bandwidth costs
Beyond the included bandwidth, Vercel charges per GB. For apps serving large files or high-resolution images, this is where bills get surprising. Use next/image optimization and CDN caching headers aggressively β not for performance alone, but to protect your wallet.
If you want a raw comparison of how flat-rate VPS pricing compares to usage-based models like this, the analysis in Hetzner vs DigitalOcean for Side Projects: True Cost After 6 Months gives useful context on when predictable billing beats pay-per-use.
Fly.io: Strengths, Limits, and Real Pricing
Fly.io runs your app in a Firecracker microVM (a lightweight virtual machine), not a serverless function. Your process starts up, listens on a port, and stays running β exactly like a traditional server, but deployed globally with a single config file. This model eliminates the architectural constraints of serverless entirely.
Pricing structure
Fly.io charges for compute by the second of actual machine run time, plus RAM allocation. A shared-cpu-1x machine with 256 MB RAM costs roughly $1.94/month if it runs 24/7. The free allowance includes three shared-CPU VMs, 160 GB of outbound transfer, and enough volume storage for small apps. For many side projects, your bill is literally $0.
The key pricing levers are: machine size, number of machines, and whether machines are stopped when idle. With auto_stop_machines = true, Fly shuts down your VM after a configurable period of inactivity, which cuts cost but reintroduces cold starts.
Persistent volumes and databases
Unlike Vercel, Fly.io lets you attach a persistent volume to your machine. You can run a SQLite database directly on the VM, which simplifies architecture and cuts out a hosted database cost entirely for smaller apps. This is a genuine architectural advantage for projects that don't need multi-region replication.
The ops tax
Fly.io requires a fly.toml config file, a Dockerfile, and some familiarity with flyctl commands. Deploying a Next.js app is not one click β you need to build a production Docker image and configure health checks, port bindings, and scaling policies manually. The documentation is good, but the initial setup takes meaningfully longer than Vercel.
Cold-Start Latency: The Numbers
This is the section most comparisons skip, so here are the actual observations from the test runs described above.
When traffic hit after the 5-minute idle period, Vercel serverless functions added between 300β900 ms of cold-start latency on the first few requests. Subsequent requests within the same burst were fast (sub-50 ms function overhead). The cold-start variance was high β the same function could cold-start in 310 ms or 870 ms on different runs. Node.js runtime initialization is the dominant factor.
Fly.io with auto_stop_machines = true and min_machines_running = 0 showed cold starts in the 1.2β2.5 second range. The VM has to boot, which is slower than a serverless function container that's pre-warmed in the runtime pool. However, once the machine is up, it stays up for the entire burst with zero per-request overhead. There's no function-level cold start on subsequent calls.
What this means in practice
If your app has steady, moderate traffic, Fly.io's cold-start penalty is irrelevant β the machine stays warm. If you have spiky, unpredictable traffic with frequent idle periods (a webhook handler, a cron-triggered job), Vercel's faster cold start is a concrete advantage. For user-facing APIs with SLA expectations, both platforms benefit from at least one always-on instance: Vercel's minimum instance count feature on Pro, or min_machines_running = 1 on Fly.io.
For teams that already monitor latency in production, the kind of observability setup covered in Datadog vs New Relic for Small Dev Teams pairs well with either platform β you'll want percentile latency tracking to catch cold-start spikes before users report them.
Developer Experience Side by Side
Developer experience is subjective, but there are concrete dimensions worth comparing.
Deployment speed
Vercel wins on raw deployment speed. A Next.js app with a moderate build goes from git push to live in under two minutes. Preview URLs are generated for every branch. Rollbacks are one click in the dashboard. These are not small things when you're iterating quickly.
Fly.io deployments require building a Docker image first. If you use Fly's remote builder, the process takes 3β6 minutes for a Node.js app with dependencies. Local builds are faster but add local resource overhead. There is no automatic preview-per-branch equivalent.
Local development parity
Fly.io's model has better local/production parity because your Dockerfile runs the same way in both environments. With Vercel, local development uses next dev or vercel dev β close but not identical to the production serverless environment. Edge middleware and some runtime behaviors differ subtly at the edges.
Logs and debugging
Vercel's log viewer in the dashboard is decent for recent logs but lacks persistence and filtering depth. flyctl logs streams stdout directly and is simple to use. Neither platform ships a built-in log aggregation solution for historical queries β both benefit from an external logging destination.
Which Workloads Fit Each Platform
The right choice often comes down to workload shape, not personal preference.
Vercel is the better fit when:
- Your app is primarily a Next.js frontend with light API routes that run in under 30 seconds
- You need preview deployments and a fast CI/CD loop with minimal config
- Traffic is globally distributed and CDN edge caching does most of the heavy lifting
- Your team is small and you want zero infrastructure management
Fly.io is the better fit when:
- You have long-running processes: WebSocket servers, background workers, queue consumers
- You want to run a database (SQLite, Redis, Postgres) on the same machine to reduce round-trips and cost
- Your workload has consistent, predictable traffic where a persistent process is cheaper than per-invocation billing
- You want to run any language or runtime β Go, Rust, Python, Elixir β without framework lock-in
A hybrid approach is also valid: Vercel for the frontend and Fly.io for the backend API. The CDN and deploy pipeline live on Vercel; the persistent server lives on Fly.io. This adds a cross-origin API call but separates concerns cleanly and avoids serverless function constraints on the backend.
Common Pitfalls and Gotchas
Both platforms have traps that aren't obvious from the documentation.
Vercel
- Serverless function size limits: Vercel enforces a 50 MB compressed function bundle limit. Apps with large native dependencies (sharp, puppeteer, prisma with query engine) can hit this. You'll need to use the
outputFileTracingExcludesconfig or switch to edge-compatible libraries. - Environment variable sprawl: Preview, development, and production environments each have separate env configs in the dashboard. Forgetting to add a variable to the production environment is a very common source of "works in preview, broken in prod" bugs.
- Paying for seat count, not usage: The Pro plan charges per team member seat. A team of five pays $100/month before any usage-based charges. For solo projects, stay on Hobby or use a personal account.
Fly.io
- Machines that never stop: If you forget to set
auto_stop_machines = truefor a staging environment, the machine runs indefinitely. Check your Fly dashboard for idle machines regularly. - Health check misconfiguration: If your app's health check endpoint takes too long to respond on startup, Fly.io will kill and restart the VM in a loop. Always expose a lightweight
/healthroute that responds immediately, before your database connection is ready. - Volume availability zones: Persistent volumes are pinned to a single availability zone. If you scale to multiple machines across zones, only the machine in the same zone as the volume can mount it. Plan your data layer before scaling out.
Wrapping Up: Which One Should You Deploy On?
There is no universally correct answer, but the decision tree is simple. If you're deploying a Next.js app, want instant CI/CD, and your backend logic fits comfortably inside short-lived serverless functions, start with Vercel. The developer experience is excellent and the free tier is genuinely useful. Watch your function execution time and bandwidth usage once you go beyond the free tier.
If you need a persistent process β a WebSocket server, a queue worker, a long-running job, or a full backend that doesn't fit the serverless model β reach for Fly.io. Expect to spend an afternoon on initial Docker and config setup, but enjoy the predictability of VM-based billing afterward.
Here are four concrete actions to take next:
- Audit your current API route durations. If any regularly approach or exceed 10 seconds, you are already outgrowing Vercel's Hobby tier constraints.
- Set up a cost alert on whichever platform you use. Both Vercel and Fly.io support billing notifications β enable them before you scale, not after.
- If you try Fly.io, start with
fly launchon a simple Node.js app before migrating your full project. The config file makes more sense once you've seen a working example. - Consider the hybrid architecture (Vercel frontend + Fly.io API) if you want the best of both worlds β fast edge delivery for static assets and full control over your backend runtime.
Frequently Asked Questions
Does Vercel charge for cold starts on the free Hobby plan?
Vercel does not charge separately for cold starts β you pay for total function execution time (GB-seconds), not for initialization. However, cold starts contribute to execution time, so a slow cold start on a memory-heavy function does increase your billable usage.
Can you run a persistent WebSocket server on Vercel?
No. Vercel serverless functions are stateless and terminate after the response is sent, so persistent TCP connections like WebSockets are not supported. For WebSocket servers, Fly.io or a traditional VPS is the right choice.
How do you prevent cold starts on Fly.io without paying for a machine that runs 24/7?
Set min_machines_running to 1 in your fly.toml to keep at least one machine warm at all times. A shared-cpu-1x machine with 256 MB RAM running continuously costs under $2/month, which is often worth paying to eliminate cold-start latency for user-facing endpoints.
Is Fly.io more expensive than Vercel for a typical side project?
For very low-traffic projects, both platforms are effectively free. As traffic grows, Fly.io's flat VM-based billing tends to be more predictable and often cheaper for consistent workloads, while Vercel's per-execution model can be cheaper for bursty or rarely-used apps.
What is the maximum execution time for a Vercel serverless function?
On the Hobby plan, the limit is 10 seconds. The Pro plan extends this to 60 seconds by default, with up to 300 seconds available for certain regions using the Fluid Compute configuration. Functions that exceed the limit return a 504 error to the client.
π€ Share this article
Sign in to saveRelated Articles
Comments (0)
No comments yet. Be the first!