Pages, routing and layouts

Files become URLs

File URL
src/pages/index.md /
src/pages/about.md /about/
src/pages/blog/index.md /blog/
src/pages/blog/launch.md /blog/launch/
src/pages/404.md the not-found page

Files and folders that start with _ are ignored. Two files that would produce the same URL stop the build. Link to pages with a trailing slash (/about/); vage check warns about links that would redirect.

Frontmatter

YAML
---
title: Pricing                 # required
description: Plans and prices. # meta description, Open Graph and llms.txt
draft: true                    # visible in dev, left out of builds
noindex: true                  # published, but kept out of search and the sitemap
canonical: /pricing/           # point search engines at another URL
image: /images/pricing.png     # social preview image
type: article                  # adds Article structured data
author: Your Name              # only real values
datePublished: 2026-10-23
---

Extra keys are allowed, and layouts can read them. This site's home page keeps all of its copy in frontmatter, which makes vagejs its CMS.

Layouts

A layout is a TypeScript file in src/layouts/ that returns HTML:

TypeScript
import { escapeHtml, type Layout } from "vagejs";

const layout: Layout = ({ content, page, site }) => `<!doctype html>
<html lang="${escapeHtml(site.lang)}">
  <head><title>${escapeHtml(page.title)}</title></head>
  <body><main>${content}</main></body>
</html>`;

export default layout;

Pick one with layout: <name> in frontmatter; default is used otherwise. content is already-rendered HTML; escape everything else. vagejs adds the description, canonical URL, Open Graph tags and JSON-LD before </head>, unless your layout already writes them.

HTML in Markdown

HTML inside Markdown is sanitized: scripts, event handlers, javascript: links, iframes and forms are removed. Put embeds in a layout, which is trusted code. If every author is trusted, you can turn this off with markdown: { html: "allow" }.

Start with one command.
You'll have a site running in a minute.

npm create vagejs@latest my-site

Read the docsUse it with your AI assistant