Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

Use Velite when your Next.js app needs MDX files treated as a validated, typed content collection rather than as route files alone. Velite builds structured data from Markdown and MDX; it does not provide Next.js routing or render a finished page. This tutorial connects a Velite collection to an App Router page and shows how to render its compiled MDX with React components.

What Velite does—and when to use it

Velite turns Markdown, MDX, and other files into application data using a declared schema. Its documentation describes Zod validation, inferred TypeScript types, multiple output formats, and framework-agnostic use. The practical benefit is a predictable collection: for example, posts with required titles, slugs, dates, and MDX bodies that your routes can query.

Velite is a good fit when content should be modeled as data and checked against a schema. If you only need MDX imported into route files or used as route content, Next.js’s native @next/mdx integration may be a more direct fit. Neither approach is universally better; choose based on your content model and route conventions.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Velite’s official documentation states, “Velite supports MDX out of the box.” That means it can compile MDX into collection data; it does not mean that the MDX body is already rendered HTML.

Set up the project and content files

The examples below use the Next.js App Router, a content directory, and a posts/*.mdx collection pattern documented by Velite. Install Velite and its documented schema package in your project, along with the React runtime used by the renderer. Use package versions compatible with your own Next.js and React installation; the cited documentation does not establish a tested compatibility matrix.

npm install velite zod

A minimal project layout can look like this:

app/n  blog/n    [slug]/n      page.tsxncontent/n  posts/n    typed-mdx.mdxncomponents/n  mdx-components.tsxnvelite.config.ts

Create a post with frontmatter and MDX content. The frontmatter values will be checked against the schema defined in the next section.

---ntitle: A typed MDX postndate: 2026-10-11nslug: typed-mdxn---nnThis post is compiled by Velite and rendered by the application.nn<Callout>This MDX element needs a React component at render time.</Callout>

Define and validate a Velite collection

Create velite.config.ts and define a collection whose fields match the post frontmatter. Velite’s documented model uses a collection pattern such as posts/*.mdx, a string title, and s.mdx() for the body. The schema can require metadata that every post needs and leave genuinely optional fields optional.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import { defineConfig, s } from 'velite';nnexport default defineConfig({n  root: 'content',n  collections: {n    posts: {n      name: 'Post',n      pattern: 'posts/*.mdx',n      schema: s.object({n        title: s.string(),n        date: s.string(),n        slug: s.slug('posts'),n        content: s.mdx(),n        description: s.string().optional(),n      }),n    },n  },n});

Velite supports JavaScript and TypeScript configuration; its reference recommends defineConfig for inference. Adapt the field names and slug behavior to the shape required by your current Velite release. Set validation behavior deliberately: the documented strict option defaults to false, which logs a warning for schema failures rather than terminating the process. For a production content pipeline, enable strict validation so invalid entries stop the build.

export default defineConfig({n  strict: true,n  // collections: ...n});

For example, removing the required title from the sample frontmatter makes the post invalid under this schema. With strict validation enabled, the Velite build should fail instead of quietly producing a usable collection. Check the command output for the file and field reported by the validator. This is content validation at build time, not a guarantee that every application-level assumption or rendered component is correct.

Build the collection and inspect its output

Run Velite’s build command to compile the content and generate collection data and inferred types:

npx velite build

The MDX field is compiled into a function-body string by default. It is neither HTML nor a React element yet. The application must evaluate that generated code with the React JSX runtime, then provide the components referenced in the source MDX.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Render the compiled MDX with React components

Velite documents a renderer that evaluates compiled MDX code using react/jsx-runtime and accepts shared or per-document components. Define a component map with an entry for each custom MDX tag used in your posts. For example:

// components/mdx-components.tsxnimport type { ComponentProps, ReactNode } from 'react';nnfunction Callout({ children }: { children: ReactNode }) {n  return <aside className="callout">{children}</aside>;n}nnexport const mdxComponents = {n  Callout,n};

Then evaluate the content when rendering the page. Keep the renderer on the server unless your use case requires otherwise, and use the MDX renderer API exposed by the installed Velite release:

import { useMDXComponent } from 'velite';nimport { mdxComponents } from '@/components/mdx-components';nnexport function PostBody({ code }: { code: string }) {n  const Content = useMDXComponent(code);n  return <Content components={mdxComponents} />;n}

The exact exported renderer helper and generated field names can vary with the Velite API version in your project; follow the installed release’s MDX guide if its API differs. The important contract is that compiled code is evaluated with the React runtime and the component map is passed at render time. Velite’s s.mdx() does not bundle Callout or other React components into the generated body.

Connect collection data to an App Router route

Import the generated collection from the output path configured for your project, find the entry using the route parameter, and render its title and MDX field. The import path and field names must match Velite’s generated output and your schema.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
// app/blog/[slug]/page.tsxnimport { notFound } from 'next/navigation';nimport { posts } from '#velite';nimport { PostBody } from '@/components/PostBody';nnexport default async function BlogPost({n  params,n}: {n  params: Promise<{ slug: string }>;n}) {n  const { slug } = await params;n  const post = posts.find((item) => item.slug === slug);nn  if (!post) notFound();nn  return (n    <article>n      <h1>{post.title}</h1>n      <PostBody code={post.content} />n    </article>n  );n}

Next.js route parameter typing and the generated Velite import alias are version- and configuration-sensitive. If your Next.js release types params differently, use the signature for that release. Likewise, configure Velite’s output or alias so #velite resolves to generated collection data; do not assume that path exists automatically in every project.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Choose a Next.js integration for your bundler

Velite documents several ways to run its build alongside Next.js: start Velite from Next.js configuration, use its Webpack plugin, or coordinate separate commands with package scripts. The choice matters because the documented VeliteWebpackPlugin does not function correctly when Turbopack is enabled.

For a Turbopack workflow: start Velite from Next.js configuration

The Velite guide presents a config-based start approach for projects adopting Turbopack. Follow that integration pattern in the Next.js configuration file, using the Velite API and file format documented for your installed version. This avoids treating the Webpack plugin as a universal solution.

For Webpack or explicit orchestration: use the matching documented method

If your project uses Webpack, Velite documents its Webpack plugin. Alternatively, run the content build and Next.js commands as coordinated scripts, which makes the ordering explicit. For example, adapt scripts to the chosen Velite watch/build command and Next.js command in your project:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
{n  "scripts": {n    "dev": "velite --watch & next dev",n    "build": "velite build && next build",n    "start": "next start"n  }n}

Use the exact watch invocation supported by the Velite version you install. In development, the watcher should rebuild collection data as content changes; in production, complete the clean content build before next build so generated imports exist when Next.js compiles the application. Avoid running the Webpack plugin while Turbopack is enabled.

Velite or native Next.js MDX?

Next.js’s App Router MDX guide, last updated August 10, 2026, documents the native @next/mdx integration. It supports MDX through route files or imports and uses an mdx-components.tsx convention, which the guide says is required when using @next/mdx with the App Router.

Need Velite Native @next/mdx
Content model Builds schema-defined collections as app data. Uses MDX through route files or imports.
Schema validation and inferred collection types Documented features include validation and inferred types. The cited Next.js guide describes MDX integration; it does not establish Velite-style collection schema validation.
Rendering custom MDX components Pass a runtime and component map when rendering compiled MDX; components are not bundled by s.mdx(). Use the App Router mdx-components.tsx convention.
Build integration Choose an integration suited to the bundler; the documented Webpack plugin does not work correctly with Turbopack. Follow the native Next.js MDX setup for the app’s route and import conventions.
Best match Content collections queried as data with a defined schema. Direct MDX routes or imports without a separate generated collection layer.

Troubleshoot common integration failures

  • Velite does not load the config: Confirm the config filename, extension, and location match the invocation and Velite version.
  • A post is missing from the collection: Check that it is under the configured root and matches the collection pattern, such as posts/*.mdx.
  • Validation fails: Compare every frontmatter key and value with the schema, including required fields such as title.
  • A custom MDX tag fails at render time: Add the corresponding React component to the map passed to the renderer. A tag in MDX is not automatically imported as a component.
  • The collection import cannot resolve: Verify the generated output or alias configuration, and ensure the content build has run before Next.js compiles the route.
  • Webpack integration breaks under Turbopack: Switch to the documented config-based approach or another supported orchestration path rather than relying on VeliteWebpackPlugin.

Sources

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.