Y
our startup worked. That's the problem.Six months ago you were hacking on a side project. Vercel for hosting, Supabase for the database, a GitHub Actions workflow you copied from a blog post. Good enough to ship. Good enough to get users. Then someone tweeted about it. Then a funding round. Then an enterprise client asking pointed questions about uptime SLAs and data residency.
Now you have a real business running on infrastructure you built in a weekend.
This is one of the best problems to have. It's also genuinely dangerous if you migrate wrong. This playbook covers the sequence what to stabilize first, what to migrate second, and what to leave alone until you absolutely can't.
The weekend project stack and why it breaks at scale
Most founders reach this point with some variation of the same stack: a TypeScript or Next.js frontend on Vercel, a managed Postgres instance on Supabase or Neon, maybe a Redis layer bolted on later when things got slow, and authentication handled by Clerk or Auth.js.
This stack is genuinely good. It's not embarrassing. Vercel runs production workloads for serious companies. The problem isn't the tools it's that none of them were configured for the load you're now seeing.
Three failure modes show up repeatedly at this stage:
Vercel function timeouts. The free and pro tiers cap serverless function execution at 10 seconds, with a hard wall at 60 seconds even on paid plans. If your backend does anything expensive PDF generation, third-party API chains, bulk data processing you'll hit this. You'll know it's happening because your error logs fill up with 504s during peak hours.
Database connection exhaustion. Managed Postgres services like Supabase use connection poolers, but the defaults aren't tuned for high concurrency. Each serverless invocation can open its own connection, and with enough traffic you saturate the pool. Queries start queuing. Latency spikes. The database looks healthy in the dashboard while your application falls over.
Cold starts under bursty traffic. Indonesian traffic patterns are famously spiky Lebaran, Harbolnas, Monday morning app opens. Serverless functions that haven't received traffic in a while take 500ms to 2 seconds to cold-start. Spread that across a user flow with four or five function calls and you've got a slow, broken experience at the worst possible moment.
None of these are fatal. All of them are fixable. But you need to fix them in the right order.
Stabilize before you migrate
The instinct when infrastructure is creaking is to immediately start rewriting things. Resist it.
Migrating a broken system to new infrastructure gives you a broken system on new infrastructure. The first two weeks should be purely about buying time: getting visibility into what's actually failing and making targeted changes to stop the bleeding.
Start with connection pooling. If you're on Supabase, enable PgBouncer in transaction mode and drop your pool size per function to something conservative 2 or 3 connections. Yes, this reduces per-function parallelism. It also stops the cascade where one traffic spike kills the database for everyone. Your p99 latency goes up slightly; your error rate goes to zero. That's the trade you want right now.
Add structured logging before anything else. You cannot migrate what you cannot observe. If you're not already shipping structured JSON logs from your API routes, do it now. Vercel's log drain can send these to Datadog, Axiom, or Logtail cheaply. You want request duration, error codes, and the user action that triggered each log line. This data will tell you exactly where to migrate first and in what order.
The mistake most teams make here is pulling in a senior engineer to design the "perfect" new architecture before they have data on what's actually slow. Don't. Spend a week with real logs and you'll often find that 80% of your pain comes from two or three specific endpoints.
The migration sequence that doesn't break things
Once you have visibility, the sequence matters. Here's the order we've seen work across multiple migrations.
Step 1: Move long-running jobs off Vercel functions first.
Anything that takes more than five seconds report generation, email sending, data processing jobs should not be a Vercel serverless function. Move these to a queue-backed worker first. A simple setup: put a job onto a Redis queue from your Vercel function, run a worker process on a small VPS or Kubernetes pod, have the worker do the actual work. Your Vercel function now just says "I queued your job" and returns in 50ms. Timeout problems disappear.
BullMQ on Node.js is the path of least resistance if you're already in the TypeScript ecosystem. If you're moving to Go for the worker layer, use a simple database-backed queue first it's less infrastructure to manage and good enough for most volumes.
Step 2: Move your database to a region you control.
Managed databases from Supabase or Neon are hosted in US regions by default. If your users are in Jakarta and your database is in US-East-1, you're adding 200-300ms to every database query before your code does anything. AWS's Jakarta region (ap-southeast-3) exists. Use it.
The migration process: snapshot your Supabase database, restore it to an RDS instance in ap-southeast-3, run both in parallel for two weeks with writes going to both, then cut over. This is less complex than it sounds if you do it before your schema has diverged significantly. If you wait until you have 50 tables and complex foreign key relationships, it gets harder.
Step 3: Decide on Vercel now, not later.
At this point you have a choice. You can stay on Vercel for your frontend and accept its constraints, or you can move to a self-hosted Next.js deployment. Both are valid. The decision point is cost and control.
If your Vercel bill is under $500/month and your traffic is predictable, stay. Vercel's infrastructure team is solving problems you don't want to solve yourself. If you're spending $2,000+ per month on Vercel or you've hit a hard limit that the platform can't solve, the migration to self-hosted infrastructure is worth the engineering investment.
What you should not do is let this decision drag for months while you pay Vercel bills that could fund another engineer.
The part most people get wrong: doing too much at once
The canonical mistake in infrastructure migrations is treating it as a project rather than a sequence of small, independent changes.
We've seen this play out at multiple funded startups in Indonesia. The team decides to migrate "the infrastructure." They design a beautiful new architecture Kubernetes on EKS, a separate microservices layer, a proper event bus. They spend six weeks building it. Then they try to migrate and discover that the application had dozens of implicit dependencies on Vercel-specific behaviors (environment variable injection, ISR caching, edge middleware) that weren't documented anywhere. The migration fails or takes months longer than planned. The business suffers.
The right frame: each change should be independently deployable and independently rollbackable. Moving your job queue to Redis doesn't touch your Vercel deployment. Moving your database to ap-southeast-3 doesn't change your frontend code. Migrating your Next.js deployment to a self-hosted server is a separate decision from both.
Small, independent, reversible. That's the pattern.
A related mistake: migrating authentication infrastructure early. Auth is where bugs cost the most. If your current auth setup works, leave it alone until everything else is stable. The number of startups that broke their login flow during an infrastructure migration is embarrassingly high. Auth is a late-stage migration item.
What a realistic six-month migration looks like
To make this concrete: a logistics SaaS that went through this recently had a Next.js app on Vercel, a Supabase Postgres instance in US-East-1, and about 15,000 daily active users split between Jakarta and Surabaya.
Month one: structured logging, connection pooling fix, job queue setup. Cost: two weeks of engineering. Result: error rate dropped from 3% to 0.4%.
Month two: database migration to ap-southeast-3 on RDS. They used AWS DMS for the initial replication and ran parallel writes for 10 days. Zero data loss on cutover. P50 database query latency dropped from 280ms to 40ms.
Month three: evaluation of Vercel spend ($1,800/month) versus self-hosting. Decision: stay on Vercel for the Next.js frontend, move all API routes to a dedicated Go service on a $120/month VPS. This is the strangler fig pattern applied to serverless you don't rewrite everything at once, you move traffic incrementally.
Month four and five: traffic migration, observability hardening, on-call runbooks.
Month six: the team could handle 10x their current traffic with the existing infrastructure. The migration cost roughly four months of one senior engineer's time. The alternative outgrowing the stack during a funding round demo would have been worse.
For a deeper look at the full infrastructure stack decisions that go into a migration like this, that post covers the underlying choices in more depth.
FAQ
Q: When is the right time to start migrating off a weekend project stack? A: When any of these are true: your Vercel bill exceeds what a VPS would cost for equivalent capacity; you've hit a platform limit you can't engineer around; your database is in the wrong region for your users; or your error rate during traffic spikes is above 1%. If none of these apply, you're probably fine for now.
Q: Do I need to rewrite everything to migrate to production infrastructure? A: No. The most effective migrations reuse most of the existing code and only replace the infrastructure layer beneath it. A Next.js app that runs on Vercel runs the same on a self-hosted server. Your business logic doesn't change. The container it runs in does.
Q: How long does a production infrastructure migration typically take for a small startup team? A: If you're doing it correctly small, independent changes budget four to six months for a team of two to three engineers doing this alongside feature work. If you try to do it all at once, you'll either take longer or break something important. The companies that rushed got burned.
Q: Should I hire an infrastructure specialist or do this in-house? A: Depends on what you have. If your team has built and run production systems before, you can do most of this internally. If your team is primarily product engineers who've never managed a database in production, bring in someone who has. The decisions made in the first migration tend to stick for years.
Q: What's the biggest thing that goes wrong during these migrations? A: Underestimating state. Serverless functions are stateless by design, which hides how much state your application actually manages in cookies, in local caches, in Vercel's edge network. When you move to a different infrastructure model, all that implicit state becomes explicit. Budget time to find and document it before you cut over.
Infrastructure migrations aren't glamorous work. They're also how you go from "this might break" to "we can sign that enterprise SLA." The teams that do it well treat it as a sequence of boring, careful changes rather than a dramatic rewrite.
If you're at the point where your infrastructure is holding back the business and you need a second set of eyes on the decisions, architecture reviews are something we do with founding teams at exactly this stage.
Internal links used:
- migration to self-hosted infrastructure direct continuation for teams deciding to leave Vercel
- full infrastructure stack decisions pillar post for deeper infrastructure context
- architecture reviews natural soft CTA
External links used:
- None kept internal
Word count: 1,980