Nextra 2 – Next.js Static Site Generator
Tags: nextra, nextjs, react
Published: 2023-01-23 23:58:03

> This article was published on Tuesday, January 24, 2023 by [Dimitri POSTOLOV](https://github.com/dimaMachina) @ [The Guild Blog](https://the-guild.dev/)

## What's Nextra

[Nextra](https://nextra.site) – Next.js Static Site Generator framework that works on top of Next.js
and React, uses Tailwind CSS and
[other amazing open-source libraries](https://nextra.site/about#credits). It lets you create your
powerful markdown content using a `theme` package.

Currently, Nextra contains two official themes:

*   [`nextra-theme-docs`](https://nextra.site/docs/docs-theme/start) theme for documentation
*   [`nextra-theme-blog`](https://nextra.site/docs/blog-theme/start) theme for your simple blog

But you can provide your own theme to fully customize to your needs.

## What's New

### MDX 2 Support

Migration to [MDX 2](https://mdxjs.com/blog/v2) comes with improved performance, supporting any JSX
runtime and JavaScript expression inside your markdown pages.

```mdx filename="Markdown"
import Hero from '@/components/hero'

<Hero />

Current year - {new Date().getFullYear()}
```

#### Markdown Import

In case of reusing some duplicated content you can export and import your markdown files.

```mdx filename="task-list.mdx"
- [x] Code
- [x] Sleep
- [ ] Eat
```

and import in your MDX page:

```mdx filename="page.mdx"
import TaskList from './task-list.mdx'

<TaskList />
```

### Support Next.js 13

Nextra 2 comes with support for the latest **Next.js 13** version and also up to Next.js 9!

### Images and Links Optimization

Static images are always optimized with `<NextImage />` component, internal links are replaced with
`<NextLink />` component, external links will have `target="_blank"` and `rel="noreferrer"` and will
inform screen readers about opening a link in a new tab.

`<NextImage />` will prevent to have layout shifts on your page. Instantiate (client-side)
navigation would be done with `<NextLink />`.

```text filename="Markdown"
![Hero](/hero.png)
[Learn more](/more)
[See examples](https://github.com/shuding/nextra/tree/main/examples)
```

will be compiled to:

```jsx
import Image from 'next/image'
import Link from 'next/link'
import nextraImage from '../../public/hero.png'

function MDXContent() {
  return (
    <>
      <Image src={nextraImage} alt="Hero" />
      <Link href="/more">Learn more</Link>
      <a
        href="https://github.com/shuding/nextra/tree/main/examples"
        target="_blank"
        rel="noreferrer"
      >
        See examples<span className="sr-only"> (opens in a new tab)</span>
      </a>
    </>
  )
}

export default MDXContent
```

### Extensible with `rehype`/`remark` Plugins

You can extend Nextra with any of `rehype`/`remark` plugins, just pass them to the `nextra`
function.

```js filename="next.config.js" {7-9}
import nextra from 'nextra'
import remarkMdxDisableExplicitJsx from 'remark-mdx-disable-explicit-jsx'

const withNextra = nextra({
  theme: 'nextra-theme-docs',
  themeConfig: './theme.config.jsx',
  remarkPlugins: [
    [remarkMdxDisableExplicitJsx, { whiteList: ['table', 'thead', 'tbody', 'tr', 'th', 'td'] }]
  ],
  rehypePlugins: []
})

export default withNextra()
```

### Remote Markdown

Rendering remote markdown is simple, you will need:

1.  Install `next-mdx-remote` and import `MDXRemote` component
2.  Compile your markdown raw string using `compileMdx` from `nextra/compile` in `getStaticProps()`
3.  Provide your compiled result code to `props.ssg`
4.  Get data from SSG with `useSSG` hook from `nextra/ssg`
5.  Provide compiled result code for `MDXRemote` via `compiledSource` prop
6.  Provide `components` from `useMDXComponents` hook from `nextra/mdx` for `MDXRemote` to prevent
    layout shifts

```mdx filename="Remote Nextra Readme" showLineNumbers {1,9,12,20,22}
import { MDXRemote } from 'next-mdx-remote' {/* 1 */}
import { compileMdx } from 'nextra/compile'
import { useSSG } from 'nextra/ssg'
import { useMDXComponents } from 'nextra/mdx'

export const getStaticProps = async () => {
  const response = await fetch('https://raw.githubusercontent.com/shuding/nextra/main/README.md')
  const markdown = await response.text()
  const mdx = await compileMdx(markdown, { defaultShowCopyCode: true }) // 2
  return {
    props: {
      ssg: mdx.result // 3
    },
    // Revalidate at most once every 1 hour
    revalidate: 60 * 60
  }
}

export const NextraReadme = () => {
  const compiledSource = useSSG() // 4
  const components = useMDXComponents()
  return <MDXRemote compiledSource={compiledSource} components={components} /> // 5-6
}

<NextraReadme />
```

<details>
  <NextraReadme />

  <summary>Click to expand Nextra's readme from GitHub 🚀</summary>
</details>

### Nextra Theme Docs Features

`nextra-theme-docs` was completely redesigned to be more flexible and configurable for all of your
needs.

<NextImage src={nextraPage} className="mt-6 rounded-3xl border border-gray-700" alt="Example of Nextra page" loading="lazy" />

#### Various Customization

Here is an overview of different options for customization elements such as:

*   Banner
*   Header (logo / chat icon / project icon)
*   Footer
*   `<head />` content and Next SEO props
*   Various search / sidebar / TOC options
*   Pagination on page
*   Dark mode
*   Edit page link
*   Hue of the primary theme color
*   404/500 page

They could be configured in your `theme.config.jsx` file.
[Read more](https://nextra.site/docs/docs-theme/theme-configuration) about all available options.

#### Builtin Full-Text Search

Full-text search is powered by [FlexSearch](https://github.com/nextapps-de/flexsearch) and Nextra
will index all of your pages at build time ⚡.

<Video src="/blog-assets/nextra-2/flexsearch.mp4" className="rounded-3xl border border-gray-700" />

#### New Syntax Highlighting

[Prismjs](https://prismjs.com) was replaced by [Shiki](https://github.com/shikijs/shiki) and
[rehype-pretty-code](https://rehype-pretty-code.netlify.app).

Below is an example of a code block with a filename, line numbers, word highlighting and line
highlighting:

````md filename="Markdown"
```jsx filename="My File" showLineNumbers /App/ {2}
function App() {
  return <div>Hello</div>
}
```
````

will be rendered as:

```jsx filename="My File" showLineNumbers /App/ {2}
function App() {
  return <div>Hello</div>
}
```

#### Next SEO Builtin

Out of the box, `nextra-theme-docs` has Next SEO installed. By default, in the front matter you can
set `title`, `description`, `canonical` and `openGraph` and they will be passed directly to the
`<NextSeo />` component.

```md filename="Markdown"
---
title: Nextra 2
description: Nextra – Next.js Static Site Generator
---
```

will be passed to Next SEO and rendered on the page as:

```html
<head>
  <title>Nextra 2</title>
  <meta name="og:title" content="Nextra 2" />
  <meta name="description" content="Nextra – Next.js Static Site Generator" />
  <meta name="og:description" content="Nextra – Next.js Static Site Generator" />
</head>
```

<Callout>
  You can manually pass Next SEO props with `useNextSeoProps` theme option. [Read
  more](https://nextra.site/docs/docs-theme/theme-configuration#seo-options) in the docs.
</Callout>

#### I18n Support

`nextra-theme-docs` comes with support i18n in your website.

To use it, provide Next.js' `i18n` field with `locales` and `defaultLocale` setup:

```js filename="next.config.js"
export default withNextra({
  i18n: {
    locales: ['en-US', 'fr-FR'],
    defaultLocale: 'en-US'
  }
})
```

Add Nextra's middleware:

```js filename="middleware.js"
export { locales as middleware } from 'nextra/locales'
```

Create your `_meta` and page files with locales suffixes:

```text
├── pages
│   ├── _meta.en-US.json
│   ├── _meta.fr-FR.json
│   ├── index.en-US.mdx
│   ├── index.fr-FR.mdx
```

```mdx filename="index.en-US.mdx"
# 🇺🇸 Hello Nextra 2
```

```mdx filename="index.fr-FR.mdx"
# 🇫🇷 Bonjour Nextra 2
```

[Learn more](https://nextra.site/docs/guide/i18n) on docs.

#### LTR/RTL Direction Support

Your website can be fully mirrored with RTL direction. All that you need it provides `dir: 'rtl'` in
your `theme.config.jsx` file.

<NextImage src={nextraRtl} className="mt-6 rounded-3xl border border-gray-700" alt="Example of Nextra page with RTL direction" loading="lazy" />

#### A11y

Accessibility is all, Nextra respects system preferences, animation will be reduced with
`reduce-motion` mode, colors will be adjusted in `contrast-more` mode.

<NextImage src={nextraContrastMode} className="mt-6 rounded-3xl border border-gray-700" alt="Example of Nextra page with contrast mode enabled" loading="lazy" />

## Conclusion

[The Guild](/) discovered Nextra 2 from the first betas and actively participated in the development
and improvement of this library. I (Dimitri) become
[an official maintainer](https://nextra.site/about#team) of this library on par with Nextra creator
amazing [Shu Ding](https://github.com/shuding/nextra) from Vercel.

In the end, we migrated all our projects' documentation to Nextra, which provides a better setup and
documentation design than our previous `guild-docs` package. Alongside we added Giscus comments at
the end of each page that synchronizes with GitHub discussions.

We receive a bunch of positive feedback and much more contributions and fixing mistakes in our docs
from our community ❤️.

<Callout emoji="🍭">In fact, even this blog uses Nextra 2 and `nextra-theme-docs`. 👀</Callout>