On this page
- What is technical SEO, and what isn't it?
- 1. Every page has a unique title
- 2. Every page has a useful description
- 3. Each page has one real address (canonical URL)
- 4. A sitemap that matches reality
- 5. A sensible robots.txt
- 6. Pages you don't want indexed say so
- 7. Structured data that tells the truth
- 8. Good-looking social previews
- 9. No broken links
- 10. Images with alt text and fixed sizes
- 11. Fast pages
- 12. Files for AI tools: llms.txt and Markdown copies
- 13. An RSS feed for your blog
- 14. Telling search engines when things change
- 15. Check the live site, not just your files
- The checklist at a glance
- Get the plumbing right, then write
What is technical SEO, and what isn't it?
Search engine optimization has roughly three parts:
- Content: pages that answer a real question well.
- Authority: other sites linking to you and mentioning you.
- Technical: everything that makes your pages easy to crawl, understand and display.
The technical part doesn't make a page worth ranking. It removes the reasons a good page might be missed, misread or shown badly. Think of it as making sure your shop has a sign, a working door and an accurate address. You still need something worth buying inside.
The good news is that technical SEO is mostly rules, and rules are what software is good at. Here's the list.
1. Every page has a unique title
The title is the blue link people click in search results and the label on their browser tab. Each page needs one, it should describe that page specifically, and no two pages should share it. When two pages have the same title, search engines have a harder time telling which one fits a search.
How vagejs handles it: title is required in every page's frontmatter, the short block of settings at the top of a Markdown file. vagejs writes it into the page's <title> tag, and vage check reports any page that's missing one or repeats another page's title.
2. Every page has a useful description
The meta description is the short summary that often appears under your title in search results. Search engines don't always use it, but when they do, a clear one helps people decide to click. Like titles, descriptions should be written for each page, not copied.
How vagejs handles it: add description to the frontmatter, and vagejs uses it in three places at once: the meta description, the summary for social previews, and the page's entry in llms.txt. The check warns when it's missing and flags duplicates across pages.
---
title: Pricing
description: Simple plans for teams of every size, with no setup fees.
---3. Each page has one real address (canonical URL)
The same page can often be reached at several addresses: with or without www, with or without a trailing slash, with tracking codes on the end. A canonical URL tells search engines which address is the real one, so your page's signals aren't split across copies.
How vagejs handles it: every indexable page gets an absolute canonical URL built from your site setting in vage.config.ts. If you need to point a page somewhere else, set canonical: in its frontmatter, and vagejs takes that page out of the sitemap so the two signals don't contradict each other. The check reports canonicals that are relative or point to another website, which are common mistakes.
Once your site is live, vage verify also checks that your http and www addresses forward to one place, so visitors and crawlers all land on the same version.
4. A sitemap that matches reality
A sitemap is a list of the pages you'd like search engines to know about. Its biggest problem on many sites is drift: pages get deleted or hidden but stay in the sitemap, or new pages never get added.
How vagejs handles it: sitemap.xml is written fresh on every build from the pages that really exist. Drafts, pages marked noindex: true and pages with a canonical pointing elsewhere are left out. With seo.lastmod: "git", the date each page last changed comes from its last commit in git, so the "last modified" dates are real instead of all set to the build day.
Submit the sitemap once in Google Search Console. vagejs keeps it accurate from then on.
5. A sensible robots.txt
robots.txt is a small file that tells crawlers which parts of your site they may visit. A single wrong line, like a leftover Disallow: / from a test site, can hide an entire site from search.
How vagejs handles it: robots.txt is generated from your config, never hand-written. By default it allows every crawler and points to your sitemap. In fact, a hand-written robots.txt in public/ is a build error, so a stale one can't sneak back in.
If you want different rules for AI companies, you can set them separately for crawlers that collect training data and crawlers that power AI search answers:
// vage.config.ts
seo: {
robots: { aiTraining: "disallow", aiSearch: "allow" },
},The crawler names come from each company's own documentation, and npx vage guidelines shows the source for each. Remember that robots.txt is a polite request that well-behaved crawlers follow, not a lock.
6. Pages you don't want indexed say so
Thank-you pages, internal notes and test pages usually shouldn't appear in search results. The standard way to say that is a robots meta tag with noindex.
How vagejs handles it: add noindex: true to a page's frontmatter. The page stays published and reachable by link, but gets the tag and leaves the sitemap and llms.txt. If you don't want the page published at all, use draft: true instead, and the check will flag any link that still points to it.
7. Structured data that tells the truth
Structured data, usually written as JSON-LD, describes a page in a format search engines read directly: "this is an article, written by this person, published on this date". It can help a page appear with richer details in results. It can also hurt if it claims things the page doesn't show.
How vagejs handles it: the home page gets WebSite data, and any page with type: article gets Article data, filled in from the same frontmatter that's visible on the page: title, description, author, dates and image. Organization data is opt-in, because only you know your organization's real details. The check reports structured data that's invalid or is missing fields Google recommends for articles. You can see the full list in SEO and AI search.
8. Good-looking social previews
When someone shares your link on a chat app or social network, the preview card comes from Open Graph tags: a title, a description, an image and the page's address. Without them, you get a bare link or a random image from the page.
How vagejs handles it: Open Graph tags are written from your frontmatter automatically. Add image: to a page and it also gets a large-image twitter:card. If your layout already writes any of these tags, vagejs leaves yours alone.
9. No broken links
Broken links waste crawlers' time and frustrate readers. They creep in whenever a page is renamed, deleted or mistyped, and they're tedious to find by hand.
How vagejs handles it: vage check follows every internal link on every page and reports links to pages that don't exist, links to unpublished drafts, links missing their trailing slash (which would redirect), and missing images or files. Every deploy runs the check first and stops on errors, so a broken link can't reach your live site by accident.
When you rename a page, add the old address to redirects in vage.config.ts. On Cloudflare those become real permanent (301) redirects, and the check fails on any redirect that points to a page that doesn't exist.
10. Images with alt text and fixed sizes
Alt text describes an image for people using screen readers and for search engines, which can't see pictures the way we do. Fixed image sizes stop the page from jumping as pictures load, which Google measures as layout shift.
How vagejs handles it: the check flags images without alt text. Width and height are filled in from each image file, and images further down the page load only when needed. With images: { optimize: true }, vagejs also makes smaller WebP copies for phones.
11. Fast pages
Page speed is part of how Google judges page experience, and it affects whether people stay. We've written a whole post on why a website with zero JavaScript loads faster, so here's the short version: vagejs pages ship no JavaScript by default, and vage audit checks every page against size budgets you control.
12. Files for AI tools: llms.txt and Markdown copies
AI assistants increasingly answer questions by reading websites. Two newer conventions try to make that easier.
llms.txt is a short, plain-text guide to your site for AI tools: its name, a summary, and a list of pages with their descriptions. vagejs writes it on every build from the same page list as the sitemap. Turn on seo.llmsTxt: { full: true } to also publish llms-full.txt with the full text of each listed page.
With seo.markdownCopies: true, vagejs also publishes a clean Markdown version of each page, linked from the page itself, and points llms.txt at those copies. Private HTML comments are left out.
To be clear about expectations: llms.txt is a proposed convention, not a search-engine standard. Some AI tools read it, and it costs nothing to publish, but it won't change your Google rankings, and no tool can guarantee an AI assistant will mention you.
13. An RSS feed for your blog
Feeds aren't a ranking factor, but they help readers and other tools follow your updates. In vagejs it's one line:
seo: { feeds: [{ under: "/blog/" }] },That writes /blog/feed.xml and links it from your blog pages.
14. Telling search engines when things change
After you publish, search engines still need to notice. Two things help:
- IndexNow: a shared protocol that Bing and some other search engines use to hear about new and changed pages.
npx vage indexnow --changed-since HEAD~1sends the pages that changed in your last commit, after asking you first. - Google Search Console: Google doesn't use IndexNow, so add your sitemap there. Then
vage connect gscandvage report searchbring your clicks and search terms into the terminal.
Both are hints. Neither guarantees a page will be crawled or indexed.
15. Check the live site, not just your files
Everything above is checked before you publish. But a live site can change after you deploy: a host can inject scripts, or an attacker can add pages. npx vage verify compares the live site with your project, including how pages look when fetched as Googlebot, and checks that Google, Bing and the main AI assistants can reach your site at all.
The checklist at a glance
| Item | What vagejs does |
|---|---|
| Unique titles and descriptions | Written from frontmatter; missing or duplicate ones are flagged |
| Canonical URLs | Absolute by default; bad ones are flagged |
| Sitemap and robots.txt | Generated on every build from real pages |
| noindex and drafts | One frontmatter line each |
| Structured data | WebSite and Article from visible facts; checked |
| Social previews | Open Graph and Twitter card tags |
| Broken links and redirects | Checked before every deploy |
| Image alt text and sizes | Flagged and filled in |
| Speed | 0 KB JavaScript by default, size budgets |
| AI files | llms.txt, Markdown copies |
| Change notifications | IndexNow and Search Console reports |
Get the plumbing right, then write
None of this replaces pages worth reading. Search engines and AI assistants still reward content that answers a real question clearly, shows who wrote it and stays up to date. What vagejs does is make the technical side something you never have to think about, so your time goes into the words.
Start a site with npm create vagejs@latest my-site (Node.js 22.12 or newer), or read SEO and AI search for every setting mentioned here.