A technical SEO checklist your website handles for you

Technical SEO is the plumbing of search: the details that let search engines and AI tools find your pages, understand them and show them properly. It's not glamorous, and most of it is easy to get wrong without noticing. Here's a checklist of what matters, in plain English, and how vagejs takes care of each item on every build.

On this page
  1. What is technical SEO, and what isn't it?
  2. 1. Every page has a unique title
  3. 2. Every page has a useful description
  4. 3. Each page has one real address (canonical URL)
  5. 4. A sitemap that matches reality
  6. 5. A sensible robots.txt
  7. 6. Pages you don't want indexed say so
  8. 7. Structured data that tells the truth
  9. 8. Good-looking social previews
  10. 9. No broken links
  11. 10. Images with alt text and fixed sizes
  12. 11. Fast pages
  13. 12. Files for AI tools: llms.txt and Markdown copies
  14. 13. An RSS feed for your blog
  15. 14. Telling search engines when things change
  16. 15. Check the live site, not just your files
  17. The checklist at a glance
  18. 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:

TypeScript
// 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.

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:

TypeScript
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~1 sends 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 gsc and vage report search bring 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.

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