All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
Shorter names for integration components
The components of integrations dropped their fumadocs/ prefix:
npx @fumadocs/cli add openapi/page
Before
Now
fumadocs/openapi/*
openapi/*
fumadocs/asyncapi/*
asyncapi/*
fumadocs/graphql/*
graphql/*
fumadocs/story/*
story/*
fumadocs/sanity/*
sanity/*
fumadocs/api-docs/*
api-docs/*
The old names are gone, update the commands in your scripts. fumadocs/base-ui and fumadocs/radix-ui are unchanged, the CLI resolves them from your configured uiLibrary.
Headless layer
GraphQL pages are now built on a headless layer, use it to build your own UI:
<GraphQLProvider /> holds the schema built from SDL, the page links and your components.
<OperationProvider /> and useOperation() derive an operation: its field, title, directives and generated example.
<TypeProvider /> and useNamedType() derive a named type: its kind, directives, relations and usages.
useGraphQL(), useComponents(), useRenderContext(), useTypeLink() and useOperationLink() expose the page state.
generateRequestSnippets() from @fumadocs/graphql/utils/snippets builds the cURL and fetch snippets of an example.
generateGraphQLSchemaUI() turns a type, field or argument into the data the Schema UI draws, the installed Schema UI only renders it.
@fumadocs/graphql/ui is built on it, its rendering is unchanged. typeLinks and operationLinks receive the name (and kind) only, the ctx argument is gone.
Install the UI
The UI of GraphQL pages can be installed with Fumadocs CLI and edited:
npx @fumadocs/cli add fumadocs/graphql/page
It installs <GraphQLPage /> itself, import it from @/components/graphql/page in place of your components/api-page.tsx.
Parts are installable too (operation, type-docs, schema-ui, playground) and passed to the new components options:
The playground is its own entry, so installing the operation or page UI no longer copies it:
npx @fumadocs/cli add fumadocs/graphql/playground
What it runs on comes from @fumadocs/graphql/playground: executeGraphQL() (moved from the package entry), inputTypeToJsonSchema() for the form model of arguments, and the stored endpoint and headers.
Highlighting out of the box
createGraphQLRenderer() highlights code blocks with the full Shiki bundle, pass a smaller shiki factory to trim it.
Default page components
createOpenAPIRenderer(), createAsyncAPIRenderer() and createGraphQLRenderer() fill the Markdown, CodeBlock and Heading components you didn't pass, rendering Markdown through Remark and code blocks through Shiki:
Select and Input follow the Shadcn UI API, so a project that already has them keeps its own. @fumadocs/story no longer ships a second copy of either.
labelVariants moved to the installed label component, leaving the input a plain Shadcn-compatible primitive.
The integrations share one implementation of these internally, instead of each keeping a copy: the selected server and its variables, the state of an async request, the coloured label of methods and kinds, and the plain-object check of both schema layers.
The request pipeline of the playground stays in the package too, so an installed playground drives it instead of copying it: encodeRequestData(), resolveMediaAdapter(), isMediaTypeSupported() and the request data types come from fumadocs-openapi/requests, and createBrowserFetcher() with usePlaygroundAuth() from fumadocs-openapi/playground.
@fumadocs/json-schema
The JSON Schema utilities of API pages are now their own package, with no Fumadocs dependencies:
import { dereference, matches, mergeAllOf, sample, stringify } from '@fumadocs/json-schema';import { bundle } from '@fumadocs/json-schema/bundle';
bundle() is a separate entry because it reads files and URLs, everything else runs in the browser.
@fumadocs/json-schema/react renders a schema into the data an API page draws: generateSchemaUI() with the SchemaData and InfoTag types. It was in the Schema UI before, where every install copied it. A labelled tag can be prose, for values like a Markdown deprecation reason.
They were @fumadocs/api-docs/schema/* before, and the API was cleaned up while moving:
Before
Now
ParsedSchema
JsonSchema
NoReference / NoReferenceSwallow
Dereferenced / DereferencedShallow
dereferenceShallow(schema)
dereference(schema)
matchesSchema(schema, value)
matches(schema, value)
typeMatches(value, type)
matchesType(value, type)
schemaToString(schema, FormatFlags.UseAlias)
stringify(schema, { alias: true })
Trim code usages and TypeScript definitions
createOpenAPIBaseRenderer() from fumadocs-openapi registers no code usage generators and no TypeScript definitions, so a page built on it bundles only what you pass:
import { createCodeUsageGeneratorRegistry } from 'fumadocs-openapi/requests/generators';import { curl } from 'fumadocs-openapi/requests/generators/curl';createOpenAPIBaseRenderer({ shiki, codeUsages: createCodeUsageGeneratorRegistry().register(curl), components: { ... },});
createOpenAPIRenderer() and fumadocs-openapi/ui register every language and TypeScript definitions for you.
Remove useStorageKey()
The hook returned (name) => storageKeyPrefix + name. Read the prefix from the page instead:
It held the UI the integrations share, and that UI is now either bundled into them or installed with Fumadocs CLI, so nothing imports it by name any more. If you imported it directly:
Before
Now
@fumadocs/api-docs/schema/*
@fumadocs/json-schema
@fumadocs/api-docs/components/schema*
npx @fumadocs/cli add fumadocs/api-docs/schema
@fumadocs/api-docs/components/* (the UI)
installed with the component that uses it
@fumadocs/api-docs/i18n
the integration's own Translations covers its keys
@fumadocs/api-docs/css/preset.css
already included by the integration's preset
The CLI namespace is unchanged, fumadocs/api-docs/schema still installs the Schema UI.
Headless API pages
API pages are now built on a headless layer, use it to build your own UI:
createAsyncAPIRenderer() and <AsyncAPIProvider /> with your own components.
the hooks of pages and operations: useAsyncAPI(), useComponents(), useRenderContext(), useServer(), useOperation() and useOperationSecurity().
useServer() resolves server URLs: resolveUrl(id) fills in the variables of a server, and the selected one carries its title.
@fumadocs/asyncapi/ui renders through the layer, its options are unchanged except content.renderAPIExampleLayout, which was never rendered and is removed.
Install the UI
The UI of API pages can be installed with Fumadocs CLI and edited, reusing the components/ui files you already have:
npx @fumadocs/cli add fumadocs/asyncapi/page
It installs <AsyncAPIPage /> itself, import it from @/components/asyncapi/page in place of your components/api-page.tsx.
To replace parts of it, install fumadocs/asyncapi/operation or fumadocs/api-docs/schema and pass them to the new components options:
The option was never rendered by API pages, and it is gone with its @fumari/json-schema-ts dependency. Passing it is now a type error, nothing else changes.
Client-safe package entry
generateFiles() reads and writes files, so the package entry ships a stubbed build under the browser condition. Client components can import createAsyncAPIRenderer() and the hooks without pulling node:fs into the bundle.
Highlighting out of the box
createAsyncAPIRenderer() highlights code blocks with the full Shiki bundle, pass a smaller shiki factory to trim it.
Default page components
createOpenAPIRenderer(), createAsyncAPIRenderer() and createGraphQLRenderer() fill the Markdown, CodeBlock and Heading components you didn't pass, rendering Markdown through Remark and code blocks through Shiki:
Select and Input follow the Shadcn UI API, so a project that already has them keeps its own. @fumadocs/story no longer ships a second copy of either.
labelVariants moved to the installed label component, leaving the input a plain Shadcn-compatible primitive.
The integrations share one implementation of these internally, instead of each keeping a copy: the selected server and its variables, the state of an async request, the coloured label of methods and kinds, and the plain-object check of both schema layers.
The request pipeline of the playground stays in the package too, so an installed playground drives it instead of copying it: encodeRequestData(), resolveMediaAdapter(), isMediaTypeSupported() and the request data types come from fumadocs-openapi/requests, and createBrowserFetcher() with usePlaygroundAuth() from fumadocs-openapi/playground.
@fumadocs/json-schema
The JSON Schema utilities of API pages are now their own package, with no Fumadocs dependencies:
import { dereference, matches, mergeAllOf, sample, stringify } from '@fumadocs/json-schema';import { bundle } from '@fumadocs/json-schema/bundle';
bundle() is a separate entry because it reads files and URLs, everything else runs in the browser.
@fumadocs/json-schema/react renders a schema into the data an API page draws: generateSchemaUI() with the SchemaData and InfoTag types. It was in the Schema UI before, where every install copied it. A labelled tag can be prose, for values like a Markdown deprecation reason.
They were @fumadocs/api-docs/schema/* before, and the API was cleaned up while moving:
Before
Now
ParsedSchema
JsonSchema
NoReference / NoReferenceSwallow
Dereferenced / DereferencedShallow
dereferenceShallow(schema)
dereference(schema)
matchesSchema(schema, value)
matches(schema, value)
typeMatches(value, type)
matchesType(value, type)
schemaToString(schema, FormatFlags.UseAlias)
stringify(schema, { alias: true })
Trim code usages and TypeScript definitions
createOpenAPIBaseRenderer() from fumadocs-openapi registers no code usage generators and no TypeScript definitions, so a page built on it bundles only what you pass:
import { createCodeUsageGeneratorRegistry } from 'fumadocs-openapi/requests/generators';import { curl } from 'fumadocs-openapi/requests/generators/curl';createOpenAPIBaseRenderer({ shiki, codeUsages: createCodeUsageGeneratorRegistry().register(curl), components: { ... },});
createOpenAPIRenderer() and fumadocs-openapi/ui register every language and TypeScript definitions for you.
Remove useStorageKey()
The hook returned (name) => storageKeyPrefix + name. Read the prefix from the page instead:
It held the UI the integrations share, and that UI is now either bundled into them or installed with Fumadocs CLI, so nothing imports it by name any more. If you imported it directly:
Before
Now
@fumadocs/api-docs/schema/*
@fumadocs/json-schema
@fumadocs/api-docs/components/schema*
npx @fumadocs/cli add fumadocs/api-docs/schema
@fumadocs/api-docs/components/* (the UI)
installed with the component that uses it
@fumadocs/api-docs/i18n
the integration's own Translations covers its keys
@fumadocs/api-docs/css/preset.css
already included by the integration's preset
The CLI namespace is unchanged, fumadocs/api-docs/schema still installs the Schema UI.
@fumadocs/base-ui@16.15.11
fumadocs-core@16.15.11
fumadocs-ui@16.15.11
Shadcn UI compatible primitives
The primitives in fumadocs-ui/components/ui/* now follow the API of Shadcn UI, so components installed by the CLI can use the ones you already have.
buttonVariants accepts the default variant of Shadcn UI:
fumadocs-ui/components/ui/scroll-area is removed, the sidebars render the scroll area primitives directly.
Mark packages side-effect free
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.
Reuse your Shadcn UI components
On projects with a components.json, the CLI leaves the button, popover and collapsible of your ui directory as they are and imports them from installed components, they share the API of Shadcn UI. cn is imported from your utils alias instead of a new lib/cn.ts, configurable in cli.json:
{ "aliases": { "utils": "./lib/utils" }}
Fumadocs' copies are only installed when you don't have them yet. The tabs and accordion primitives are Fumadocs specific, they are installed next to their components instead of the ui directory.
customize updates the imports of your route files to the installed layouts.
feature ai and feature feedback install the primitives of your configured uiLibrary, they always used the Radix UI ones before.
Mark packages side-effect free
All packages now declare sideEffects in package.json, so bundlers can tree-shake unused modules. Packages shipping stylesheets list them as side effects to keep CSS imports.