Wiki &
Checklists.
Everything you need before deploying. Pre-launch checklists, cache strategies, and the 5 golden rules of hosting cost management.
This wiki is based on public pricing and real horror stories. It's a side-project, not legal or financial advice — treat these numbers as educated estimates.
Cache aggressively
Static content = CDN, not origin. Use Cloudflare free tier in front of everything.
Measure requests
>200 requests/session is a red flag. Profile on staging, set budgets, monitor in production.
Sample analytics
10-30% sampling is enough for decisions. 100% logging is a luxury only small sites can afford.
Billing alerts from day 1
Set alerts at $100, $200, $500. Use a virtual card with spending limits for experiments.
Build portably
Vendor lock-in = cost risk. Keep business logic vendor-neutral. Have a migration plan ready.
Pre-Launch Checklist6 categories · Interactive progress tracking+
Measurements
0/4Load Testing
0/3Billing Safety
0/3Cache & CDN
0/4Performance
0/5Analytics
0/4Cache Strategy TableRecommended headers for every resource type+
| Resource | Cache-Control | Notes |
|---|---|---|
| Static JSON/HTML | public, max-age=2592000, stale-while-revalidate=86400 | 30 days + 1 day SWR |
| Archival pages | public, max-age=604800 to 2592000 | 7-30 days; manual busting on changes |
| Assets (JS/CSS w/ fingerprint) | public, max-age=31536000, immutable | 1 year, immutable |
| API with dynamic data | public, max-age=60, stale-while-revalidate=300 | 1 min + 5 min SWR |
| User data (auth) | private, no-cache | Never CDN |
Key rule: Cache everything that is static or near-static. Archival data (like emails in jmail) is the perfect candidate — content doesn't change, cache for 30 days.
Provider Decision TreeWhen to switch based on session volume+
Emergency PlanImmediate actions when costs spike+
Immediate Actions (no redeploy)
- 1Turn off
AGGRESSIVE_PRELOADfeature flag — eliminates ~70% of requests - 2Enable degraded mode: simpler UI, pagination, no animations/prefetches
- 3Increase cache TTL via Cloudflare dashboard (e.g. from 1h to 24h)
If Bill Keeps Growing
- 1Switch DNS to Cloudflare-cached version (proxy mode)
- 2Disable Vercel Analytics (~36% of jmail's bill)
- 3Enable rate limiting on edge (Cloudflare rate limiting rules)
Prevention (set up before you need it)
- 1Attach a virtual card with a hard spending cap ($100–$200) to Vercel billing — the simplest and most effective safeguard
- 2Enable Vercel Spend Management — set a monthly limit with auto-pause. Available on Pro/Team plans (check your dashboard, features may change)
- 3Add a kill switch env var (
APP_KILL_SWITCH) — check it in your root layout or middleware, return a static maintenance page when set totrue - 4Set up Cloudflare rate limiting — free plan gives 5 rules. Example:
/api/*at 100 req/min/IP, everything else at 300 req/min/IP
For the full layered playbook — virtual cards, Spend Management, Cloudflare setup, kill switches, and more — see the Viral Protection guide.
Architecture by PhaseRecommended stack at each growth stage+
Next.js → Vercel Pro + Cloudflare DNS (proxy, free tier) + Supabase + Plausible/Umami
Run the cost calculator. Consider CF Workers (OpenNext) or VPS + CDN. Enable analytics sampling.
CF Workers + R2 + D1/Neon, or Hetzner/Railway + aggressive CDN. Vercel only for preview/staging.
Monitoring AlertsThresholds and actions for cost spikes+
| Condition | Threshold | Action |
|---|---|---|
| Request spike | >10× average | Alert + investigate source |
| p95 latency | >2s | Check origin / cache miss rate |
| Error rate | >5% | Immediate response |
| Vercel billing | >$200/mo | Evaluate if worth staying |
| Vercel billing | >$500/mo | Consider migration to CF Workers |
Avoiding Vendor Lock-in5 principles for portable architecture+
“Build on tech that can be moved absolutely anywhere.” — Wes Bos
<Link> vs <a>When each is the right choice+
Next.js logs a warning when you use <a> instead of <Link> for internal routes — and it's right. But the opposite problem is never flagged: wrapping external URLs in <Link> when a plain <a> is better.
With prefetch={true} (the default!), Next.js tries to prefetch the destination route — for an external URL, that's a wasted cross-origin request. Even with prefetch={false}, <Link> wraps navigation in the router, intercepts the click, and parses the URL — unnecessary work for a link that opens a new tab anyway.
| Scenario | Use | Why |
|---|---|---|
| Internal navigation (SPA routing) | <Link prefetch={false}> | Client-side routing, preserves React state, no full page reload. |
| External link (https://...) | <a target="_blank" rel="noopener noreferrer"> | <Link> adds router overhead with zero benefit — the browser opens a new tab anyway. |
| Anchor on the same page (#id) | <a href="#id"> | No router needed — pure scroll behavior. |
| Download / mailto / tel | <a> | Not routes — the browser handles these natively. |
HostCost approach: <Link prefetch={false}> for internal routes, plain <a> for external links. Every link type chosen deliberately.
DogfoodingHow this site applies its own principles+
This site applies every principle it teaches. Here's how: