Nextra
"Nextra documentation framework: MDX-powered Next.js docs and blog sites, sidebar navigation, full-text search, i18n, themes (docs and blog), frontmatter configuration, and custom components."
Nextra is an opinionated Next.js framework for content-heavy sites — primarily documentation and blogs. It eliminates boilerplate by mapping the filesystem to navigation, compiling MDX automatically, and providing built-in search, syntax highlighting, and dark mode. You write MDX files, organize them in directories, and Nextra generates a fully navigable documentation site with table of contents, breadcrumbs, and pagination. The framework offers two official themes (`nextra-theme-docs` and `nextra-theme-blog`) that handle layout, styling, and interactive features. Customization happens through `theme.config.tsx` and MDX component overrides rather than building from scratch. ## Key Points - Organize `_meta.json` to control sidebar order and titles explicitly — do not rely on filesystem alphabetical ordering for user-facing navigation. - Use Nextra's built-in `<Callout>`, `<Steps>`, `<Tabs>`, and `<Cards>` components before building custom ones; they handle dark mode, accessibility, and responsive design. - Set `docsRepositoryBase` to enable "Edit this page" links, lowering the barrier for community contributions. - Use frontmatter `searchable: false` for pages that should not appear in search results (changelogs, legal pages). - Keep `_meta.json` files in every directory — without them, pages appear in alphabetical order with raw filenames as titles. - Enable `defaultShowCopyCode` in the Nextra config so all code blocks get copy buttons without per-block annotation. - Use the `filename` attribute on code blocks to show which file the code belongs to. - Deploy on Vercel for zero-config static export, or use `next export` for hosting on any static file server. - **Nesting pages too deeply**: More than 3 levels of nesting makes navigation unwieldy. Flatten the structure and use categories in `_meta.json` instead. - **Skipping `_meta.json`**: Without it, the sidebar shows raw filenames in alphabetical order. Always define display titles and ordering. - **Using the Pages Router for new projects and expecting App Router features**: Nextra v2 uses Pages Router. If you need App Router features, wait for Nextra v3 or consider fumadocs. - **Overloading theme.config.tsx with business logic**: Keep it declarative. Complex logic should live in separate components or hooks, not inline in the config object. ## Quick Example ```bash npm install nextra nextra-theme-docs ``` ``` </Tab> <Tab> ```
skilldb get seo-content-skills/NextraFull skill: 387 linesNextra — Next.js Documentation Framework
Core Philosophy
Nextra is an opinionated Next.js framework for content-heavy sites — primarily documentation and blogs. It eliminates boilerplate by mapping the filesystem to navigation, compiling MDX automatically, and providing built-in search, syntax highlighting, and dark mode. You write MDX files, organize them in directories, and Nextra generates a fully navigable documentation site with table of contents, breadcrumbs, and pagination. The framework offers two official themes (nextra-theme-docs and nextra-theme-blog) that handle layout, styling, and interactive features. Customization happens through theme.config.tsx and MDX component overrides rather than building from scratch.
Setup
Docs Theme
npm install nextra nextra-theme-docs
// next.config.mjs
import nextra from "nextra";
const withNextra = nextra({
theme: "nextra-theme-docs",
themeConfig: "./theme.config.tsx",
defaultShowCopyCode: true,
latex: true,
search: {
codeblocks: false,
},
});
export default withNextra({
reactStrictMode: true,
});
// theme.config.tsx
import type { DocsThemeConfig } from "nextra-theme-docs";
import { useConfig } from "nextra-theme-docs";
import { useRouter } from "next/router";
const config: DocsThemeConfig = {
logo: <span className="font-bold text-xl">My Docs</span>,
project: {
link: "https://github.com/org/repo",
},
docsRepositoryBase: "https://github.com/org/repo/tree/main/docs",
useNextSeoProps() {
const { asPath } = useRouter();
if (asPath !== "/") {
return { titleTemplate: "%s – My Docs" };
}
return { title: "My Docs" };
},
head: function Head() {
const { frontMatter, title } = useConfig();
return (
<>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta
property="og:title"
content={frontMatter.title || title}
/>
<meta
property="og:description"
content={
frontMatter.description || "Documentation for My Project"
}
/>
</>
);
},
sidebar: {
defaultMenuCollapseLevel: 1,
toggleButton: true,
autoCollapse: true,
},
toc: {
backToTop: true,
float: true,
},
footer: {
text: (
<span>
{new Date().getFullYear()} My Project. Built with Nextra.
</span>
),
},
editLink: {
text: "Edit this page on GitHub",
},
feedback: {
content: "Question? Give us feedback →",
labels: "feedback",
},
navigation: {
prev: true,
next: true,
},
};
export default config;
Project Structure
docs/
├── pages/
│ ├── _meta.json
│ ├── index.mdx
│ ├── getting-started/
│ │ ├── _meta.json
│ │ ├── installation.mdx
│ │ └── configuration.mdx
│ ├── guides/
│ │ ├── _meta.json
│ │ ├── basics.mdx
│ │ └── advanced.mdx
│ └── api-reference/
│ ├── _meta.json
│ └── endpoints.mdx
├── theme.config.tsx
├── next.config.mjs
└── package.json
Key Techniques
Sidebar Navigation with _meta.json
// pages/_meta.json
{
"index": {
"title": "Introduction",
"theme": {
"layout": "full"
}
},
"getting-started": {
"title": "Getting Started",
"type": "menu"
},
"guides": "Guides",
"api-reference": "API Reference",
"---": {
"type": "separator"
},
"changelog": {
"title": "Changelog",
"href": "/changelog",
"newWindow": false
},
"github": {
"title": "GitHub",
"href": "https://github.com/org/repo",
"newWindow": true
}
}
// pages/getting-started/_meta.json
{
"installation": "Installation",
"configuration": "Configuration",
"quick-start": {
"title": "Quick Start",
"display": "hidden"
}
}
MDX Frontmatter and Page Options
---
title: Installation Guide
description: How to install and set up the project
searchable: true
---
import { Callout, Steps, Tabs, Tab } from 'nextra/components'
# Installation
<Steps>
### Step 1: Install dependencies
<Tabs items={['npm', 'pnpm', 'yarn']}>
<Tab>
```bash
npm install my-library
```
</Tab>
<Tab>
```bash
pnpm add my-library
```
</Tab>
<Tab>
```bash
yarn add my-library
```
</Tab>
</Tabs>
### Step 2: Configure
Create a config file in your project root:
```typescript filename="my-library.config.ts" {3-5} copy
export default {
// highlight-start
output: './dist',
format: 'esm',
target: 'es2022',
// highlight-end
}
Step 3: Verify
<Callout type="info"> Run `npx my-library doctor` to verify your setup. </Callout> </Steps> ```Internationalization (i18n)
// next.config.mjs
import nextra from "nextra";
const withNextra = nextra({
theme: "nextra-theme-docs",
themeConfig: "./theme.config.tsx",
});
export default withNextra({
i18n: {
locales: ["en", "es", "ja"],
defaultLocale: "en",
},
});
// theme.config.tsx — i18n config
const config: DocsThemeConfig = {
i18n: [
{ locale: "en", text: "English" },
{ locale: "es", text: "Español" },
{ locale: "ja", text: "日本語" },
],
// ...
};
pages/
├── getting-started.en.mdx
├── getting-started.es.mdx
└── getting-started.ja.mdx
Custom Components
// components/api-table.tsx
import React from "react";
interface ApiProp {
name: string;
type: string;
default?: string;
description: string;
required?: boolean;
}
export function ApiTable({ props }: { props: ApiProp[] }) {
return (
<div className="overflow-x-auto my-6">
<table className="w-full text-sm">
<thead>
<tr className="border-b border-gray-200 dark:border-gray-700">
<th className="text-left py-2 pr-4">Prop</th>
<th className="text-left py-2 pr-4">Type</th>
<th className="text-left py-2 pr-4">Default</th>
<th className="text-left py-2">Description</th>
</tr>
</thead>
<tbody>
{props.map((prop) => (
<tr
key={prop.name}
className="border-b border-gray-100 dark:border-gray-800"
>
<td className="py-2 pr-4 font-mono text-xs">
{prop.name}
{prop.required && (
<span className="text-red-500 ml-1">*</span>
)}
</td>
<td className="py-2 pr-4 font-mono text-xs text-purple-600 dark:text-purple-400">
{prop.type}
</td>
<td className="py-2 pr-4 font-mono text-xs text-gray-500">
{prop.default ?? "—"}
</td>
<td className="py-2 text-gray-700 dark:text-gray-300">
{prop.description}
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
Blog Theme
npm install nextra nextra-theme-blog
// next.config.mjs
import nextra from "nextra";
const withNextra = nextra({
theme: "nextra-theme-blog",
themeConfig: "./theme.config.tsx",
});
export default withNextra({});
// theme.config.tsx
const config = {
head: ({ title, meta }: { title: string; meta: Record<string, string> }) => (
<>
<meta name="author" content="Author Name" />
{meta.description && (
<meta name="description" content={meta.description} />
)}
{meta.tag && <meta name="keywords" content={meta.tag} />}
</>
),
footer: <small>CC BY-NC 4.0 {new Date().getFullYear()} Author Name</small>,
readMore: "Read More →",
darkMode: true,
};
export default config;
Best Practices
- Organize
_meta.jsonto control sidebar order and titles explicitly — do not rely on filesystem alphabetical ordering for user-facing navigation. - Use Nextra's built-in
<Callout>,<Steps>,<Tabs>, and<Cards>components before building custom ones; they handle dark mode, accessibility, and responsive design. - Set
docsRepositoryBaseto enable "Edit this page" links, lowering the barrier for community contributions. - Use frontmatter
searchable: falsefor pages that should not appear in search results (changelogs, legal pages). - Keep
_meta.jsonfiles in every directory — without them, pages appear in alphabetical order with raw filenames as titles. - Enable
defaultShowCopyCodein the Nextra config so all code blocks get copy buttons without per-block annotation. - Use the
filenameattribute on code blocks to show which file the code belongs to. - Deploy on Vercel for zero-config static export, or use
next exportfor hosting on any static file server.
Anti-Patterns
- Fighting the conventions: Nextra is opinionated by design. Trying to override the layout system extensively often results in fragile CSS hacks. If you need full layout control, use raw Next.js with MDX instead.
- Nesting pages too deeply: More than 3 levels of nesting makes navigation unwieldy. Flatten the structure and use categories in
_meta.jsoninstead. - Skipping
_meta.json: Without it, the sidebar shows raw filenames in alphabetical order. Always define display titles and ordering. - Using the Pages Router for new projects and expecting App Router features: Nextra v2 uses Pages Router. If you need App Router features, wait for Nextra v3 or consider fumadocs.
- Overloading theme.config.tsx with business logic: Keep it declarative. Complex logic should live in separate components or hooks, not inline in the config object.
- Ignoring built-in search: Nextra includes FlexSearch-based full-text search. Installing Algolia or another search provider without disabling the built-in one creates duplicate search experiences.
- Not testing i18n fallbacks: If a translated page is missing, Nextra falls back to the default locale. Ensure fallback content makes sense and does not confuse users.
- Large images in MDX files: Nextra does not automatically optimize images. Use
next/imagevia a custom component or pre-optimize images before committing.
Install this skill directly: skilldb add seo-content-skills
Related Skills
Contentlayer
"Contentlayer and Velite for type-safe content management: transforming Markdown/MDX into typed data, schema validation, computed fields, Next.js integration, hot reload, and migration between content tools."
Core Web Vitals
Core Web Vitals optimization: LCP, INP, and CLS measurement, diagnosis, and improvement strategies for better search rankings and user experience.
Fumadocs
"fumadocs documentation framework: Next.js App Router native, MDX content collections, full-text search, OpenAPI integration, TypeScript-first, customizable UI components, and content source adapters."
Mdx
"MDX authoring with Next.js: Markdown + JSX, custom components, frontmatter extraction, @next/mdx, mdx-bundler, contentlayer integration, rehype/remark plugins, and syntax highlighting with Shiki or Prism."
Next SEO
"Next.js SEO and metadata management: meta tags, Open Graph, Twitter cards, JSON-LD structured data, canonical URLs, robots directives, and sitemap generation using the Metadata API and next-seo."
Programmatic SEO
Programmatic SEO strategies: generating thousands of search-optimized pages from structured data, template design, internal linking, and indexing at scale.