deploy · tutorial · vps
Next Build OOMs? The 2GB Swapfile Fix
next build dies with Killed on small boxes: link step eats 1.5GB. Swapfile plus heap cap plus off-peak builds, five minutes. Inside.

The deploy died at "Collecting page data"
Friday deploy, forty routes, 1GB box. Build spun through "Compiled successfully," reached "Collecting page data…," and died mid-word: Killed. No trace. No code. Just the kernel's assassin ending the build because RAM ran out mid-link.
Locally on 16GB it never happened. On the $5 box it happened every time past a dozen routes — always at the same step, always silent, always Friday. Dreading deploys set in the way dentist appointments do: necessary, painful, vaguely your fault.
Swapfile triage takes an evening to learn and five minutes to fix. This post is the five minutes.
Build RAM vs box RAM
| Consumer | Idle | Build spike |
|---|---|---|
| OS + daemons | ~150MB | ~150MB |
| Live app (PM2, serving!) | ~250MB | ~250MB |
| next build workers | 0 | 600–900MB at link |
| Node default heap | — | Up to 2GB allowed |
| 1GB box total | ~400MB fine | ~1.4GB → OOM killer |
Three things htop stakeouts teach:
- The app stays up while building — nobly, expensively. PM2 keeps serving users beside the build, which is correct behavior costing 250MB you can't borrow. The spike lands on live traffic, not an empty box. Good architecture, bad arithmetic.
- Linking parallelizes against you. A worker per core, each holding hundreds of MB of module graph, peaking exactly at "Collecting page data" — every log of this death ends mid-sentence at the same step. Predictable murders are preventable murders.
- Bigger boxes mask it at 2x price. Upgrading to 2GB doubles server cost forever to cover a 90-second spike. Swap covers the spike for $0 — shock absorber, not engine. My $5 box builds forty routes today; the upgrade can wait for real traffic.
The OOM post covered diagnosis broadly. This one is the swapfile, specifically, completely.
Swapfile next build vps routine
From the Hetzner provisioning this repo ships — same commands, every fresh box.
Step 1 — Confirm memory, not code.
dmesg | tail -20 | grep -i "oom\|killed process"
free -h # 50MB free + node as victim = memory, certain in 30 secondsOut of memory: Killed process (node) timestamped to your build is the whole diagnosis. Code bugs leave traces; the OOM killer leaves one word and a timestamp. Match the timestamp to the push and skip the other ninety minutes suspecting everything else.
Step 2 — Add the 2GB swapfile.
sudo fallocate -l 2G /swapfile && sudo chmod 600 /swapfile
sudo mkswap /swapfile && sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
sudo sysctl vm.swappiness=10 # RAM first, swap for spikes onlyReserved instantly, private permissions, surviving reboots, spike-only temperament. Verify with free -h (Swap row: 2.0G). Five minutes, no reboot, builds pass tonight. The single highest-ROI five minutes in small-box operations — tally kept, lessons filed.
Step 3 — Cap the heap, build off-peak.
# deploy hook, before npm run build:
export NODE_OPTIONS="--max-old-space-size=1536"
# plus: standalone output (smaller resident), builds at low-traffic hours1.5GB heap across 1GB RAM + 2GB swap leaves the live app untouched while linking peaks. Standalone output shrinks boot and resident memory; off-peak builds avoid competing with users for the same spike window. Cap bounds the hunger, swap absorbs it, timing dodges it — three layers, zero OOMs since.
That's what flat bills buy — even the smallest box builds clean.
Build ledger, before and after
| 20-route app, 1GB box | Before swap | After swap + cap |
|---|---|---|
npm run build |
Killed at page data |
Green in ~3 min |
free -h mid-build |
50MB, then death | 800MB swap used, alive |
| Live traffic during | Dead with builder | Served, untouched |
| Friday feeling | Dread | Boredom (correct) |
The honest bill: swap is disk (slower than RAM — builds take a minute longer), and chronic swap use (not spikes) means buy RAM. Watch vmstat outside build windows: quiet means healthy, busy means upgrade. Checks run monthly; quiet for a year running. Shock absorbers absorb shocks; engines do work. Know which yours is.
FAQ
Is swapfile next build vps safe for SSD longevity?
Yes for spike patterns: ~90 seconds of paging per deploy writes megabytes, trivial against NVMe endurance ratings (hundreds of TBW). SSD killers are chronic swap (24/7 paging from undersized boxes), not episodic spikes. Spike-only swap is the intended use; vmstat outside builds tells you which pattern you have. Mine's been spikes-only for a year.
Why not just set NODE_OPTIONS without swap?
Cap alone shrinks appetite but the box still holds 1GB against live app plus workers — slower Killed instead of fast Killed. Swap alone works but pages aggressively. Together: bounded spike, absorbed landing. Either half alone is half a fix wearing confidence. Both, always, five minutes total.
Does zram beat swapfiles on tiny boxes?
Different tool, same job: zram compresses RAM in place (faster than disk, bounded by CPU), swapfile extends onto disk (slower,roomier). 1GB boxes often run both (zram first, swapfile overflow) — belt and suspenders for the price of two config lines. Either alone fixes builds; together they cover stranger spikes (sharp + PDF + build simultaneously).
Should builds run on the server at all (vs CI artifacts)?
Server builds trade minutes for truth (native modules, server env, zero transfer); CI artifacts trade truth for speed (prebuilt, possibly stale-env). Solo scale: build on box (correctness first, minutes cheap). Team scale: CI artifacts with staging parity checks (speed matters at volume). Match the builder to the stakes, not the fashion.
How big should swap be relative to RAM?
2x RAM up to 2GB total swap covers build spikes on 1–2GB boxes (empirical, dozens of apps). Past 4GB RAM, swap matters less (headroom usually suffices) — keep 1–2GB as OOM insurance regardless. Swap sizing is shock-absorber sizing: cover the biggest spike observed, plus margin, verified by free -h during real builds.
When do I stop tuning and buy the 2GB plan?
When vmstat shows swap activity outside builds, reloads time out under normal load, or monthly build minutes exceed your patience. RAM at Hetzner-class pricing costs less than any tuning hour past this point. The swapfile bought months-to-years of $5 flat; upgrading spends dollars to reclaim attention. Buy RAM with joy, not defeat — growth did this.
Keep reading
- Next.js 'Killed' on 1GB VPS? The 5-Minute Swapfile Fix — the diagnosis half of this pair
- Deploy Next.js on Hetzner $5 by Dinner Tonight — the box this swapfile lives on
- PM2 Reloads Nobody Feels: Next.js With Zero Downtime — the reload builds feed into
+ all the boring stuff (analytics, auth, SQLite ↔ Supabase, full marketplace, webhooks)
Command from your phone.
Built so autonomous AI agents build what you want without breaking what's already paying you.
- Built-in analytics — cookie-free mode, $0 forever, no PostHog bill
- SQLite ↔ Supabase: one setting, same field names
- Full digital marketplace & feedback boards included
- 3 payment rails: Stripe, LemonSqueezy & Dodo Payments
- Agent fences: lint gate, read-only data access, auto-rollback
- Ship from your phone via SSH & WireGuard/Tailscale in under a minute
$199
Get BoringPushOne-time payment · Lifetime updates · Unlimited projects.
Keep reading


