Blog

A blog built with Nuxt Content: one markdown file per post, a validated frontmatter contract, complete SEO metadata, translations and a regression gate.

Nuxfire comes with a blog built with Nuxt Content. Add markdown files to start publishing: the build validates every post and generates its search and social metadata.

What's Included

  • Blog index and post pages, with one <h1> per post
  • Site-wide search integration
  • Complete SEO per post: title, description, canonical, Open Graph and Twitter tags, BlogPosting structured data, language, hreflang and sitemap lastmod
  • Posts in several languages, linked as translations of each other
  • A bun run check:seo gate that catches regressions
  • Responsive design and dark mode support

File Structure

Blog posts live in apps/web/content/blog, as their own Nuxt Content collection (apps/web/content.config.ts). Each post is one markdown file whose frontmatter is validated at build time:

---
title: "Specific title without the brand"
description: "One or two sentences that describe this post."
date: "2026-09-25"
author: "Your Name"
lang: en
ogImage: "/images/blog/my-cover.png"
---

Frontmatter

FieldRequiredMeaning
titleYesThe page title and the single <h1>. The brand is appended for you: do not write it.
descriptionYesSearch and social description of this post, never the site default.
dateYesYYYY-MM-DD or an ISO 8601 datetime with a timezone. A date-only value means midnight UTC.
updatedNoSame format, not before date. Feeds article:modified_time and the sitemap lastmod.
authorYesThe author name shown on the page and in the structured data.
authorTypeNoPerson or Organization (default Organization).
langYesen, pt-br or es. It has no default: it sets <html lang>, og:locale and hreflang.
translationsYesLanguage to slug of every version of the post, itself included: one for each of en, pt-br and es.
categoryNoShown on the card and used as article:section.
readTimeNoShown on the card, for example 8 min.
tagsNoUsed as article:tag and as keywords in the structured data.
imageNoThe cover shown on the post page. It can be an SVG.
ogImageNoThe image social networks read: a .png or .jpg path under apps/web/public. Falls back to the default site image.

Translations

Every post is written in all three languages, one file per language. Link the versions by repeating the same translations block in every one of them, with a key for each language; each key is the language of the post it points to:

translations:
  en: my-post-english-slug
  pt-br: my-post-portuguese-slug
  es: my-post-spanish-slug

The blog index shows each post once, in the language the visitor is browsing in (English when that language has no version), and a post that was never translated stays visible in its own language. The head and the sitemap list every version reciprocally, with x-default pointing to the English one. bun run check:seo fails if a version is missing, is written in another language or does not point back, and it rejects a post that does not list all three languages. Give each version its own cover when the image contains text.

Cover images

Design the cover as a 16:9 SVG in apps/web/public/images/blog, then render the PNG that social networks read. Facebook's sharing documentation lists JPEG, GIF and PNG for og:image; SVG is not among them.

bun run generate:og

The command writes a 1200x675 PNG next to every SVG cover and next to the default site image (apps/web/public/images/og/default.svg), and running it twice changes nothing. It runs on your machine with sharp, so open each PNG and commit it.

Check Before You Publish

Build the site with its real address and run the gate against the generated pages:

SITE_URL=https://your-domain bun run --cwd apps/web build
bun run check:seo
  • Every post has a language, valid dates, a raster ogImage that exists, and a consistent set of translations.
  • Every page has its own title and description, one <h1>, an absolute canonical, a social image and, for posts, BlogPosting structured data in the right language.
  • The sitemap lists every post with lastmod and the same hreflang as the page head, and lists nothing that asks not to be indexed.

Without a build, the command still lints the frontmatter of every post and says that the page audit was skipped. To write posts with an AI agent, load the content specialist described in Nuxfire Stack Specialists.

Nuxfire Production Kit

Ready to build and launch your SaaS?

Get 100% full source code ownership, zero proprietary wrappers, and architecture engineered for millions of requests on Cloudflare.

© 2026 Nuxfire