From Vercel Pro to a /mo VPS: 7-day Next.js migration report

10 min read Original article ↗

I moved my Next.js site from Vercel ($20/mo Pro) to a $10/mo Hostinger VPS. 7-day report.

A solo founder's writeup of leaving managed hosting for a self-managed VPS, with the actual technical steps, the bugs that showed up, and the cost / performance numbers seven days in.

By Samarth Bhamare. April 2026.


Why I left Vercel

Last week, Vercel paused my account. Free-tier CPU overage. Fair on Vercel's part, except for one specific friction: when I tried to upgrade to Pro, my Indian payment cards were rejected at $20 per month checkout.

This isn't unique to Vercel. Stripe-based US-first SaaS platforms regularly fail on Indian cards for higher-tier plans. Lemon Squeezy and Stripe itself had also rejected my onboarding earlier this year for similar reasons. So I had a paused production site and no clean upgrade path on the platform hosting it.

Two options: keep banging on Vercel support, or move. I gave Vercel about 90 minutes, then went looking.

Seven days later, the site runs on a Hostinger KVM 2 VPS in Mumbai for $10 a month. Most things run better than they did on Vercel. Some things run worse. Honest writeup.

What I was running

  • Next.js 16 with App Router. Server components, API routes, dynamic rendering on most pages.
  • ~5,000 monthly visitors, growing.
  • Several cron jobs every 6 hours via Vercel Cron (newsletter drips, scheduled emails).
  • Heavy build pipeline: 2,300+ JSON skill files, ~100 blog posts, a research PDF, a few large content files.
  • External services unchanged across migration: Upstash Redis, Razorpay, PayPal, Cloudflare DNS.

The build pipeline tipped me into free-tier overage. Each push triggered a full Next.js production build. CPU minutes burned faster than I expected. Reasonable behavior, but Pro-tier billing wasn't accessible to me with Indian cards.

What I picked

Three options I considered:

  • DigitalOcean. Cheapest VPS at $4/mo for 1GB RAM, but to match what I needed (4-8GB) you're at $24-48/mo.
  • Linode (Akamai). Similar pricing to DigitalOcean.
  • Hostinger KVM VPS. $10/mo for 8GB RAM, 2 cores, 100GB disk. Mumbai data center for India latency.

Hostinger won on three things specifically:

  1. Indian cards work. They take Indian credit cards and UPI without underwriting issues. This was 80% of the decision.
  2. Mumbai data center. Real latency win for an India-skewing audience: TTFB went from ~140ms (Vercel's nearest edge) to ~25ms (Mumbai).
  3. 8GB RAM at $10/mo. The same memory on DigitalOcean is roughly 3x the cost.

The risk: Hostinger has a reputation for slow shared hosting. The KVM VPS line is a different product, properly virtualized with dedicated resources. Reviews of the VPS specifically (not the shared hosting) are generally positive, though I had no first-hand experience until last week.

The actual migration

Four hours of work over two evenings. Steps in order:

Provision and install basics

Ubuntu 24.04 LTS, root SSH access. First commands:

apt update && apt upgrade -y
apt install -y nginx certbot python3-certbot-nginx git curl
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
apt install -y nodejs
npm install -g pm2

Node 22, nginx, certbot, pm2. Standard Linux web stack. ~6 minutes.

Clone repo and build

mkdir -p /var/www && cd /var/www
git clone <repo>
cd <repo>
npm install
npm run build

First build took ~3 minutes. No issues.

Start under PM2

pm2 start "npm run start" --name myapp
pm2 save
pm2 startup

App on port 3000, PM2 keeps it alive on crashes, comes back on reboot.

nginx reverse proxy

/etc/nginx/sites-available/myapp.com:

server {
    listen 80;
    server_name myapp.com www.myapp.com;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Symlink to sites-enabled, reload nginx, test the IP serves the site.

DNS migration via Cloudflare

This was the hairy part. Domain registered at Hostinger but using Vercel's nameservers (ns1.vercel-dns.com, ns2.vercel-dns.com) from when I first set up Vercel. Clean migration:

  1. Add domain to Cloudflare (free plan), get assigned nameservers.
  2. At registrar, change nameservers to Cloudflare's.
  3. In Cloudflare DNS, add A records for @ and www pointing to the VPS IP.

What I did wrong: at the registrar I added Cloudflare nameservers without removing Vercel's. For a few days the domain had four NS records (two Cloudflare, two Vercel). DNS resolvers cached the Vercel delegation, queried Vercel's nameservers, got back Vercel deployment IPs.

Symptom: ~50% of users got the Vercel "deployment paused" page instead of the live site, depending on which resolver their network used. Took a day to diagnose because from my own networks the site worked.

Fix: at the registrar, remove Vercel nameservers entirely so only Cloudflare remains. Then in Vercel's project Domains UI AND in Vercel's account-level DNS Domains UI, remove the domain. That second step is non-obvious and easy to miss.

If you're migrating, do both nameserver changes AND zone deletions in the same session. Don't leave one provider half-configured.

Let's Encrypt cert

certbot --nginx -d myapp.com -d www.myapp.com

Certbot reads nginx config, talks to Let's Encrypt, drops in cert, modifies nginx to listen on 443. Renewal cron auto-installed. I went one further and got a wildcard cert (*.myapp.com) so future subdomains are covered, but -d is enough for most.

Migrate environment variables

vercel env pull from local before migration gave me .env.production.local. Scp'd to VPS.

One sharp edge: Vercel's env export adds literal \n characters to multi-line values that aren't actually multi-line in source. API signing keys and SMTP password came out with trailing \n characters that broke signature verification at runtime. Fix:

sed -i 's/\\n"$/"/' .env.production.local

Run that BEFORE you start the app. Otherwise spend an hour debugging "invalid signature" errors.

PM2 startup so app survives reboots

pm2 startup
pm2 save

systemd integration. If VPS reboots (Hostinger does monthly maintenance), app comes back without intervention.

Total migration: 4 hours including DNS confusion. Without that mistake, ~2 hours.

Incidents in the first 7 days

Day 2: OOM during a build

First real outage. Pushed a deploy, build process spiked memory to 6GB+ during Turbopack's bundling pass, kernel OOM killer started picking processes. Killed sshd and the running Next.js server. Site unreachable ~30 minutes until I rebooted via Hostinger panel.

Diagnosis: I had thought "KVM 2" meant 2GB RAM. Turns out the "KVM 2" name refers to the plan tier, not memory. I actually had 8GB. The OOM happened because I had no swap configured and Next.js builds can briefly spike past available RAM even when the floor is high.

Fix:

fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab
sysctl vm.swappiness=10

2GB swap, swappiness low so kernel prefers RAM. Build spikes now use swap as overflow instead of crashing the box. Hasn't happened again.

100% my mistake, not Hostinger's.

Day 4: DNS split-brain

The Vercel nameserver leftover described above. Some users hit live site, others hit Vercel's paused-deployment page. Took a day to diagnose because from my own networks the site worked. Fixed by removing Vercel nameservers from registrar and deleting the zone from Vercel's team-level DNS panel. Cached delegations expired in 24-48 hours.

Also my mistake, but Vercel having two separate Domains pages (project-level and team-level) made it harder to find than it should have been.

Other minor things

  • One payment failure on day 3 because of the \n env var issue. Fixed in 5 minutes.
  • One certbot renewal that initially failed because nginx was reloading during the cert challenge. Auto-retry succeeded.
  • A few SSH disconnects when laptop went to sleep mid-deploy. Annoying but not the host's fault.

What Hostinger does better than Vercel for my workload

Cost. $10/mo vs $20/mo on Pro. Half price.

Latency to actual users. Audience is roughly 60% Indian, 30% US, 10% other. Vercel's edge served US fast, Indian users slowly (nearest edge for India is Singapore). Hostinger Mumbai serves Indian users fast (~25ms TTFB), US users slower (~200ms). For my audience that's a net improvement.

No build-minute pricing surprises. On Vercel I was nervous about every push. On Hostinger, builds happen on the VPS using its included CPU. Deploy storms have no marginal cost.

Full Linux access. Need to debug something? SSH in, run a script, look at logs, restart a process. On Vercel everything was through dashboard or CLI. Less abstract on a VPS.

Indian-card billing actually works. The decisive factor for me.

What Vercel does better than Hostinger

Zero ops. On Vercel you push to git and deploy happens. On Hostinger I run a deploy.sh that pulls, builds, restarts PM2. Not hard but it's an extra concept.

Edge runtime. Vercel's edge would have served static content from the closest node globally. Hostinger Mumbai is fast for Indians, slow for everyone else. If your audience is genuinely global with strong American skew, Vercel still wins on global TTFB.

Preview deployments. Vercel auto-builds every PR with a preview URL. I built nothing equivalent on the VPS. For a solo project this is fine, for a team it's a real loss.

Built-in observability. Vercel's analytics, speed insights, log streaming are all immediate. On the VPS I wired up basic logging through PM2 and rely on Cloudflare analytics for traffic. Less polished.

Cron via UI. Vercel Cron is a checkbox in vercel.json. On the VPS, you edit the system crontab. Same effect, less ergonomic.

When each is the right choice

Stay on Vercel if:

  • Audience is US-centric and you benefit from edge runtime to all of North America
  • You don't want to think about ops at all
  • You're on free tier and not over the line, OR you can afford Pro and your cards work for it
  • You value preview deployments per PR (real for teams)

Move to a VPS like Hostinger if:

  • Paying for Pro/Business and the price feels high relative to your usage
  • Audience has geographic concentration that Vercel's edge doesn't naturally serve well
  • You're in a country whose payment cards Stripe-based platforms reject
  • You want the option to host other small apps on the same machine
  • Comfortable spending ~4 hours one-time setting up nginx, PM2, certbot, and willing to do occasional ops work

What I'd tell anyone considering the move

Do all migration steps in one session. Don't leave Vercel half-deconfigured. Half-migrated DNS is the worst outage profile because users get inconsistent behavior depending on which resolver they hit.

Add swap from day one. Even with 8GB RAM, Next.js production builds can spike. 30 seconds of setup, saves you a 30-minute outage.

Write a deploy.sh script the first day. Manual git pull && npm run build && pm2 restart works once. Third time you do it, you'll forget a step. Script it.

Use Cloudflare for DNS. Their UI is clean, nameservers are fast, free tier covers everything most projects need.

Don't move on a Friday. Move Saturday morning so you have all weekend if something breaks. Mine did break (the OOM and DNS issue), having time to fix without customer pressure helped.

Bottom line

For an indie founder running a Next.js production site at low to moderate scale, with an audience that benefits from a regional data center, Hostinger KVM 2 at $10/mo is meaningfully better than Vercel Pro at $20/mo. The trade-off is 4 hours of one-time setup plus occasional ops work.

If you're in a similar position (Vercel paused you, your cards don't work for Pro, you want to control more of your stack, you want to host multiple small projects on one machine), this migration is worth the effort.


Last updated April 25, 2026. Open to questions on any specific step. Reach me at samarthbhamare at gmail dot com.