Configurations
Available options.
Main Config
Primary options for your app.
import { defineConfig } from "fumapress";
export default defineConfig({
// ...
});Site
The site information like name and linked git repository:
import { defineConfig } from "fumapress";
export default defineConfig({
site: {
name: "Fumapress",
baseUrl: import.meta.env.DEV ? "http://localhost:3000" : "https://press.fumadocs.dev",
git: {
user: "fuma-nama",
branch: "dev",
repo: "fumapress",
},
},
});The repository is used for the icon link in navbar, and the link to source file of pages.
Source file links are resolved against the detected git root, set git.rootDir to override it, such as when building in an environment without the .git directory.
URLs
baseUrl is required for some features to know the absolute URL of a page.
import { defineConfig } from "fumapress";
export default defineConfig({
site: {
baseUrl: "https://press.fumadocs.dev",
},
});Page URLs have no trailing slash, the deployment adapters configure hosts to serve them that way.
Locales
With i18n, every page links its translations with hreflang. Locale codes are used as is, map the ones that are not BCP 47 language tags:
import { defineConfig } from "fumapress";
export default defineConfig({
site: {
hreflang: {
cn: "zh-Hans",
tw: "zh-Hant",
},
},
});Git Providers
git.provider supports github (default), gitlab, and bitbucket, the navbar icon link and source file URLs follow the given provider. For self-hosted instances, pass the instance URL with git.url:
import { defineConfig } from "fumapress";
export default defineConfig({
site: {
git: {
provider: "gitlab",
url: "https://gitlab.example.com",
user: "fuma-nama",
branch: "dev",
repo: "fumapress",
},
},
});Layouts
Specify or customize page UI with renderPage, renderRoot, and renderNotFound.
import { createDocsLayoutPage } from "fumapress/layouts/docs";
import { defineConfig } from "fumapress";
const DocsLayout = createDocsLayoutPage<typeof config.$context>();
const config = defineConfig({
renderPage: (props) => <DocsLayout {...props} />,
});
export default config;renderNotFound customizes the not found screen, shown for unknown URLs and notFound() calls:
import { defineConfig } from "fumapress";
import { Link } from "fumapress/client";
export default defineConfig({
renderNotFound: () => (
<main>
<h1>Page not found</h1>
<Link href="/">Back to home</Link>
</main>
),
});See Layouts for details.
Render Mode
mode controls how routes are rendered:
default: when your content source will not change after production build. It still emits API routes, such as the search API endpoint, which require a running server to host.static: same asdefault, but will not emit API routes. Production builds emit only static files, which can be served via CDNs.dynamic: when your content source will change after production build. Requires a running server to host.
import { defineConfig } from "fumapress";
export default defineConfig({
// ...
mode: "static",
});See Deployment for hosting each mode.
Preset
By default, Fumapress adds recommended plugins automatically:
- Sitemap
- robots.txt
- llms.txt
- RSS
- Search with Flexsearch
- OG images with Takumi
- Image optimization matching your deployment target
Plugins you add yourself take priority, e.g. adding oramaSearchPlugin() replaces the default search.
To start from an empty plugin list instead:
import { defineConfig } from "fumapress";
export default defineConfig({
// ...
preset: false,
});Loader Options
loaderOptions configures the Loader API that Fumapress creates from your content sources. A common use is loader plugins, such as resolving the icon frontmatter field to Lucide icons:
import { defineConfig } from "fumapress";
import { lucideIconsPlugin } from "fumadocs-core/source/plugins/lucide-icons";
export default defineConfig({
// ...
loaderOptions: {
plugins: [lucideIconsPlugin()],
},
});For dynamic content sources (e.g. a CMS), alwaysRevalidate: true refetches them on every request:
import { defineConfig } from "fumapress";
import { lucideIconsPlugin } from "fumadocs-core/source/plugins/lucide-icons";
export default defineConfig({
// ...
loaderOptions: {
alwaysRevalidate: true,
},
});Leave it disabled to control this yourself with getPressContext().revalidateLoader().
Meta
To add meta tags, you can leverage the meta config.
import { defineConfig } from "fumapress";
export default defineConfig({
meta: {
root() {
return (
<>
<meta property="og:type" content="website" />
{/* you can use it for link tags as well */}
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="" />
<link
href="https://fonts.googleapis.com/css2?family=Geist+Mono:wght@100..900&family=Geist:wght@100..900&display=swap"
rel="stylesheet"
/>
</>
);
},
page(page) {
return <>{/* page-level meta tags */}</>;
},
},
});UI
Tailwind CSS
Create a src/app.css file:
@import "tailwindcss";
@import "fumadocs-ui/css/neutral.css";
@import "fumadocs-ui/css/preset.css";
@import "fumapress/css/preset.css";It will be automatically loaded, restart the dev server if there's one running.
You can change the color theme or add custom styles, like:
@import "tailwindcss";
@import "fumadocs-ui/css/neutral.css";
@import "fumadocs-ui/css/black.css";
@import "fumadocs-ui/css/preset.css";
@import "fumapress/css/preset.css";
@theme {
--default-font-family: "Geist", sans-serif;
}Using Radix UI
Fumapress uses the Base UI headless component library by default, same as Fumadocs. If you are using Radix UI, Fumapress also supports the Radix UI build of Fumadocs UI.
You can enable it by installing fumadocs-ui without the @fumadocs/base-ui alias:
npm i fumadocs-ui
npm uninstall @base-ui/reactVite Plugin
The press() plugin connects Fumapress to Vite:
import { defineConfig } from "vite";
import press from "fumapress/vite";
import { fumadocsMdx } from "fumadocs-mdx/vite";
import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
plugins: [press(), fumadocsMdx(), tailwindcss()],
});It takes the options of the app itself, like the directory layout and deployment target:
Prop
Type
Deployment Adapter
Vercel, Netlify, and Cloudflare are detected from the environment, other targets fall back to waku/adapters/node. Set adapter when the detected one isn't what you deploy to, see Deployment:
export default defineConfig({
plugins: [
press({
adapter: "waku/adapters/vercel",
}),
],
});CLI
The fumapress CLI runs Vite with the environments your app needs, use it instead of calling vite directly.
{
"scripts": {
"dev": "fumapress dev",
"build": "fumapress build",
"start": "fumapress start"
}
}dev and start accept --host (-h) and --port (-p), the port can also be set with the PORT environment variable. dev listens on port 3000, start picks a free port from 8080.
npm run dev -- --port 4000Server Entry
The server entry file is optional, you can create one if needed. Useful for implementing custom router.
Custom server entries use Waku.js APIs directly. Since Fumapress manages Waku as its own dependency, install it explicitly for direct API access, matching the version pinned by Fumapress:
npm i waku@1.0.0-rc.0import _adapter from "waku/adapters/default";
// your main config file
import pressConfig from "../press.config";
import { createRouter } from "fumapress/router";
import { fsRouterFn } from "fumapress/router/fs";
const router = await createRouter(pressConfig);
const modules = import.meta.glob("./pages/**/*.{ts,tsx,js,jsx}", {
base: "/src",
});
// file-system router
const pages = router.createPages(fsRouterFn(modules));
const middlewareFns = router.createMiddlewares();
const adapter = router.patchAdapter(_adapter);
export default adapter(pages, { middlewareFns });You can also use Waku Config-based Routing instead of the file-system router, see the linked docs for usage.
import _adapter from "waku/adapters/default";
// your main config file
import pressConfig from "../press.config";
import { createRouter } from "fumapress/router";
const router = await createRouter(pressConfig);
const pages = router.createPages(async ({ createPage }) => {
// note: root element is already created by Fumapress
createPage({
render: "static",
path: "/hello-world",
component() {
// ...
},
});
});
const middlewareFns = router.createMiddlewares();
const adapter = router.patchAdapter(_adapter);
export default adapter(pages, { middlewareFns });Last updated on
