Capítulo 54 de 456
MDX é markdown com suporte a JSX embutido, permitindo escrever conteúdo com componentes React interativos. Next.js suporta MDX local (via @next/mdx) tanto como páginas por file-based routing quanto via import direto, com Server Components por padrão no App Router.
@next/mdx: pacote que configura o Next.js para processar .md/.mdx como páginas, rotas ou imports; fonte de dados são arquivos locais.pageExtensions: opção do next.config.mjs que precisa incluir md/mdx para que esses arquivos virem páginas/rotas.mdx-components.tsx: arquivo obrigatório na raiz do projeto (ou src/) que define componentes MDX globais via useMDXComponents(); sem ele, @next/mdx não funciona no App Router.app/mdx-page/page.mdx) ou ser importado num componente React (import Welcome from '@/markdown/welcome.mdx').import(@/content/${slug}.mdx) dentro de uma rota dinâmica, combinado com generateStaticParams e dynamicParams = false para 404 em slugs não pré-gerados.mdx-components.tsx afetam todos os MDX; componentes locais passados via prop components no import sobrescrevem os globais só naquela página.app/mdx-page/layout.tsx) aplica estilo compartilhado a todas as páginas MDX daquele segmento.@next/mdx não suporta nativamente; alternativas são remark-frontmatter, remark-mdx-frontmatter, gray-matter. Em vez disso, @next/mdx permite export const metadata = {...} direto no arquivo .mdx, importável de fora.remark-gfm para GitHub Flavored Markdown); exigem next.config.mjs/.ts (ESM only).mdxRs (experimental): compilador MDX baseado em Rust, não recomendado para produção; aceita config de jsxRuntime, jsxImportSource, providerImportSource, mdxType (gfm|commonmark).pnpm add @next/mdx @mdx-js/loader @mdx-js/react @types/mdx
// next.config.mjs
import createMDX from '@next/mdx'
const nextConfig = {
pageExtensions: ['js', 'jsx', 'md', 'mdx', 'ts', 'tsx'],
}
const withMDX = createMDX({})
export default withMDX(nextConfig)
.mdx como extensão de página válida.// mdx-components.tsx (obrigatório no App Router)
import type { MDXComponents } from 'mdx/types'
const components: MDXComponents = {}
export function useMDXComponents(): MDXComponents {
return components
}
// app/blog/[slug]/page.tsx — import dinâmico de MDX
export default async function Page({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params
const { default: Post } = await import(`@/content/${slug}.mdx`)
return <Post />
}
export function generateStaticParams() {
return [{ slug: 'welcome' }, { slug: 'about' }]
}
export const dynamicParams = false
// mdx-components.tsx — customização global (h1 e img)
const components = {
h1: ({ children }) => <h1 style={{ color: 'red', fontSize: '48px' }}>{children}</h1>,
img: (props) => <Image sizes="100vw" style={{ width: '100%', height: 'auto' }} {...props} />,
} satisfies MDXComponents
next/image no lugar de <img>).export const metadata = {
author: 'John Doe',
}
# Blog post
.mdx, importável em page.tsx via import BlogPost, { metadata } from '@/content/blog-post.mdx'.// next.config.mjs — plugins com Turbopack (strings, não funções)
const withMDX = createMDX({
options: {
remarkPlugins: ['remark-gfm', ['remark-toc', { heading: 'The Table' }]],
rehypePlugins: ['rehype-slug', ['rehype-katex', { strict: true, throwOnError: true }]],
},
})
mdx-components.tsx no App Router: @next/mdx simplesmente não funciona sem esse arquivo.@next/mdx não processa YAML frontmatter por padrão; é preciso plugin extra ou usar export const metadata.mdxRs em produção: ainda experimental, não recomendado..mdx na extensão do import dinâmico: import(@/content/${slug}.mdx) precisa da extensão explícita.mdx-components.tsx na raiz é obrigatório para MDX funcionar com App Router.generateStaticParams/dynamicParams = false permitem prerender rotas de conteúdo por slug.mdx-components.tsx), locais (prop components no import) ou via layout compartilhado (inclusive com @tailwindcss/typography).export const metadata no MDX ou plugins remark de frontmatter.img nos componentes MDX customizados.