How to Document a Monorepo
Best practices for documenting monorepos. Structure your root README, package READMEs, and shared documentation for large codebases.
Monorepos are powerful but hard to navigate without good documentation. When dozens of packages live in one repository, developers need clear guidance on what's where, how things connect, and how to contribute. Here's how to document a monorepo effectively.
The root README
The root README is the entry point. It should answer: "What is this repository, what's in it, and how do I get started?"
# acme-platform
Monorepo for the Acme platform. Contains the web app, API server,
shared libraries, and infrastructure config.
## Packages
| Package | Description | Version |
|---------|-------------|---------|
| [@acme/web](./packages/web) | Next.js web application | 2.1.0 |
| [@acme/api](./packages/api) | Express API server | 1.8.0 |
| [@acme/ui](./packages/ui) | Shared React components | 3.0.0 |
| [@acme/utils](./packages/utils) | Shared utilities | 1.2.0 |
| [@acme/config](./packages/config) | ESLint, TypeScript configs | 1.0.0 |
## Getting Started
\`\`\`bash
git clone https://github.com/acme/platform.git
cd platform
pnpm install
pnpm dev
\`\`\`
## Architecture
See [docs/architecture.md](./docs/architecture.md) for system design.Key elements
- Package table — Every package with a description and link to its directory
- Single setup command — One
pnpm installfrom the root, not per-package setup - Architecture link — Pointer to deeper design docs
- Dependency graph — Optional but helpful for complex monorepos
Package-level READMEs
Every package directory should have its own README covering:
- What the package does — Independent of the monorepo context
- Installation — How to use it (if published to npm)
- API/Usage — The package's public interface
- Development — How to work on this specific package
# @acme/ui
Shared React component library for Acme products.
## Usage
\`\`\`tsx
import { Button, Card } from "@acme/ui";
export function App() {
return (
<Card>
<Button variant="primary">Click me</Button>
</Card>
);
}
\`\`\`
## Development
\`\`\`bash
# From repo root
pnpm --filter @acme/ui dev # Start dev server
pnpm --filter @acme/ui test # Run tests
pnpm --filter @acme/ui build # Build for production
\`\`\`
## Components
| Component | Description |
|-----------|-------------|
| Button | Primary, secondary, and ghost variants |
| Card | Container with glass morphism styling |
| Input | Form input with validation states |The docs/ folder
For anything that doesn't fit in a README, use a docs/ folder at the root:
docs/
├── architecture.md # System design and data flow
├── deployment.md # How to deploy each package
├── contributing.md # Contribution guidelines
├── adr/ # Architecture Decision Records
│ ├── 001-monorepo.md
│ ├── 002-shared-ui.md
│ └── 003-api-versioning.md
└── guides/
├── adding-a-package.md
└── database-migrations.mdArchitecture Decision Records (ADRs)
ADRs document why decisions were made. They're invaluable in monorepos where architectural choices affect multiple packages:
# ADR 002: Shared UI Component Library
## Status: Accepted
## Context
Multiple packages duplicate UI components. Changes need
to be applied in multiple places.
## Decision
Create @acme/ui as a shared component library.
All packages import from this single source.
## Consequences
- Single place to update component styles
- Breaking changes affect all consumers
- Need versioning strategy for the packageDependency documentation
In a monorepo, understanding how packages depend on each other is critical:
## Dependency Graph
\`\`\`
@acme/web ──→ @acme/ui ──→ @acme/utils
│ ↑
└──→ @acme/api ────────────┘
│
└──→ @acme/config
\`\`\`Tools like Nx and Turborepo can generate dependency graphs automatically.
Common scripts
Document the top-level scripts in your root README or a dedicated file:
## Scripts
| Command | Description |
|---------|-------------|
| `pnpm dev` | Start all packages in development mode |
| `pnpm build` | Build all packages |
| `pnpm test` | Run all tests |
| `pnpm lint` | Lint all packages |
| `pnpm --filter @acme/web dev` | Start only the web app |
| `pnpm changeset` | Create a changeset for versioning |Versioning and changelogs
For published packages, use Changesets to manage versioning:
- Each PR that changes a package includes a changeset file
- Changesets are accumulated and released together
- Each package gets its own CHANGELOG.md
Tips for maintainability
- Automate the package table. Use a script to regenerate the root README's package table from
package.jsonfiles. - Enforce README existence. Add a CI check that every package directory has a README.
- Link between packages. If
@acme/webuses@acme/ui, the web README should link to the UI README. - Keep docs close to code. Package-specific docs live in the package directory, not in the root
docs/. - Review docs in PRs. If a PR changes a package's public API, it should update that package's README.
Generate your monorepo README
ReadmeBot can generate READMEs by analysing your repository structure, which works well for individual packages within a monorepo. For monorepo-specific guidance, check our monorepo README template.
You can also score your existing README against best practices to find quick improvements across all your packages.