On this page
- Why do some websites cost money to host and others don't?
- What's the catch?
- Step 1: create your site
- Step 2: write your pages
- Step 3: check it before it goes anywhere
- Step 4: pick a host
- Step 5: make sure it's really live
- Step 6: tell search engines you exist
- Moving to another host later
- What does it cost in practice?
- The hidden saving: no upkeep
- Ready to publish?
Hosting a website used to mean a monthly bill, a server to look after and a control panel full of settings you were scared to touch. For a lot of sites, it doesn't anymore. If your website is made of ready-built files, you can often host it for nothing. Here's how that works, what the catch is, and how to go from a folder of Markdown files to a live site with vagejs.
Why do some websites cost money to host and others don't?
There are two broad ways to run a website.
A dynamic site builds each page at the moment someone asks for it. A program on a server reads from a database, assembles the page and sends it back. That needs a computer running all the time, with server software that has to be kept patched, plus a database that has to be backed up. Someone has to pay for that computer and that upkeep.
A static site is built ahead of time. Every page is already a finished HTML file before anyone visits. The host's only job is to hand out files, which is about the simplest, cheapest thing a server can do. That's why several large hosting companies offer free plans for static sites: serving files costs them very little, and they can spread them across data centers around the world.
vagejs is a static site generator. It reads your Markdown files and layouts, and writes the finished site into a folder called dist/. That folder is your whole website. Anything that can serve files can host it.
What's the catch?
Free static hosting is a great deal, but go in with clear eyes:
- Free plans have limits. Each host sets its own limits on things like bandwidth, builds or the number of sites. For a typical small business site, portfolio or blog they're rarely an issue, but check your host's current terms before you rely on them.
- Static means the same page for everyone. User accounts, shopping carts with live stock and personalized dashboards need a server or a third-party service. vagejs is built for content sites: marketing pages, docs, blogs and portfolios.
- Terms change. A free plan today might look different next year. The good news is that a static site isn't tied to any one host, so moving is mostly a matter of uploading the same folder somewhere else.
That last point is underrated. Because the output is plain files, you're never locked in. Your words live in Markdown files you own, your design lives in layouts you own, and the built site works anywhere.
Step 1: create your site
You'll need Node.js 22.12 or newer on your computer. Then run:
npm create vagejs@latest my-site
cd my-site
npm install
npm run devOpen the address the dev server prints. You'll see your new site, and it reloads every time you save a file. The folder looks like this:
my-site/
├── src/pages/ every .md file is a page
├── src/layouts/ the HTML around each page
├── public/ files copied as-is, like images and favicons
└── vage.config.ts site settingsStep 2: write your pages
Every Markdown file in src/pages/ becomes a page, and its place in the folder decides its web address. src/pages/about.md becomes /about/, and src/pages/blog/first-post.md becomes /blog/first-post/.
Each file starts with a short block of settings called frontmatter, then the page itself:
---
title: About us
description: Who we are, what we do, and how to reach us.
---
# About us
We're a small studio in Leeds making furniture by hand.The title and description feed the search results, social previews and the sitemap automatically. You don't need to know HTML to write pages, and if you'd rather not write them yourself, an AI coding assistant like Claude Code or Codex can do it; every vagejs site includes instructions those assistants read on their own.
Step 3: check it before it goes anywhere
This is the step most hosting guides skip, and the one that saves the most embarrassment:
npm run checkIt looks over the whole site and reports broken links, missing titles and descriptions, images without alt text, links to websites you haven't approved, and more, each with the file to fix. It writes nothing, so run it as often as you like. When it reports zero errors, you're ready to publish.
Before your first deploy, also set site in vage.config.ts to your real domain. The sitemap, canonical URLs and social previews all depend on it, and the check reminds you while it's still the placeholder.
Step 4: pick a host
vagejs has one-command publishing for four hosts (Cloudflare Workers, GitHub Pages, Cloudflare Pages and Netlify), and the built folder works on any other.
Cloudflare Workers
Cloudflare now hosts new static sites as Workers, and it's what we use for vagejs.com. Set it once in your config:
// vage.config.ts
deploy: { target: "cloudflare-workers", cloudflareWorker: "my-site" },Then sign in with npx wrangler login and run:
npx vage deployWhat you get:
- No downtime. vagejs uploads a new version and switches traffic to it in one step, so your domain doesn't go offline during a deploy.
- Real redirects. Old addresses listed in
redirectsbecome permanent (301) redirects. - Your own 404 page for addresses that don't exist.
- Security headers, including a Content-Security-Policy worked out from your pages, which tells browsers to refuse scripts you didn't add.
For a custom domain, add a wrangler.jsonc file with your routes. vagejs reads it, shows it in the deploy plan, and refuses to deploy if it points at a different Worker or folder than expected.
GitHub Pages
If your code already lives on GitHub, GitHub Pages is a natural fit. Push your project first:
npx vage deploy:github --remote https://github.com/you/site.gitThat shows you exactly what will be committed and pushed, and waits for a yes. It refuses to commit secret-looking files like .env, and never force-pushes over someone else's work. Then:
npx vage deployThis adds a GitHub Actions workflow that checks, builds and publishes your site, turns on Pages if needed, and waits for GitHub to confirm it worked before saying "deployed".
A repository named anything other than <your-username>.github.io is served from a subfolder, such as https://<your-username>.github.io/my-site/ (GitHub calls these project sites). vagejs supports that since 0.9: set site: "https://<your-username>.github.io/my-site" in vage.config.ts and it adds the subfolder to every link, image and stylesheet in the build. Keep writing links from the site root (/about/) as usual. A custom domain works too, and GitHub's own Pages documentation covers that in detail.
Cloudflare Pages
If you already have a Cloudflare Pages project, set deploy: { target: "cloudflare-pages", cloudflareProject: "my-site" } in vage.config.ts and npx vage deploy publishes to it, and branches other than your main one get their own preview address. For new sites, we recommend Workers.
Netlify
Create the site in Netlify first, then name it in your config:
// vage.config.ts
deploy: { target: "netlify", netlifySite: "my-site" },Sign in with npx netlify-cli login (or set NETLIFY_AUTH_TOKEN) and run npx vage deploy, or skip the config line and use npx vage deploy --target netlify --project my-site. The build writes Netlify's _headers file with the same security headers as on Cloudflare, and a _redirects file with your redirects as permanent (301) redirects. vagejs only reports success when the live site answers.
Anywhere else
npm run build writes your whole site into dist/. Upload that folder to any static host and it works. Vercel is the common example: it has no vagejs deploy command, so set the build command to npm run build and the output folder to dist, and Vercel serves the files.
Step 5: make sure it's really live
"Deployed" should mean visitors can see the site, not just that an upload finished. On Cloudflare and Netlify, vagejs only reports success when the live address actually answers. On GitHub Pages, it waits until GitHub confirms the publish worked.
After that, one more command is worth running:
npx vage verifyIt compares the live site with your project, page by page, and tells you about anything that doesn't match: an extra script, a link you didn't add, a page that shouldn't be there. It also checks that search engines and the main AI assistants can reach your site, and that your http and www addresses forward to one place.
Step 6: tell search engines you exist
A new site won't show up in search results on its own straight away. Two things help:
- Google Search Console. Add your site and submit the sitemap at
/sitemap.xml. vagejs writes it on every build and keeps it in step with your real pages. - IndexNow. Bing and some other search engines accept instant notices about new and changed pages. Add an IndexNow key to your config, then run
npx vage indexnow --changed-since HEAD~1after each deploy. It asks before sending anything.
Neither guarantees indexing or rankings. They just make sure search engines know where to look.
Moving to another host later
Say your free plan changes, or you outgrow it, or you simply prefer another company. With a static site, moving is refreshingly dull. Your pages, layouts and settings don't change at all. You point deploy at a different target in vage.config.ts (or upload dist/ by hand), publish, and then switch your domain's DNS records to the new host.
If any addresses changed along the way, list the old ones under redirects so old links and search results still land on the right page. Then run npx vage verify against the new host to confirm every page matches your files. There's no database to export, no plugins to reinstall and no theme settings to recreate, because none of those exist.
What does it cost in practice?
Here's what a typical small site on this setup needs:
| Item | Cost |
|---|---|
| vagejs | Free, MIT license |
| Hosting on a free static plan | Often nothing, within the host's limits |
| SSL certificate (the padlock) | Included by Cloudflare, GitHub Pages and Netlify |
| Database, server patches, plugin updates | None needed |
| Domain name | Paid yearly to a registrar |
The domain name is usually the only bill. Hosts' plans and prices change, so check the current terms on their sites. Still, for many content sites, the total yearly cost comes down to the price of the domain.
The hidden saving: no upkeep
The monthly bill isn't the only cost of a website. There's also time: updating server software, patching plugins, restoring a backup after something breaks, cleaning up after a break-in.
A static site cuts most of that. There's no server software of yours to update, no database to back up, and no admin login for strangers to guess at. Your content is in text files, and with git every change is saved, so going back to last Tuesday's version is one command. New vagejs sites also get automatic dependency updates through Dependabot and a CI check on every push, so the small amount of upkeep left mostly comes to you as a ready-made pull request.
Ready to publish?
Here's the whole journey in one place:
npm create vagejs@latest my-site # create
cd my-site && npm install
npm run dev # write, with live preview
npm run check # fix anything it finds
npx vage deploy # publish, after you approve the plan
npx vage verify # confirm the live site matchesFrom an empty folder to a fast, checked website on free hosting, without a server to babysit. The deployment guide has every option for each host, and getting started walks you through your first site.