Welcome! This is the repo for Directus' documentation.
- Node.js 22.18 or later
- pnpm
pnpm installCopy the example environment file:
cp .env.example .envUpdate the environment variables in the .env file with proper secret keys for the different
services.
Start the development server on http://localhost:3000:
pnpm devpnpm buildThe repository includes scripts that keep docs routes stable when files move and that index the docs into Typesense.
pnpm stable-ids:ensure # Add missing stableId frontmatter
pnpm stable-ids:check # Validate stableId frontmatter
pnpm redirects:sync # Update redirects.json for moved pages
pnpm redirects:check # Check redirect coverage without writing files
pnpm index:docs # Build the search index in Typesense
pnpm typesense:cleanup-preview # Delete stale Typesense preview indexes
pnpm typecheck:scripts # Type check repository scriptsStable IDs give each public docs page a permanent identity. Nuxt Content derives
its unique page IDs from file paths, so moving a page changes its built-in ID.
Redirect sync compares the current branch to origin/main, so moved pages keep
their old URLs working.
CI runs pnpm stable-ids:check and pnpm redirects:check for docs changes.
- New docs page: run
pnpm stable-ids:ensure, then commit the newstableId. - Moved docs page: keep the existing
stableId, runpnpm redirects:sync, then commitredirects.json. - Deleted, split, or merged docs page: run
pnpm redirects:sync, review.docs/redirect-decisions-needed.md, choose target redirects, then re-runpnpm redirects:check. - Before opening a PR: run
pnpm stable-ids:checkandpnpm redirects:check.
Redirect scripts compare against origin/main by default. To check a release branch
or another target, fetch it first, then pass --base directly to the script:
git fetch origin release/v13
node scripts/redirects-sync.ts --base origin/release/v13 --no-write --fail-on-unresolved
node scripts/redirects-sync.ts --base origin/release/v13 --write-deterministic --fail-on-unresolvedPages live as Markdown files under content/. Frontmatter fields are validated by the schema in content.config.ts.
Framework guides live under content/frameworks/<framework>/. The numeric prefix on filenames (01., 02., …) controls sidebar sort order only — it has no semantic meaning, renumber freely.
The section frontmatter field controls grouping on the /frameworks/<framework> hub page:
section: start-here— appears in the "Start Here" block at the top.section: guides(or unset) — appears in the "Guides" block below.
Minimal frontmatter for a new framework guide:
---
title: Fetch Data from Directus with Foo
description: Learn how to integrate Directus in your Foo app.
section: start-here
technologies:
- foo
navigation:
title: Data Fetching
---The documentation automatically deploys to Vercel when changes are merged into the main branch. Simply:
- Open a Pull Request with your changes
- This should trigger a deploy preview as well.
- Once PR is approved and merged to main, Vercel will automatically build and deploy the updated documentation
- Community Platform (Questions, Live Discussions)
- GitHub Issues (Report Bugs)
- Roadmap (Roadmap & Feature Requests)
Search is powered by Typesense. The browser palette (UCommandPalette-based) lives at app/components/DocsSearchPalette.vue and queries Typesense directly via app/services/typesenseService.ts. The official typesense npm client is used by the indexer only.
The indexer at scripts/index-docs.ts walks /content, chunks each Markdown page, attaches synonyms, and pushes everything to Typesense. OpenAPI indexing is deferred to a later branch. Run it locally with:
pnpm index:docsCI runs the same command on every push to main (production index) and on every PR commit (per-branch preview index). See .github/workflows/search-index.yml.
Indexes use a blue/green slot pattern with a stable alias:
main-> aliasdirectus-docs, slotsdirectus-docs-a/directus-docs-b- Branch
bry/foo-> aliasdirectus-docs-preview-bry-foo, slots...-a/...-b - Local branch runs use the same branch-derived alias as CI
Each indexer run writes to whichever slot the alias is not currently pointing at, swaps the alias, then deletes the previous slot.
For one-off writes, override the index target with TYPESENSE_INDEX_TARGET=....
The browser reads from TYPESENSE_COLLECTION when set. Otherwise it derives the same branch alias as the indexer. The app reads the alias, never the -a / -b slot name.
PR preview indexes are deleted when same-repo PRs close. The cleanup job deletes the branch alias and both fixed slots:
pnpm typesense:cleanup-preview --branch bry/fooFor one-time cleanup of accumulated preview indexes, run a dry run first:
pnpm typesense:cleanup-preview --stale --dry-run
pnpm typesense:cleanup-preview --staleStale cleanup keeps preview aliases for currently open PR branches and deletes the rest. It requires TYPESENSE_URL, TYPESENSE_PRIVATE_API_KEY, and authenticated gh.
Section boosts and personalization live in buildPersonalizedSortBy in app/composables/useDocsSearch.ts. The same sectionPriority array drives both the Typesense _eval boost order and the chip-bar render order in the palette.
Search synonyms live in server/data/synonyms.ts and are pushed to Typesense on every indexer run. Two formats: multiway (equivalent terms) and oneway (directional shorthand -> canonical, e.g. db -> database). Header comment in the file explains both.
Write H2s and first paragraphs so they work as standalone search results.
© 2004-2024, Monospace, Inc.
