Skip to content

Metadata and SEO

Titles, descriptions, Open Graph images, sitemaps, and per-page head control.

AI-generated · awaiting reviewUpdated

Nimbus handles the metadata baseline automatically and gives you per-page and site-wide control where you need it.

Titles and descriptions

title and description frontmatter populate <title> and <meta name="description">, and feed the search snippet and llms.txt indexes. Site-wide fallbacks come from the Nimbus config:

astro.config.tsts
const nimbusConfig = defineNimbusConfig({
  site: "https://docs.example.com",
  title: "Acme",
  description: "Build with Acme.",
});

Open Graph images

Set a site-wide fallback card and alt text, then override per page:

astro.config.tsts
const nimbusConfig = defineNimbusConfig({
  // …
  socialImage: "/og.png",
  socialImageAlt: "Acme documentation",
});
---
title: Pricing
socialImage: /og/pricing.png
---

Nimbus also ships an OG image route, so pages without an explicit image get a generated card: the site’s logo, the page’s section and its title. See Customize OG cards.

A docs page uses its frontmatter socialImage, or else its generated card, /og/<page>.png.

Other pages, such as the 404 page and hand-written routes, use the first that exists: config.socialImage, public/opengraph.png or public/logo.png, then the generated /og.png card.

Image paths are logical paths without Astro’s deployment base. For a site deployed at /docs, keep socialImage: "/og.png"; Nimbus produces /docs/og.png. Absolute and protocol-relative image URLs are preserved.

Image sizes

og:image:width and og:image:height are written only when the size is known, so a link preview is never cropped to the wrong shape:

  • Generated cards (/og.png and /og/<page>.png) are 1200 × 630.
  • config.socialImage, the auto-detected public/opengraph.png or public/logo.png, and every image under public/og/ are measured at build time.
  • Any other image, such as a remote URL or a per-page file elsewhere in public/, gets no size tags. Pass the size where you know it, as socialImageSize on NimbusHead or on the starter’s BaseLayout:
<NimbusHead title={title} socialImage="/diagrams/cover.png" socialImageSize={{ width: 1600, height: 900 }} />

Sitemap and robots

When site is set, the sitemap integration and /robots.txt are wired automatically. Disable the sitemap with sitemap: false in the integration options.

The sitemap is written as sitemap-index.xml plus sitemap-0.xml, and /sitemap.xml is a copy of the index for tools that only try that name. A site that serves its own /sitemap.xml, as a file in public/, a sitemap.xml route, or a dynamic [name].xml route at the root, keeps it.

A docs page’s <lastmod> is its frontmatter lastUpdated, or else the date of the last commit to its file, matching its “Last updated” line. Pages with no content file, such as API pages, have none.

A serialize option in sitemap runs afterwards, so it can change or drop the value.

Git dates need the repository’s history. On a shallow clone, which most CI systems make by default, the build says so once and leaves out every git date: the sitemap’s lastmod and the “Last updated” line on pages. Fetch the full history to restore them, with fetch-depth: 0 in GitHub Actions or git fetch --unshallow.

Per-page and site-wide head

Add elements to <head> site-wide via config.head, or per page via frontmatter — the two are merged:

---
title: Analytics-tracked page
head:
  - tag: meta
    attrs: { name: "robots", content: "noindex" }
  - tag: link
    attrs: { rel: "canonical", href: "https://example.com/canonical" }
---

Valid tags: meta, link, script, style, title, noscript, base. To exclude a page from crawlers without hand-writing the tag, use noindex: true.

Canonical URLs

On versioned sites, Nimbus emits <link rel="canonical"> pointing older versions at the current one, plus <link rel="alternate"> between siblings — driven by previousSlug.

Type to search…

↑↓ navigate↵ selectEsc close