Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/shuding/nextra/llms.txt

Use this file to discover all available pages before exploring further.

The Nextra Blog Theme turns any Next.js + MDX project into a fully-featured blog. It provides a ready-made <Layout>, <Navbar>, and <Footer>, auto-generates a post listing from your MDX files, supports tag filtering, computes reading-time estimates, and ships with dark mode out of the box. Posts are written as plain MDX files with YAML frontmatter — no database or CMS required.
A live demo is available at demo.vercel.blog. The full source code for that demo lives in the examples/blog directory of the Nextra repository.

What You Get

  • Post listing page built automatically from all MDX files in your posts directory
  • Tag pages that filter posts by topic
  • RSS feed generation helpers
  • Reading-time estimates calculated from post content
  • Dark mode and a <ThemeSwitch> component
  • Comments support via the <Comments> component
  • Custom MDX components — override any element (headings, dates, code blocks) per-site

Manual Setup

1
Install dependencies
2
Create a new directory and install Next.js, React, Nextra, and Nextra Blog Theme:
3
npm
npm install next react react-dom nextra nextra-theme-blog
yarn
yarn add next react react-dom nextra nextra-theme-blog
pnpm
pnpm add next react react-dom nextra nextra-theme-blog
bun
bun add next react react-dom nextra nextra-theme-blog
4
If you already have a Next.js project, only add nextra and nextra-theme-blog.
5
Configure the Nextra plugin
6
Create next.config.mjs at the project root:
7
import nextra from 'nextra'

const withNextra = nextra({
  // Show copy-code buttons on all code blocks by default
  defaultShowCopyCode: true,
  // Compute reading time for every post
  readingTime: true,
})

export default withNextra({
  reactStrictMode: true,
})
8
Setting readingTime: true makes Nextra inject a readingTime object into every MDX page’s metadata, which the blog theme surfaces automatically in post cards and post headers.
9
Create the root layout
10
Create app/layout.jsx (or app/layout.tsx). The blog theme exposes <Layout>, <Navbar>, <Footer>, and <ThemeSwitch> from nextra-theme-blog, plus <Banner>, <Head>, and <Search> from nextra/components:
11
import { Footer, Layout, Navbar, ThemeSwitch } from 'nextra-theme-blog'
import { Banner, Head, Search } from 'nextra/components'
import { getPageMap } from 'nextra/page-map'
import 'nextra-theme-blog/style.css'

export const metadata = {
  title: 'My Blog',
}

export default async function RootLayout({ children }) {
  const banner = (
    <Banner storageKey="v1-launch">
      🎉 Welcome to my new blog!{' '}
      <a href="/posts/hello-world" style={{ textDecoration: 'underline' }}>
        Read the first post →
      </a>
    </Banner>
  )

  return (
    <html lang="en" suppressHydrationWarning>
      <Head backgroundColor={{ dark: '#0f172a', light: '#fefce8' }} />
      <body>
        <Layout banner={banner}>
          <Navbar pageMap={await getPageMap()}>
            <Search />
            <ThemeSwitch />
          </Navbar>

          {children}

          <Footer>
            {new Date().getFullYear()} © My Blog.{' '}
            <a href="/rss.xml" style={{ float: 'right' }}>
              RSS
            </a>
          </Footer>
        </Layout>
      </body>
    </html>
  )
}
12
Pass a backgroundColor object to <Head> to set the browser UI color in supported mobile browsers — separately for dark and light mode.
13
Create the MDX components file
14
The blog theme exports a useMDXComponents helper that registers its built-in overrides. Merge them with any custom components you want:
15
import { useMDXComponents as getBlogMDXComponents } from 'nextra-theme-blog'

const blogComponents = getBlogMDXComponents({
  // Override individual HTML elements or add custom ones:
  h1: ({ children }) => (
    <h1 style={{ color: 'hotpink' }}>{children}</h1>
  ),
  // Customise how post dates are rendered:
  DateFormatter: ({ date }) =>
    date.toLocaleDateString('en', {
      day: 'numeric',
      month: 'long',
      year: 'numeric',
    }),
})

export function useMDXComponents(components) {
  return {
    ...blogComponents,
    ...components,
  }
}
16
Write your first post
17
Posts are MDX files with YAML frontmatter. Create the posts directory and add a page:
18
---
title: Hello, World!
date: 2024-01-15
description: My very first post on this Nextra-powered blog.
author: Your Name
tags: [announcement, meta]
---

Welcome to my blog! This is the first post. Nextra reads the frontmatter
above and uses it to build the post listing, tag pages, and RSS feed.
19
All frontmatter fields map directly to the BlogMetadata type:
20
FieldTypeDescriptiontitlestringPost title, shown in listings and the <h1>datestring (ISO 8601)Publication date, used for sortingdescriptionstringShort summary shown in post cardsauthorstringAuthor name displayed on the posttagsstring[]Topic tags; generates /tags/<tag> pagesreadingTimeReadingTimeAuto-injected by Nextra when readingTime: true
21
Start the development server
22
npm
npm run dev
yarn
yarn dev
pnpm
pnpm dev
bun
bun dev
23
Visit http://localhost:3000 to see your blog home page, and http://localhost:3000/posts/hello-world to read your first post.

Post Frontmatter Fields

Nextra’s blog theme reads the following fields from each MDX page’s YAML frontmatter. All fields are optional, but title and date are strongly recommended so the post listing sorts and renders correctly.
type BlogMetadata = {
  author?: string        // Author name
  date?: string          // ISO 8601 date string, e.g. "2024-01-15"
  description?: string   // Short summary for post cards and SEO
  readingTime?: ReadingTime // Auto-injected when readingTime: true in config
  tags?: string[]        // Array of tag strings
  title?: string         // Post title
}
The readingTime field is injected automatically by Nextra when you set readingTime: true in next.config.mjs. You do not need to add it manually to your frontmatter.

Content Directory Structure

A typical Nextra blog project looks like this:
my-blog/
├── app/
│   ├── layout.jsx              # Root layout with <Layout>, <Navbar>, <Footer>
│   ├── page.mdx                # Blog home / post index
│   ├── posts/
│   │   ├── hello-world/
│   │   │   └── page.mdx        # A post at /posts/hello-world
│   │   └── getting-started/
│   │       └── page.mdx        # A post at /posts/getting-started
│   ├── tags/
│   │   └── [tag]/
│   │       └── page.jsx        # Tag filter page at /tags/<tag>
│   └── rss.xml/
│       └── route.js            # RSS feed at /rss.xml
├── mdx-components.jsx          # MDX component overrides
├── next.config.mjs             # Nextra plugin config
└── package.json
Nest each post inside its own subdirectory (posts/my-post/page.mdx) instead of using a flat file (posts/my-post.mdx). This lets you co-locate images and assets alongside the post without polluting the root posts directory.

Exported Components

The nextra-theme-blog package exports the following components for use in your layout and pages:
ExportDescription
LayoutRoot wrapper; accepts banner prop
NavbarTop navigation bar; accepts pageMap and child components
FooterBottom footer bar
ThemeSwitchDark/light/system mode toggle button
ExportDescription
PostCardCard component for rendering post previews in a listing
CommentsComment section component for individual post pages
ExportDescription
useMDXComponentsReturns the theme’s default MDX element map; accepts overrides
useThemeRe-exported from next-themes; returns the active theme and setter

Next Steps

Docs Theme

Switch to the docs theme for a full sidebar, TOC, and search experience.

Custom Theme

Roll your own layout component with complete control over the UI.

Blog Example Source

Browse the full example source code on GitHub.

Live Blog Demo

See the blog theme running live on Vercel.

Build docs developers (and LLMs) love