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#

text
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#

FileRole
docs.config.tsThe single configuration object. Consumed by createSource, RootProvider, and DocsLayout.
lib/source.tsCreates the content source. Server-only; never import it from a client component.
app/layout.tsxLoads fonts, imports pzzadocs/styles.css, and wraps the tree in RootProvider (theme and search dialog state).
app/docs/layout.tsxRenders DocsLayout with the page tree. Everything under /docs inherits the header and sidebar.
app/docs/[[...slug]]/page.tsxResolves the slug to a page, builds metadata, and renders DocsPage.
app/api/search/route.tsReturns 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:

FileURL
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:

  1. Rename app/docs to app/handbook.
  2. Set baseUrl: "/handbook" in docs.config.ts.
  3. Update nav.links so 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. generateStaticParams returns every page from getPages(), so all docs are pre-rendered at build time. The search route is marked force-static and becomes a JSON file in the build output.
  • Content reads at build time. createSource reads contentDir relative to process.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 editUrl in 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.