Written by
Fuma Nama
At
Sun Nov 16 2025
Fumadocs MDX 14
Performance Improvements & API redesign.
We are pleased to announce Fumadocs MDX 14. This update introduces several major enhancements designed to:
- Improve flexibility, taking the plugin approach further.
- Improve performance & memory consumption.
- Improve browser/dynamic compilation suport.
New Model
The output is now separated into:
.source/server: the content data available for server (e.g. RSC, SSR), should not be referenced in client code..source/browser: the data available for browser, with built-in serialization, chunking and loader layer..source/dynamic: interface for dynamic content compilation, only generated for collections withdynamic: true.
Breaking Changes
Entry Files
Fumadocs MDX now generates multiple entry files in .source folder.
To migrate, add/update the path aliases in tsconfig.json for new entry files.
{
"compilerOptions": {
"paths": {
"fumadocs-mdx:collections/*": [".source/*"]
}
}
}Import your collections from the entry files instead of @/.source:
import { docs } from '@/.source';
import { docs } from 'fumadocs-mdx:collections/server';
// access collections on server-side, e.g.
import { loader } from 'fumadocs-core/source';
export const source = loader({
source: docs.toFumadocsSource(),
});The new browser createClientLoader() should work seamlessly with old usage.
See Browser Entry for more examples of browserCollections.
Fumadocs Adapter
The adapter for loader() API is also changed.
For docs collection, create.sourceAsync() (Vite) is now consistent with Next.js:
import { docs } from 'fumadocs-mdx:collections/server';
import { loader } from 'fumadocs-core/source';
export const source = loader({
baseUrl: '/docs',
source: await create.sourceAsync(docs.doc, docs.meta),
source: docs.toFumadocsSource(),
});For doc collections, createMDXSource() (Next.js) is renamed to toFumadocsSource().
If you use create.sourceAsync() (Vite) for doc collections, you should also switch to toFumadocsSource().
import { blogPosts } from 'fumadocs-mdx:collections/server';
import { toFumadocsSource } from 'fumadocs-mdx/runtime/server';
import { loader } from 'fumadocs-core/source';
export const blog = loader({
baseUrl: '/blog',
// for Next.js
source: createMDXSource(blogPosts, []),
// for Vite
source: await create.sourceAsync(blogPosts, []),
source: toFumadocsSource(blogPosts, []),
});Async & Dynamic Mode
On Next.js, Async Mode now aligns with the behaviour on Vite to generate async imports. This enables server-side chunking to improve memory usage.
import { defineDocs } from 'fumadocs-mdx/config';
export const docs = defineDocs({
dir: 'content/docs',
docs: {
// This no longer forces dynamic compilation!
async: true,
},
});Instead, we introduced a dynamic option to enable dynamic compilation. This is available for both Vite and Next.js.
import { defineDocs } from 'fumadocs-mdx/config';
export const docs = defineDocs({
dir: 'content/docs',
docs: {
dynamic: true,
},
});By enabling Async or Dynamic modes, the relevant collections are considered lazy-loaded, offering a load() function to load compiled properties.
Updated Signature for postInstall()
It now accepts the framework plugin options, you can customise more properties:
import { postInstall } from 'fumadocs-mdx/next';
// or
import { postInstall } from 'fumadocs-mdx/vite';
postInstall('source.config.ts');getDefaultMDXOptions() -> applyMdxPreset()
To support a broader range of presets and accommodate dynamic modes, getDefaultMDXOptions() has been renamed to applyMdxPreset().
import { defineCollections, getDefaultMDXOptions } from 'fumadocs-mdx/config';
import { myPlugin } from './remark-plugin';
export const blog = defineCollections({
type: 'doc',
mdxOptions: getDefaultMDXOptions({
remarkPlugins: [myPlugin],
// Alternatively, use a function to customize plugin order:
remarkPlugins: (v) => [myPlugin, ...v],
}),
});Introduction of lastModified Plugin
The lastModifiedTime option has been replaced by a dedicated lastModified plugin.
This shift promotes a plugin-based architecture for better extensibility.
import { defineConfig } from 'fumadocs-mdx/config';
import lastModified from 'fumadocs-mdx/plugins/last-modified';
export default defineConfig({
plugins: [lastModified()],
});Removal of Multiple dir Support
Support for specifying multiple directories in a single collection has been discontinued. Instead, utilize the files property to filter and include specific files.
import { defineDocs } from 'fumadocs-mdx/config';
export const docs = defineDocs({
dir: 'content/guides',
docs: {
files: ['./i-love-fumadocs/**/*.{md,mdx}'],
},
});Disabling Default Generation of extractedReferences
The automatic generation of extractedReferences is no longer enabled by default. To retain this functionality, explicitly activate it via the postprocess option.
import { defineDocs } from 'fumadocs-mdx/config';
export const docs = defineDocs({
dir: 'content/docs',
docs: {
postprocess: {
extractLinkReferences: true,
},
},
});Vite: generateIndexFile -> index
The generateIndexFile option of our Vite plugin has been renamed to index.
import { defineConfig } from 'vite';
import mdx from 'fumadocs-mdx/vite';
import * as MdxConfig from './source.config';
export default defineConfig({
plugins: [
mdx(MdxConfig, {
index: {
// options
},
}),
],
});Patch Changes
- Resolved an issue with meta file validation when using Bun.
- Introduced optimizations to reduce unnecessary entry files re-generations.
Thank you for your continued support of Fumadocs. If you encounter any issues during the update, welcome to reach out through our GitHub Discussions.