Server Infrastructure
You vibe-coded something that works on your laptop. Now you want other people to use it. That gap — between "runs on my machine" and "runs on the internet" — is what infrastructure is about. The good news: you don't need a DevOps career to cross it. You need a working mental model and the willingness to let AI handle the fiddly config.
This chapter demystifies the hosting landscape, gives you the trade-offs in plain language, and hands you a default path that takes a solo builder from prototype to production without drowning in choices.
The five places code can live
Almost every hosting product on earth is a variation of one of these five categories. Learn these and the marketing pages stop being confusing.
- Static hosting — Plain files (HTML, CSS, JavaScript, images) served straight to the browser. No server "runs" your code; it just hands over files. Think of it as a folder on the internet. Examples: GitHub Pages, Cloudflare Pages, Netlify, Vercel (static mode).
- Edge functions — Tiny snippets of code that run on servers physically close to your user, all over the world. They start almost instantly and are great for lightweight logic: auth checks, redirects, small API calls. Examples: Cloudflare Workers, Vercel Edge Functions, Deno Deploy.
- Serverless functions — Code that runs on demand and disappears when idle. You're billed per request, not per hour. You write a function; the platform handles the machines. Examples: AWS Lambda, Google Cloud Functions, Vercel Functions.
- Containers — Your app plus its entire environment (the right language version, libraries, system tools) packaged into a portable box called a container. The platform keeps that box running. More control, slightly more setup. Examples: Fly.io, Railway, Render, Google Cloud Run.
- Virtual machines (VMs) — A whole computer you rent in a data center. You install and manage everything yourself. Maximum control, maximum responsibility. Examples: AWS EC2, DigitalOcean Droplets, Hetzner.
A couple of jargon terms, decoded
- Cold start — When code hasn't run in a while, the platform has to wake it up. That first request is slower (a fraction of a second to a few seconds). Edge functions barely have this; serverless functions sometimes do; always-on containers and VMs don't.
- Scaling — Handling more users without falling over. Automatic scaling means the platform adds capacity for you. Manual scaling means you click buttons or it just breaks under load.
- State — Data that needs to stick around (a database, uploaded files, a user session). Static and serverless layers are often "stateless" — they forget everything between requests — so state lives in a separate database or storage service.
The trade-off table
| Hosting type | Cost (idle → busy) | Scaling | Cold starts | Complexity | Best for |
|---|---|---|---|---|---|
| Static | Free → very cheap | Automatic, effortless | None | Lowest | Marketing sites, docs, blogs, frontends |
| Edge functions | Free tier → cheap | Automatic, global | Negligible | Low | Auth, redirects, light APIs, personalization |
| Serverless | $0 when idle → scales with use | Automatic | Sometimes noticeable | Low–medium | APIs, webhooks, bursty/unpredictable traffic |
| Containers | Pay while running | Automatic-ish, configurable | None (if kept warm) | Medium | Full backends, long-running jobs, custom runtimes |
| VMs | Pay 24/7 | Manual | None | Highest | Special hardware, legacy software, full control |
The pattern: as you move down the table, you trade simplicity and low idle cost for control and flexibility. Most vibe coders should fight to stay near the top.
When to pick which
- Just a website or frontend? Static hosting. Done. It's free, fast, and nearly impossible to break.
- Need a little backend logic — a contact form, an API key kept secret, an auth check? Edge or serverless functions. You stay on a generous free tier and scale to zero when nobody's using it.
- A real app with a database, background jobs, or a framework that expects a long-running server? A container platform like Railway, Render, or Fly.io. This is the sweet spot for most "actual product" projects.
- You need a specific GPU, special system software, or total control? A VM. Only go here when something above genuinely can't do the job, because now you are the sysadmin.
A useful rule: pick the simplest option that can do the job, and only move down a tier when you hit a real wall — not an imagined one.
How AI wires up deploys and config
This is where vibe coding shines. Deployment config is exactly the kind of precise, well-documented, boilerplate-heavy work AI is great at. You direct; it writes.
Effective prompts sound like:
- "Add a
Dockerfilefor this Node app and a Railway config to deploy it." - "Write a GitHub Actions workflow that deploys the
dist/folder to Cloudflare Pages on every push tomain." - "I'm getting a cold-start timeout on my serverless function — what's likely wrong and how do I fix the config?"
Here's the kind of file AI will produce for you — a deploy workflow that ships a static site automatically whenever you push code:
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci && npm run build
- name: Publish to Cloudflare Pages
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CF_API_TOKEN }}
command: pages deploy dist --project-name=my-app
You don't need to memorize this syntax. You need to recognize what it does: on every push to main, it checks out your code, builds it, and publishes the result. When something breaks, you paste the error back to the AI and ask it to fix the config.
A few directing tips that save real pain:
- Make AI explain before it acts. "Before writing config, tell me which hosting type fits this project and why." This catches over-engineering early.
- Keep secrets out of code. API keys and passwords go in the platform's environment variables / secrets store, never in files you commit. Ask AI to use a secrets reference, as in the
CF_API_TOKENabove. - Deploy early, deploy often. Get a "hello world" live on day one. A pipeline that's been working since the start is far easier to debug than one assembled at launch.
A recommended default path for the solo builder
Here's a route that has worked for countless one-person projects. Each step is taken only when you actually need it.
-
Prototype: static + a managed backend service. Put your frontend on static hosting (Cloudflare Pages, Vercel, or Netlify). For data and auth, lean on a managed backend like Supabase or Firebase so you skip running a database yourself. Cost: effectively zero.
-
Early production: add edge or serverless functions. When you need server-side logic — secret API calls, webhooks, custom auth — add functions on the same platform. Still scales to zero, still cheap, still one deploy.
-
Real product: move the backend to a container platform. When the app outgrows functions (long-running processes, a framework that wants a persistent server, background jobs), containerize it and deploy to Railway, Render, or Fly.io. Have AI write the
Dockerfileand platform config. -
Scale or specialize: only then consider VMs or a cloud provider like AWS. This is where complexity (and your bill) jumps. Most solo builders never need this step, and that's a sign of doing things right — not a limitation.
The mistake to avoid is starting at step 4 because it's what "real engineers" supposedly use. The opposite is true: starting simple is the senior move. You can always graduate to more control, but you can't easily get back the months you'd lose wrestling infrastructure you didn't need.
The takeaway
Infrastructure is a ladder, not a leap. Static at the top, VMs at the bottom, and most of your work happily living in the upper rungs. Know the five categories, pick the simplest one that does the job, let AI write the config, and ship something live as early as you can. The rest is just moving down a rung when — and only when — reality forces you to.
Cost Safety: CLI vs API
One bill can ruin a launch, and it rarely comes from hosting. It comes from a metered AI API. The tools you code with day to day — Claude Code, Cursor, and the like — are usually a flat-rate subscription: the cost of one more prompt is effectively zero. The moment your app calls a raw AI API or SDK, the economics flip: you're billed per token, per request, with no ceiling. A buggy retry, an unbounded batch job, or an agent that loops can quietly turn a $0 idle bill into a four-figure surprise overnight. That's "bill shock," and it's the most common way solo builders get burned.
Put a cage around any paid API before it ships:
- Set a hard spend cap in the provider dashboard — a real ceiling, not just an email alert.
- Prefer the flat-rate CLI for development; save the metered API for the production feature that truly needs it.
- Rate-limit your own calls — cap concurrency and requests per minute — and watch the usage dashboard the first few days.
- Use cheap/small models for bulk work, and test on tiny inputs first (one record, not the whole table).
- Never ship an unthrottled loop that calls a paid API. Bound every loop.