Getting Started
Get Pepa running and publish your first doc in under ten minutes.
611 wordsΒ·4 min read
Pepa is an open-source documentation platform you own completely. Clone it, fill it with your content, and ship it β no vendor lock-in, no monthly bill, no login required to read your own docs.
This guide walks you through setup from zero to a live site with your first custom page.
Markdown plus React components. If you know Markdown, you already know 80% of what you need.
No nav config files. The sidebar is generated from your file's frontmatter. Add a file, set three fields, done.
Pepa exports to a folder of static HTML. It runs on GitHub Pages, Netlify, Vercel, S3 β anything that can serve files.
Before you begin
You'll need three things installed on your machine:
Node.js 20 or later
Check your version with node --version. If you need to install or upgrade,
download from nodejs.org or use a version manager like
nvm or fnm.
pnpm
Pepa uses pnpm as its package manager. If you have Node installed, you
already have corepack β just run:
corepack enable
corepack prepare pnpm@latest --activateOr install pnpm directly: npm install -g pnpm
Git
Check with git --version. Git ships with macOS and most Linux distros.
Windows users can get it from git-scm.com.
Set up Pepa
Clone the repository
Replace my-docs with whatever you want to call your project:
git clone https://github.com/your-org/pepa my-docs
cd my-docsWant to push your docs to your own GitHub repo later? Delete the .git
folder and run git init to start fresh with your own history.
Install dependencies
From inside the my-docs folder:
pnpm installThis installs everything in one shot β the Next.js app, the shared UI package, and all tooling.
Start the dev server
cd apps/docs
pnpm devOpen localhost:3000. You should see this page. Every change you make to an MDX file hot-reloads in the browser instantly.
Make it yours
Open apps/docs/pepa.config.ts. This is the one file that controls your
site's name and which top-level nav tabs are visible:
const config: PepaConfig = {
name: "my-docs", // β change this to your project name
sections: [
{ id: "docs", label: "Docs", href: "/getting-started", enabled: true },
{ id: "api-reference", label: "API Reference", href: "/api-reference", enabled: false }, // β enable when ready
{ id: "cookbook", label: "Cookbook", href: "/cookbook/overview", enabled: false },
],
// ...
}Save the file. The header updates immediately.
Write your first doc
Create a new file anywhere under apps/docs/content/docs/. The file path
becomes the URL. For example:
content/docs/introduction.mdx β localhost:3000/introduction
content/docs/api/auth.mdx β localhost:3000/api/auth
Paste this starter frontmatter and save:
---
title: My First Page
description: A short description shown under the title.
type: tutorial
section: docs
nav: Tutorials
order: 1
---
Hello, world! This is my first Pepa page.Your page appears in the sidebar immediately β no restart needed.
How the sidebar works
There is no nav config file. The sidebar is generated entirely from your frontmatter fields:
| Field | What it does |
|---|---|
section | Which top-level tab this page belongs to (docs, api-reference, cookbook, contributors) |
nav | The sidebar group label within that section (Tutorials, Reference, How-to Guides, etc.) |
order | Position within the group β lower numbers appear first |
navParent | Optional sub-section within a group, creates a collapsible nested group |
hidden: true | Keeps the page out of the sidebar (useful for landing pages) |
A page with nav: Reference and order: 2 will appear as the second item in
the "Reference" group. That's it β no other config needed.
To create a nested sub-section, add navParent: "Authentication" to any
page's frontmatter. It groups under a collapsible "Authentication" heading
inside whatever nav group the page belongs to.
How the project is organized
pepa/
βββ apps/
β βββ docs/
β βββ content/docs/ β Your MDX files live here
β βββ app/ β Next.js App Router pages and layouts
β βββ components/ β Sidebar, TOC, MDX renderer, top tabs
β βββ lib/ β nav.ts (builds the sidebar), vars.ts (text variables)
β βββ scripts/ β CLI tools: search index, find-replace sweep, llms.txt
β βββ openapi/ β Your OpenAPI spec (copied to public/ at build time)
β βββ pepa.config.ts β Site name, enabled sections, feature flags
β
βββ packages/
βββ ui/
βββ src/ β Shared components: Callout, Tabs, Steps, Tiles, etc.
βββ snippets/ β Reusable content blocks (edit once, updates everywhere)
The only folder you'll spend most of your time in is content/docs/. Everything
else can stay as-is until you want to customize deeper.
Writing in MDX
MDX is Markdown with superpowers. Everything you already know from Markdown works exactly the same β headings, bold, lists, code blocks, links. MDX just lets you drop in React components when you need richer content.
What does an MDX file look like?
---
title: How to Authenticate
description: Add bearer token auth to your API requests.
type: how-to
section: docs
nav: How-to Guides
order: 1
---
## Get your API key
Go to your dashboard and copy your key.
<Callout type="warning">
Never commit your API key to version control.
</Callout>
## Make your first request
```bash
curl https://api.example.com/v1/widgets \
-H "Authorization: Bearer YOUR_API_KEY"
```Which components can I use?
All components are globally available β no import statements needed. Just use them directly:
| Component | What it's for |
|---|---|
<Callout type="tip"> | Tips, warnings, notes, danger alerts |
<Steps><Step title="..."> | Numbered step sequences |
<Tabs><Tab label="..."> | Multi-tab content (great for multi-language code) |
<Tiles><Tile title="..."> | Card grids for navigation or feature overviews |
<Accordion><AccordionItem title="..."> | Collapsible sections |
<Kbd>βK</Kbd> | Keyboard shortcut styling |
<Var name="productName" /> | Text variables (edit in lib/vars.ts) |
See every component in action on the Feature Showcase page.
What's the difference between all the `type` values?
The type field follows the DiΓ‘taxis framework β a
way of thinking about what kind of content a page is:
- tutorial β Learning-oriented. Teaches by doing. ("Build your first X")
- how-to β Task-oriented. Solves a specific problem. ("How to do X")
- reference β Information-oriented. Facts and specs. ("The X field acceptsβ¦")
- explanation β Understanding-oriented. Answers "why". ("Why Pepa works this way")
You can also use quickstart, cookbook, faq, glossary, changelog,
or migration for special content types. The type value doesn't change
how the page renders β it's there to help you think clearly about what
you're writing.
Build and deploy
When you're ready to publish:
pnpm buildThis runs the full pipeline: validates all frontmatter, compiles MDX, generates
the search index, and exports a static site into apps/docs/out/. Upload that
folder to any static host.
If you're deploying to GitHub Pages at a path like
https://you.github.io/my-docs/, uncomment the basePath line in
apps/docs/next.config.ts and set it to /my-docs.
Why the schema is your friend
Every MDX file is validated against a schema before the build runs. If you delete a required field or typo a value, the build fails immediately with a clear error pointing at the exact file β instead of silently shipping a broken page.
Try it: delete the title field at the top of this file and save. Watch the
terminal. Then add it back.
You're editing a live example. This page is at
apps/docs/content/docs/getting-started.mdx. Saving any change here
hot-reloads in the browser and re-validates against the schema. It's a safe
place to experiment.
Where to go next
Wire up your OpenAPI spec and get an auto-generated, interactive API explorer.
Short, copy-pasteable recipes for common documentation patterns.
Full reference for every component, snippet, and text variable available in MDX.
A single page demoing every component side-by-side. Good for copy-pasting.