# Nx Documentation Site [](https://starlight.astro.build) The Nx documentation site built with Astro and Starlight, featuring advanced content management through Markdoc and dynamic plugin documentation generation. ## Architecture Overview This documentation site leverages Astro's static site generation capabilities with Starlight for documentation-specific features. The architecture consists of: ### Core Technologies - [**Astro**](https://docs.astro.build) - Static site generator with island architecture - [**Starlight**](https://starlight.astro.build) - Documentation theme with built-in navigation, search, and i18n - **React** - For implementing UI components - **Netlify** - Deployment and hosting ### Key Features - [Markdoc](https://markdoc.dev) with custom tags for rich content such as videos, graphs, etc. - TailwindCSS for styling in Astro and React components - Dynamic API documentation generation from Nx packages and CLI commands - Community plugin registry ## Information Architecture Principles When creating or reorganizing documentation, follow these 5 principles to determine where content belongs. ### 1. Progressive Disclosure (The "Journey" Rule) - **Concept:** Don't overwhelm the user. Reveal complexity only as they advance in their journey. - **The Test:** _Is this for the First 30 Minutes (Getting Started), the First 30 Days (Features), or Forever (Reference)?_ ### 2. Category Homogeneity (The "Scan" Rule) - **Concept:** Items in a list must be of the same "type" (noun, verb, or concept) to reduce cognitive load. - **The Test:** _Does this list mix Concepts (Mental Model), Tasks (Update Nx), and Products (React)? If yes, split it._ ### 3. Type-Based Navigation (The "Intent" Rule) - **Concept:** Separate **Learning** (Narrative/Guides) from **Looking Up** (Reference/API). - **The Test:** _Is the user here to learn a workflow (Guide) or look up a flag syntax (Reference)?_ ### 4. The Pen & Paper Test (The "Theory" Rule) - **Concept:** Distinguish Architecture from Features to keep "Core Concepts" pure. - **The Test:** _Can I explain this using only a pen and paper?_ - **Yes:** It goes in **How Nx Works** (Architecture). - **No (I need a terminal):** It goes in **Platform Features** (Feature). ### 5. Universal vs. Specific (The "Placement" Rule) - **Concept:** Distinguish Platform features from Ecosystem tools to prevent "Features" from becoming a junk drawer. - **The Test:** _Does this feature apply to EVERY user (e.g., Caching, Agents)?_ - **Yes:** **Platform Features**. - **No (Only React users):** **Technologies**. ### Sidebar Structure The sidebar has 4 top-level sections that follow the user journey: 1. **Getting Started** - Essential setup, tutorials, and core concepts (How Nx Works, Platform Features) 2. **Technologies** - Framework and tool-specific guides (React, Angular, Node, build tools, test tools) 3. **Knowledge Base** - Recipes, troubleshooting, and topic-specific guides 4. **Reference** - Exhaustive facts, no narrative (CLI commands, configuration, API docs) ## Project Structure ``` astro-docs/ ├── src/ │ ├── assets/ # Images and static assets to be optimized by Astro │ │ ├── nx/ # Nx branding assets │ │ ├── nx-cloud/ # Nx Cloud assets │ │ └── nx-console/ # Nx Console assets │ ├── components/ # React and Astro components │ │ ├── layout/ # Layout components (e.g. Sidebar) │ │ ├── markdoc/ # Markdoc tag components │ │ └── utils/ # Utility functions │ ├── content/ # Documentation content │ │ ├── banner.json # Banner collection (generated by prebuild-banner) │ │ ├── docs/ # Main documentation files (.mdoc, .mdx) │ │ └── approved-community-plugins.json # Powers plugin registry │ ├── pages/ # Dynamic pages and routes (e.g. devkit) │ ├── plugins/ # Content loaders and plugins │ │ ├── *.loader.ts # Dynamic content loaders (e.g. CLI commands and API docs generation) │ │ └── utils/ # Plugin utilities │ └── styles/ # Global styles ├── public/ # Static assets not to be optimized by Astro (fonts, robots.txt) ├── astro.config.mjs # Astro configuration ├── markdoc.config.mjs # Markdoc tags configuration ├── sidebar.mts # Sidebar structure definition └── package.json ``` ## Plugins and Loaders ### Content Loaders The site uses custom content loaders to dynamically generate documentation: - **PluginLoader** (`plugin.loader.ts`) - Generates official plugin documentation (generators, executors, migrations) - **CommunityPluginsLoader** (`community-plugins.loader.ts`) - Generates data for plugin registry (e.g. GitHub stars, npm downloads) - **NxReferencePackagesLoader** (`nx-reference-packages.loader.ts`) - Generated data for CNW, Devkit, nx cli (e.g. nx core related things) ## Content Management ### Content Types 1. **Regular Documentation** (`src/content/docs/`) - Written in `.mdoc` (Markdoc) or `.mdx` (MDX) format - Organized by sections: getting-started, concepts, guides, api - File-based routing (filename = URL path) 2. **Dynamic Plugin Documentation** - Auto-generated from Nx packages - Includes generators, executors, and migrations - Updated during build process - **Note**: Requires a rebuild and restart to reflect changes 3. **CLI Documentation** - Auto-generated from Nx CLI commands - Parsed from actual CLI implementation - **Note**: Requires a rebuild and restart to reflect changes ### Markdoc Tags The site includes custom Markdoc tags for rich content. **Note**: Starlight supports many Markdown and Markdoc features, such as code blocks, asides, etc. - https://starlight.astro.build/components/using-components/#using-a-component-in-markdoc - https://starlight.astro.build/guides/authoring-content #### Layout & Organization - `{% aside %}` - Highlighted information boxes - `{% cardgrid %}`, `{% card|linkcard %}` - Card layouts - `{% tabs %}`, `{% tabitem label="some-label" %}` - Tab layouts - Use the `syncKey` so tabs are auto switched to the users preference if it makes sense. - e.g. `{% tabs syncKey="package-manager" %}` #### Interactive Components - `{% graph %}` - Interactive project/task graph visualization - `{% project_details %}` - Project configuration viewer #### Media & Embeds - `{% youtube %}` - YouTube video embeds - `{% video_player %}` - Custom video player - `{% iframe %}` - Generic iframe embeds #### Developer Tools - `{% github_repository %}` - GitHub repo cards - `{% stackblitz_button %}` - StackBlitz demo launcher - `{% install_nx_console %}` - IDE extension installer #### Content Enhancement - `{% badge %}` - Status/label pills - `{% metrics %}` - Metrics display - `{% testimonial %}` - Customer testimonials ## Development Workflow ### Getting Started ```bash # Install dependencies and link workspace packages # This will build Nx packages as well for API docs nx serve astro-docs # Or run astro dev directly # This will not build Nx packages cd astro-docs npx astro dev # Custom ports (useful for AI agents with git worktrees) npx astro dev --port 3000 ``` ### Adding New Content #### Regular Documentation 1. Create `.mdoc` file in `src/content/docs/` 2. Add frontmatter with title and description 3. Use Markdoc tags for rich content 4. File location determines URL structure Example: ```markdown --- title: 'My New Guide' description: 'Learn how to use this feature' --- # Introduction {% aside type="note" title="Important" %} This is a note about the feature. {% /aside %} ``` #### Adding Custom Markdoc Tags 1. Create Astro component in `src/components/markdoc/` 2. (Optional) Create React component for more complex components, or ones that need to be shared with blog or non-docs pages 3. Register in `markdoc.config.mjs` 4. Define attributes and validation ### Updating Plugin Documentation Plugin documentation is auto-generated during build. To update: 1. Make changes to the plugin's schema/implementation 2. Run the build process 3. The loader will automatically fetch and generate updated docs ### Sidebar Management The sidebar structure is defined in `sidebar.mts`. To add new sections: ```javascript export const sidebar = [ { label: 'Section Name', items: [ { label: 'Page Title', link: 'path/to/page', }, // Nested sections { label: 'Subsection', collapsed: true, items: [...] } ] } ]; ``` > Note there is a special case for sidebar items appearing in the sidebar. Such as the `Reference` section which is handled via the `[sidebar-reference-updater](./src/plugins/sidebar-reference-updater.middleware.ts)` middleware. ## Styling and Theming - Uses Tailwind CSS v4 with Vite plugin - Global styles in `src/styles/global.css` - Component-specific styles use Tailwind utilities - Dark/light mode support built into Starlight and customized in `global.css` ## Configuration Files ### `astro.config.mjs` - Site configuration - Integration setup (React, Markdoc, Starlight) - Vite plugins - Build options ### `markdoc.config.mjs` - Custom tag definitions - Attribute validation - Component mappings ### `sidebar.mts` - Navigation structure - Section organization - Dynamic content injection points ## Banner Configuration The floating banner promotes events/webinars. It's fetched at **build time** from a Framer CMS page and stored as an Astro content collection. ### Setup Set `BANNER_URL` to point to a Framer page that renders banner JSON: ``` BANNER_URL=https://your-framer-site.framer.app/api/banners/main ``` The Framer page should render JSON inside a `
` tag:
```json
{
"title": "Event Title",
"description": "Event description",
"primaryCtaUrl": "https://...",
"primaryCtaText": "Learn More",
"secondaryCtaUrl": "",
"secondaryCtaText": "",
"enabled": true,
"activeUntil": "2025-12-31T00:00:00.000Z"
}
```
### Schema
| Field | Type | Required | Description |
| ------------------ | -------- | -------- | ------------------------- |
| `title` | string | Yes | Banner headline |
| `description` | string | Yes | Banner body text |
| `primaryCtaUrl` | string | Yes | Primary button URL |
| `primaryCtaText` | string | Yes | Primary button text |
| `secondaryCtaUrl` | string | No | Secondary button URL |
| `secondaryCtaText` | string | No | Secondary button text |
| `enabled` | boolean | Yes | Show/hide the banner |
| `activeUntil` | ISO 8601 | No | Auto-hide after this date |
### Behavior
- Banner is fetched during `prebuild-banner` target and saved to `src/content/banner.json` as a collection (array)
- Uses Astro content collection with `file()` loader and schema validation
- Requires rebuild/redeploy to update the banner
- Users can dismiss the banner (stored in localStorage)
- If `enabled` is `false` or `activeUntil` has passed, the banner won't show
- If `BANNER_URL` is not set, an empty collection is generated
## Versioned Docs
When a new major Nx version is released (or about to be released), create a versioned snapshot of the docs site so the previous version remains accessible at `{major}.nx.dev` (e.g. `22.nx.dev`).
### Creating a Version Snapshot
```bash
node ./scripts/create-versioned-docs.mts 22
```
This will:
1. Fetch tags from origin, find the latest stable release for that major (e.g. `22.6.4`)
2. Checkout that tag, install deps, and build the docs site
3. Create an orphan git branch `22` containing only the pre-built static site plus minimal scaffolding (root `package.json`, `nx.json`, `pnpm-lock.yaml`, `netlify.toml`, and a no-op `nx-dev` project) so Netlify's configured build command succeeds instantly
4. Return to your original branch
If no stable tags exist for that major version, it builds from the current branch.
For Nx 21+, the script builds `astro-docs` (Astro/Starlight). For legacy Nx 18–20, it builds `nx-dev` (Next.js with static export) — this path will be removed once those versions are no longer maintained.
#### Flags
- `--force` — overwrite an existing local/remote `{major}` branch
- `--redirect-to-prod` — skip the build and produce a branch that 301s every path to `https://nx.dev/docs`. Used to retire an old versioned subdomain (e.g. `16.nx.dev`) without maintaining its docs
```bash
# Retire an old versioned site
node ./scripts/create-versioned-docs.mts 16 --redirect-to-prod
```
### Pushing the Branch
```bash
git push -f origin 22
```
### Deployment Setup
Versioned sites are served via Netlify branch deploys of the main `nx-dev` Netlify site, with custom domains managed in Squarespace.
- **Netlify** — each `{major}` branch is deployed as a [branch deploy](https://docs.netlify.com/site-deploys/overview/#branch-deploy-controls) of the `nx-dev` site. The branch's root `netlify.toml` overrides the UI build settings so Netlify serves the pre-built static files (no rebuild, no `@netlify/plugin-nextjs`). Add the branch to the site's branch deploy allowlist, then add `{major}.nx.dev` as a domain alias pointing at the branch deploy
- **Squarespace** — DNS for `nx.dev` is managed in Squarespace. Add a CNAME for `{major}` pointing at the Netlify branch deploy hostname