MDX-блог на Next.js своими руками - как сделан этот блог
Как я собрал блог на Next.js 16 App Router, который работает на одних markdown-файлах, без CMS. Структура папок, настройка MDX и SEO на реальном коде.
Главное
Кладём статьи как .mdx файлы в src/content/posts и рендерим через @next/mdx - блог работает без CMS. Файл и есть URL, а вместо frontmatter список и метаданные строятся на meta export.
Содержание
У блога, который вы сейчас читаете, нет ни базы данных, ни админки. Каждая статья - это один markdown-файл. Рассказываю, как всё устроено, без утайки.
Почему файлы
Инструментов для блогов много, но для соло-разработчика большинство из них избыточны.
- CMS: тянет за собой админку, интеграции и счета
- Интеграция с Notion: удобно, но упираешься в рендеринг, скорость и кастомизацию
- Markdown-файлы: статьи версионируются вместе с кодом, это бесплатно, а
git pushи есть публикация
Я выбрал третий вариант. Трения меньше всего.
Структура папок
Если оставить только суть, выглядит так.
src/
├── app/
│ ├── page.tsx # 홈 - 글 목록
│ ├── posts/[slug]/page.tsx # 글 상세
│ └── sitemap.ts # /sitemap.xml
├── content/posts/*.mdx # ← 글은 여기에만 추가
└── lib/posts.ts # 목록·메타 로딩
Имя файла становится URL. hello.mdx открывается как /posts/hello.
Настройка MDX
Чтобы использовать MDX в App Router, подключаем @next/mdx. В Next 16 по умолчанию работает Turbopack, поэтому плагины remark/rehype нужно передавать строковыми именами (ссылки на функции передать нельзя).
const withMDX = createMDX({
options: {
remarkPlugins: ["remark-gfm"], // 표·취소선 지원
rehypePlugins: ["rehype-slug"], // 제목 앵커
},
})
meta export вместо frontmatter
Обычно заголовок и дату пишут в блоке --- (frontmatter) в начале markdown-файла, но MDX умеет содержать JavaScript, так что есть способ почище. Просто экспортировать объект.
export const meta = {
title: "글 제목",
date: "2026-07-06",
category: "dev",
}
## 본문 시작
Страница списка динамически импортирует каждый файл и читает только этот meta.
const mod = await import(`@/content/posts/${slug}.mdx`)
return mod.meta // 본문 렌더 없이 메타만
Ни библиотеки парсинга, ни отдельного индекса не требуется.
SEO с самого начала
Если цель блога - приток читателей, SEO нужно закладывать не потом, а сразу. Я с самого начала настроил метаданные для каждой статьи, Open Graph, структурированные данные JSON-LD, а также sitemap.xml, robots.txt и rss.xml. Об этом подробнее расскажу в следующей статье.
Итоги
- Статья - это один
.mdxфайл, имя файла равно URL @next/mdx+ строковые плагины (Turbopack)export const metaвместо frontmatter- SEO с первого коммита
С этой структурой вы поднимете свой блог за 30 минут. Я таким способом продолжаю копить истории о своих продуктах, например про Волну дня.
Частые вопросы
Почему MDX-файлы вместо CMS?
Статьи версионируются вместе с кодом, это бесплатно, а деплой равен публикации - для соло-разработчика это минимум трения. Плюс можно свободно вставлять картинки, код и компоненты.
Как построить список статей без frontmatter?
В начале каждого .mdx экспортируется объект meta, а страница списка динамически импортирует файлы и читает только этот meta. Отдельная библиотека парсинга не нужна.
Похожие статьи
- 💻 Разработка
Если у одного бакета два владельца, побеждает тот, чей apply был последним
Я добавил одно lifecycle-правило для S3, и terraform apply упал. Причина: конфигурацией lifecycle одного и того же бакета владели два ресурса, каждый сам по себе. S3 lifecycle работает не на уровне отдельных правил, а на уровне документа целиком, поэтому последний победитель тихо стирает правила соперника.
- 💻 Разработка
Тесты были зелёными, а уведомление не отправилось ни разу
Код, ставивший задачу в очередь, падал с первого дня, каждый раз. Ошибка проглатывалась, а тесты благодаря мокам оставались зелёными. История о том, как одно двоеточие тихо убило три фичи.
- 💻 Разработка
Пришло оповещение, что база упала. База не падала ни разу
За сутки накопилось четыре оповещения уровня CRITICAL. 504, Prisma P2028, 500 в админке и «сервис DATABASE недоступен». Я первым делом открыл метрики RDS: все 21 час база держала CPU максимум на 19,7% и чувствовала себя прекрасно. Тормозила не база, а круговые поездки через Атлантику, которых на один запрос приходилось двадцать пять. А оповещение о «недоступности» хелсчек сочинил сам про себя.