Project Structure
Where files live in a PzzaDocs project and what each one is responsible for.
A finished setup touches six files in your app plus a content folder. Nothing is hidden: every route is a file you own and can edit.
File tree#
my-app/
├── app/
│ ├── layout.tsx # fonts, stylesheet, RootProvider
│ ├── page.tsx # optional: redirect / to /docs
│ ├── api/
│ │ └── search/
│ │ └── route.ts # JSON search index
│ └── docs/
│ ├── layout.tsx # DocsLayout (header + sidebar)
│ └── [[...slug]]/
│ └── page.tsx # DocsPage for every doc
├── content/
│ └── docs/
│ ├── meta.json # top-level ordering
│ ├── index.mdx # /docs
│ └── guides/
│ ├── meta.json # folder label and ordering
│ ├── index.mdx # /docs/guides
│ └── setup.mdx # /docs/guides/setup
├── docs.config.ts # defineConfig
└── lib/
└── source.ts # createSource(config)Responsibilities#
| File | Role |
|---|---|
docs.config.ts | The single configuration object. Consumed by createSource, RootProvider, and DocsLayout. |
lib/source.ts | Creates the content source. Server-only; never import it from a client component. |
app/layout.tsx | Loads fonts, imports pzzadocs/styles.css, and wraps the tree in RootProvider (theme and search dialog state). |
app/docs/layout.tsx | Renders DocsLayout with the page tree. Everything under /docs inherits the header and sidebar. |
app/docs/[[...slug]]/page.tsx | Resolves the slug to a page, builds metadata, and renders DocsPage. |
app/api/search/route.ts | Returns getSearchIndex() as JSON for the search dialog. |
content/docs/** | Your MDX pages and meta.json files. |
URL mapping#
Routes are derived from file paths relative to contentDir, with baseUrl prepended:
| File | URL |
|---|---|
content/docs/index.mdx | /docs |
content/docs/installation.mdx | /docs/installation |
content/docs/guides/index.mdx | /docs/guides |
content/docs/guides/setup.mdx | /docs/guides/setup |
The slug passed to getPage is the array of path segments after baseUrl, so /docs/guides/setup becomes ["guides", "setup"] and /docs becomes [].
Mounting under a different path#
baseUrl and the route folder must agree. To serve docs from /handbook instead of /docs:
- Rename
app/docstoapp/handbook. - Set
baseUrl: "/handbook"indocs.config.ts. - Update
nav.linksso the tab hrefs point at the new prefix.
The content folder does not need to move; contentDir is independent of baseUrl.
Deployment#
PzzaDocs has no runtime requirements beyond Next.js itself, so it deploys anywhere Next.js does.
- Static generation.
generateStaticParamsreturns every page fromgetPages(), so all docs are pre-rendered at build time. The search route is markedforce-staticand becomes a JSON file in the build output. - Content reads at build time.
createSourcereadscontentDirrelative toprocess.cwd(). Make sure the content folder is included in your deployment and that the build runs from the project root. - Caching. Compiled pages are cached in memory keyed by file path and modification time. In development, editing an MDX file invalidates its entry on the next request. In production the cache is filled during the build.
- Edit links. If you set
editUrlin the config, each page footer links to the page's source file. Pair it with your repository URL so readers can open pull requests against the docs.
Serverless file access
On platforms that trace file dependencies for serverless functions, confirm the content/docs folder is shipped with the function bundle. Because every page is statically generated, this only matters if you opt a route out of static rendering.