on this page

You’ve pushed your project to GitHub, the build runs clean, and now you’re staring at a page full of logos: Vercel, Netlify, Cloudflare Pages, GitHub Pages. Each one promises to put your site on the internet for free, and each one’s homepage reads like it was written by people who have never met a beginner. So which button do you press?

Before you pick, it helps to know what you’re actually buying (even at the price of nothing). Once you see what a frontend host does under the hood, the four options stop looking interchangeable and start looking like what they are: the same basic job with different opinions bolted on.

What a frontend host actually does

Strip away the marketing and a frontend host does one boring, useful loop. It watches your GitHub repository. When you push, it pulls your latest code, installs your dependencies, and runs your build command. Your build spits out a folder of plain static files: HTML, CSS, JavaScript, images. The host grabs that folder, copies it onto a CDN (a Content Delivery Network, a fleet of servers spread around the world so your files sit close to whoever’s loading them), and hands you a URL with HTTPS already turned on.

That’s the whole trick. You write code and push it. The host turns your source into shippable files and serves them, fast and encrypted, without you renting a server or installing anything. If you want the longer version of this pipeline (DNS, builds, certificates, all of it), the localhost to production guide walks the full path. This guide is narrower: given that you understand the loop, which host should you hand your project to?

The important thing to hold onto is that word static. A frontend host serves files. It does not, by default, run a backend that talks to a database or holds a long-lived connection open. Some of these hosts can run small server-side functions on the side, but their core competency is shipping files to browsers, fast. Forget that and you’ll spend an afternoon wondering why your Node and Express server “isn’t deploying.”

The four beginner options, honestly

All four do the loop above. Where they differ is what they’re tuned for and the catch nobody mentions until you hit it.

GitHub Pages

Heads up. You're leaving raindev.fyi

This link heads to pages.github.com, an external site we don't control. Cool to keep going?

Continue
is free, and it’s about as simple as hosting gets, especially since your code already lives on GitHub. For a portfolio, a docs site, or anything that’s pure static output, it’s hard to beat. The catch: it really is static only. No server functions, no environment-variable-driven backend, nothing dynamic. And the moment your build setup gets even slightly custom, GitHub Pages can get fiddly, often nudging you into a GitHub Actions workflow file to do what other hosts do with two dropdowns.

Vercel

Heads up. You're leaving raindev.fyi

This link heads to vercel.com, an external site we don't control. Cool to keep going?

Continue
is the company behind Next.js, and it shows. If you’re building a Next.js app, this is the host that understands every feature without you configuring anything: server rendering, image optimization, the lot. The developer experience is genuinely smooth, preview deploys are excellent, and a hobby project fits comfortably in the free tier. The catch is mostly about growth, not getting started: the free tier is for personal projects, and once something turns commercial the pricing wants a closer look.

Cloudflare Pages

Heads up. You're leaving raindev.fyi

This link heads to pages.cloudflare.com, an external site we don't control. Cool to keep going?

Continue
rides Cloudflare’s CDN, which is one of the largest on earth, so your files load quickly almost everywhere. The free tier is generous, with no cap on bandwidth, which is unusual and genuinely nice for a side project that unexpectedly gets popular. For an Astro site or any plain static build it’s a great default. The catch: the dynamic side (Cloudflare’s serverless functions, called Workers) is its own ecosystem with its own way of doing things, so it’s less plug-and-play than Vercel if you go past static.

Netlify

Heads up. You're leaving raindev.fyi

This link heads to www.netlify.com, an external site we don't control. Cool to keep going?

Continue
pioneered a lot of what the other three now copy: connect a repo, get automatic builds and deploy previews. It still does the polished extras well, especially redirect rules and built-in form handling that catch submissions without you writing a backend. For a marketing site that needs a contact form and some URL redirects, that’s real time saved. The catch: the free tier has build-minute and bandwidth limits that a busy site can bump into, so keep an eye on the meter.

The comparison, in one table

HostFree tierBest forCustom domainsPreview deploysMain gotcha
GitHub PagesFree, unlimitedPortfolios, docs, plain static sitesYes, free HTTPSNo native PR previewsStatic only, no server functions
VercelHobby tier, personal useNext.js appsYes, free HTTPSYes, per pull requestCommercial use needs a paid plan
Cloudflare PagesFree, unmetered bandwidthAstro and static sites, global speedYes, free HTTPSYes, per pull requestDynamic features mean learning Workers
NetlifyFree, with build-minute limitsSites needing redirects or formsYes, free HTTPSYes, per pull requestFree limits on builds and bandwidth

The settings everyone gets wrong

Whichever host you pick, the first deploy asks the same two questions, and beginners trip on both. Getting these right is most of the battle.

The build command is what the host runs to turn your source into files. For most modern projects that’s npm run build (npm being the Node Package Manager, the tool that installs your libraries and runs the scripts defined in your package.json). Most hosts guess this correctly when they detect your framework, but if you’ve renamed your scripts, you set it yourself.

# What the host actually runs on its server
npm ci
npm run build

The output directory (Netlify calls it the publish directory) is the folder your build leaves behind, the one the host should actually serve. This is the single most common reason a deploy “succeeds” but shows a blank page or a 404: the host built your files, then served the wrong folder. The defaults depend on your tool:

Astro / Vite     ->  dist
Create React App ->  build
Next.js          ->  handled by the adapter, you don't set this

For Astro and Vite projects the answer is dist. For an old Create React App project it’s build. For Next.js you generally don’t touch this at all, because Vercel (or the framework adapter on another host) wires it up for you. Set the wrong one and you’ll see a confidently green build followed by a page that isn’t there.

Environment variables and the prefix that bites

Environment variables are the configuration values you don’t hardcode: an API key, a backend URL, a feature flag. You set them once in the host’s dashboard, and the build reads them.

Here’s the gotcha that catches nearly everyone. Frontend build tools only expose a variable to the browser if its name starts with a specific prefix:

FrameworkPrefixExample
AstroPUBLIC_PUBLIC_API_URL
ViteVITE_VITE_API_URL
Next.jsNEXT_PUBLIC_NEXT_PUBLIC_API_URL

A variable named API_URL with no prefix stays invisible to your frontend code, which is why your fetch call suddenly points at undefined in production. Add the prefix and it works.

Custom domains and preview deploys

A custom domain turns your-project.pages.dev into yourname.dev. All four hosts let you add one, and all four issue the HTTPS certificate for free and renew it automatically, so you’re not buying or installing anything. You point your domain’s DNS at the host, wait a few minutes, and it’s live.

Preview deploys are the feature you’ll miss most if you skip it. When you open a pull request, Vercel, Netlify, and Cloudflare Pages each build that branch separately and give you a private URL to look at. You see the change running on the real internet before it touches your main site, which makes “can I see it?” a link instead of a screenshot. GitHub Pages doesn’t do this natively, which is one of the clearer reasons to reach for one of the others once your project grows past a single person.

Which one should I use?

Skipping the diplomacy, here are concrete picks.

Building an Astro site or a plain static site? Use Cloudflare Pages or GitHub Pages. Cloudflare if you want preview deploys and that unmetered bandwidth; GitHub Pages if you want the absolute shortest path and your code’s already there.

Building a Next.js app? Use Vercel. They make Next.js, every feature works on the first try, and you’ll spend zero time fighting configuration. You can host Next.js elsewhere, but on Vercel it just goes.

Need redirects or form handling without standing up a backend? Use Netlify. The redirect rules and built-in forms are the thing it does better than the others, and for a marketing site that’s exactly the friction you want gone.

If you genuinely don’t know yet, Cloudflare Pages is a safe default for most static and Astro projects, and nothing here locks you in. Moving a static site between hosts is an afternoon, not a migration.

Common mistakes

Most failed first deploys come down to one of these four, and now that you’ve read the rest of this guide, each one should look familiar.

Wrong output directory. The build goes green and the site is blank or 404s. You told the host to serve build when your tool wrote to dist, or the reverse. Match the directory to your framework and it appears.

Environment variables set locally but not on the host. Your .env file lives on your laptop and never gets pushed (rightly, it’s in .gitignore). The host has never seen those values. Add every variable your app needs in the host’s dashboard, with the correct prefix, then redeploy.

Expecting a static host to run a backend. You wrote a Node and Express server, or you’re connecting straight to PostgreSQL from the browser, and you’re trying to deploy it to a frontend host. That’s not what these do. Your frontend goes on Cloudflare Pages or Vercel; your server goes somewhere built to run it, like Railway or Render, and the two talk over HTTPS.

A build that passes locally but fails on the host. Almost always a different Node version. Your laptop runs Node 20, the host defaults to Node 18, and some package quietly disagrees. Pin the version so both machines match:

{
  "engines": {
    "node": "20.x"
  }
}

Now go ship it

Pick the host that fits the project in front of you, set the build command and output directory, add your environment variables with the right prefix, and push. The first deploy that comes back green with a real URL is the moment the thing you built stops being a localhost secret and becomes something you can send to a stranger. That’s the whole point of all of this: not the perfect host, just the project that’s actually live.