# Content linter Source: https://www.mintlify.com/github/docs/content/content-linter How to run the GitHub Docs content linter, what it checks, and how to fix or suppress lint errors. The GitHub Docs content linter enforces style guide rules in Markdown source files. It runs automatically before every commit and in CI, and you can also run it manually at any time. ## How it works The linter uses [markdownlint](https://github.com/DavidAnson/markdownlint) as its framework. On top of the standard markdownlint rules, GitHub Docs adds custom rules that check Markdown and Liquid syntax specific to this repository. Rules are defined in four layers: * **Native markdownlint rules** — configured in `src/content-linter/style/base.ts` * **GitHub markdown linters** — from [markdownlint-github](https://github.com/github/markdownlint-github) * **Search-replace checks** — simple string/regex patterns in `src/content-linter/style/github-docs.ts` * **Custom docs rules** — individual files in `src/content-linter/lib/linting-rules/` Custom rule IDs use the `GHD###` format (for example, `GHD038`). Rules from markdownlint use the `MD###` format (for example, `MD011`). ## Severity levels Every rule has one of two severities: | Severity | Effect | | --------- | ----------------------------------------------------------------------------- | | `error` | Prevents the commit from completing. Must be fixed before merging. | | `warning` | Reported but does not block a commit or merge. Should be fixed when possible. | Most rules start as warnings and are promoted to errors once existing violations are resolved across the content. ## Running the linter ### Automatically on pre-commit When you commit staged files from the command line, the linter runs automatically via a pre-commit hook (powered by `lint-staged`). Both warnings and errors are reported, but only errors prevent the commit from completing. If errors are reported, fix them, re-add the changed files, and commit again. When editing files in the GitHub UI, the pre-commit hook does not run. CI will still report any `error`-severity violations. ### Manually on staged and changed files Run the linter on all files you have staged or changed: ```shell theme={null} npm run lint-content ``` To report only `error`-severity violations (skip warnings): ```shell theme={null} npm run lint-content -- --errors ``` ### On specific files or directories Run the linter on one or more specific paths. Separate multiple paths with a space: ```shell theme={null} npm run lint-content -- \ --paths content/actions/creating-actions/about-custom-actions.md content/get-started ``` ### Auto-fix errors Some rules are fixable automatically. When a rule has `fixable: true` in its description, you can apply fixes automatically. Fix staged and changed files: ```shell theme={null} npm run lint-content -- --fix ``` Fix specific files or directories: ```shell theme={null} npm run lint-content -- \ --fix --paths content/FILENAME.md content/DIRECTORY ``` ### Run specific rules To test a particular rule or set of rules, pass their names with `--rules`. You can use either the short name (`MD001`) or the long name (`heading-increment`): ```shell theme={null} npm run lint-content -- \ --rules heading-increment code-fence-line-length ``` Run specific rules on specific paths: ```shell theme={null} npm run lint-content -- \ --rules image-alt-text-length image-no-gif \ --paths content/actions ``` ### View all options ```shell theme={null} npm run lint-content -- --help ``` ## What the linter checks The custom rules in `src/content-linter/lib/linting-rules/` cover these categories: * `image-alt-text-end-punctuation` — Alt text must end with punctuation. * `image-alt-text-exclude-start-words` — Alt text must not start with "Image" or "Graphic." * `image-alt-text-length` — Alt text must be between 40 and 150 characters. * `image-file-kebab-case` — Image filenames must use kebab-case. * `image-no-gif` — Animated GIFs are not allowed in the docs. * `internal-links-no-lang` — Internal links must not include a language code prefix like `/en/`. * `internal-links-old-version` — Internal links must not reference deprecated version paths. * `internal-links-slash` — Internal links must start with a forward slash. * `link-punctuation` — Punctuation must not be included inside link brackets. * `link-quotation` — Links must not be wrapped in quotation marks. * `liquid-data-tags` — Liquid `{% data %}` tags must reference valid data paths. * `liquid-ifversion-versions` — `{% ifversion %}` conditions must use valid version names. * `liquid-quoted-conditional-arg` — Liquid conditional arguments must not be quoted. * `liquid-syntax` — Liquid tags must be syntactically valid. * `liquid-tag-whitespace` — Liquid tags must have proper internal whitespace. * `liquid-versioning` — Liquid versioning blocks must follow correct patterns. * `table-liquid-versioning` — Liquid versioning inside tables must be properly formed. * `frontmatter-schema` — Frontmatter must conform to the required schema. * `frontmatter-versions-whitespace` — Frontmatter version values must not have extraneous whitespace. * `frontmatter-curly-quotes` — Frontmatter must not contain curly quotes. * `frontmatter-content-type` — The `contentType` frontmatter field must use a valid content type. * `frontmatter-hidden-docs` — Hidden docs must follow the correct pattern. * `frontmatter-children` — The `children` frontmatter on index pages must be valid. * `frontmatter-hero-image` — Hero images on landing pages must meet requirements. * `frontmatter-intro-links` — Intro text must not contain links. * `frontmatter-landing-carousels` — Landing page carousel data must be valid. * `frontmatter-video-transcripts` — Video transcript frontmatter must be valid. * `code-annotation-comment-spacing` — Code annotation comments must have correct spacing. * `code-annotations` — Code annotation syntax must be valid. * `yaml-scheduled-jobs` — Scheduled workflow examples must not run on congested times (e.g., on the hour). * `third-party-action-pinning` — Third-party actions must be pinned to a full-length commit SHA. * `third-party-actions-reusable` — Third-party action disclaimers must use the approved reusable. * `github-owned-action-references` — First-party actions must use reusables instead of hardcoded version tags. * `hardcoded-data-variable` — Product names must use Liquid variables, not plain text strings. * `outdated-release-phase-terminology` — Release phase terms must use current approved language. * `early-access-references` — Early access content must not appear in public docs. * `journey-tracks-guide-path-exists` — Every guide path referenced in `journeyTracks` must exist. * `journey-tracks-liquid` — Journey track titles and descriptions must use valid Liquid syntax. * `journey-tracks-unique-ids` — Journey track `id` values must be unique within a page. * `rai-app-card-structure` — RAI app card components must follow the correct structure. * `rai-reusable-usage` — RAI content must use the approved reusables. * `table-column-integrity` — Table columns must have consistent widths and separators. * `table-liquid-versioning` — Liquid versioning inside tables must be properly formed. * `ctas-schema` — CTA frontmatter must conform to the required schema. * `expired-content` — Warns 14 days before an expiration date and flags content that has passed its expiration date. ## Tagging content with an expiration date When you must include content that will become outdated, wrap it in expiration HTML comments. The linter will warn you 14 days before the date and flag it for remediation on or after the date. ```markdown theme={null} This content does not expire. This content expires on June 30, 2025. This content also does not expire. ``` For content inside HTML tables, place the expiration tags around the entire row: ```html theme={null} macOS The macos-11 label is closing down after June 30, 2025. ``` ## Suppressing rules Occasionally you may need to document something that intentionally violates a lint rule. Suppress only the specific rules needed, not all rules. | Comment | Effect | | ----------------------------------------------- | ------------------------------------------ | | `` | Disable specific rule for the current line | | `` | Disable specific rule for the next line | | `` | Disable rule from this point | | `` | Re-enable the rule | | `` | Disable all rules from this point | | `` | Re-enable all rules | **Example:** Suppressing a false positive on a regular expression that looks like a reversed link: ```markdown theme={null} (^|/)[Cc]+odespace/ ``` For content inside a code block: ````markdown theme={null} ``` (^|/)[Cc]+odespace/ ``` ```` The `search-replace` plugin does not support disabling individual rules. To suppress a search-replace violation, disable the entire plugin with ``. ## Bypassing the pre-commit hook If the linter catches errors that you did not introduce (for example, in a file you only partially modified), you can bypass the git pre-commit hook with `--no-verify`: ```shell theme={null} git commit -m 'MESSAGE' --no-verify ``` Only bypass the hook when you are certain you did not introduce the flagged errors. Errors that are bypassed locally will still fail in CI. ## Custom rule locations | Location | Purpose | | ----------------------------------------------- | ------------------------------------------------ | | `src/content-linter/lib/linting-rules/` | Individual TypeScript files for each custom rule | | `src/content-linter/lib/linting-rules/index.ts` | Imports and exports all custom rules | | `src/content-linter/style/github-docs.ts` | Configures all rules, sets severities | | `src/content-linter/style/base.ts` | Configures native markdownlint rules | | `src/content-linter/tests/unit/` | Unit tests for custom rules | Rule IDs in the `GHD03X` range are candidates for upstreaming to the markdownlint community. # Content model Source: https://www.mintlify.com/github/docs/content/content-model How GitHub Docs is organized — content types, index pages, and the frontmatter that drives site navigation. The GitHub Docs site is built from Markdown files in the `/content` directory. Every page, category, and product follows a strict content model. Understanding that model lets you place new content correctly, wire up navigation, and choose the right layout from the start. ## Content types Every article has a `contentType` frontmatter field that declares what kind of content it is. The site uses this value to filter articles on product guides pages (when using `layout: product-guides`) and to apply the right structural expectations during linting. One of `get-started`, `concepts`, `how-tos`, `reference`, `tutorials`, `rai`, `landing`, `homepage`, or `other`. Introductory content for people who are new to a feature. Orientates the reader and links to next steps. Explains background knowledge — what something is and why it works the way it does. No step-by-step procedures. Task-based articles that walk the reader through completing a specific goal. Structured factual content: API parameters, configuration options, syntax tables. Designed to be scanned, not read linearly. End-to-end learning exercises with a concrete outcome. Longer than how-tos and include explanatory context. Responsible AI content. Only used for files that live in directories with `responsible-use` in the name. Product landing pages — only applies to `content//index.md` files. ## Index pages Every product, category, and map topic has an `index.md` file that acts as the landing page for that section. The `index.md` must declare a `children` array that lists every page directly nested under it. The site **only** knows about paths that appear in a `children` array. If a file exists in the `/content` directory but is not listed in a parent `index.md`, its URL returns 404. A typical category `index.md` looks like this: ```yaml theme={null} --- title: Managing your account and profile intro: You can manage information about yourself and your GitHub account. versions: fpt: '*' ghes: '*' ghec: '*' children: - /customizing-your-profile - /managing-your-personal-account-settings - /managing-subscription-and-notifications-on-github --- ``` The paths in `children` are relative to the current `index.md`. They point to either a subdirectory (which must itself have an `index.md`) or a `.md` file (written without the extension). ## Product landing pages A product landing page (`layout: product-landing`) is the main entry point for a top-level GitHub product such as Actions or Codespaces. In addition to `children`, these pages support `featuredLinks` to highlight key articles, and optionally `changelog` to pull recent entries from the GitHub Changelog. ```yaml theme={null} --- title: GitHub Actions shortTitle: GitHub Actions intro: Automate, customize, and execute your software development workflows right in your repository. layout: product-landing versions: fpt: '*' ghes: '*' ghec: '*' children: - /quickstart - /learn-github-actions - /using-workflows featuredLinks: gettingStarted: - /actions/quickstart startHere: - /actions/learn-github-actions/understanding-github-actions popular: - /actions/using-workflows/workflow-syntax-for-github-actions - /actions/using-workflows/events-that-trigger-workflows popularHeading: Most-used reference pages changelog: label: actions prefix: 'GitHub Actions: ' --- ``` ### featuredLinks sections | Key | Purpose | | ---------------- | ---------------------------------------------------------------------- | | `gettingStarted` | Links shown in the "Get started" column | | `startHere` | Links shown in the "Start here" column | | `guideCards` | Links displayed as guide cards | | `popular` | Links shown under the "Popular" heading (or a custom `popularHeading`) | | `videos` | Array of `{ title, href }` objects for a video section | ## The homepage The homepage (`content/index.md`) is the only file that uses `childGroups`. Where a normal index page lists children as a flat array, the homepage groups them into named sections displayed in the main content area. ```yaml theme={null} --- title: GitHub Docs versions: fpt: '*' ghes: '*' ghec: '*' children: - /get-started - /account-and-profile - /actions - /codespaces childGroups: - name: Get started icon: rocket children: - /get-started - name: CI/CD and DevOps icon: gear children: - /actions - /codespaces --- ``` Every path in a `childGroups.children` array must also appear in the top-level `children` array. ## Product guides pages A product guides page (for example, the [Actions guides page](https://docs.github.com/en/actions/guides)) uses `layout: product-guides` and renders a filterable list of articles. You can populate it two ways: * **`learningTracks`** — references named learning tracks defined in `data/learning-tracks/*.yml`. The featured track is configured in that YAML file. * **`includeGuides`** — an explicit list of article paths. Each article must have a `contentType` in its frontmatter for the filter UI to work. ```yaml theme={null} --- title: Guides layout: product-guides versions: fpt: '*' ghes: '*' ghec: '*' learningTracks: actions includeGuides: - /actions/guides/about-continuous-integration - /actions/guides/setting-up-continuous-integration-using-workflow-templates - /actions/guides/building-and-testing-nodejs --- ``` ## Journey pages Journey landing pages (`layout: journey-landing`) present a set of sequential learning paths. Each path is a `journeyTracks` entry with an `id`, a `title`, an optional `description`, and an ordered `guides` array. ```yaml theme={null} --- title: Learn GitHub Actions layout: journey-landing versions: fpt: '*' ghes: '*' ghec: '*' journeyTracks: - id: getting_started title: 'Getting started with {% data variables.product.prodname_actions %}' description: 'Learn the basics of GitHub Actions.' guides: - href: /actions/quickstart - href: /actions/learn-github-actions alternativeNextStep: 'Want to skip ahead? See [AUTOTITLE](/actions/using-workflows).' - href: /actions/using-workflows - id: advanced title: 'Advanced {% data variables.product.prodname_actions %}' guides: - href: /actions/using-workflows/workflow-syntax-for-github-actions - href: /actions/deployment/deploying-with-github-actions --- ``` The `alternativeNextStep` field renders a branch prompt beneath a step — useful when readers might want to skip ahead or take a different path through the material. It supports Liquid variables and `[AUTOTITLE]` links. ## How the site discovers pages The site build does not crawl the filesystem. It walks the `children` graph starting from `content/index.md`. Every reachable path becomes a valid URL; everything else does not exist from the site's perspective. This means: * Adding a new article requires both creating the `.md` file **and** listing it in the parent `index.md`. * Renaming or moving a file requires updating the `children` entry and adding a `redirect_from` entry on the new page. * Deleting a file requires removing it from `children` (and adding a redirect if the URL should remain accessible). # Filenames and directory structure Source: https://www.mintlify.com/github/docs/content/filenames-and-structure How the /content directory maps to URLs, filename conventions, index pages, link formats, and how to add new articles correctly. The `/content` directory is the single source of truth for all English Markdown content on the GitHub Docs site. Its directory structure maps directly to the URL structure of the published site. ## Directory layout ``` content/ ├── index.md # Homepage (docs.github.com/en) ├── get-started/ │ ├── index.md # docs.github.com/en/get-started │ ├── quickstart/ │ │ ├── index.md │ │ └── hello-world.md │ └── learning-about-github/ │ ├── index.md │ └── about-github-and-git.md ├── actions/ │ ├── index.md # docs.github.com/en/actions │ ├── quickstart.md │ └── using-workflows/ │ ├── index.md │ └── workflow-syntax-for-github-actions.md └── codespaces/ ├── index.md └── getting-started/ ├── index.md └── quickstart.md ``` Every directory that has child pages needs an `index.md`. That file becomes the landing page for the directory URL and declares the navigation via its `children` frontmatter. Directory names for categories and map topics can match either the `title` or `shortTitle` frontmatter of the `index.md` inside. ## Filename conventions Filenames are the [kebab-case](https://en.wikipedia.org/wiki/Letter_case#Kebab_case) equivalent of the article's `title` frontmatter. | Title frontmatter | Filename | | ------------------------------------- | ---------------------------------------- | | `About GitHub CLI` | `about-github-cli.md` | | `Getting started with GitHub Desktop` | `getting-started-with-github-desktop.md` | | `Workflow syntax for GitHub Actions` | `workflow-syntax-for-github-actions.md` | ### Handling punctuation and Liquid variables When a title contains punctuation, omit it from the filename: ``` title: "GitHub's Billing Plans" → githubs-billing-plans.md ``` When a title contains a Liquid variable, use the words the variable renders as: ``` title: 'About {% data variables.product.prodname_emus %}' → about-enterprise-managed-users.md ``` A test in CI validates that filenames and titles match. If the title legitimately cannot match the filename (for example, because it contains a Liquid variable), set [`allowTitleToDifferFromFilename: true`](/content/frontmatter#allowtitletodifferfromfilename) in frontmatter to suppress the check. ## The index.md pattern Every product, category, and map topic directory must contain an `index.md`. This file: * Renders as the landing page for that URL segment. * Declares every child page through the `children` frontmatter array. * Is the only mechanism through which the site discovers nested pages. If a `.md` file exists on disk but is not listed in a parent `index.md` `children` array, its URL returns **404**. The site build does not crawl the filesystem — it walks the `children` graph. A minimal `index.md`: ```yaml theme={null} --- title: Using workflows intro: You can create workflows to automate your software development life cycle processes. versions: fpt: '*' ghes: '*' ghec: '*' children: - /about-workflows - /triggering-a-workflow - /workflow-syntax-for-github-actions - /reusing-workflows --- ``` ## How content maps to URLs The path from `content/` to the file maps directly to the URL, with these rules: * The `/content` prefix is stripped. * File extensions (`.md`) are dropped. * `index.md` files become the bare directory URL. * On GitHub.com (`fpt`), the version segment (`free-pro-team@latest`) is removed from URLs automatically. | File path | Published URL | | ----------------------------------------------------------------------- | ---------------------------------------------------------------- | | `content/actions/index.md` | `/en/actions` | | `content/actions/quickstart.md` | `/en/actions/quickstart` | | `content/actions/using-workflows/index.md` | `/en/actions/using-workflows` | | `content/actions/using-workflows/workflow-syntax-for-github-actions.md` | `/en/actions/using-workflows/workflow-syntax-for-github-actions` | On GitHub Enterprise Server, a version segment is inserted: ``` /en/enterprise-server@3.12/actions/quickstart ``` ## Adding a new article Create a `.md` file in the appropriate directory. Name it as the kebab-case version of the article title. ``` content/actions/using-workflows/caching-dependencies-to-speed-up-workflows.md ``` Add at minimum `title` and `versions`. Add `contentType`, `intro`, and any other relevant fields. ```yaml theme={null} --- title: Caching dependencies to speed up workflows intro: To make your workflows faster and more efficient, you can create and use caches for dependencies and other commonly reused files. versions: fpt: '*' ghes: '>=3.5' ghec: '*' contentType: how-tos --- ``` Open the `index.md` in the same directory and add the new filename (without extension) to the `children` array. ```yaml theme={null} children: - /about-workflows - /triggering-a-workflow - /workflow-syntax-for-github-actions - /caching-dependencies-to-speed-up-workflows # ← new entry - /reusing-workflows ``` ## Link format requirements Links to other docs pages follow a strict format enforced by the build and validated in CI. ### Internal links Internal links must: * Start with the **product ID** (the first path segment under `/content`, e.g. `/actions`, `/codespaces`, `/admin`). * Include the **full filepath** to the target article. * Omit the file extension. ```markdown theme={null} [About GitHub Actions](/actions/learn-github-actions/understanding-github-actions) [About GitHub Actions](learn-github-actions/understanding-github-actions) [About GitHub Actions](/actions/learn-github-actions/understanding-github-actions.md) ``` The site's link rewriter (`src/content-render/unified/rewrite-local-links.ts`) adds the correct language code and version segment at render time. For example: ``` /actions/quickstart → /en/actions/quickstart (GitHub.com) → /en/enterprise-server@3.12/actions/quickstart (GHES 3.12) ``` ### AUTOTITLE for internal links Use the `AUTOTITLE` keyword instead of typing out link text manually. The site substitutes the target article's `title` frontmatter at render time, so link text stays accurate even if a title changes. ```markdown theme={null} For more information, see [AUTOTITLE](/actions/using-workflows). ``` `AUTOTITLE` only works on internal links. Use normal link text for external URLs. ### Linking to the same article in a different version To link from a `fpt` article to the equivalent `ghec` article: ```markdown theme={null} {% ifversion fpt %} For more information, see the [{% data variables.product.prodname_ghe_cloud %} documentation](/enterprise-cloud@latest/{{ currentArticle }}). {% endif %} ``` The `currentArticle` variable resolves to the path of the current page, so the link remains correct if the article URL changes. ### Preventing version transforms By default, internal links are rewritten to match the current version. To link to a specific version regardless of context (for example, to pin a link to GitHub.com from an Enterprise article), include the version in the path: ```markdown theme={null} [GitHub's Terms of Service](/free-pro-team@latest/github/site-policy/github-terms-of-service) ``` ### Image paths Image paths must start with `/assets` and include the full path with extension: ```markdown theme={null} ![Screenshot of the settings page](/assets/images/help/settings/settings-account-delete.png) ``` ## Whitespace control in Liquid When using Liquid conditionals inside Markdown lists or tables, extra blank lines break the rendering. Use the hyphen (`-`) whitespace control character to strip newlines adjacent to a Liquid tag. Without whitespace control, a versioned table row causes a rendering break: ``` Column A | Column B | Column C ---------|----------|--------- Row for all versions | B1 | C1{% ifversion ghes %} GHES-only row | B2 | C2{% endif %} Row for all versions | B3 | C3 ``` With whitespace control, the Liquid tag sits on its own line without introducing extra newlines: ``` Column A | Column B | Column C ---------|----------|--------- Row for all versions | B1 | C1 {%- ifversion ghes %} GHES-only row | B2 | C2 {%- endif %} Row for all versions | B3 | C3 ``` The `{%-` strips the newline to the **left** of the tag; `-%}` strips it to the **right**. You can apply them to one or both sides as needed. # Frontmatter reference Source: https://www.mintlify.com/github/docs/content/frontmatter Complete reference for every YAML frontmatter field recognized by the GitHub Docs site, with types, defaults, and examples. [YAML frontmatter](https://jekyllrb.com/docs/front-matter/) is a block of key-value metadata at the top of every Markdown file, delimited by `---`. The GitHub Docs site reads frontmatter to control rendering, navigation, versioning, and search behavior. The full schema is validated by the test suite. See [`src/frame/lib/frontmatter.ts`](https://github.com/github/docs/blob/main/src/frame/lib/frontmatter.ts) for the authoritative source. ```yaml theme={null} --- title: About GitHub CLI shortTitle: GitHub CLI intro: GitHub CLI is an open source tool for using GitHub from your computer's command line. versions: fpt: '*' ghes: '*' ghec: '*' contentType: concepts --- ``` `title` and `versions` are the only **required** fields. All other fields are optional unless otherwise noted. *** ## Core fields Sets the human-readable title rendered as the `

` at the top of the page and in the browser `` tag. Supports Liquid variables. ```yaml theme={null} title: 'About {% data variables.product.prodname_emus %}' ``` </ParamField> <ParamField type="string"> An abbreviated title used in breadcrumbs and sidebar navigation. Falls back to `title` if omitted. Maximum lengths by article type: | Article type | Max characters | | ------------ | -------------- | | Articles | 31 | | Categories | 27 | | Map topics | 30 | ```yaml theme={null} title: Contributing to projects with GitHub Desktop shortTitle: Contributing to projects ``` </ParamField> <ParamField type="string"> A short description of the page rendered directly after the `title`. Appears in search results and on parent index pages as the article summary. ```yaml theme={null} intro: Learn how to use GitHub CLI to interact with GitHub from your terminal. ``` </ParamField> <ParamField type="string"> A statement describing the access level required to perform the tasks in this article. Rendered after the `intro`. ```yaml theme={null} permissions: Organization owners can configure two-factor authentication requirements. ``` </ParamField> <ParamField type="string"> A product callout rendered after the `intro` and `permissions` statement. Use this to flag that a feature requires a specific GitHub plan. ```yaml theme={null} product: 'GitHub Codespaces is available for organizations using {% data variables.product.prodname_ghe_cloud %}.' ``` </ParamField> *** ## Versioning <ParamField type="object"> Declares which versions of GitHub this page applies to. Keys map to product plans; values are [SemVer ranges](https://semver.org/) or `'*'` (all releases). Recognized keys: | Key | Product | | ------ | ---------------------------- | | `fpt` | GitHub.com (Free, Pro, Team) | | `ghes` | GitHub Enterprise Server | | `ghec` | GitHub Enterprise Cloud | **All versions:** ```yaml theme={null} versions: fpt: '*' ghes: '*' ghec: '*' ``` **Enterprise Server only, all releases:** ```yaml theme={null} versions: ghes: '*' ``` **GitHub.com and GHES 2.20 or later:** ```yaml theme={null} versions: fpt: '*' ghes: '>=2.20' ``` **GHES 2.22 and 3.0 only:** ```yaml theme={null} versions: fpt: '*' ghes: '>=2.22 <3.1' ``` </ParamField> <ParamField type="string[]"> A list of old URLs that should redirect to this page. Add entries when you rename, move, or consolidate articles so existing links remain valid. ```yaml theme={null} redirect_from: - /articles/first-launch/ - /articles/error-github-enterprise-version-is-too-old/ - /articles/getting-started-with-github-for-windows/ ``` </ParamField> *** ## Layout and navigation <ParamField type="string"> Selects the page layout component. If omitted, the default article layout is used. | Value | Use | | ------------------ | ------------------------------ | | `product-landing` | Top-level product pages | | `product-guides` | Filterable guides index pages | | `category-landing` | Category overview pages | | `journey-landing` | Sequential learning path pages | | `release-notes` | Release notes pages | | `graphql-explorer` | Interactive GraphQL explorer | | `inline` | Minimal layout, no sidebar | | `false` | No layout wrapper | </ParamField> <ParamField type="string[]"> Lists the relative paths of all pages directly nested under this index page. Required on every `index.md` file. ```yaml theme={null} children: - /quickstart - /learn-github-actions - /using-workflows - /sharing-automations ``` <Warning> If a page is not listed in `children`, its URL returns 404 — even if the file exists on disk. </Warning> </ParamField> <ParamField type="array"> Groups children into named sections on the homepage. Only valid in `content/index.md`. Each entry has a `name`, an optional `icon`, and a `children` array whose values must also appear in the top-level `children` field. ```yaml theme={null} childGroups: - name: Get started icon: rocket children: - /get-started - name: CI/CD and DevOps icon: gear children: - /actions - /codespaces ``` </ParamField> <ParamField type="object"> Renders highlighted article links on product landing pages and the homepage. Supported sub-keys: | Sub-key | Type | Description | | ---------------- | ------------------- | --------------------------------------------------- | | `gettingStarted` | `string[]` | Links in the "Get started" column | | `startHere` | `string[]` | Links in the "Start here" column | | `guideCards` | `string[]` | Links shown as guide cards | | `popular` | `string[]` | Links under the "Popular" heading | | `popularHeading` | `string` | Custom heading to replace "Popular" | | `videos` | `{ title, href }[]` | Video links with custom heading via `videosHeading` | ```yaml theme={null} featuredLinks: gettingStarted: - /actions/quickstart startHere: - /actions/learn-github-actions/understanding-github-actions popular: - /actions/using-workflows/workflow-syntax-for-github-actions - /actions/using-workflows/events-that-trigger-workflows popularHeading: Most-used reference pages ``` </ParamField> *** ## Table of contents <ParamField type="boolean"> Controls whether the auto-generated "In this article" mini TOC appears above the article body. Defaults to `true` on articles and `false` on map topics and `index.md` pages. Set to `false` to suppress the mini TOC on a specific article: ```yaml theme={null} showMiniToc: false ``` <Note> Do not add a hardcoded "In this article" section manually — the page will show duplicate TOCs. </Note> </ParamField> *** ## Content classification <ParamField type="string"> Declares the article type. Used to filter articles on product guides pages when `layout: product-guides` is set. Allowed values: `get-started`, `concepts`, `how-tos`, `reference`, `tutorials`, `rai`, `landing`, `homepage`, `other`. ```yaml theme={null} contentType: how-tos ``` </ParamField> *** ## Platform and tool defaults <ParamField type="string"> Overrides the initial platform tab selection. Without this field, the platform that matches the reader's operating system is shown. Use `linux` for articles about GitHub Actions runners, which are OS-independent from the reader's perspective. Allowed values: `mac`, `windows`, `linux`. ```yaml theme={null} defaultPlatform: linux ``` </ParamField> <ParamField type="string"> Overrides the initial tool tab selection. Without this field, the GitHub web UI (`webui`) is selected. User preferences override this default once a reader clicks a tool tab. Allowed values: `webui`, `cli`, `desktop`, `curl`, `codespaces`, `vscode`, `importer_cli`, `graphql`, `powershell`, `bash`, `javascript`. ```yaml theme={null} defaultTool: cli ``` </ParamField> *** ## Product guides and learning tracks <ParamField type="string[]"> Renders a list of learning tracks on a product's sub-landing page. References learning track names defined in `data/learning-tracks/*.yml`. Only applicable with `layout: product-guides`. ```yaml theme={null} learningTracks: - actions ``` </ParamField> <ParamField type="string[]"> An explicit list of article paths to include in a product guides page. Each article must have a `contentType` for the filter UI to work. Only applicable with `layout: product-guides`. ```yaml theme={null} includeGuides: - /actions/guides/about-continuous-integration - /actions/guides/setting-up-continuous-integration-using-workflow-templates - /actions/guides/building-and-testing-nodejs - /actions/guides/building-and-testing-powershell ``` </ParamField> <ParamField type="array"> Defines journey tracks for `layout: journey-landing` pages. Each track has an `id`, a `title`, an optional `description`, and a `guides` array. Each guide entry requires an `href` and accepts an optional `alternativeNextStep`. ```yaml theme={null} journeyTracks: - id: getting_started title: 'Getting started with {% data variables.product.prodname_actions %}' description: 'Learn the basics of GitHub Actions.' guides: - href: /actions/quickstart - href: /actions/learn-github-actions alternativeNextStep: 'Want to skip ahead? See [AUTOTITLE](/actions/using-workflows).' - href: /actions/using-workflows - id: advanced title: 'Advanced {% data variables.product.prodname_actions %}' guides: - href: /actions/using-workflows/workflow-syntax-for-github-actions - href: /actions/deployment/deploying-with-github-actions ``` </ParamField> *** ## Changelog integration <ParamField type="object"> Renders a "What's new" feed on product landing pages by pulling recent entries from [GitHub Changelog](https://github.blog/changelog/). Education pages pull from `https://github.blog/category/community/education` instead. | Sub-key | Required | Description | | -------- | -------- | ------------------------------------------------------------ | | `label` | Yes | Matches labels used in the GitHub Changelog | | `prefix` | No | String prefix to strip from each changelog title in the feed | ```yaml theme={null} changelog: label: actions prefix: 'GitHub Actions: ' ``` With `prefix: 'GitHub Actions: '`, a changelog entry titled "GitHub Actions: Reusable workflows are now GA" renders as "Reusable workflows are now GA" in the docs feed. </ParamField> *** ## Miscellaneous <ParamField type="boolean"> When `true`, suppresses the linter check that flags mismatches between a page's `title` frontmatter and its filename. Use this when the title contains Liquid variables or punctuation that cannot appear in a filename. For example, a page with `title: 'About {% data variables.product.prodname_emus %}'` must be named `about-enterprise-managed-users.md`. Set `allowTitleToDifferFromFilename: true` to prevent test failures. ```yaml theme={null} allowTitleToDifferFromFilename: true ``` </ParamField> <ParamField type="object"> Overrides the "Ask the GitHub community" link in the page footer with a custom name and URL. Properties: `name` (string) and `href` (string). ```yaml theme={null} communityRedirect: name: GitHub Education Community href: https://github.com/orgs/community/discussions/categories/github-education ``` </ParamField> *** ## Escaping single quotes YAML uses single quotes to wrap frontmatter strings. To include a literal single quote inside a single-quoted string, double it: ```yaml theme={null} title: 'GitHub''s Billing Plans' ``` Alternatively, switch the outer delimiter to double quotes: ```yaml theme={null} title: "GitHub's Billing Plans" ``` # Images and media Source: https://www.mintlify.com/github/docs/content/images-and-media How to add, store, format, and version screenshots, diagrams, and videos in GitHub Docs. GitHub Docs uses static images—screenshots, diagrams, and graphs—to complement written instructions. Videos are used rarely and only when they provide information that cannot be conveyed well in text. This page covers where images and videos live, how to format them, and the quality standards they must meet. ## When to add a screenshot Screenshots make articles more visually scannable and help readers locate UI elements. However, they increase page load time, require ongoing maintenance, and can be confusing when captured at different zoom levels than the reader is using. Add a screenshot only when a UI element is genuinely difficult to find: <CardGroup> <Card title="Add a screenshot when..." icon="check"> * The element is small or visually subtle (for example, a small edit button with no visible label). * The element is not immediately visible—for example, it is inside a dropdown menu. * The interface has multiple competing choices that could cause confusion (for example, three different elements that could all be interpreted as "Settings"). </Card> <Card title="Do not add a screenshot when..." icon="x"> * Text instructions alone make the step clear. * The UI element is visually prominent through size, color, and placement. * You are showing a command or its output—use a code block instead. * The interface shows only simple options like a single checkbox. </Card> </CardGroup> ## Screenshot technical requirements | Requirement | Specification | | -------------- | -------------------------------------------------------- | | File format | PNG only. No GIFs. | | Resolution | 144 dpi | | Width | 750–1000 pixels for full-column images | | File size | 250 KB or less | | Naming | Kebab-case, descriptive: `data-pack-purchase-button.png` | | macOS captures | Must be retina images | Screenshots captured on macOS: in Snagit, go to **Snagit** > **Preferences** > **Advanced** and deselect "Scale down retina images when sharing." ## Screenshot visual style * Show just enough surrounding context to help readers find the element on screen. * Resize your browser window to reduce negative space. * Use light theme whenever possible. * For GitHub: select "Light default" in your appearance settings. * For VS Code: select "GitHub light default" from the GitHub Theme extension. * If your username and avatar appear, replace them with `@octocat`'s username and avatar (`https://avatars.githubusercontent.com/u/583231?v=4`) using browser developer tools. * Do not include a cursor in the screenshot. ### Showing dropdown menus * If your goal is to show the reader where the menu is, show the menu **closed**. * If your goal is to help the reader distinguish between options inside the menu, show the menu **open** and without focus (no cursor or hover state). ## Highlighting elements To draw attention to a specific UI element, use the GitHub Docs Snagit theme to apply a dark orange contrasting stroke around the element. * Color: `fg.severe` from the Primer Design System (HEX `#BC4C00`, RGB `188, 76, 0`) * Corner rounding: 4 px * Spacing: gap between UI element and stroke should be approximately equal to the stroke width <Steps> <Step title="Download the Snagit theme"> Navigate to `snagit-theme-github-docs.snagtheme` in the `github/docs` repository and download it. </Step> <Step title="Import into Snagit"> Open Snagit, select the **Shape** tool, then select **Import** under "Quick styles" and choose the downloaded theme file. </Step> <Step title="Apply the highlight"> Open a screenshot in Snagit, select the dark orange rectangle from the Shapes sidebar, and drag across the UI element you want to highlight. Adjust the size by dragging edges. </Step> <Step title="Set resolution and export"> In the "Resize image" dialog, set pixel depth to 144 dpi and pixel width to 1000 px maximum, then export as PNG. </Step> </Steps> ## Alt text Every image must have alt text. Alt text is read by screen readers and appears when an image fails to load. **Rules for alt text:** * Express the core idea or meaning of the image, not a literal description. * Use 40–150 characters. * End with a punctuation mark (usually a period). * Do not start with "Image…" or "Graphic…"—screen readers announce this automatically. * Begin with the type of graphic: "Screenshot of…" or "Diagram that shows…" * Put multi-word UI element names in double quotation marks inside the alt text. * Describe any visual highlighting: "…is outlined in dark orange." **Format for screenshot alt text:** > Screenshot of the `Product name` + `UI element` shown. The `UI element` + `state of element/controls`, and its `keyboard shortcut XYZ`, are outlined in dark orange. **Examples:** ```markdown theme={null} ![Screenshot of the GitHub committers by repository table. The horizontal kebab icon and "Download CSV report" button are outlined in dark orange.](/assets/images/billing/download-csv.png) ![Screenshot of file options in a GitHub repository. A button with an arrow indicating a dropdown menu, labeled "Code," is outlined in dark orange.](/assets/images/contributing/repository-code-button.png) ![Diagram showing a five-step process by which a GitHub Actions runner can be automatically added to named classes of runners and then requested by specific jobs.](/assets/images/actions/arc-runner-scale-sets.png) ``` **For diagrams and graphs:** explain the information conveyed by the diagram in the article text, and use alt text to express the core idea without duplicating the page text. **For command-line interface screenshots:** do not use screenshots to show commands and their output. Instead, use code blocks. Only use CLI screenshots when showing UI elements in a terminal application. ## Image file names Use descriptive names that include the feature name, action, and UI element. Mirror product language. Use kebab-case. Do not use Liquid conditionals in file names. | Use | Avoid | | --------------------------------- | --------------------- | | `data-pack-purchase-button.png` | `purchase_button.png` | | `actions-workflow-run-status.png` | `screenshot1.png` | When replacing an existing image, keep the existing filename. If you must rename an image, search the repository for all references to the old filename and update them. ## Image storage Images live in the `/assets/images/` directory. The directory structure organizes images by product version. ``` /assets/images/ ├── (images for all plans) ├── enterprise/ │ ├── enterprise-server/ (images for all GHES releases or current+future) │ ├── 3.10/ (images that apply to GHES 3.10 and earlier only) │ ├── 3.9/ │ └── ... ``` | Directory | Usage | | ---------------------------------------------- | ------------------------------------------------------------ | | `/assets/images/` | Images not specific to any enterprise product | | `/assets/images/enterprise/enterprise-server/` | Images for all GHES releases, or current and future releases | | `/assets/images/enterprise/3.10/` | Images that apply to GHES 3.10 and earlier only | Image paths in Markdown must start with `/assets` and include the full path with file extension: ```markdown theme={null} ![Alt text.](/assets/images/help/settings/settings-account-delete.png) ``` ## Versioning images When an image is the same across all GitHub plans, no versioning is needed. When it differs by plan or GHES release, use Liquid conditionals. ### Versioning by plan ```markdown theme={null} {% ifversion fpt or ghec %} ![An image of foo bar for GitHub Free, Pro, Team, and Enterprise Cloud.](/assets/images/foo/bar.png) {% else %} ![An image of foo bar for GitHub Enterprise Server.](/assets/images/enterprise/foo/bar.png) {% endif %} ``` ### Versioning by GHES release If an image changes in GHES 3.10, move the existing image to `/assets/images/enterprise/3.10/` and place the new image at the original path. Then add a Liquid conditional: ```markdown theme={null} {% ifversion fpt or ghec %} ![Image for GitHub.com.](/assets/images/foo/bar.png) {% elsif ghes < 3.10 %} ![Image for GHES 3.9 and earlier.](/assets/images/enterprise/3.10/foo/bar.png) {% else %} ![Image for GHES 3.10 and later.](/assets/images/enterprise/foo/bar.png) {% endif %} ``` When a GHES release is retired, its numbered directory is removed from `/assets/images/enterprise/`. ## Videos Videos are used rarely in GitHub Docs. When included, they supplement written text—they never replace it. Videos must be owned by GitHub and must be well-produced. ### When to use a video <Note> The Docs team does not create or maintain video content. Videos are purely supplemental and are not a content type owned by the Docs team. </Note> Use the following checklist before adding any video: * Is the video the only effective way to communicate the information? * Does GitHub own the video? * Is the video well produced (professional narration, clear visuals, trusted source)? * Is it accessible to the broadest group of users? * Is it less than five minutes long? * Does it have a specific audience and purpose? If the answer to any of these is "no," the video is not suitable for GitHub Docs. ### Video types | Type | Purpose | Max length | Placement | | ---------------- | -------------------------------------------------------- | ------------------------------------------ | ------------------------------------------------ | | Product overview | Show what the product does and get people interested | Under 1 minute | Landing pages, guides | | Feature video | Supplement conceptual or procedural content | 5 minutes | Guides, conceptual articles, procedural articles | | Tutorial | Help novice users get started; explain complex workflows | 5 min per video, 15 min total for a series | Guides | ### Accessibility requirements A video cannot be added to GitHub Docs unless it meets all of these requirements: * No flashing or strobe effects * Closed captions (human-generated or proofread auto-captions) * No graphics overlapping where captions appear * Legible typography * Sufficient contrast on any overlays * Text on screen long enough to be read twice before it disappears * A proofread descriptive transcript (scene-by-scene description of audio and visual content) * Videos do not autoplay ### Video hosting Videos must be hosted on a platform GitHub owns and controls. Currently, GitHub's videos are hosted on YouTube. Embed videos using YouTube's Privacy Enhanced Mode by replacing the domain: ```markdown theme={null} <!-- Standard URL (do not use) --> https://www.youtube.com/embed/VIDEO_ID <!-- Privacy Enhanced Mode (use this) --> https://www.youtube-nocookie.com/embed/VIDEO_ID ``` ### Adding video frontmatter For landing pages with an embedded video, add these properties to the YAML frontmatter: ```yaml theme={null} title: Example product landing page product_video: 'https://www.youtube-nocookie.com/embed/VIDEO_ID' product_video_transcript: /content/video-transcripts/transcript-example-video ``` ### Transcripts Every video linked or embedded in GitHub Docs must have a descriptive transcript. Transcripts are stored as articles in `content/video-transcripts/` with filenames like `transcript-VIDEO-NAME.md`. Transcript frontmatter: ```yaml theme={null} title: Transcript - VIDEO NAME product_video: 'https://www.youtube-nocookie.com/embed/VIDEO_ID' ``` A transcript includes: * All spoken words (do not paraphrase) * Speaker identification when there are multiple speakers * Descriptions of relevant visual elements and non-speech sounds in brackets: `[Background music plays.]` * `End of transcript.` at the end, followed by a link to the product landing page Do not use Liquid variables or reusables in transcripts—the text must faithfully reflect what is spoken in the video. ### Versioning videos If a video applies only to specific GitHub plans, version it with Liquid conditionals: ```markdown theme={null} {% ifversion ghec %} [Embed video for GitHub Enterprise Cloud] {% endif %} ``` # Links and redirects Source: https://www.mintlify.com/github/docs/content/links-and-redirects How to format internal and external links in GitHub Docs, and how to configure redirects when content moves. GitHub Docs uses specific link formats to ensure links stay accurate across versions and languages. This page covers how to write internal and external links, how the server transforms links at render time, and how to set up redirects when content moves. ## Internal links Links to other pages within GitHub Docs must follow a specific format so the server can apply the correct language and version prefix automatically. **Rules for internal links:** * Start with a product ID: `/actions/...`, `/admin/...`, `/get-started/...` * Include the entire filepath from the product root * Do not include the file extension (`.md` or `.mdx`) * Do not include a language prefix (`/en/`) or version prefix (`/enterprise-server@3.10/`) ```markdown theme={null} <!-- Correct --> [AUTOTITLE](/actions/creating-actions/about-custom-actions) [AUTOTITLE](/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax) <!-- Incorrect – includes file extension --> [AUTOTITLE](/actions/creating-actions/about-custom-actions.md) <!-- Incorrect – includes language prefix --> [AUTOTITLE](/en/actions/creating-actions/about-custom-actions) ``` ### AUTOTITLE Use `AUTOTITLE` as the link text for all internal links to other articles. At render time, the server replaces `AUTOTITLE` with the article's current title, so the link text stays accurate even when titles change. ```markdown theme={null} For more information, see [AUTOTITLE](/actions/writing-workflows/about-workflows). For more information, see [AUTOTITLE](/actions/writing-workflows/about-workflows#triggering-a-workflow). ``` <Note> `AUTOTITLE` does not work for same-page section links. When linking to a section on the same page, write the full header text manually. ```markdown theme={null} For more information, see [Preventing transformations](#preventing-transformations), later in this article. ``` </Note> ### Linking to specific sections To link to a section heading in another article, append the anchor to the path: ```markdown theme={null} For more information, see [AUTOTITLE](/contributing/style-guide-and-content-model/style-guide#alerts). ``` When linking to two or more specific sections in the same article, name the article at the end: ```markdown theme={null} See [Heading one](/path/to/article#section-one) and [Heading two](/path/to/article#section-two) in "Article title." ``` ### Linking to a specific tool If a link goes to an article with a tool switcher and you want to pre-select a specific tool, add the `?tool=` query parameter and indicate the tool in surrounding text: ```markdown theme={null} For more information, see the GitHub CLI documentation in [AUTOTITLE](/issues/tracking-your-work-with-issues/using-issues/creating-an-issue?tool=cli). ``` ## How the server transforms internal links When GitHub Docs renders a page, all internal links undergo transformations in `src/content-render/unified/rewrite-local-links.ts`. A link written as: ``` /actions/creating-actions/about-custom-actions ``` Renders on GitHub.com with the language code prepended: ``` /en/actions/creating-actions/about-custom-actions ``` Renders on GitHub Enterprise Server with both the language code and version: ``` /en/enterprise-server@3.10/actions/creating-actions/about-custom-actions ``` This is why internal links must not include language or version prefixes—they are applied automatically based on the reader's context. ### Preventing transformations To prevent a link from being Enterprise-ified (for example, when linking to a Dotcom-only article from Enterprise content), include the preferred version in the path: ```markdown theme={null} [GitHub's Terms of Service](/free-pro-team@latest/github/site-policy/github-terms-of-service) ``` With the version explicitly included, the server does not apply an automatic version prefix. ### Linking to the current article in a different version When you want to link to the same article in a different product version, use the `currentArticle` property instead of hardcoding the path. This ensures the link keeps working even if the article URL changes: ```markdown theme={null} {% ifversion fpt %} Organizations that use GitHub Enterprise Cloud can choose to allow publicly or privately published sites. For more information, see [the GitHub Enterprise Cloud documentation](/enterprise-cloud@latest/{{ currentArticle }}). {% endif %} ``` To link to a different article in a specific version: ```markdown theme={null} For more information, see [ARTICLE TITLE](/) in the VERSION documentation. ``` To link to the same article in a specific version: ```markdown theme={null} For more information, see [the VERSION documentation](/VERSION/{{ currentArticle }}). ``` ## External links For links to pages outside GitHub Docs, use standard Markdown link syntax with the full page title and destination site name. Do not put the link in quotation marks. ```markdown theme={null} <!-- Correct --> See [Add subtitles and captions](https://support.google.com/youtube/answer/2734796) in the YouTube documentation. <!-- Incorrect – missing site name --> See [Add subtitles and captions](https://support.google.com/youtube/answer/2734796). <!-- Incorrect – uses generic anchor text --> See [the YouTube docs](https://support.google.com/youtube/answer/2734796). ``` It is not necessary to link to an external product's website simply because you mention the product by name. ### External sites that are not rewritten Some external URLs are registered in `src/redirects/lib/external-sites.json`. Links to these sites are not rewritten by the server. The file stores key-value pairs where the key is the old internal path and the value is the external destination: ```json theme={null} { "/github-status": "https://www.githubstatus.com/", "/articles/github-security": "https://github.com/security" } ``` ## Link formatting rules * Do not repeat the same link more than once in the same article. * Do not include punctuation marks inside hyperlink brackets. * Do not use inline links where words in a sentence are hyperlinked without additional context. This pattern is difficult to translate and read. * Do not apply styling (bold, italics) to links or wrap them in quotation marks. ```markdown theme={null} <!-- Correct --> OAuth2 tokens can be acquired programmatically. For more information, see [AUTOTITLE](/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps). <!-- Incorrect – inline link, punctuation inside brackets --> Read [more about OAuth2.](/apps/building-integrations/setting-up-and-registering-oauth-apps/) ``` Introduce links with "For more information, see" or "see" when context makes the purpose of the link obvious. Link text should be the article title. ## Legacy filepaths and redirects for links GitHub Docs contains many links that use legacy filepaths like `/article/article-name` or `/github/article-name`, and links that reference articles by old names. These links work because of redirects, but they are technically bugs. When you add a new link, always use the current filepath and article name—not a legacy path. ## Configuring redirects for moved content When an article's title, location, or version changes, create a redirect so existing bookmarks and external links continue to work. ### Redirecting across files (same version) If you rename or move an article and want the old URL to redirect to the new one for all versions, add `redirect_from` to the new article's frontmatter: ```yaml theme={null} --- title: Creating your first commit redirect_from: - /content/get-started/all-about-commits --- ``` The `redirect_from` value is the old path without the content directory prefix or file extension. Multiple old paths can be listed: ```yaml theme={null} redirect_from: - /articles/first-launch - /articles/error-github-enterprise-version-is-too-old - /articles/getting-started-with-github-for-windows ``` ### Automatic version redirects If a URL is entered without a version (`https://docs.github.com/ARTICLE`), the site automatically redirects to the first available version in this order of precedence: 1. Free, Pro, or Team (`fpt`) 2. GitHub Enterprise Cloud (`ghec`) 3. GitHub Enterprise Server (`ghes`) So if an article is only available in `ghec` and `ghes`, `https://docs.github.com/ARTICLE` redirects to the Enterprise Cloud version automatically. ### Redirecting across versions When you want a URL for one version to redirect to a different version (or to a different page entirely), update `src/redirects/lib/static/redirect-exceptions.txt`. Each entry lists the destination path (with version), followed by an indented list of source paths: ```text theme={null} /enterprise-cloud@latest/organizations/managing-membership-in-your-organization/exporting-member-information-for-your-organization - /enterprise-server@3.3/organizations/managing-membership-in-your-organization/exporting-member-information-for-your-organization - /enterprise-server@3.4/organizations/managing-membership-in-your-organization/exporting-member-information-for-your-organization - /enterprise-server@3.5/organizations/managing-membership-in-your-organization/exporting-member-information-for-your-organization ``` Use this when, for example, you remove the `fpt` version of an article and want it to redirect to a version lower in the precedence order rather than `ghec`. ### Redirecting to external sites When content moves entirely outside GitHub Docs, add an entry to `src/redirects/lib/external-sites.json`: ```json theme={null} { "/github-status": "https://www.githubstatus.com/", "/articles/github-security": "https://github.com/security" } ``` <Warning> External redirects should be rare. Prefer keeping content on the docs site where possible. </Warning> ## Preserving links with anchors If you know external resources link to a specific section of an article, add an HTML anchor to preserve the link even if the heading text changes: ```markdown theme={null} <!-- Anchor to maintain the current example link. --> <a name="section-title-that-might-change"></a> ## New section title ``` Use an HTML comment to explain why the anchor is present so future contributors do not remove it. ## Quick reference <AccordionGroup> <Accordion title="Internal link to another article"> ```markdown theme={null} [AUTOTITLE](/product/category/article-name) ``` </Accordion> <Accordion title="Internal link to a section in another article"> ```markdown theme={null} [AUTOTITLE](/product/category/article-name#section-heading) ``` </Accordion> <Accordion title="Link to same article in a different version"> ```markdown theme={null} {% raw %}[the GitHub Enterprise Cloud documentation](/enterprise-cloud@latest/{{ currentArticle }}){% endraw %} ``` </Accordion> <Accordion title="External link"> ```markdown theme={null} [Page title](https://external-site.com/path/to/page) in the External Site documentation. ``` </Accordion> <Accordion title="Redirect from an old path (frontmatter)"> ```yaml theme={null} redirect_from: - /old/path/to/article ``` </Accordion> <Accordion title="Prevent Enterprise version transformation"> ```markdown theme={null} [GitHub's Terms of Service](/free-pro-team@latest/github/site-policy/github-terms-of-service) ``` </Accordion> </AccordionGroup> # Liquid helpers in GitHub Docs Source: https://www.mintlify.com/github/docs/content/liquid-helpers Reference for all custom Liquid tags available in GitHub Docs content files, including data, versioning, octicons, tool switchers, and platform switchers. GitHub Docs extends the standard [Liquid](https://shopify.github.io/liquid/) templating language with a set of custom tags. These tags are processed server-side before Markdown rendering and power versioning, reusable content, icon rendering, and UI interactions like tool and platform switchers. ## `{% data %}` — variables and reusables The `{% data %}` tag inserts content from files in the `data/` directory. It is the primary mechanism for both variable substitution and reusable content inclusion. ```liquid theme={null} {% data variables.product.prodname_actions %} {% data reusables.repositories.navigate-to-repo %} ``` See [Reusables and variables](/content/reusables-and-variables) for the full reference. ## `{% ifversion %}` — version conditionals The `{% ifversion %}` tag conditionally renders content based on the product version the reader is currently viewing. It supports `{% elsif %}`, `{% else %}`, and must be closed with `{% endif %}`. ### Syntax ```liquid theme={null} {% ifversion VERSION_EXPRESSION %} Content for matching versions. {% elsif OTHER_EXPRESSION %} Content for these versions instead. {% else %} Content for all other versions. {% endif %} ``` ### Version identifiers | Identifier | Product | | ---------- | ---------------------------- | | `fpt` | GitHub.com (free, pro, team) | | `ghes` | GitHub Enterprise Server | | `ghec` | GitHub Enterprise Cloud | ### Combining conditions ```liquid theme={null} {% ifversion fpt or ghec %} This appears on GitHub.com and GitHub Enterprise Cloud. {% endif %} ``` ```liquid theme={null} {% ifversion ghes >= 3.6 %} This appears on GitHub Enterprise Server 3.6 and later. {% endif %} ``` ```liquid theme={null} {% ifversion ghes < 3.10 %} This appears on older GitHub Enterprise Server releases. {% endif %} ``` ### Real-world example From `content/account-and-profile/concepts/account-management.md`: ```liquid theme={null} {% ifversion ghes < 3.21 %} ## About converting your personal account Converting a personal account into an organization allows you to move to a shared account where a large number of people can collaborate. {% else %} ## About moving your work to an organization You can move repositories and projects from your personal account to an organization while keeping your personal account intact. {% endif %} ``` ## `{% octicon %}` — inline icons The `{% octicon %}` tag renders an [Octicon](https://primer.style/foundations/icons/) inline within the text. This is used to reference the same icons that appear in the GitHub UI, so documentation can match what readers see on screen. ### Syntax ```liquid theme={null} {% octicon "ICON-NAME" aria-label="ACCESSIBLE LABEL" %} {% octicon "ICON-NAME" aria-hidden="true" aria-label="LABEL" %} ``` ### Examples ```liquid theme={null} Click {% octicon "mark-github" aria-label="The github octocat logo" %} in the upper-left corner. Select {% octicon "three-bars" aria-label="Open global navigation menu" %} at the top left of any page. Click {% octicon "kebab-horizontal" aria-label="Show workflow options" %} to open the dropdown. Use {% octicon "filter" aria-hidden="true" aria-label="filter" %} **Filter** to narrow results. ``` <Note> Always provide either `aria-label` or both `aria-hidden="true"` and `aria-label`. Octicons used purely for decoration should use `aria-hidden="true"` so screen readers skip them. </Note> ## Tool switcher tags Tool tags display content selectively based on which tool the reader has selected. The reader can switch between tools using tabs that appear above the first tool-tagged section on the page. ### Available tool tags | Tag | Tool | | ------------------------------------------ | ------------------------ | | `{% webui %}` / `{% endwebui %}` | GitHub.com web interface | | `{% cli %}` / `{% endcli %}` | GitHub CLI (`gh`) | | `{% desktop %}` / `{% enddesktop %}` | GitHub Desktop | | `{% curl %}` / `{% endcurl %}` | cURL (REST API calls) | | `{% codespaces %}` / `{% endcodespaces %}` | GitHub Codespaces | | `{% vscode %}` / `{% endvscode %}` | Visual Studio Code | | `{% graphql %}` / `{% endgraphql %}` | GraphQL API | | `{% powershell %}` / `{% endpowershell %}` | PowerShell | | `{% bash %}` / `{% endbash %}` | Bash | | `{% javascript %}` / `{% endjavascript %}` | JavaScript | ### Example From `content/actions/how-tos/manage-workflow-runs/disable-and-enable-workflows.md`: ```liquid theme={null} ## Disabling a workflow {% webui %} {% data reusables.repositories.navigate-to-repo %} {% data reusables.repositories.actions-tab %} 1. In the left sidebar, click the workflow you want to disable. 1. Click {% octicon "kebab-horizontal" aria-label="Show workflow options" %} and click **Disable workflow**. {% endwebui %} {% cli %} To disable a workflow, use the `workflow disable` subcommand. gh workflow disable WORKFLOW {% endcli %} ``` ### Setting the default tool By default the web UI tab is selected. To change the initial tool selection for a page, set `defaultTool` in the frontmatter: ```yaml theme={null} defaultTool: cli ``` The reader's last explicit selection takes precedence over `defaultTool` for the rest of their session. ## Platform switcher tags Platform tags display content selectively based on the reader's operating system. GitHub Docs detects the reader's OS and selects the matching platform tab automatically. ### Available platform tags | Tag | Platform | | ------------------------------------ | -------- | | `{% mac %}` / `{% endmac %}` | macOS | | `{% windows %}` / `{% endwindows %}` | Windows | | `{% linux %}` / `{% endlinux %}` | Linux | ### Example From `content/actions/how-tos/manage-runners/larger-runners/use-larger-runners.md`: ```liquid theme={null} {% linux %} {% data reusables.actions.run-jobs-larger-runners %} {% endlinux %} {% windows %} {% data reusables.actions.run-jobs-larger-runners %} {% endwindows %} {% mac %} To run jobs on macOS larger runners, update the `runs-on` key in your workflow YAML to use one of the GitHub-defined labels for macOS runners. {% endmac %} ``` ### Setting the default platform If the reader's OS is not the right default for a given page (for example, a page about GitHub Actions runners where Linux is almost always the relevant platform), override it with `defaultPlatform`: ```yaml theme={null} defaultPlatform: linux ``` ## Callout tags Callouts render styled alert boxes in the published page. The GitHub Docs source uses Liquid-style callout tags; these map to styled blockquotes in the rendered output. <Note> Modern GitHub Docs articles use the GFM alert syntax (`> [!NOTE]`, `> [!WARNING]`, `> [!TIP]`) as an alternative to Liquid callout tags. Both syntaxes are supported. </Note> ### Note ```liquid theme={null} {% note %} **Note:** Scheduled workflows only run on the default branch. {% endnote %} ``` Equivalent GFM syntax: ```markdown theme={null} > [!NOTE] > Scheduled workflows only run on the default branch. ``` ### Warning ```liquid theme={null} {% warning %} **Warning:** Deleting a repository is permanent and cannot be undone. {% endwarning %} ``` Equivalent GFM syntax: ```markdown theme={null} > [!WARNING] > Deleting a repository is permanent and cannot be undone. ``` ### Tip ```liquid theme={null} {% tip %} **Tip:** You can use `gh repo clone` to clone a repository using the GitHub CLI. {% endtip %} ``` ## Whitespace control Liquid tags introduce newlines into the rendered output. Inside Markdown lists and tables, extra blank lines break the list or table structure. Use a hyphen immediately inside the tag delimiters to strip the adjacent whitespace. | Syntax | Effect | | ------------- | ------------------------------------ | | `{%- tag %}` | Strip whitespace **before** the tag. | | `{% tag -%}` | Strip whitespace **after** the tag. | | `{%- tag -%}` | Strip whitespace on **both sides**. | ### Example: versioning a list item ```liquid theme={null} 1. Clone the repository. {%- ifversion ghes %} 1. Configure your enterprise hostname. {%- endif %} 1. Open a pull request. ``` Without `{%-`, a blank line appears before "Configure your enterprise hostname," which breaks the ordered list numbering. ### Example: versioning a table row ```markdown theme={null} | Feature | Status | |---|---| | Code scanning | Available | {%- ifversion ghes >= 3.5 %} | Secret scanning | Available | {%- endif %} | Dependabot alerts | Available | ``` ## `indented_data_reference` When a reusable needs to appear inside an ordered list, use `indented_data_reference` instead of `{% data %}` so the list indentation is preserved: ```markdown theme={null} 1. Navigate to your repository. {% indented_data_reference reusables.repositories.actions-tab spaces=3 %} 1. Select the workflow. ``` The `spaces` argument specifies how many spaces to prepend to each line of the reusable content. # Markdown and Liquid in GitHub Docs Source: https://www.mintlify.com/github/docs/content/markdown-and-liquid An overview of GitHub Flavored Markdown, Liquid templating, frontmatter, links, images, and whitespace control used in GitHub Docs content files. GitHub Docs content files are written in [GitHub Flavored Markdown](https://github.github.com/gfm/) (GFM) with [Liquid](https://shopify.github.io/liquid/) templating layered on top. Every `.md` file in the `content/` directory can use the full GFM feature set plus a set of custom Liquid tags that handle versioning, reusable content, and UI interactions. ## Frontmatter Every content file begins with a YAML frontmatter block delimited by `---`. The frontmatter provides metadata that controls how the page is rendered, which versions it appears in, and how it appears in navigation. ```yaml theme={null} --- title: About GitHub Actions shortTitle: About Actions intro: 'Use {% data variables.product.prodname_actions %} to automate, customize, and execute your software development workflows right in your repository.' permissions: '{% data reusables.actions.actions-permissions %}' versions: fpt: '*' ghes: '>=3.0' ghec: '*' defaultTool: cli defaultPlatform: linux redirect_from: - /articles/about-github-actions contentType: concepts --- ``` ### Required and common fields | Field | Required | Description | | ----------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | `title` | Yes | Page title rendered as an `<h1>` and in the browser tab. | | `versions` | Yes | Controls which product versions include the page. See [Versioning](/content/versioning). | | `shortTitle` | No | Abbreviated title used in breadcrumbs and navigation. Maximum 31 characters for articles. | | `intro` | No | Summary sentence rendered beneath the title. | | `permissions` | No | Permission statement rendered after the intro. | | `defaultTool` | No | Initial tool tab selection. One of: `webui`, `cli`, `desktop`, `curl`, `codespaces`, `vscode`, `graphql`, `powershell`, `bash`, `javascript`. | | `defaultPlatform` | No | Initial platform tab selection. One of: `mac`, `windows`, `linux`. | | `redirect_from` | No | Array of legacy URLs that redirect to this page. | | `contentType` | No | Article type: `get-started`, `concepts`, `how-tos`, `reference`, `tutorials`. | <Note> The `versions` frontmatter field is **required** on every page. Omitting it will cause test failures. See [Versioning](/content/versioning) for the full syntax. </Note> ### Escaping single quotes in frontmatter YAML requires escaping single quotes inside single-quoted strings by doubling them: ```yaml theme={null} # Two single quotes in a row escape the apostrophe title: 'GitHub''s Billing Plans' # Alternatively, switch to double quotes title: "GitHub's Billing Plans" ``` ### The `allowTitleToDifferFromFilename` field If a page title contains Liquid variables or punctuation that cannot appear in a filename, set this flag to `true` to suppress test failures: ```yaml theme={null} title: 'About {% data variables.product.prodname_emus %}' allowTitleToDifferFromFilename: true ``` ## GitHub Flavored Markdown GitHub Docs supports the full [GFM spec](https://github.github.com/gfm/), including: * Fenced code blocks with language identifiers * Tables * Task lists * Strikethrough * Autolinks * Footnotes Code blocks should always include a language identifier: ````markdown theme={null} ```yaml versions: fpt: '*' ghes: '>=3.0' ``` ```` ## Liquid templating Liquid is a templating language processed server-side before the Markdown is rendered. GitHub Docs uses [liquidjs](https://liquidjs.com/) with several custom tags. ### Available tags | Tag | Purpose | | -------------------------------------------- | -------------------------------------------------------------------- | | `{% data %}` | Insert a variable or reusable content block. | | `{% ifversion %}` | Conditionally render content based on product version. | | `{% elsif %}` / `{% else %}` / `{% endif %}` | Branches within `{% ifversion %}`. | | `{% octicon %}` | Render an [Octicon](https://primer.style/foundations/icons/) inline. | | `{% webui %}` / `{% endwebui %}` | Show content only in the Web UI tool tab. | | `{% cli %}` / `{% endcli %}` | Show content only in the CLI tool tab. | | `{% mac %}` / `{% endmac %}` | Show content only on the macOS platform tab. | | `{% windows %}` / `{% endwindows %}` | Show content only on the Windows platform tab. | | `{% linux %}` / `{% endlinux %}` | Show content only on the Linux platform tab. | | `{% note %}` / `{% endnote %}` | Render an informational callout. | | `{% warning %}` / `{% endwarning %}` | Render a warning callout. | | `{% tip %}` / `{% endtip %}` | Render a tip callout. | ## Autogenerated mini TOC Every article page automatically generates an "In this article" section above the content body. This mini table of contents links to every `H2` heading in the file. <Note> Only `H2` headers appear in the mini TOC. `H3` and `H4` headings are not included. Do not manually add an "In this article" section — it creates a duplicate. </Note> Mini TOCs do not appear on product landing pages, category landing pages, or map topic pages. You can suppress the mini TOC on a specific article by setting `showMiniToc: false` in frontmatter. ## Internal links and AUTOTITLE Internal links must start with a product ID and use the full filepath without the file extension: ```markdown theme={null} /actions/creating-actions/about-custom-actions /github-cli/github-cli/about-github-cli ``` The server rewrites these links at render time to include the current language code and version prefix. For example, when viewed in a GitHub Enterprise Server context, `/actions/quickstart` becomes `/en/enterprise-server@3.12/actions/quickstart`. ### AUTOTITLE To avoid duplicating article titles in link text and to ensure titles stay current as articles are renamed, use the `AUTOTITLE` keyword as the link text: ```markdown theme={null} For more information, see [AUTOTITLE](/actions/quickstart). ``` The rendered link text is automatically filled in with the target article's current `title` frontmatter value. ### Linking to the current article in a different version Use the `currentArticle` property to create a cross-version link that stays valid even if the article URL changes: ```markdown theme={null} {% ifversion fpt %} For more information, see the [{% data variables.product.prodname_ghe_cloud %} documentation](/enterprise-cloud@latest/{{ currentArticle }}). {% endif %} ``` ### Preventing version transformations By default, internal links are rewritten to match the current version context. To pin a link to a specific version (for example, linking to a GitHub.com-only policy page from an Enterprise article), include the version in the path: ```markdown theme={null} [GitHub's Terms of Service](/free-pro-team@latest/github/site-policy/github-terms-of-service) ``` ## Image paths Images are stored under `/assets/` and must be referenced using their full path including the file extension: ```markdown theme={null} ![Screenshot of the Actions tab in repository settings.](/assets/images/help/repository/actions-tab.png) ``` Always include descriptive alt text. Alt text should describe what is shown in the image, not just repeat the surrounding prose. ## Whitespace control When Liquid tags appear inside Markdown lists or tables, the extra newlines they introduce can break the rendered output. Use the hyphen (`-`) modifier on either or both sides of a Liquid tag to strip the adjacent whitespace: ```liquid theme={null} {%- ifversion ghes %} ``` ### Example: versioning a table row Without whitespace control, inserting a Liquid conditional mid-table breaks the table: ```markdown theme={null} Column A | Column B | Column C ---------|----------|--------- For all versions | B1 | C1{% ifversion ghes %} GHES only | B2 | C2{% endif %} For all versions | B3 | C3 ``` With whitespace control on its own line, the source remains readable and the table renders correctly: ```markdown theme={null} Column A | Column B | Column C ---------|----------|--------- For all versions | B1 | C1 {%- ifversion ghes %} GHES only | B2 | C2 {%- endif %} For all versions | B3 | C3 ``` The `{%-` strips the newline to the left of the tag, preventing an empty line from appearing between table rows. ## Filenames Article filenames are [kebab-case](https://en.wikipedia.org/wiki/Letter_case#Kebab_case) versions of the article `title` frontmatter. For example: | Title | Filename | | ---------------------------------------------- | ------------------------------------------------- | | `About GitHub CLI` | `about-github-cli.md` | | `Contributing to projects with GitHub Desktop` | `contributing-to-projects-with-github-desktop.md` | | `GitHub's Billing Plans` | `githubs-billing-plans.md` | If a title contains Liquid (such as `About {% data variables.product.prodname_emus %}`), the filename uses the rendered text (`about-enterprise-managed-users.md`) and the page requires `allowTitleToDifferFromFilename: true`. # Reusables and variables Source: https://www.mintlify.com/github/docs/content/reusables-and-variables How to use, create, and choose between reusable content blocks and short string variables in GitHub Docs. GitHub Docs manages shared content through two complementary systems: **reusables** for multi-sentence blocks like paragraphs and procedural steps, and **variables** for short strings like product names and URLs. Both are stored under `data/` and inserted into content files using the `{% data %}` Liquid tag. ## How they differ | | Reusables | Variables | | ---------------- | ----------------------------------------- | --------------------------------------- | | Location | `data/reusables/<category>/<filename>.md` | `data/variables/<filename>.yml` | | Format | Markdown file (one reusable per file) | YAML file (multiple variables per file) | | Content type | Paragraphs, steps, lists, tables | Short strings, product names, URLs | | Reference syntax | `{% data reusables.category.filename %}` | `{% data variables.file.key %}` | ## Variables Variables are short strings stored in YAML files under `data/variables/`. Each file groups related variables together. The path to a variable in the `{% data %}` tag matches the directory path and key within the YAML file. ### Referencing variables Given the file structure: ``` data/ variables/ product.yml actions.yml ``` Variables are referenced as: ```liquid theme={null} {% data variables.product.prodname_actions %} {% data variables.product.prodname_ghe_cloud %} {% data variables.actions.hosted_runner %} ``` ### Product name variables The most commonly used variables are in `data/variables/product.yml`. Use these consistently instead of hardcoding product names — they allow for centralized updates and correct localization. <AccordionGroup> <Accordion title="GitHub platform variables"> | Variable | Renders as | When to use | | ----------------------------------------------- | ------------------------ | ----------------------------------------------- | | `variables.product.github` | GitHub | Generic reference to the GitHub platform. | | `variables.product.prodname_dotcom` | GitHub | Deprecated alias for `github`. Prefer `github`. | | `variables.product.prodname_dotcom_the_website` | GitHub.com | When the `.com` domain specifically matters. | | `variables.product.prodname_enterprise` | GitHub Enterprise | Any GitHub Enterprise product. | | `variables.product.prodname_ghe_server` | GitHub Enterprise Server | GHES specifically. | | `variables.product.prodname_ghe_cloud` | GitHub Enterprise Cloud | GHEC specifically. | </Accordion> <Accordion title="Product feature variables"> | Variable | Renders as | | ---------------------------------------------- | ------------------------ | | `variables.product.prodname_actions` | GitHub Actions | | `variables.product.prodname_codespaces` | Codespaces | | `variables.product.prodname_github_codespaces` | GitHub Codespaces | | `variables.product.prodname_copilot` | GitHub Copilot | | `variables.product.prodname_cli` | GitHub CLI | | `variables.product.prodname_desktop` | GitHub Desktop | | `variables.product.prodname_pages` | GitHub Pages | | `variables.product.prodname_registry` | GitHub Packages | | `variables.product.prodname_GHAS` | GitHub Advanced Security | | `variables.product.prodname_dependabot` | Dependabot | | `variables.product.prodname_discussions` | GitHub Discussions | | `variables.product.prodname_sponsors` | GitHub Sponsors | </Accordion> <Accordion title="Version-aware variables"> Some variables use `{% ifversion %}` internally to return different strings depending on the current version context. For example: ```yaml theme={null} # data/variables/product.yml prodname_container_registry_namespace: >- {% ifversion fpt or ghec %}`ghcr.io`{% elsif ghes %}<code>containers.<em>HOSTNAME</em></code>{% endif %} ``` When referenced as `{% data variables.product.prodname_container_registry_namespace %}`, this renders `ghcr.io` on GitHub.com and a hostname-relative URL on GitHub Enterprise Server. </Accordion> </AccordionGroup> ### Creating a new variable <Steps> <Step title="Choose or create a YAML file"> Find the relevant file in `data/variables/` (for example, `product.yml` for product names, `actions.yml` for Actions-specific strings). Create a new file only if no existing file fits the category. </Step> <Step title="Add the key-value pair"> Add a descriptive key and its string value: ```yaml theme={null} # data/variables/product.yml prodname_my_new_feature: 'GitHub My New Feature' ``` For nested variables: ```yaml theme={null} # data/variables/foo/bar.yml nested: values: label: 'My Label' ``` Reference nested variables as `{% data foo.bar.nested.values.label %}`. </Step> <Step title="Reference it in content"> Use the `{% data %}` tag with the full dotted path: ```liquid theme={null} {% data variables.product.prodname_my_new_feature %} ``` </Step> </Steps> ## Reusables Reusables are longer Markdown content blocks — paragraphs, steps, tables — that appear in multiple articles. Each reusable lives in its own `.md` file under `data/reusables/`. ### Referencing reusables Given the file `data/reusables/repositories/navigate-to-repo.md`, reference it as: ```liquid theme={null} {% data reusables.repositories.navigate-to-repo %} ``` The dotted path maps directly to the directory structure and filename (without the `.md` extension). ### Real examples Common reusables used throughout the GitHub Docs source: ```liquid theme={null} {% data reusables.repositories.navigate-to-repo %} {% data reusables.repositories.actions-tab %} {% data reusables.actions.enterprise-github-hosted-runners %} {% data reusables.cli.cli-learn-more %} ``` A reusable file can contain any valid Markdown, including Liquid conditionals: ```markdown theme={null} <!-- data/reusables/repositories/about-READMEs.md --> You can add a README file to a repository to communicate important information about your project. A README, along with a repository license{% ifversion fpt or ghec %}, contribution guidelines, and a code of conduct{% elsif ghes %} and contribution guidelines{% endif %}, communicates expectations for your project. ``` ### Reusables in ordered lists When a reusable appears as a step inside an ordered list, use `indented_data_reference` with a `spaces` argument to preserve list indentation: ```markdown theme={null} 1. Navigate to your repository. {% indented_data_reference reusables.repositories.actions-tab spaces=3 %} 1. Click **New workflow**. ``` The `spaces` value is the number of spaces the reusable lines should be indented, matching the list item indentation level. ### Creating a new reusable <Steps> <Step title="Identify the right directory"> Reusables are organized by task or product area. Look in `data/reusables/` for a directory that fits your content. For example: * `data/reusables/actions/` for GitHub Actions steps * `data/reusables/repositories/` for repository navigation steps * `data/reusables/organizations/` for organization management steps Create a new directory only if no existing directory fits. </Step> <Step title="Create the Markdown file"> Create a new `.md` file with a descriptive kebab-case name: ``` data/reusables/notifications/your-reusable-name.md ``` </Step> <Step title="Write the content"> Write valid Markdown. You can use Liquid variables and conditionals inside reusables: ```markdown theme={null} Before you begin, ensure that {% data variables.product.prodname_cli %} version 2.0 or later is installed. Run `gh --version` to check. ``` </Step> <Step title="Reference it in content"> Add the `{% data %}` tag wherever the reusable should appear: ```liquid theme={null} {% data reusables.notifications.your-reusable-name %} ``` </Step> </Steps> <Warning> Do not edit a reusable without checking all articles that reference it. Changes affect every page that includes the reusable. Search the `content/` directory for `reusables.your.reusable-name` before making modifications. </Warning> ## When to use reusables vs. variables <CardGroup> <Card title="Use a variable" icon="tag"> * Product names and trademarked strings * Short UI labels that appear inline in sentences * URLs that may change across versions * Strings fewer than one sentence long ```liquid theme={null} {% data variables.product.prodname_actions %} {% data variables.product.prodname_ghe_cloud %} ``` </Card> <Card title="Use a reusable" icon="file-lines"> * Navigation steps repeated across multiple how-to articles * Prerequisite paragraphs shared by related articles * Permission statements used by multiple pages * Any content block longer than one sentence ```liquid theme={null} {% data reusables.repositories.navigate-to-repo %} {% data reusables.cli.cli-learn-more %} ``` </Card> </CardGroup> ## Versioning reusables and variables Both reusables and variable values support Liquid version conditionals. This lets a single shared string serve all versions without duplicating files. ### Versioned variable value ```yaml theme={null} # data/variables/product.yml login_url: >- {%- ifversion fpt or ghec %} [`https://github.com/login`](https://github.com/login) {%- elsif ghes %} `http(s)://HOSTNAME/login` {%- endif %} ``` ### Versioned reusable content ```markdown theme={null} <!-- data/reusables/repositories/about-READMEs.md --> You can add a README file to a repository to communicate important information about your project. A README, along with a repository license, citation file{% ifversion fpt or ghec %}, contribution guidelines, and a code of conduct{% elsif ghes %} and contribution guidelines{% endif %}, communicates expectations for your project and helps you manage contributions. ``` Reusables that include Liquid conditionals inherit their version context from the page that includes them — the same version the reader is currently viewing. ## Directory structure reference ``` data/ ├── variables/ │ ├── product.yml # Product names, URLs │ ├── actions.yml # GitHub Actions strings │ ├── codespaces.yml # Codespaces strings │ ├── copilot.yml # Copilot strings │ └── ... └── reusables/ ├── repositories/ # Repo navigation steps ├── actions/ # Actions-specific steps ├── organizations/ # Org management steps ├── cli/ # CLI learn-more notes └── ... ``` # Style guide Source: https://www.mintlify.com/github/docs/content/style-guide Writing conventions for GitHub Docs—voice, tone, formatting, terminology, and article structure. GitHub Docs follows a consistent style so readers can trust that information is clear, accurate, and presented the same way across all articles. This guide covers the rules you need to write content that fits GitHub Docs. <Note> These guidelines are specific to GitHub Docs. For general style questions not covered here, consult the [Microsoft Style Guide](https://docs.microsoft.com/style-guide/welcome/). For GitHub brand questions, see the [GitHub Brand Guide](https://brand.github.com). </Note> ## Voice and tone Write for your audience. GitHub Docs readers range from beginners to experienced engineers, so use clear language without assuming expertise. * **Second person.** Address the reader as "you." Never use "we" to refer to the reader. * **Active voice.** Passive voice is acceptable when you need to emphasize the object of an action, but prefer active constructions. * **Authentic and direct.** Be confident and empathetic. Avoid filler phrases and marketing language. * **Global audience.** Avoid idioms, slang, and region-specific turns of phrase. | Use | Avoid | | -------------------------------------------------- | ------------------------------------------------- | | You can configure this setting in your repository. | We can configure this setting in your repository. | | GitHub Actions runs the workflow. | The workflow is run by GitHub Actions. | | Click **Save**. | Please click the Save button. | ## Sentence structure Keep sentences short and focused. One idea per sentence makes content easier to read and translate. * Lead with the most important information. * Use parallel structure in lists and headings. * Spell out words rather than abbreviating them, except when the abbreviation appears in the product UI. | Use | Avoid | | ------------- | ----- | | Repository | Repo | | Administrator | Admin | ## Headings Use sentence case for all headings—capitalize only the first word and proper nouns. ```markdown theme={null} ## Setting up your repository ✓ ## Setting Up Your Repository ✗ ``` * Start articles with an H2 (`##`). Do not use H1—the page title renders as H1 automatically. * Do not skip heading levels. An H4 must follow an H3, not an H2. * Include text between every heading and its first subheading. * Each heading at the same level on a page must be unique. ```markdown theme={null} ## Heading (H2) Introductory text. ### Subheading (H3) Text. #### Subheading (H4) Text. ``` ## Formatting UI elements <AccordionGroup> <Accordion title="Bold for interactive UI elements"> Use bold for UI elements that can be clicked, selected, or otherwise interacted with. Omit the word "button" or "checkbox" from the description. * Click **Settings**. * Select **Enable for all new repositories**. * Select the **Backup email addresses** dropdown menu and click **Only allow primary email**. Use quotation marks for non-interactive UI text. * Under "IP allow list", click **Edit**. </Accordion> <Accordion title="Code formatting for commands, filenames, and paths"> Use backticks to render inline code for: * File names and directory names: `README.md`, `.github/workflows/` * Commands: `git lfs install` * Code references: `ghe-cluster-status` * Branch names: `main`, `USERNAME.github.io` Do not use italics or bold for filenames. | Use | Avoid | | --------------------------------------- | ----------------------------------------- | | In your `README.md` file… | In your *README.md* file… | | In your `.github/workflows/` directory… | In your **.github/workflows/** directory… | </Accordion> <Accordion title="Keyboard shortcuts"> Use the HTML `<kbd>` tag for each individual key. Describe Mac shortcuts before Windows/Linux. ```html theme={null} <kbd>Command</kbd>+<kbd>B</kbd> (Mac) or <kbd>Ctrl</kbd>+<kbd>B</kbd> (Windows/Linux) ``` Use full words for Apple modifier keys (`Command`, `Option`, `Control`), not symbols (`⌘`, `⌥`, `⌃`). </Accordion> </AccordionGroup> ## Code blocks Keep code lines to about 60 characters to avoid horizontal scrolling. Place explanatory text before the code block rather than inside it as comments. Always specify the language after the opening fence: ` ```shell `, ` ```yaml `, ` ```javascript `. Rules for code blocks: * Always specify the language after the opening fence (` ```shell `, ` ```yaml `, ` ```javascript `). * Write placeholder values in ALL CAPS with dashes: `git checkout -b BRANCH-NAME`, not `git checkout -b <branch-name>`. * Do not include a `$` prompt before commands. * Comment out command output so readers can copy and paste commands without modification. <CodeGroup> ```shell correct.sh theme={null} git lfs install # Git LFS initialized. ``` ```shell avoid.sh theme={null} $ git lfs install > Git LFS initialized. ``` </CodeGroup> ## Capitalization * Use sentence case for headings, titles, and short titles. * Product names follow their official casing (see [Product names](#product-names)). * Do not capitalize commonly used features like "pull requests," "issues," or "topics." * Feature names are always lowercase; product names are always singular. | Product | Feature | | ----------------- | ------------------- | | GitHub Actions | an action | | GitHub Codespaces | a codespace | | GitHub Packages | a package | | GitHub Pages | a GitHub Pages site | ## Article types GitHub Docs uses distinct article types. Each type has a specific purpose and structure. <CardGroup> <Card title="Conceptual" icon="book-open"> Explains what something is and why it matters. Does not include step-by-step instructions. Use when readers need to understand a concept before acting. </Card> <Card title="Procedural" icon="list-ordered"> Gives numbered steps to complete a specific task. Every step includes an action. Prerequisites appear before the steps, not within them. </Card> <Card title="Referential" icon="table"> Documents options, settings, parameters, or event lists. Often uses tables. Readers scan rather than read linearly. </Card> <Card title="Quickstart" icon="bolt"> Gets a reader to a working outcome in under 10 minutes. Assumes minimal background. Links to longer procedural articles for depth. </Card> <Card title="Tutorial" icon="graduation-cap"> A longer, learning-oriented walk-through. Includes context and explanation alongside steps. Readers complete a meaningful project by the end. </Card> <Card title="Troubleshooting" icon="wrench"> Addresses specific errors or unexpected behaviors. Each problem and its solution are paired together. Symptoms precede causes and fixes. </Card> </CardGroup> ## Product names Always use full, official product names. Never abbreviate or shorten them unless reproducing exact UI text. Product names are never possessive. Use Liquid variables for product names—do not write them in plain text. This allows name changes to propagate across the site automatically. ```markdown theme={null} {% data variables.product.prodname_actions %} → GitHub Actions {% data variables.product.prodname_dotcom %} → GitHub {% data variables.product.prodname_ghe_server %} → GitHub Enterprise Server {% data variables.product.prodname_ghe_cloud %} → GitHub Enterprise Cloud {% data variables.product.company_short %} → GitHub ``` When referring to GitHub Codespaces as a product, always include "GitHub." Individual remote environments created with the technology are called "codespaces" (lowercase). ## Alerts Alerts highlight information that warrants breaking the flow of an article. Use them sparingly—no consecutive alerts, and no more than one per section. Keep alerts concise; if content requires multiple sentences or a list, use a section heading instead. <AccordionGroup> <Accordion title="Note"> Provides additional context users may need but can act without. Use for caveats that affect certain users or products in preview. ```markdown theme={null} > [!NOTE] > Metadata for GitHub tokens is currently in public preview and subject to change. ``` </Accordion> <Accordion title="Tip"> Non-essential recommendations or best practices users can follow at their discretion. Particularly useful in articles for new users. ```markdown theme={null} > [!TIP] > When you @mention an organization, only those you're a member of will autocomplete. ``` </Accordion> <Accordion title="Important"> Key information users must know to achieve their goal. ```markdown theme={null} > [!IMPORTANT] > Runner Scale Sets do not support multiple labels. ``` </Accordion> <Accordion title="Warning"> Highlights potential risks before a user starts or continues a task. Particularly relevant for command-line or API processes. ```markdown theme={null} > [!WARNING] > After a certificate has been signed and issued, the certificate cannot be revoked. ``` </Accordion> <Accordion title="Caution"> Alerts users to dangerous or destructive actions, especially where there is a security risk or potential for data loss. ```markdown theme={null} > [!CAUTION] > This action permanently deletes the repository and cannot be undone. ``` </Accordion> </AccordionGroup> <Warning> Do not use Liquid syntax (`{% note %}`) for new alerts. Use the Markdown blockquote syntax shown above. Liquid alert syntax is still supported in legacy content but should not be added to new articles. </Warning> ## Inclusive language GitHub Docs is read by a global developer community. Use words that are inclusive, anti-racist, and accessible. | Use | Avoid | | ------------------- | ------------- | | Allowlist | Whitelist | | Denylist | Blacklist | | Default/main branch | Master branch | ## Procedural steps Always use numbered lists for procedures. Present prerequisites and conceptual context before the numbered steps, not within individual steps. Each step must include an action. Within each step, use this order: 1. Whether the step is optional 2. Reason or result of the step (if needed for clarity) 3. Location of the action 4. Action **Pattern:** Optionally, to `REASON`, in `LOCATION`, take `ACTION`. **Examples:** * Click **Payment information**. * Under your organization name, click **Settings**. * To confirm your change, click **Remove credit card**. * Optionally, to see your plan's details, click **Show details**. ## Placeholders Write placeholder text in ALL CAPS connected with dashes. Always explain what the placeholder represents. ```markdown theme={null} Run `git init YOUR-REPOSITORY`, replacing YOUR-REPOSITORY with the name of your repository. ``` | Use | Avoid | | ----------------------------- | ---------------------------------- | | `git checkout -b BRANCH-NAME` | `git checkout -b <branch-name>` | | `git checkout -b BRANCH-NAME` | `git checkout -b your-branch-name` | # Versioning documentation Source: https://www.mintlify.com/github/docs/content/versioning How GitHub Docs controls which content appears for each product version using frontmatter and Liquid conditionals. GitHub Docs serves content for multiple product versions from a single source tree. Two independent mechanisms work together to version content: the `versions` frontmatter field restricts which versions include a given page, and Liquid conditionals inside the page body conditionally render specific paragraphs, sentences, or code blocks. ## Product versions GitHub Docs recognizes three top-level product versions: | Version key | Product | | ----------- | ---------------------------------------------------- | | `fpt` | GitHub.com free, pro, and team plans (free-pro-team) | | `ghes` | GitHub Enterprise Server | | `ghec` | GitHub Enterprise Cloud | A page that applies to all versions includes all three keys. A page that applies only to GitHub Enterprise Server omits `fpt` and `ghec`. <Note> As of early 2021, `fpt` URLs do not include the version segment. A helper function (`src/versions/lib/remove-fpt-from-path.ts`) strips `free-pro-team@latest` from rendered URLs automatically. Links to `fpt` content do not require version prefixes. </Note> ## The `versions` frontmatter field The `versions` field is **required** on every page. Its value is an object whose keys are version identifiers. The value for each key is a semver range expression that controls which releases of that version include the page. Use `'*'` to include all releases of a version: ```yaml theme={null} versions: fpt: '*' ghes: '*' ghec: '*' ``` ## Version range examples <CodeGroup> ```yaml GitHub.com only theme={null} title: About your personal dashboard versions: fpt: '*' ghec: '*' ``` ```yaml GitHub Enterprise Server only theme={null} title: Downloading your license versions: ghes: '*' ``` ```yaml GitHub.com and recent GHES releases theme={null} title: About your personal dashboard versions: fpt: '*' ghes: '>=2.20' ghec: '*' ``` ```yaml Specific GHES range theme={null} title: Some transitional feature versions: fpt: '*' ghes: '>=2.22 <3.1' ``` </CodeGroup> Range expressions use the [semver](https://semver.org/) format: | Expression | Meaning | | --------------- | ----------------------------------------- | | `'*'` | All releases | | `'>=3.0'` | Version 3.0 and later | | `'>=2.22 <3.1'` | Versions 2.22, 2.23, and 3.0, but not 3.1 | ## Liquid version conditionals Within the body of a page, use `{% ifversion %}` to conditionally render content. Liquid conditionals are processed at render time based on the version the reader is currently viewing. ### Basic conditional ```liquid theme={null} {% ifversion ghes %} This content only appears when reading GitHub Enterprise Server documentation. {% endif %} ``` ### Conditional with else ```liquid theme={null} {% ifversion fpt or ghec %} You can manage billing from your account settings on GitHub.com. {% else %} Contact your site administrator to manage your license. {% endif %} ``` ### Multi-branch conditional ```liquid theme={null} {% ifversion fpt %} This is GitHub.com free, pro, or team content. {% elsif ghec %} This is GitHub Enterprise Cloud content. {% elsif ghes %} This is GitHub Enterprise Server content. {% endif %} ``` ### Version range in Liquid ```liquid theme={null} {% ifversion ghes >= 3.4 %} This feature was introduced in GitHub Enterprise Server 3.4. {% endif %} ``` ```liquid theme={null} {% ifversion ghes < 3.6 %} This note only appears for older Enterprise Server releases. {% endif %} ``` ### Combining version checks Use `or` and `and` to combine version conditions: ```liquid theme={null} {% ifversion fpt or ghec %} Available on GitHub.com and GitHub Enterprise Cloud. {% endif %} ``` ```liquid theme={null} {% ifversion ghes and ghes >= 3.5 %} Available on GitHub Enterprise Server 3.5 and later. {% endif %} ``` ## Choosing between frontmatter and Liquid conditionals <AccordionGroup> <Accordion title="Use versions frontmatter when..."> The **entire page** only applies to certain versions. If a page describes a feature that does not exist on GitHub Enterprise Server at all, exclude the `ghes` key from `versions`. Readers on a GHES-scoped docs site will receive a 404 rather than landing on an irrelevant page. </Accordion> <Accordion title="Use Liquid conditionals when..."> **Part of a page** varies by version. If a feature works on all versions but the UI differs, keep the page visible to all versions and use `{% ifversion %}` blocks around the version-specific paragraphs or steps. </Accordion> </AccordionGroup> ## Feature-based versioning For features that span multiple product versions but shipped at different times across those versions, you can define a named feature flag in `data/features/` rather than repeating a complex version expression everywhere. The feature file specifies a `versions` object using the same semver syntax, and pages reference it by name: ```yaml theme={null} # data/features/my-feature.yml versions: fpt: '*' ghes: '>=3.6' ghec: '*' ``` ```liquid theme={null} {% ifversion my-feature %} Content for versions where my-feature is available. {% endif %} ``` ## Linking across versions ### Linking to the same article in a different version Use the `currentArticle` property to create a version-aware cross-link. The link remains valid even if the article URL changes: ```liquid theme={null} {% ifversion fpt %} For more information, see the [{% data variables.product.prodname_ghe_cloud %} documentation](/enterprise-cloud@latest/{{ currentArticle }}). {% endif %} ``` ### Preventing link transformation By default, internal links are rewritten to match the reader's current version. To pin a link to a specific version — for example, linking to a GitHub.com-only terms page from Enterprise content — include the version in the path: ```markdown theme={null} [GitHub's Terms of Service](/free-pro-team@latest/github/site-policy/github-terms-of-service) ``` ## Versioning reusables and variables Liquid conditionals can appear inside reusable Markdown files under `data/reusables/` and inside variable YAML values in `data/variables/`. This allows a single reusable or variable to render different text depending on the current version. Example from `data/variables/product.yml`: ```yaml theme={null} prodname_container_registry_namespace: >- {% ifversion fpt or ghec %}`ghcr.io`{% elsif ghes %}<code>containers.<em>HOSTNAME</em></code>{% endif %} ``` When this variable is referenced in content, it automatically resolves to the correct value for the current version context. ## Versioning tables and lists When versioning individual rows in a table or items in a list, use [whitespace control](/content/markdown-and-liquid#whitespace-control) to avoid introducing stray newlines that break Markdown rendering: ```markdown theme={null} | Feature | Available | |---|---| | Code scanning | Yes | {%- ifversion ghes >= 3.5 %} | Secret scanning | Yes | {%- endif %} | Dependabot alerts | Yes | ``` # Deployments Source: https://www.mintlify.com/github/docs/contributing/deployments How GitHub Docs deployments work, including the merge queue, production rollout timing, staging environments, and branch cleanup. GitHub Docs deployments are automated. When a pull request is merged, the changes flow through a deployment pipeline that publishes them to [docs.github.com](https://docs.github.com) without any manual intervention. This page explains how that pipeline works. ## Two repositories GitHub Docs runs from two repositories: | Repository | Visibility | Purpose | | ----------------------------------------------- | ---------- | --------------------------------------------------- | | [`github/docs`](https://github.com/github/docs) | Public | Community contributions, content source | | `github/docs-internal` | Private | Internal GitHub team work, additional configuration | External contributors work exclusively in `github/docs`. The deployer service, maintained by the `@github/docs-engineering` team, handles deployment for both repositories. ## Merge queue The `main` branch in `github/docs` uses a [merge queue](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/merging-a-pull-request-with-a-merge-queue). When a pull request is approved and ready to merge, it enters the queue rather than merging directly. The merge queue runs required checks on the combined state of the queue (your changes together with any other queued pull requests) before merging to `main`. This prevents individual pull requests from breaking the build for others. <Note> You do not need to do anything to add your pull request to the merge queue. A maintainer will add it after approval. </Note> ## Production deployments Once a pull request merges to `main`, the deployer service automatically picks up the change and publishes it to [docs.github.com](https://docs.github.com). <Steps> <Step title="Pull request merges to main"> The merge queue completes all checks and merges the pull request into the `main` branch. </Step> <Step title="Deployment is triggered"> The deployer service detects the new commit on `main` and starts a production deployment automatically. </Step> <Step title="Changes go live"> The updated content is published to docs.github.com. This can take **up to 24 hours** from the time of merge. </Step> <Step title="Status is displayed on the pull request"> The deployment status is shown on the pull request's page on github.com once the deployment completes. </Step> </Steps> <Tip> After your pull request merges, you can track its deployment status directly on the PR page. Look for the **Deployments** section in the sidebar. </Tip> ## Staging environments (review deployments) Review deployments provide a live preview of a pull request's changes before it merges to `main`. These staging environments let reviewers see how content changes look on the actual site without affecting production. <Note> Review deployment configuration is managed by the `@github/docs-engineering` team. Details about available staging environments for a specific pull request will appear in the pull request's deployment section on GitHub. </Note> ## Branch cleanup After a pull request is closed — whether merged or not — the source branch is automatically deleted. This keeps the repository clean and avoids accumulating stale branches. <Warning> Make sure you have committed and pushed all work you want to keep before closing a pull request. Branches are deleted automatically after the PR closes and cannot be recovered from the repository. </Warning> ## Summary | Event | What happens | | ----------------------- | ---------------------------------------------------------------- | | PR approved | Maintainer adds it to the merge queue | | Merge queue checks pass | PR merges to `main` | | Commit lands on `main` | Production deployment starts automatically | | Deployment completes | Changes are live on docs.github.com (up to 24 hours after merge) | | PR closes | Source branch is automatically deleted | # Pull requests Source: https://www.mintlify.com/github/docs/contributing/pull-requests How to fork the repository, make content changes, run the linter, and submit a pull request for review. Content contributions to GitHub Docs are made through pull requests against the `github/docs` repository. This page covers the full workflow, from forking the repository to getting your pull request merged. ## Before you start Review [Types of contributions](/contributing/types-of-contributions) to confirm that the change you want to make is in scope. Pull requests for out-of-scope changes (such as infrastructure or workflow files) will be closed. ## Fork and clone the repository <Steps> <Step title="Fork the repository"> Go to [github/docs](https://github.com/github/docs) and click **Fork**. This creates a copy of the repository under your GitHub account. </Step> <Step title="Clone your fork"> Clone your fork to your local machine: ```bash theme={null} git clone https://github.com/YOUR-USERNAME/docs.git cd docs ``` </Step> <Step title="Install dependencies"> Install Node.js v24 (the version specified in `package.json` under `"engines"`), then do a clean install of dependencies: ```bash theme={null} npm ci ``` See the [local development setup](/development/setup) page for full environment requirements. </Step> <Step title="Create a branch"> Create a new branch from `main` for your changes. Use a short, descriptive name: ```bash theme={null} git checkout -b fix/clarify-actions-permissions ``` Prefix suggestions: * `fix/` — corrections to existing content * `add/` — new content * `update/` — updates to existing content </Step> </Steps> ## Making content changes Only modify files in the following locations. Changes to anything else will not be accepted. | Path | What it contains | | ------------------------------- | -------------------------------- | | `/content/**/*.md` | All documentation pages | | `/data/reusables/**` | Reusable content snippets | | `/data/variables/**` | Variables (except `product.yml`) | | `/data/release-notes/**` | Release note entries | | `/data/glossaries/external.yml` | External glossary terms | | `/data/product-examples/**` | Product example data | <Warning> Do not modify files outside these paths — including GitHub Actions workflows, scripts, application source code, or configuration files. Those changes will not be reviewed or merged. </Warning> ### Writing style Follow these principles from the GitHub Docs [style guide](https://docs.github.com/en/contributing/style-guide-and-content-model/style-guide): * **Second person**: Use "you" to address the reader directly. * **Active voice**: Choose active constructions over passive ones. * **Sentence case for headings**: Capitalize only the first word and proper nouns. * **Inclusive language**: Avoid gendered language, ableist terms, and idioms. * **Precise terminology**: Spell out abbreviations on first use. Avoid informal shorthand like "repo" or "PR." ## Run the linter before submitting Run the content linter to catch errors before submitting your pull request: ```bash theme={null} npm run lint-content ``` The linter checks for broken internal links, incorrect frontmatter, Liquid syntax errors, and style rule violations. Fix all reported errors before opening your pull request. <Tip> You can also run the linter against only the files you changed to speed things up: ```bash theme={null} npm run lint-content -- --paths content/path/to/your-file.md ``` </Tip> ## Self-review checklist Before marking your pull request as ready for review, check the following: <AccordionGroup> <Accordion title="Content accuracy"> * [ ] All information is technically accurate. * [ ] Code examples are correct and tested. * [ ] Links point to existing, relevant pages. * [ ] Procedures follow the actual product UI. </Accordion> <Accordion title="Writing quality"> * [ ] Headings use sentence case. * [ ] Instructions use second person ("you") and active voice. * [ ] No broken or placeholder text remains. * [ ] The change makes sense without additional context. </Accordion> <Accordion title="Linting and formatting"> * [ ] `npm run lint-content` passes with no errors. * [ ] Frontmatter fields (`title`, `shortTitle`, `intro`) are present and accurate. * [ ] Liquid tags are correctly opened and closed. </Accordion> </AccordionGroup> The full self-review checklist is available in the [GitHub Docs contributing guide](https://docs.github.com/en/contributing/collaborating-on-github-docs/self-review-checklist). ## Opening the pull request <Steps> <Step title="Push your branch"> ```bash theme={null} git push origin fix/clarify-actions-permissions ``` </Step> <Step title="Open the pull request"> Go to [github/docs](https://github.com/github/docs) and click **Compare & pull request**. Fill in the pull request template: * **Title**: A short description of what the PR changes. * **Description**: Explain *why* the change is needed, not just what changed. Link to the relevant issue if one exists. * **Type of change**: Select the appropriate option in the template. </Step> <Step title="Link to an issue"> If your pull request resolves an open issue, add a closing keyword in the description: ``` Closes #1234 ``` This automatically closes the issue when the PR is merged. </Step> <Step title="Allow maintainer edits"> Enable **Allow edits from maintainers** on your pull request. This lets the docs team make minor corrections directly on your branch without needing to ask you. </Step> </Steps> ## The review process After you open a pull request, a docs team member will review it. The team is small, so review times vary depending on current workload. During review, you may receive: * **Requests for changes** — Make the requested updates on your branch and push them. The pull request will update automatically. * **Approvals** — Once approved, the pull request is eligible to enter the merge queue. * **Closing without merge** — If the change is out of scope or duplicates existing content, the team will close the PR and explain why. <Note> The docs team may make small edits directly to your branch (such as fixing linter errors or adjusting formatting) rather than requesting changes. You'll see these as additional commits on your branch. </Note> ## Merge queue GitHub Docs uses a [merge queue](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/merging-a-pull-request-with-a-merge-queue) on the `main` branch. When your pull request is approved and added to the queue, it is merged automatically once all required checks pass. After your pull request merges, your changes are automatically deployed to [docs.github.com](https://docs.github.com). Deployment can take up to 24 hours. Your source branch is automatically deleted after the pull request closes. # Translations Source: https://www.mintlify.com/github/docs/contributing/translations How GitHub Docs handles translations, which languages are supported, and what external contributors can do. GitHub Docs is internationalized and available in multiple languages. This page explains how the translation process works, which content gets translated, and what role external contributors play. ## How translations work English is the source of truth for all GitHub Docs content. The translation pipeline is automated and managed internally by GitHub, working with professional translators to localize English content into supported languages. <Note> **Translated content is not accepted as external contributions.** Pull requests that modify files in translated language directories will not be merged. If you want to help improve GitHub Docs, contribute to the English source content in `/content` instead. </Note> The general flow is: <Steps> <Step title="English content is authored"> Writers create or update content in English under the `/content` directory in `github/docs`. This is the canonical version of every document. </Step> <Step title="Content is picked up for translation"> The automated pipeline detects new or changed English content and sends it to professional translators for localization. </Step> <Step title="Translated content is published"> Completed translations are published to the localized versions of docs.github.com (for example, `docs.github.com/ja` for Japanese). </Step> </Steps> ## Supported languages GitHub Docs supports multiple languages. The set of enabled languages is controlled by the `ENABLED_LANGUAGES` environment variable in the application. At the time of writing, supported languages include: | Language | Code | | -------------------- | ---- | | English | `en` | | Chinese (Simplified) | `zh` | | Japanese | `ja` | | Spanish | `es` | | Portuguese (Brazil) | `pt` | | French | `fr` | | Russian | `ru` | | Korean | `ko` | | German | `de` | The English (`en`) locale is always enabled and serves as the source of truth. Other languages are enabled as translations become available. ## What gets translated Not all content in the repository is translated. The translation pipeline covers: * All files in `/content` * `/data/release-notes` * `/data/reusables` * `/data/variables` (except `/data/variables/product.yml`) * `/data/glossaries/external.yml` * `/data/product-examples` Files outside these paths — such as scripts, application code, and workflow configuration — are not translated. ## Translation guidelines for the pipeline The internal translation process follows these rules, which also apply to the automated tooling: * Liquid tags such as `{% data %}`, `{% ifversion ... %}`, `{% note %}`, and `{{ someVariable }}` are **never translated**. Only the surrounding prose is localized. * Frontmatter properties `title`, `shortTitle`, `intro`, and `permissions` are translated. All other frontmatter keys remain in English. * Every `{% ifversion ... %}` tag must have a matching `{% endif %}`. * All `.yml` files must remain valid YAML after translation. * Frontmatter blocks must remain valid YAML after translation. <Warning> If you notice that Liquid tags, code samples, or frontmatter keys have been incorrectly modified in a translated page, this is a translation pipeline issue. Do not open a pull request to fix it — report it as an issue instead so the team can address it upstream. </Warning> ## What external contributors can do External contributors cannot submit translated content, but they can help improve the translations indirectly: <CardGroup> <Card title="Improve the English source" icon="pen-to-square" href="/contributing/pull-requests"> Clear, well-structured English content produces better translations. Contributing improvements to the English source benefits all languages. </Card> <Card title="Report translation issues" icon="circle-exclamation" href="https://github.com/github/docs/issues/new/choose"> If you find a translation that is inaccurate, missing, or contains untranslated Liquid tags, open an issue to report it. </Card> </CardGroup> ## Localized site URLs Translated versions of GitHub Docs are available at language-prefixed URLs: ``` https://docs.github.com/en # English (default) https://docs.github.com/ja # Japanese https://docs.github.com/zh # Chinese (Simplified) https://docs.github.com/es # Spanish https://docs.github.com/pt # Portuguese (Brazil) ``` Users can switch languages using the language picker on any docs.github.com page. # Types of contributions Source: https://www.mintlify.com/github/docs/contributing/types-of-contributions Learn what kinds of contributions are accepted in the github/docs repository and where to direct other types of feedback. The `github/docs` repository is the home of the content powering [docs.github.com](https://docs.github.com). The docs team maintains this repository, and community contributions are welcome — but only for specific kinds of changes. This page explains what is and isn't accepted so you can direct your effort to the right place. ## What we accept <CardGroup> <Card title="Issues" icon="circle-exclamation"> Bug reports, broken link reports, and content suggestions via GitHub Issues. </Card> <Card title="Content pull requests" icon="code-pull-request"> Corrections and improvements to `.md` files in `/content` and select `/data` directories. </Card> <Card title="Typo fixes in site policy" icon="scale-balanced"> Minor fixes to the site policy section published on docs.github.com. </Card> <Card title="Expanded explanations" icon="book-open"> New content that fills important gaps, when there is a compelling reason for the addition. </Card> </CardGroup> ## Issues Use [GitHub Issues](https://docs.github.com/en/github/managing-your-work-on-github/about-issues) to report problems or suggest improvements. Before opening a new issue: 1. Search [open issues](https://github.com/github/docs/issues) to check whether the same thing has already been reported. 2. If it hasn't been reported, open an issue using one of the available [issue templates](https://github.com/github/docs/issues/new/choose). 3. The team will use the issue to discuss the problem before any work begins. <Note> If an issue has a **triage** label, the team hasn't reviewed it yet. Do not begin work on triaged issues until a team member has confirmed the direction. </Note> ## Pull requests [Pull requests](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests) are the way to suggest content changes. When a pull request is merged into the default branch, the changes are automatically deployed to the live site within 24 hours. Content pull requests are accepted for: * **`/content`** — All Markdown files that become docs.github.com pages. * **`/data/reusables`** — Reusable content snippets referenced across multiple pages. * **`/data/variables`** — Variables used in content (except `/data/variables/product.yml`). * **`/data/release-notes`** — Release note entries. * **`/data/glossaries/external.yml`** — External glossary terms. * **`/data/product-examples`** — Product example data. <Tip> The fastest way to make a small fix — like a typo or a broken link — is to click **Make a contribution** at the bottom of any page on docs.github.com. This opens the file directly in the GitHub editor without needing to fork the repository locally. </Tip> ### Content we do not accept Some contributions are outside the scope of what the team can review and maintain: * Edits made purely for tone, readability, or stylistic preference * Topics that are too niche or a matter of personal preference * Changes to the underlying site infrastructure, build tooling, or GitHub Actions workflows If you're unsure whether your proposed change falls within scope, open an issue to discuss it before writing the pull request. ## REST API reference documentation The REST API reference docs on docs.github.com are generated automatically from the [github/rest-api-description](https://github.com/github/rest-api-description) repository. Pull requests to `github/docs` cannot change this content. If you find an inaccuracy in the REST API reference, open an issue in the [github/rest-api-description](https://github.com/github/rest-api-description/issues/new?template=schema-inaccuracy.md) repository instead. ## Site policy GitHub's site policies are published on docs.github.com. You can open a pull request in `github/docs` to fix a typo in the site policy section. For any other site policy changes, see the [CONTRIBUTING guide in the site-policy repository](https://github.com/github/site-policy/blob/main/CONTRIBUTING.md). ## Translations GitHub Docs is available in multiple languages, but **translated content is not accepted as external contributions**. Translations are handled through an automated internal process using professional translators. English is the source of truth for all content. See [Translations](/contributing/translations) for more detail on how the translation process works. ## Support The docs team is not able to help with support questions in this repository. If you are experiencing a problem with GitHub that is unrelated to the documentation: * Contact [GitHub Support](https://support.github.com/contact) directly. * For account-specific issues, use [GitHub Support](https://support.github.com/contact?tags=docs-contributing-guide). Issues and pull requests opened here for support purposes will be redirected to GitHub Support, then closed and locked. # Debugging the application Source: https://www.mintlify.com/github/docs/development/debugging Attach a debugger in VS Code, understand nodemon restarts, use fixture tests, and run the test suite. This page covers debugging the GitHub Docs Node.js application — not content files. These tools help you inspect server behavior, middleware, and application logic. ## Debugging with VS Code The repository includes a pre-configured VS Code debug configuration that works with nodemon's `--inspect` flag. <Steps> <Step title="Build the application"> If you haven't already, run the build step before starting: ```bash theme={null} npm run build ``` </Step> <Step title="Start the server in debug mode"> ```bash theme={null} npm run debug ``` This starts nodemon with the `--inspect` flag, which opens the V8 inspector on `127.0.0.1:9229` and prints a message like: ``` Debugger listening on ws://127.0.0.1:9229/... ``` </Step> <Step title="Open the Debug panel in VS Code"> Click the **Run and Debug** icon in the Activity Bar (or press <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>D</kbd> on Windows/Linux, <kbd>⇧⌘D</kbd> on macOS). </Step> <Step title="Select the Node: Nodemon configuration"> In the **Run and Debug** panel, open the configuration dropdown at the top and select **Node: Nodemon**. Press <kbd>F5</kbd> or click the green **Start Debugging** button. VS Code will display all running Node processes. Look for the process that was started with the `--inspect` flag. </Step> <Step title="Attach to the inspected process"> Select the node process that shows the `--inspect` flag. VS Code will attach the debugger. You can now set breakpoints, step through code, inspect variables, and use the Debug Console. </Step> </Steps> <Tip> For more detail on the VS Code + nodemon workflow, see the [VS Code nodemon recipe](https://github.com/Microsoft/vscode-recipes/tree/main/nodemon) and the [VS Code debugging guide](https://code.visualstudio.com/docs/editor/debugging). </Tip> <Warning> The Node.js debugger only helps with issues in the application code (TypeScript source in `src/`). It does not help debug content rendering issues in Markdown or Liquid template files. </Warning> ## Understanding nodemon restarts nodemon watches specific file types and directories and restarts the server when it detects changes. Knowing what does and does not trigger a restart saves debugging time. **Triggers a restart:** * Any `.ts`, `.json`, `.yml`, `.md`, `.html`, or `.scss` file inside a watched directory (mainly `src/`) * Changes to `package.json` or other config files at the root **Does not trigger a restart:** * `content/` — documentation Markdown files * `data/reusables/`, `data/variables/`, `data/glossaries/`, `data/product-examples/`, `data/learning-tracks/` * `assets/`, `script/`, `tests/`, `translations/`, `rest-api-description/`, `semmle-code/` Content files are loaded dynamically per request, so you can edit them and refresh your browser without waiting for a restart. Application source files require a restart, which nodemon handles automatically. ## Key environment variables for development Set these in your `.env` file or inline when starting the server. | Variable | Example value | Effect | | ----------------------- | ----------------------- | ------------------------------------------------------------------------------------ | | `NODE_ENV` | `development` | Enables development-mode logging and error output. Set automatically by `npm start`. | | `ENABLED_LANGUAGES` | `en,ja,pt` | Controls which language trees are loaded. Defaults to `en`. | | `ELASTICSEARCH_URL` | `http://localhost:9200` | Points search to a local Elasticsearch instance instead of production. | | `TRANSLATIONS_ROOT` | `/path/to/translations` | Overrides the default translations directory. | | `ENABLE_FASTLY_TESTING` | `true` | Enables the `/fastly-cache-test` route for inspecting Fastly cache headers. | | `HYDRO_ENDPOINT` | *(your endpoint)* | Sends analytics events to a local mock instead of production. | <Note> When `ELASTICSEARCH_URL` is not set, search requests are proxied to the production endpoint. Set it only if you're working on search indexing or query logic. </Note> ## Using the fixture server for testing The fixture server loads a small, self-contained content tree from `src/fixtures/fixtures` instead of the full content directory. It is the recommended way to test application behavior in isolation. <CodeGroup> ```bash Start fixture dev server theme={null} npm run fixture-dev ``` ```bash Start fixture server with debugger theme={null} npm run fixture-dev-debug ``` ```bash Run fixture tests theme={null} npm run fixture-test ``` ```bash Run a specific fixture test file theme={null} npm run fixture-test -- src/fixtures/tests/your-test.ts ``` </CodeGroup> The fixture content includes a small but representative set of pages, layouts, and data that exercise the full rendering pipeline without loading the entire `content/` tree. ## Running the test suite The project uses [Vitest](https://vitest.dev/) as its test runner. All test commands are available via `npm test`. ### Running all tests ```bash theme={null} npm test ``` ### Running a specific test file or directory ```bash theme={null} npm test -- src/your-feature/tests/ ``` ### Scoped test commands Several pre-configured test commands set the right environment variables automatically: <CodeGroup> ```bash Fixture tests theme={null} npm run test:fixtures ``` ```bash Article API tests theme={null} npm run test:article-api ``` ```bash Search tests (requires local Elasticsearch) theme={null} npm run test:search ``` ```bash Landing page tests theme={null} npm run test:landings ``` ```bash Language tests (loads all languages) theme={null} npm run test:languages ``` ```bash Changelog tests theme={null} npm run test:changelogs ``` </CodeGroup> <Note> `npm run test:search` and `npm run test:languages` require a running local Elasticsearch instance at `http://localhost:9200`. Start one via Docker before running these. </Note> ### Type checking Run the TypeScript compiler without emitting files to check for type errors across the codebase: ```bash theme={null} npm run tsc ``` ### Linting ```bash theme={null} npm run lint # ESLint on all .ts and .tsx files npm run lint-content # Content linter for Markdown files in content/ and data/ npm run prettier # Auto-format .ts, .tsx, .scss, .yml, and .yaml files npm run prettier-check # Check formatting without making changes ``` ## Quick reference | Command | Description | | --------------------------- | ------------------------------------------------ | | `npm run debug` | Start server with Node.js inspector on port 9229 | | `npm run fixture-dev` | Start fixture server (lightweight content tree) | | `npm run fixture-dev-debug` | Fixture server with inspector attached | | `npm run fixture-test` | Run tests against fixture content | | `npm test` | Run the full Vitest test suite | | `npm run tsc` | Type-check the TypeScript codebase | | `npm run lint` | Lint TypeScript source files | | `npm run lint-content` | Lint Markdown content files | # Running the site locally Source: https://www.mintlify.com/github/docs/development/running-locally Start the development server, configure languages, use the fixture server, and understand hot reload behavior. After completing the [local setup](/development/setup), you can start the development server and browse the docs site at `http://localhost:4000`. ## Starting the server ```bash theme={null} npm start ``` This runs: ``` cross-env NODE_ENV=development ENABLED_LANGUAGES=en nodemon src/frame/server.ts ``` The server starts on **port 4000** with `NODE_ENV=development` and English content enabled. nodemon watches for file changes and restarts the server automatically. <Tip> `npm start` and `npm run dev` are equivalent — both invoke the same command. </Tip> To stop the server at any time, press <kbd>Ctrl</kbd>+<kbd>C</kbd> in your terminal. ## Starting the server in debug mode Use `npm run debug` to start the server with the Node.js inspector attached: ```bash theme={null} npm run debug ``` This runs: ``` cross-env NODE_ENV=development ENABLED_LANGUAGES=en nodemon --inspect src/frame/server.ts ``` The `--inspect` flag enables the V8 inspector protocol on `127.0.0.1:9229`. You can then attach a debugger from VS Code or Chrome DevTools. See [Debugging](/development/debugging) for a step-by-step guide. ## Enabling additional languages By default, the server only loads English content (`ENABLED_LANGUAGES=en`). Loading all languages at startup would significantly increase memory usage and startup time. To enable one or more additional languages, set `ENABLED_LANGUAGES` before starting the server: <CodeGroup> ```bash Japanese and Portuguese theme={null} ENABLED_LANGUAGES=en,ja,pt npm start ``` ```bash All languages theme={null} ENABLED_LANGUAGES=en,es,ja,pt,zh,ru,fr,ko,de npm start ``` ```bash English only (default) theme={null} npm start ``` </CodeGroup> You can also set `ENABLED_LANGUAGES` in your `.env` file to avoid typing it every time. <Note> Restart the server after changing `ENABLED_LANGUAGES`. The application reads this variable at startup and does not reload it on the fly. </Note> ### Supported language codes The full set of language codes is defined in `src/languages/lib/languages.ts`: | Code | Language | | ---- | -------------------------------- | | `en` | English | | `es` | Spanish (Español) | | `ja` | Japanese (日本語) | | `pt` | Portuguese (Português do Brasil) | | `zh` | Simplified Chinese (简体中文) | | `ru` | Russian (Русский) | | `fr` | French (Français) | | `ko` | Korean (한국어) | | `de` | German (Deutsch) | ## Serving all languages without nodemon If you want to run with all languages enabled and skip nodemon's restart overhead, use: ```bash theme={null} npm run start-all-languages ``` This runs `tsx src/frame/server.ts` directly with `NODE_ENV=development` and no `ENABLED_LANGUAGES` restriction — meaning all supported languages are served. ## Using the fixture dev server The fixture server loads a lightweight set of test content from `src/fixtures/fixtures` instead of the full content tree. It starts much faster and is useful when working on application code rather than documentation content. ```bash theme={null} npm run fixture-dev ``` This is equivalent to: ``` cross-env ROOT=src/fixtures/fixtures npm start ``` A debug variant is also available: ```bash theme={null} npm run fixture-dev-debug ``` <Tip> Use the fixture server when you're iterating on server logic, middleware, or rendering behavior and don't need the full content tree loaded. </Tip> ## Hot reload behavior The server uses [nodemon](https://nodemon.io/) to watch for changes and restart automatically. The watch configuration is in `package.json` under `"nodemonConfig"`: **Watched file extensions:** `ts`, `json`, `yml`, `md`, `html`, `scss` **Directories ignored by nodemon** (changes here do not trigger a restart): * `assets/` * `script/` * `tests/` * `content/` * `translations/` * `data/reusables/` * `data/variables/` * `data/glossaries/` * `data/product-examples/` * `data/learning-tracks/` * `rest-api-description/` * `semmle-code/` <Warning> Changes to files inside `content/` and `data/` do **not** trigger a server restart. The server reads content dynamically on each request, so you can edit Markdown and Liquid files and refresh your browser to see the result without waiting for a restart. </Warning> Changes to TypeScript source files in `src/`, configuration files, or schema files will trigger nodemon to restart the server. Watch the terminal output to confirm the restart has completed before refreshing your browser. ## Command reference | Command | Description | | ----------------------------- | ------------------------------------------------ | | `npm start` | Start the dev server on port 4000 (English only) | | `npm run dev` | Alias for `npm start` | | `npm run debug` | Start with Node.js inspector on port 9229 | | `npm run start-all-languages` | Start without language restriction, no nodemon | | `npm run fixture-dev` | Start with fixture content (faster startup) | | `npm run fixture-dev-debug` | Fixture server with Node.js inspector | # Setting up your local environment Source: https://www.mintlify.com/github/docs/development/setup Install Node.js, clone the repository, and prepare the GitHub Docs application to run on your machine. The GitHub Docs site is a dynamic Node.js web application powered by Express. It runs on macOS, Windows, and Linux. ## System requirements | Requirement | Version | | ----------- | -------------------- | | Node.js | `^24` | | npm | Bundled with Node.js | | Git | Any recent version | <Note> The required Node.js version is declared in `package.json` under the `"engines"` field. Using a different major version may cause unexpected build or runtime errors. </Note> ## Two ways to get started <Tabs> <Tab title="Local setup"> Set up the full development environment on your own machine. This gives you the most control and the fastest feedback loop for code changes. <Steps> <Step title="Install Node.js 24"> Download the Node.js 24 LTS installer from [nodejs.org](https://nodejs.org) and run it. If you use a Node.js version manager like [`nodenv`](https://github.com/nodenv/nodenv) or [`nvm`](https://github.com/nvm-sh/nvm), switch to Node.js 24 before continuing. Verify your installation: ```bash theme={null} node --version # Should output v24.x.x ``` </Step> <Step title="Clone the repository"> ```bash theme={null} git clone https://github.com/github/docs cd docs ``` </Step> <Step title="Install dependencies"> Use `npm ci` for a clean, reproducible install. This reads `package-lock.json` exactly and does not modify it. ```bash theme={null} npm ci ``` <Note> Run `npm ci` again any time you pull changes that update `package-lock.json`. You do not need to run it on every pull — only when dependencies change. </Note> </Step> <Step title="Build static assets"> The build step compiles JavaScript bundles and CSS files using Next.js with webpack. ```bash theme={null} npm run build ``` This step is required before starting the server for the first time. Like `npm ci`, you only need to re-run it when the build configuration changes — not on every code change. </Step> <Step title="Verify your setup"> Start the development server to confirm everything is working: ```bash theme={null} npm start ``` Open [http://localhost:4000](http://localhost:4000) in your browser. You should see the GitHub Docs site running locally. Press <kbd>Ctrl</kbd>+<kbd>C</kbd> to stop the server. </Step> </Steps> </Tab> <Tab title="GitHub Codespaces"> GitHub Codespaces gives you a fully configured cloud development environment in your browser — no local installation required. You can be ready to edit, preview, and test changes in minutes. <Steps> <Step title="Open the repository in a codespace"> Go to [github.com/github/docs](https://github.com/github/docs), click the **Code** button, select the **Codespaces** tab, and click **Create codespace on main**. GitHub will provision a container with all required dependencies pre-installed. </Step> <Step title="Wait for setup to complete"> The codespace runs `npm ci` and `npm run build` automatically as part of its `postCreateCommand`. Watch the terminal for the setup to finish before running any commands. </Step> <Step title="Start the server"> Once setup is complete, run: ```bash theme={null} npm start ``` Codespaces will detect the forwarded port and offer to open the site in your browser. </Step> </Steps> <Tip> For full details on Codespaces configuration for this repository, see the [Working on GitHub Docs in a codespace](https://docs.github.com/en/contributing/setting-up-your-environment-to-work-on-github-docs/working-on-github-docs-in-a-codespace) guide. </Tip> </Tab> </Tabs> ## Environment variables The repository ships with a `.env.example` file that documents optional environment variables for local development. Copy it to a new `.env` file and fill in values as needed: ```bash theme={null} cp .env.example .env ``` Key variables you may want to configure: | Variable | Default | Description | | ----------------------- | --------------------------------- | ----------------------------------------------------------------- | | `ELASTICSEARCH_URL` | *(unset — proxies to production)* | URL of a local Elasticsearch instance for search. | | `ENABLED_LANGUAGES` | `en` | Comma-separated list of language codes to serve. | | `TRANSLATIONS_ROOT` | *(unset)* | Path to a local translations repository. | | `HYDRO_ENDPOINT` | *(unset)* | Endpoint for sending analytics events in local development. | | `ENABLE_FASTLY_TESTING` | *(unset)* | Set to `true` to enable the `/fastly-cache-test` debugging route. | <Note> When `ELASTICSEARCH_URL` is not set, the application proxies search requests to the production Elasticsearch endpoint. You only need a local Elasticsearch instance if you're working on search functionality. </Note> ## Quick reference: setup commands ```bash theme={null} git clone https://github.com/github/docs cd docs npm ci # Clean install of all dependencies npm run build # Compile static assets (Next.js + webpack) npm start # Start the development server on port 4000 ``` # Deployments Source: https://www.mintlify.com/github/docs/engineering/deployments How changes to the docs codebase are deployed to staging and production. Staging and production deployments are fully automated by a deployer service built and maintained by `@github/docs-engineering`. You do not manually trigger deployments — merging a pull request is sufficient. ## Two repositories GitHub Docs runs from two separate repositories: | Repository | Visibility | Purpose | | ---------------------- | ---------- | ----------------------------------------------------------- | | `github/docs` | Public | Open-source contributions, public content | | `github/docs-internal` | Private | Internal features, early access content, staff-only changes | Both repositories follow the same deployment process described on this page. ## Merge queue The `main` branch on both repositories is protected by a **merge queue**. You cannot merge a pull request directly into `main` — the queue validates and batches merges automatically. <Note> If your PR appears stuck waiting to merge, check the merge queue status on the PR page. The queue runs required checks before allowing the merge. </Note> ## Production deployments When a pull request is merged to `main`, deployment to production is triggered automatically. The deployment status is visible directly on the PR page on github.com. **It can take up to 24 hours for changes to be visible on the live site.** This is normal and expected — do not open a follow-up PR to re-apply a change that was already merged. <Tip> To verify that your change is live, check the PR page for a successful deployment status indicator. </Tip> ## Branch deletion After a pull request is closed (merged or otherwise), the branch is **automatically deleted**. You do not need to delete it manually. This does not affect the deployment process. ## Review and staging environments Review environments are provisioned for pull requests so you can preview changes before merge. <Note> Review environment details are maintained by `@github/docs-engineering`. Contact the team in `#docs-engineering` if review environments are not loading for your PR. </Note> ## Clearing the Fastly edge cache The docs site is served through Fastly as an edge cache layer. If you need to force-purge the cache — for example, after a critical content correction — run: ```bash theme={null} npm run purge-fastly-edge-cache ``` <Warning> Cache purges affect production traffic globally. Only run this when necessary and coordinate with `@github/docs-engineering` beforehand. </Warning> ## Checking deployment status You can monitor the deployment for any merged PR directly on its page on github.com. Look for the deployment status in the PR timeline or in the **Environments** section of the repository. If a deployment is stalled or failed, contact `@github/docs-engineering` in the `#docs-engineering` Slack channel. ## Getting help * Slack: `#docs-engineering` * Team: `@github/docs-engineering` # GraphQL docs Source: https://www.mintlify.com/github/docs/engineering/graphql-docs How GraphQL schema documentation is generated, validated, and rendered. The GraphQL API documentation at docs.github.com/graphql is generated by fetching schema data directly from GitHub's GraphQL API. The sync script produces version-specific JSON files in `src/graphql/data/`, which are then consumed at render time by Next.js pages. ## How the pipeline works The sync script in `src/graphql/scripts/sync.ts` performs an introspection query against GitHub's GraphQL API for each supported version. It writes: * **`src/graphql/data/schema-VERSION.json`** — One schema file per version (e.g., `ghec`, `ghes-3.13`) * **`src/graphql/data/previews.json`** — Preview features available across versions * **`src/graphql/data/upcoming-changes.json`** — Upcoming breaking changes * **`src/graphql/data/changelog.json`** — GraphQL API changelog entries A `.github/workflows/sync-graphql.yml` workflow runs on a schedule to keep these files current. ## Directory structure ``` src/graphql/ ├── components/ # React components rendering GraphQL reference pages ├── data/ # Auto-generated JSON schema files (do not edit manually) │ ├── ghec/ │ │ └── schema.json │ ├── ghes-3.13/ │ │ └── schema.json │ ├── previews.json │ ├── upcoming-changes.json │ └── changelog.json ├── lib/ │ ├── index.ts # Data-loading functions for Next.js pages │ ├── non-schema-scalars.json # Custom scalars from graphql-ruby │ ├── types.json # High-level GraphQL types and kinds │ └── validator.ts # Schema structure validation ├── pages/ # Next.js page files └── scripts/ └── sync.ts # Pipeline entrypoint ``` Content files for the GraphQL docs are Markdown files in `content/graphql/`. Those files use Liquid to loop over the context data injected by the Next.js pages. <Note> All files inside `src/graphql/data/` are generated. Edit `lib/*.json` and `scripts/*.ts` instead. Do not commit manual changes to data files. </Note> ## Running the sync locally <Steps> <Step title="Ensure API access"> You need a GitHub token with access to the GraphQL API. Set it in your `.env`: ```bash theme={null} GITHUB_TOKEN=ghp_your_token_here ``` </Step> <Step title="Run the sync script"> ```bash theme={null} npm run sync-graphql ``` This fetches the current schema for all versions and writes the output to `src/graphql/data/`. </Step> <Step title="Verify the output"> Check that the schema files were updated. The `data/ghec/schema.json` file should reflect the latest introspection result. ```bash theme={null} git diff src/graphql/data/ ``` </Step> </Steps> ## Schema validation The project uses `@graphql-inspector/core` (a dev dependency) to validate GraphQL schema structure. The validator is configured in `src/graphql/lib/validator.ts` and runs as part of the test suite: ```bash theme={null} npm run test -- src/graphql/tests ``` The validator catches structural issues in the schema data before they can affect rendered pages. ### Editable configuration files | File | Purpose | | ----------------------------- | ------------------------------------------------------------------------ | | `lib/non-schema-scalars.json` | Custom scalar types from `graphql-ruby` that are not in the GraphQL spec | | `lib/types.json` | High-level type taxonomy used in rendering | | `lib/validator.ts` | TypeScript validator used in `tests/graphql.ts` | Do not manually edit any file inside `data/` — regenerate it with `npm run sync-graphql`. ## How rendering works GraphQL data is loaded in Next.js pages using `getServerSideProps`. The `getGraphqlSchema()` function from `lib/index.ts` provides: * The schema for the requested version * Preview features for that version * Upcoming breaking changes * The changelog Markdown files in `content/graphql/` use Liquid to loop over the context data and call HTML includes in the `includes/` directory for rendering individual schema items. ## Adding a new GHES version When a new GHES version releases, you need to add a new schema file for it: <Steps> <Step title="Update the version list"> Add the new version to the version list in `src/graphql/scripts/sync.ts`. </Step> <Step title="Run the sync"> ```bash theme={null} npm run sync-graphql ``` A new `data/ghes-X.XX/schema.json` file is created. </Step> <Step title="Update content if needed"> Check `content/graphql/` for any version-gated content that may need updates for the new version. </Step> <Step title="Commit the generated file"> Commit the new schema file. It is large (100 KB+) but must be committed because the site reads it at runtime. </Step> </Steps> ## Troubleshooting <AccordionGroup> <Accordion title="Sync fails with an auth error"> Check that your `GITHUB_TOKEN` is set in `.env`, has the correct scopes, and has SSO authorized for the `github` org. </Accordion> <Accordion title="Schema not loading in the browser"> Verify that the file `src/graphql/data/VERSION/schema.json` exists for the version being requested. Check that the version detection logic in `lib/index.ts` maps correctly to the file name. </Accordion> <Accordion title="Content not rendering"> * Check Liquid syntax in the relevant `content/graphql/` file. * Confirm the expected context properties (`context.graphql.*`) are available. * Check the HTML includes in the `includes/` directory. </Accordion> <Accordion title="Validation errors in tests"> Schema structure must match the JSON schema defined in `lib/validator.ts`. If you see validation failures after a sync, compare the generated schema shape to what the validator expects and update `validator.ts` accordingly. </Accordion> </AccordionGroup> ## Getting help * Slack: `#docs-engineering` * Repo: `github/docs-engineering` # REST API docs Source: https://www.mintlify.com/github/docs/engineering/rest-api-docs How REST API documentation is generated, synced, and maintained from the OpenAPI source. The REST API documentation on docs.github.com/rest is **auto-generated** from the OpenAPI description stored in the open-source [`github/rest-api-description`](https://github.com/github/rest-api-description) repository. The pipeline reads that OpenAPI source and produces Markdown files, data files, and rendered React pages — without requiring manual content authoring for each endpoint. ## How the pipeline works The entry point is the `.github/workflows/sync-openapi.yml` workflow, which runs on a daily schedule and can also be triggered manually. A single workflow run drives three pipelines simultaneously: * **REST** — generates `content/rest/` Markdown files and `src/rest/data/` JSON files * **Webhooks** — generates `src/webhooks/data/` JSON files * **GitHub Apps** — generates `src/github-apps/data/` JSON files When the workflow completes, it opens a pull request in `github/docs-internal` with the label `github-openapi-bot`. Reviewers know a PR with that label contains automated content changes and can review the diff without expecting hand-written copy. <Note> The SHA of the `github/rest-api-description` commit that produced the data is tracked in `src/rest/lib/config.json`. This gives you a precise audit trail for every generated file. </Note> ## Directory structure ``` src/rest/ ├── components/ # React components that render REST pages ├── data/ # Auto-generated JSON data files (do not edit manually) ├── lib/ │ └── config.json # Pipeline configuration (versions, frontmatter defaults, etc.) ├── pages/ # Next.js page files for REST API routes ├── scripts/ │ └── update-files.ts # Pipeline entrypoint └── tests/ # Vitest tests for the pipeline ``` The Markdown files that live in `content/rest/` are also auto-generated but are partially editable — see [Content team guidance](#content-team-guidance) below. ## Configuring the pipeline `src/rest/lib/config.json` controls how the pipeline behaves. Key fields: | Field | Purpose | | --------------------- | ---------------------------------------------------------------------------- | | `api-versions` | Calendar-date API versions available per docs version | | `versionMapping` | Maps OpenAPI version names to docs short names | | `frontmatterDefaults` | Default frontmatter applied to every generated Markdown file | | `targetDirectory` | The `content/` subdirectory where Markdown files are written | | `indexOrder` | Controls child ordering in the `index.md` of `targetDirectory` | | `sha` | Auto-updated SHA of the `rest-api-description` commit used for the last sync | ## Running the pipeline locally <Steps> <Step title="Clone the OpenAPI description repo"> Clone [`github/rest-api-description`](https://github.com/github/rest-api-description) **inside** your local `docs-internal` checkout: ```bash theme={null} git clone https://github.com/github/rest-api-description ``` </Step> <Step title="Set up authentication"> Add a classic GitHub token with `repo` scope to your `.env` file and enable SSO for the `github` org: ```bash theme={null} GITHUB_TOKEN=ghp_your_token_here ``` </Step> <Step title="Run the sync script"> ```bash theme={null} npm run sync-rest -- -s rest-api-description models-gateway -o rest ``` The `-o rest` flag is the default, so you can omit it. This writes updated files to `src/rest/data/` and `content/rest/`. </Step> </Steps> ## Triggering the workflow manually If you need to pick up OpenAPI changes before the next scheduled run, you can manually trigger the workflow: <Steps> <Step title="Confirm the OpenAPI change is merged"> The OpenAPI change must be merged into the `main` branch of `github/rest-api-description` before you trigger the workflow. </Step> <Step title="Run the workflow"> Go to the [sync-openapi workflow](https://github.com/github/docs-internal/actions/workflows/sync-openapi.yml) and click **Run workflow**. Leave the source branch set to `main`. A new pull request with the `github-openapi-bot` label will be opened in `github/docs-internal`. </Step> </Steps> ### Triggering against an unmerged branch If the OpenAPI change is still in a pull request on `github/rest-api-description`, run the workflow and supply the **branch name** from that PR. This lets you validate the docs impact before the OpenAPI change merges. ## Content team guidance Writers can make limited edits to files in `content/rest/` without being overwritten: * **All frontmatter except `versions`** — You can change the title, intro, children order, and other frontmatter fields. The pipeline will **not** overwrite them on subsequent runs. * **`versions` frontmatter** — The pipeline overwrites this on every run. Do not edit it manually. * **Introduction paragraphs** — Add content **above** the auto-generation boundary comment: ```markdown theme={null} <!-- Content after this section is automatically generated --> ``` Anything below that comment will be replaced on the next sync. ## Escalation paths <AccordionGroup> <Accordion title="Pipeline failure"> 1. Check the workflow logs in `.github/workflows/sync-openapi.yml` 2. Verify your token has access to `github/rest-api-description` 3. Look for OpenAPI schema validation errors in the output 4. Review the generated diff in `src/rest/data/` for unexpected changes 5. Check `config.json` for version mapping issues 6. If the problem is in the schema itself, escalate to `#api-platform` Slack </Accordion> <Accordion title="OpenAPI schema issues"> Schema problems originate in `github/rest-api-description`, owned by the API Platform team. Reach out in `#api-platform` Slack or open an issue there. </Accordion> <Accordion title="General questions"> Ask in the `#docs-engineering` Slack channel or open an issue in `github/docs-engineering`. </Accordion> </AccordionGroup> ## Known limitations * **Shared pipeline** — REST, Webhooks, and GitHub Apps cannot be synced independently. Running `npm run sync-rest` syncs all three. * **Version frontmatter overwrite** — The `versions` field in generated Markdown is always overwritten. Do not rely on manually set values. * **Introduction placement** — Writer-authored introductions must appear above the `<!-- Content after this section is automatically generated -->` comment. * **Calendar-date API versions** — When a new calendar-date version is added to the OpenAPI, `api-versions` in `config.json` must be updated manually before the next sync. # REST documentation pipeline Source: https://www.mintlify.com/github/docs/engineering/rest-pipeline How REST API reference documentation is auto-generated from OpenAPI, including the sync workflow, manual triggers, local development, and pipeline configuration. The REST documentation pipeline auto-generates Markdown files in `content/rest/` from the OpenAPI description maintained in the [`github/rest-api-description`](https://github.com/github/rest-api-description) repository. The generated pages power the REST API reference at docs.github.com/rest. ## How it works The pipeline is triggered by the `sync-openapi.yml` GitHub Actions workflow. When the workflow runs, it executes `npm run sync-rest`, which reads the OpenAPI schema and: * **Creates** new Markdown files for new endpoints * **Updates** existing Markdown files when endpoints change * **Deletes** Markdown files for removed endpoints All output lands in the `content/rest/` directory. The workflow then opens a pull request in `github/docs-internal` with the label `github-openapi-bot` so the changes can be reviewed before merging. ## Shared pipeline The `sync-openapi.yml` workflow runs three pipelines together in a single pull request: <CardGroup> <Card title="REST" icon="code"> Generates REST API reference pages. Entrypoint: `npm run sync-rest` </Card> <Card title="GitHub Apps" icon="github"> Generates GitHub Apps permission reference pages. </Card> <Card title="Webhooks" icon="webhook"> Generates webhook event reference pages. Entrypoint: `npm run sync-webhooks` </Card> </CardGroup> <Warning> Because all three pipelines share the same workflow, you cannot run REST independently of Webhooks and GitHub Apps in the automated workflow. In local development you can run each script separately. </Warning> ## Triggering the workflow ### Scheduled runs The workflow runs automatically on a daily schedule. PRs created by the workflow carry the `github-openapi-bot` label. ### Triggering manually (from `main`) To sync sooner than the next scheduled run, trigger the workflow manually from the Actions tab using the default input options. This pulls from the `main` branch of `github/rest-api-description`. <Steps> <Step title="Open the workflow"> Go to the `sync-openapi.yml` workflow in the `github/docs-internal` Actions tab. </Step> <Step title="Click Run workflow"> Leave the source branch input as `main` and click **Run workflow**. </Step> <Step title="Review the pull request"> The workflow opens a new pull request in `github/docs-internal` with the `github-openapi-bot` label. </Step> </Steps> ### Triggering for an unmerged PR in rest-api-description If you need to propagate OpenAPI changes from a pull request that has not yet merged into `github/rest-api-description`: <Steps> <Step title="Open the workflow"> Go to the `sync-openapi.yml` workflow in the `github/docs-internal` Actions tab. </Step> <Step title="Enter the source branch"> Provide the **branch name** from the unmerged pull request in `github/rest-api-description` as the source branch input. </Step> <Step title="Run the workflow"> Click **Run workflow**. The resulting pull request in `github/docs-internal` will contain docs based on that unmerged branch. </Step> </Steps> ## Running the pipeline locally Use local development to preview REST documentation changes before triggering the automated workflow. <Steps> <Step title="Clone rest-api-description inside your docs-internal directory"> ```bash theme={null} git clone https://github.com/github/rest-api-description ``` The repository must be cloned at the root of your `docs-internal` working directory (not in a subdirectory). </Step> <Step title="Set a GitHub token in .env"> ```bash theme={null} GITHUB_TOKEN=<your-classic-token> ``` The token requires `repo` scopes. If you are a GitHub employee, enable SSO for the `github` organization on the token. </Step> <Step title="Run the sync script"> ```bash theme={null} npm run sync-rest -- -s rest-api-description models-gateway -o rest ``` The `-s` flag specifies the source directory (the cloned repo), and `-o rest` specifies the output pipeline. The `-o rest` flag is the default and can be omitted. </Step> </Steps> To run the Webhooks pipeline locally: ```bash theme={null} npm run sync-webhooks ``` ## Pipeline configuration The file `src/rest/lib/config.json` controls the behavior of the REST pipeline. Edit this file to configure version mappings and index ordering. | Property | Description | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | `api-versions` | Calendar-date API versions available for each docs version | | `versionMapping` | Maps OpenAPI version names (from `github/rest-api-description`) to the short names used in `docs-internal` | | `frontmatterDefaults` | Default frontmatter values added to every generated Markdown file in `content/rest/` | | `targetDirectory` | The directory inside `content/` where generated Markdown files are written | | `indexOrder` | Controls the order of child directories in `content/rest/index.md`. Use `startsWith` to pin directories to the top; all other directories are appended | | `sha` | The commit SHA from `github/rest-api-description` used to generate the current data. Updated automatically on each pipeline run | ## Generated files | Path | Description | | ---------------------------------- | -------------------------------------------------------------------------- | | `src/rest/data/` | Auto-generated data files produced by the pipeline. Do not edit manually. | | `content/rest/` | Auto-generated Markdown reference pages served to users. | | `src/rest/lib/config.json` | Pipeline configuration file. Edit to adjust version mappings and ordering. | | `src/rest/scripts/update-files.ts` | Entrypoint script for the REST pipeline (`npm run sync-rest`). | ## Content team guidance Content writers can manually edit certain parts of generated Markdown files in `content/rest/`: * **Any frontmatter except `versions`** — The pipeline overwrites `versions` on each run but does not touch other frontmatter fields. * **Introduction paragraphs** — Add content *above* the following comment in the file: ```markdown theme={null} <!-- Content after this section is automatically generated --> ``` Content below this comment is replaced on each pipeline run. <Note> When a new Markdown file is first created by the pipeline, it receives all frontmatter properties from `frontmatterDefaults` in `config.json`. Writers can then customize any frontmatter field except `versions`. </Note> ## Monitoring and escalation PRs created by the automated workflow carry the `github-openapi-bot` label. The `sha` field in `src/rest/lib/config.json` tracks which commit from `github/rest-api-description` was used to generate the current docs, providing an audit trail. If the pipeline fails: <Steps> <Step title="Check workflow logs"> Review the failed run in `.github/workflows/sync-openapi.yml`. </Step> <Step title="Verify repo access"> Confirm that the workflow has access to `github/rest-api-description`. </Step> <Step title="Check for schema validation errors"> Look for OpenAPI schema validation errors in the workflow output. </Step> <Step title="Review config.json"> Check `src/rest/lib/config.json` for version mapping issues, especially after a new API version is introduced. </Step> <Step title="Escalate if needed"> For issues with the OpenAPI schema itself, escalate to the API Platform team via the `#api-platform` Slack channel. </Step> </Steps> **Ownership:** * Pipeline failures → `#docs-engineering` Slack or open an issue in `github/docs-engineering` * OpenAPI schema issues → `#api-platform` Slack (API Platform team owns `github/rest-api-description`) # Search Source: https://www.mintlify.com/github/docs/engineering/search How docs.github.com search works, including the Elasticsearch backend, scraping and indexing pipeline, AI search autocomplete, and the search API endpoints. Search on docs.github.com is powered by **Elasticsearch**. When a user types a query, the server calls Elasticsearch and returns ranked results. This page explains how the search index is built, how to run the pipeline locally, and how the search API works. ## Search types The site supports two search modes: <CardGroup> <Card title="General search" icon="search"> Returns docs pages matching the query, sorted by popularity. Served from the `/api/search/v1` endpoint. Example: query `clone` returns URLs to docs pages about cloning repositories. </Card> <Card title="AI search autocomplete" icon="sparkles"> Returns human-readable full-sentence questions that best match the query. Based on previous searches and popular pages. Served from the `/api/search/ai-search-autocomplete/v1` endpoint. Example: query `How do I clone` returns `How do I clone a repository?` </Card> </CardGroup> You can query the general search endpoint directly: ``` https://docs.github.com/search?version=<VERSION>&language=<LANGUAGE>&query=<QUERY> ``` * **VERSION**: a numbered GHES version (e.g. `3.12`), `ghec`, or `dotcom` * **LANGUAGE**: one of `es`, `ja`, `pt`, `zh`, `ru`, `fr`, `ko`, `de` * **QUERY**: any alphanumeric string ## Architecture Elasticsearch stores pre-built indexes that the server queries at runtime. Indexes are populated through a two-step pipeline: 1. **Scrape** — fetch each page's content via the Article API and write structured JSON records to disk 2. **Index** — upload those JSON records into Elasticsearch The scrape step calls the Article API (`/api/article?pathname=<path>`) on a locally running server for each indexable page. Each record includes `title`, `intro`, `breadcrumbs`, `headings`, `content` (plain text, not HTML), and a unique `objectID` (the page permalink). ```json theme={null} { "objectID": "/en/actions/creating-actions/about-custom-actions", "breadcrumbs": "GitHub Actions / Creating actions", "title": "About custom actions", "headings": "About custom actions\nTypes of actions\n...", "content": "Actions are individual tasks that you can combine...", "intro": "Actions are individual tasks that you can combine...", "toplevel": "GitHub Actions", "popularity": 0 } ``` <Note> The `objectID` is set explicitly to the page permalink. This guarantees that subsequent indexing runs overwrite existing records rather than creating duplicates. </Note> ## Environment configuration | Variable | Description | | ------------------- | ------------------------------------------------------------------------------------------------------------------ | | `ELASTICSEARCH_URL` | URL of the Elasticsearch cluster. Required for search tests and manual indexing. Example: `http://localhost:9200/` | Set this in your `.env` file for local development: ```bash theme={null} ELASTICSEARCH_URL=http://localhost:9200/ ``` ## Running the pipeline manually ### General search Run the scrape and index steps separately, or together using the combined command. <Steps> <Step title="Start the scrape server"> The scrape server is a production-mode instance of the docs app running on port 4002 with minimal rendering enabled: ```bash theme={null} npm run general-search-scrape-server ``` This sets `MINIMAL_RENDER=true` and `CHANGELOG_DISABLED=true` to reduce memory usage during scraping. </Step> <Step title="Scrape page content"> In a separate terminal, run the scrape script against the running server: ```bash theme={null} npm run general-search-scrape -- <scrape-directory> ``` To scrape a specific language and version only: ```bash theme={null} npx tsx src/search/scripts/scrape/scrape-cli.ts -l en -V fpt <scrape-directory> ``` The script writes one JSON file per page into the target directory. </Step> <Step title="Index scraped records into Elasticsearch"> Upload the scraped records to Elasticsearch: ```bash theme={null} npm run index-general-search -- <scrape-directory> ``` </Step> </Steps> **Combined command** — starts the scrape server automatically, waits for it to be ready, runs the scrape, then exits: ```bash theme={null} npm run general-search-scrape-with-server ``` <Warning> The combined command sets `--max_old_space_size=8192`. Full scrapes across all versions and languages can take 40+ minutes and require significant memory. </Warning> For GHES release scraping specifically: ```bash theme={null} npm run ghes-release-scrape-with-server ``` ### AI search autocomplete AI search autocomplete data comes from an internal data repository, not from scraping. Clone [`github/docs-internal-data`](https://github.com/github/docs-internal-data) to the root of the docs directory, then index: ```bash theme={null} npm run index-ai-search-autocomplete -- docs-internal-data ``` ### Text analysis To analyze how Elasticsearch processes text (useful for debugging relevance issues): ```bash theme={null} npm run analyze-text ``` ## Running search tests Search tests require a running Elasticsearch instance: ```bash theme={null} npm run test:search ``` This sets `ELASTICSEARCH_URL=http://localhost:9200/` automatically via the test script. Language tests that involve search also need the variable: ```bash theme={null} npm run test:languages ``` ## Production workflow In production, search indexes are rebuilt automatically by GitHub Actions: | Workflow | Schedule | Scope | | ------------------------------- | ------------- | -------------------------- | | `index-general-search.yml` | Every 4 hours | All versions and languages | | `index-autocomplete-search.yml` | Daily | AI autocomplete data | You can manually trigger either workflow from the Actions tab. For urgent index updates after merging to `main`, trigger `index-general-search.yml` with a specific version and language to reduce run time (a single version/language takes 5–10 minutes versus \~40 minutes for all). <Tip> When manually triggering, run only `free-pro-team@latest` + `en` first, then expand to other versions and languages as needed. </Tip> ## Key files | Path | Description | | ---------------------------------------------------- | ---------------------------------------------------- | | `src/search/components/Search.tsx` | Browser-side search input component | | `src/search/components/SearchResults.tsx` | Browser-side search results rendering | | `src/search/middleware/general-search-middleware.ts` | Server-side entrypoint for `/search` page | | `src/search/middleware/search-routes/` | API route handlers for search endpoints | | `src/search/scripts/scrape/` | Scrape scripts and `lib/build-records-from-api.ts` | | `src/search/scripts/index/` | Indexing scripts for general search and autocomplete | | `src/search/scripts/analyze-text.ts` | Text analysis utility | | `src/search/tests/` | Search tests (require `ELASTICSEARCH_URL`) | ## Search features * **Typo tolerance** — Elasticsearch returns results even for misspelled queries. * **Advanced query syntax** — Supports exact matching with quotes (`"exact phrase"`) and term exclusion with a minus sign (`-excluded`). Enabled in the browser client. * **Multilingual** — Indexes exist for each supported language. Search respects the language of the current docs URL. * **Weighted attributes** — Title is ranked higher than body content. * **Version-scoped** — Each query targets the index for the requested GitHub product version. <Note> There is a lag of up to 4 hours between content changes merging to `main` and those changes appearing in search results, due to the indexing schedule. </Note> # Server overview Source: https://www.mintlify.com/github/docs/engineering/server-overview Architecture of the docs.github.com Node.js application, including the Express and Next.js stack, subject folder pattern, and key src/ directories. The docs.github.com application is a dynamic Node.js web server built on Express and Next.js. This page describes how the application is structured, what each major directory does, and how to run it locally. ## History <Steps> <Step title="Ruby on Rails"> The site started as a Ruby on Rails web application. </Step> <Step title="Jekyll"> It was converted to a static site powered by [Jekyll](https://jekyllrb.com/), a Ruby static site generator. Many authoring conventions from this era are still in use today: Markdown content files, Liquid templating, frontmatter, and `redirect_from` support. </Step> <Step title="Nanoc"> The site migrated to [Nanoc](https://nanoc.app/), another Ruby static site generator. </Step> <Step title="Node.js + Express + Next.js (current)"> Today the site is a dynamic Node.js server powered by Express. Middleware handles HTTP redirects, language header detection, and dynamic content generation across all flavors of GitHub product documentation. </Step> </Steps> ## Technology stack The application runs on **Node.js** (v24+) with the following core frameworks: * **Express** — HTTP server and middleware pipeline * **Next.js** — React rendering and routing (currently transitioning from the pages router to the app router) * **React** — UI components * **TypeScript** — used throughout `src/` The entry point is `src/frame/server.ts`, which calls `src/frame/start-server.ts` to initialize the Express app. ## Subject folder pattern The `src/` directory is organized by **subject** rather than by technical role (client, server, stylesheet, etc.). Each subject folder represents a major capability of the site and contains all the code for that capability in one place: middleware, components, scripts, tests, and documentation. ``` src/ xsubject/ README.md lib/ middleware/ components/ pages/ stylesheets/ scripts/ tests/ ``` A subject folder is created when a capability has its own specific tests. Not every element listed above is required — use only what the subject needs. <Note> Two broad folders exist for code that is difficult to assign to a specific subject: * `src/frame/` — cross-cutting infrastructure (header, footer, global sidebar, middleware orchestration) * `src/workflows/` — process automation rather than production application code </Note> ## Key src/ directories <CardGroup> <Card title="src/frame/" icon="layout-template"> The "spine" of the application. Handles Express server setup, the full middleware pipeline, shared React layout components (header, footer, global sidebar), the `req.context` object, and Next.js integration. Code belongs here only when it is truly cross-cutting — used by three or more subjects — or is fundamental infrastructure. </Card> <Card title="src/content-render/" icon="file-text"> Markdown rendering pipeline. Transforms raw Markdown files (with Liquid templating) into HTML served to the client. Includes remark/rehype plugins for GFM, syntax highlighting, and custom GitHub Docs extensions. </Card> <Card title="src/search/" icon="search"> Elasticsearch-backed search. Exposes the `/api/search/v1` and `/api/search/ai-search-autocomplete/v1` endpoints, browser-side search components, and the scraping and indexing scripts used to populate the search index. </Card> <Card title="src/rest/" icon="code"> REST API reference documentation pipeline. Auto-generates Markdown in `content/rest/` from the OpenAPI description in `github/rest-api-description`. Contains the sync script, generated data files, and config. </Card> <Card title="src/graphql/" icon="git-merge"> GraphQL API reference documentation. Similar pipeline to REST — syncs schema data and generates documentation pages for the GraphQL API. </Card> <Card title="src/webhooks/" icon="webhook"> Webhook event reference documentation. Shares the sync pipeline with REST and GitHub Apps (`sync-openapi.yml`). </Card> <Card title="src/content-linter/" icon="check-circle"> Content quality checking. Runs markdownlint rules and custom rules against Markdown files in `content/` and `data/`. Used in CI and as a pre-commit hook. </Card> <Card title="src/languages/" icon="globe"> Internationalization. Language detection middleware, translation file management, and the `ENABLED_LANGUAGES` configuration that controls which languages the server serves. </Card> <Card title="src/versions/" icon="tag"> Version management. Detects the requested GitHub product version from URLs and populates `req.context` with version information for conditional rendering. </Card> <Card title="src/redirects/" icon="arrow-right"> URL redirect handling. Builds and serves the redirect map derived from `redirect_from` frontmatter and other redirect sources. </Card> </CardGroup> ## Middleware pipeline The middleware pipeline is defined in `src/frame/middleware/index.ts` and executes in this order for every request: 1. **Connection management** — timeout handling and abort detection 2. **Security and headers** — Helmet, CORS 3. **Language detection** — parses `Accept-Language` headers and URL language prefix 4. **Context initialization** — builds the base `req.context` object 5. **URL normalization and redirects** — resolves redirect rules before serving content 6. **Page finding** — locates the matching page in the site tree 7. **Subject-specific middleware** — version detection, feature flags, breadcrumbs, TOC 8. **Page rendering** — renders Markdown to HTML and sends the response 9. **Error handling** — 404 and 500 error pages Each subject registers its middleware into this pipeline. When adding new middleware, decide first whether it belongs in a specific subject directory. ## Build and run <Tabs> <Tab title="Development"> ```bash theme={null} npm ci # Clean install of dependencies npm run build # Next.js build with webpack (run once per branch) npm start # Start dev server with nodemon on port 4000 ``` The development server starts with `NODE_ENV=development` and `ENABLED_LANGUAGES=en`. It uses `nodemon` to reload on changes to `.ts`, `.json`, `.yml`, `.md`, `.html`, and `.scss` files. Visit [http://localhost:4000](http://localhost:4000) when the server is running. <Tip> To enable additional languages locally, edit the `start` script in `package.json` and update `ENABLED_LANGUAGES`. For example, set `ENABLED_LANGUAGES='en,ja,pt'` to add Japanese and Portuguese. Restart the server for the change to take effect. </Tip> </Tab> <Tab title="Production / CI"> ```bash theme={null} npm run start-for-ci ``` Starts the server with `NODE_ENV=production` and `ENABLED_LANGUAGES=en` using `tsx` directly (no nodemon). Used in CI environments and review deployments. </Tab> <Tab title="Debug"> ```bash theme={null} npm run debug ``` Starts the server in development mode with the Node.js inspector attached (`--inspect`). Connect your debugger to the inspector port for breakpoint debugging. </Tab> </Tabs> ## Adding a new subject folder When a new capability grows to the point of having its own tests, create a subject folder under `src/`: <Steps> <Step title="Create the folder structure"> Create `src/mysubject/` with at minimum a `README.md` and `tests/` directory. </Step> <Step title="Add tests to the workflow"> Open `.github/workflows/test.yml` and add an entry for your test files. This file is manually maintained — new test files do not run automatically. </Step> <Step title="Add to branch protection"> After your entry in `test.yml` merges to `main`, add it to the branch protection required checks so it gates pull requests. </Step> <Step title="Register middleware (if needed)"> If your subject has Express middleware, import it into `src/frame/middleware/index.ts` at the appropriate position in the pipeline. </Step> </Steps> # Testing Source: https://www.mintlify.com/github/docs/engineering/testing How to run the test suite, what tests exist, and how to add new tests. The docs codebase uses [Vitest](https://vitest.dev/) as its test runner. Each `src/` subject directory contains its own `tests/` subdirectory. Playwright handles end-to-end browser tests separately. ## Running tests ### Run the full suite ```bash theme={null} npm test ``` This runs all Vitest tests matching the patterns in `vitest.config.ts`: ```ts theme={null} include: [ '**/*.{test}.?(c|m)[jt]s?(x)', 'src/**/tests/*.[jt]s', 'src/**/tests/**/*.[jt]s', ] ``` Playwright tests (`playwright-*.spec.ts`) are excluded from this glob and must be run separately. ### Run a specific subject Pass the path of a test directory or file to scope the run: ```bash theme={null} npm test -- src/graphql/tests npm test -- src/rest/tests npm test -- src/content-linter/tests ``` ### Fixture-based test suites Several test suites require a local fixture server. Use `npm run fixture-test` instead of `npm test` for these: ```bash theme={null} npm run fixture-test ``` This sets `ROOT=src/fixtures/fixtures` and runs tests under `src/fixtures/tests/`. ## Named test suite aliases `package.json` defines several aliases for common test scenarios. Use these instead of constructing long environment variable chains by hand. <Tabs> <Tab title="Fixtures"> ```bash theme={null} npm run test:fixtures ``` Runs `src/fixtures/tests/` with the fixture root and translations fixture root set. </Tab> <Tab title="Search"> ```bash theme={null} npm run test:search ``` Runs `src/search/tests/` against a local Elasticsearch instance at `http://localhost:9200/`. You must have Elasticsearch running locally for these tests to pass. </Tab> <Tab title="Article API"> ```bash theme={null} npm run test:article-api ``` Runs `src/article-api/tests/` with `--no-file-parallelism --maxWorkers=1` to avoid port conflicts. </Tab> <Tab title="Changelogs"> ```bash theme={null} npm run test:changelogs ``` Runs `src/changelogs/tests/` with a fixture changelog feed. </Tab> <Tab title="Landings"> ```bash theme={null} npm run test:landings ``` Runs `src/landings/tests/` against the fixture root. </Tab> <Tab title="Languages"> ```bash theme={null} npm run test:languages ``` Runs `src/languages/tests/` with all languages enabled and a local Elasticsearch instance. </Tab> </Tabs> ## Playwright end-to-end tests Browser tests use [Playwright](https://playwright.dev/) and require a running local server pointed at the fixture root. ```bash theme={null} npm run playwright-test ``` This runs tests in `src/fixtures/playwright.config.ts` using the Google Chrome project. The `start-for-playwright` server must be running, or Playwright's `webServer` configuration will start it automatically. ## Test configuration The Vitest configuration lives in `vitest.config.ts` at the repo root: ```ts theme={null} export default { test: { include: [ '**/*.{test}.?(c|m)[jt]s?(x)', 'src/**/tests/*.[jt]s', 'src/**/tests/**/*.[jt]s', ], exclude: ['**/tests/playwright-*.spec.ts'], watch: false, alias: { '@/': new URL('./src/', import.meta.url).pathname, }, globalSetup: './src/tests/vitest.setup.ts', teardownTimeout: 500, }, } ``` The `@/` alias maps to `src/`, so test files can use `import { foo } from '@/rest/lib/config'` instead of relative paths. ## Test structure Each subject directory follows the same layout: ``` src/rest/ └── tests/ ├── rest.ts # Main test file └── fixtures/ # Fixture data used by tests (if needed) ``` When you add a new subject, create a `tests/` subdirectory inside it. Vitest will automatically discover files matching the glob patterns. ## Adding tests to CI The `.github/workflows/test.yml` workflow runs Vitest tests in a matrix. Each row in the matrix corresponds to a subject directory name: ```yaml theme={null} matrix: name: - archives - article-api - assets - graphql - rest # ... ``` When you add a new subject with tests, add its name to the matrix. Then add it to the **required status checks** in the branch protection rules for `main` — tests not listed as required checks will not block merges. <Warning> If you add a test suite to the matrix but forget to add it to required checks, a failing test will not prevent a broken PR from merging. </Warning> ## Search tests and Elasticsearch The `test:search` and `test:languages` suites send real queries to Elasticsearch. They require a running Elasticsearch instance: ```bash theme={null} # Start Elasticsearch (version must match @elastic/elasticsearch in package.json) docker run -p 9200:9200 -e "discovery.type=single-node" elasticsearch:8.x # Then run npm run test:search npm run test:languages ``` These tests are skipped automatically when `ELASTICSEARCH_URL` is not set, so they will not break CI runs without the service. ## Getting help * Slack: `#docs-engineering` * Repo: `github/docs-engineering` # Troubleshooting Source: https://www.mintlify.com/github/docs/engineering/troubleshooting Solutions to common issues contributors encounter when working on the GitHub Docs codebase. <Note> The canonical version of the contributor troubleshooting guide lives at [docs.github.com/contributing/setting-up-your-environment-to-work-on-github-docs/troubleshooting-your-environment](https://docs.github.com/en/contributing/setting-up-your-environment-to-work-on-github-docs/troubleshooting-your-environment). This page covers engineering-specific issues not addressed there. </Note> ## Failed status checks If a required check fails on your PR, read the full log before asking for help. Most failures have a specific error message that points to the root cause. <AccordionGroup> <Accordion title="Content lint failures"> The content linter enforces style and structure rules on Markdown files. Run it locally to see the same errors CI sees: ```bash theme={null} npm run lint-content -- --paths content/path/to/file.md ``` Common causes: * Incorrect heading hierarchy (skipping from `##` to `####`) * Use of raw HTML instead of Liquid or Markdown equivalents * Broken internal links * Missing or invalid frontmatter fields Run the linter on the entire content directory to catch all issues: ```bash theme={null} npm run lint-content ``` </Accordion> <Accordion title="TypeScript errors (tsc check)"> Run the type checker locally to reproduce the error: ```bash theme={null} npm run tsc ``` This runs `tsc --noEmit` and reports all type errors without emitting output files. </Accordion> <Accordion title="Link check failures"> The link checker validates internal and external links. Run it locally: ```bash theme={null} npm run check-links-internal npm run check-links-external ``` Internal link failures are often caused by a page being referenced that does not exist yet, or a redirect not being set up after moving content. </Accordion> <Accordion title="Test failures"> Run the failing test suite locally using the subject name: ```bash theme={null} npm test -- src/SUBJECT/tests ``` For fixture-dependent tests, use: ```bash theme={null} npm run fixture-test -- src/fixtures/tests ``` See [Testing](/engineering/testing) for the full list of test aliases. </Accordion> </AccordionGroup> ## Stalled status checks A status check that never starts (stuck in "queued" state) is different from one that fails. * **Required checks that never start** may indicate a workflow concurrency issue. Cancelling the stuck run and re-running it often resolves this. * **The merge queue check** can stall if a PR earlier in the queue has a blocking failure. Check the merge queue status page for the repository. * If a check is stuck for more than 30 minutes, ping `@github/docs-engineering` in `#docs-engineering`. ## Node.js version issues The project requires Node.js version 24 or higher, as specified in `package.json`: ```json theme={null} "engines": { "node": "^24" } ``` If you see unexpected errors on startup or during tests, verify your Node.js version: ```bash theme={null} node --version ``` Use a version manager like [nvm](https://github.com/nvm-sh/nvm) or [fnm](https://github.com/Schniz/fnm) to switch versions: ```bash theme={null} nvm use 24 # or fnm use 24 ``` ## Build failures If `npm run build` fails: <Steps> <Step title="Clear the Next.js cache"> ```bash theme={null} rm -rf .next ``` </Step> <Step title="Reinstall dependencies"> ```bash theme={null} rm -rf node_modules && npm ci ``` </Step> <Step title="Run the build again"> ```bash theme={null} npm run build ``` Check the error output carefully — Next.js build errors often include the file and line number of the problem. </Step> </Steps> ## Search not working locally The search feature requires a running Elasticsearch instance. Without it, search returns no results and `test:search` fails. ```bash theme={null} # Start Elasticsearch locally (Docker) docker run -p 9200:9200 \ -e "discovery.type=single-node" \ docker.elastic.co/elasticsearch/elasticsearch:8.19.1 ``` The Elasticsearch version must match `@elastic/elasticsearch` in `package.json` (currently `8.19.1`). Once running, set the URL in your environment: ```bash theme={null} ELASTICSEARCH_URL=http://localhost:9200/ npm run test:search ``` For a full local search experience, you also need to index content: ```bash theme={null} npm run index-general-search ``` ## Pages returning 404 locally A page returns 404 if it exists as a Markdown file but is not listed in the `children` frontmatter of its parent `index.md`. Check the parent directory's `index.md` for a `children:` list. If your file is not in that list, add it: ```markdown theme={null} --- title: My section children: - /my-section/existing-page - /my-section/your-new-page # Add this --- ``` <Note> This is enforced by the content linter. A missing `children` entry will also cause a lint failure in CI. </Note> ## Missing content after auto-sync If content is missing after running a sync script (REST, GraphQL, webhooks), check: 1. The sync script completed without errors 2. The generated files in `src/*/data/` were updated 3. Your local server was restarted — the dev server does not hot-reload data files in all cases Restart the dev server after running any sync script: ```bash theme={null} npm start ``` ## Debugging the local server For an interactive debugger session: ```bash theme={null} npm run debug ``` This starts the server with `--inspect` and `NODE_ENV=development`. Attach a debugger using the Node.js inspector protocol (Chrome DevTools or VS Code). ## Getting help <CardGroup> <Card title="Open an issue" icon="circle-dot" href="https://github.com/github/docs-engineering/issues/new"> For bugs, unexpected behavior, or persistent failures. Use `github/docs-engineering` for engineering issues. </Card> <Card title="Docs Engineering Slack" icon="slack"> For internal staff: post in `#docs-engineering`. For urgent issues affecting production, tag `@github/docs-engineering`. </Card> </CardGroup> # Webhooks and GitHub Apps Source: https://www.mintlify.com/github/docs/engineering/webhooks-and-apps How webhook and GitHub Apps documentation is generated from the OpenAPI and other automated pipelines. Webhook event documentation and GitHub Apps endpoint documentation are both auto-generated from the OpenAPI stored in [`github/rest-api-description`](https://github.com/github/rest-api-description). They share the same `sync-openapi.yml` workflow as the REST pipeline, but write output to separate directories. Several other documentation types — audit logs, secret scanning, and CodeQL CLI — have their own independent sync scripts. ## The shared OpenAPI pipeline The `.github/workflows/sync-openapi.yml` workflow triggers three pipelines in a single run: <CardGroup> <Card title="REST" icon="code"> Writes Markdown to `content/rest/` and data to `src/rest/data/` </Card> <Card title="Webhooks" icon="webhook"> Writes data to `src/webhooks/data/` </Card> <Card title="GitHub Apps" icon="github"> Writes data to `src/github-apps/data/` </Card> </CardGroup> All three pipelines are triggered by `npm run sync-rest`. For webhooks and GitHub Apps, the script writes to different output directories using the `-o` flag. Automated PRs carry the `github-openapi-bot` label. ## Webhooks pipeline The webhooks pipeline generates documentation for `docs.github.com/webhooks-and-events/webhooks/webhook-events-and-payloads`. ### Directory structure ``` src/webhooks/ ├── components/ # React components for rendering webhook event pages ├── data/ # Auto-generated JSON files (do not edit manually) ├── lib/ │ └── config.json # SHA of last synced rest-api-description commit ├── middleware/ # Express middleware for injecting webhook data ├── pages/ # Next.js page files ├── scripts/ │ └── sync.ts # Pipeline entrypoint └── tests/ # Vitest tests ``` The content file `content/webhooks-and-events/webhooks/webhook-events-and-payloads` can have manually authored frontmatter and an introductory paragraph. Automated content is appended after that. ### Running locally ```bash theme={null} npm run sync-rest -- -s rest-api-description -o webhooks ``` Or use the dedicated script alias: ```bash theme={null} npm run sync-webhooks ``` ## GitHub Apps pipeline The GitHub Apps pipeline generates the endpoint permission tables for: * Endpoints available for GitHub App installation access tokens * Endpoints available for GitHub App user access tokens * Endpoints available for fine-grained personal access tokens * Permissions required for GitHub Apps * Permissions required for fine-grained personal access tokens ### Directory structure ``` src/github-apps/ ├── components/ # React components for endpoint/permission tables ├── data/ # Auto-generated JSON files (do not edit manually) ├── lib/ │ └── config.json # SHA of last synced rest-api-description commit ├── pages/ # Next.js page files ├── scripts/ # Pipeline scripts └── tests/ # Vitest tests ``` ### Running locally ```bash theme={null} npm run sync-rest -- -s rest-api-description -o github-apps ``` ### Content team guidance Writers can update frontmatter and add an introduction paragraph in the associated Markdown file above the auto-generation comment: ```markdown theme={null} <!-- Content after this section is automatically generated --> ``` The `versions` frontmatter property is overwritten on every pipeline run. ## Other automated documentation pipelines Several other doc types are generated by independent sync scripts with their own workflows. <AccordionGroup> <Accordion title="Audit logs — npm run sync-audit-log"> **Workflow**: `.github/workflows/sync-audit-logs.yml` **Script**: `src/audit-logs/scripts/sync.ts` Generates audit log event documentation. Run manually with: ```bash theme={null} npm run sync-audit-log ``` </Accordion> <Accordion title="Secret scanning — npm run sync-secret-scanning"> **Workflow**: `.github/workflows/sync-secret-scanning.yml` **Script**: `src/secret-scanning/scripts/sync.ts` Generates the list of supported secret scanning patterns. Run manually with: ```bash theme={null} npm run sync-secret-scanning ``` </Accordion> <Accordion title="CodeQL CLI — npm run sync-codeql-cli"> **Workflow**: `.github/workflows/sync-codeql-cli.yml` **Script**: `src/codeql-cli/scripts/sync.ts` Generates CodeQL CLI reference documentation. Run manually with: ```bash theme={null} npm run sync-codeql-cli ``` </Accordion> <Accordion title="GraphQL — npm run sync-graphql"> **Workflow**: `.github/workflows/sync-graphql.yml` **Script**: `src/graphql/scripts/sync.ts` Fetches the GraphQL schema from GitHub's API. See [GraphQL docs](/engineering/graphql-docs) for details. </Accordion> </AccordionGroup> ## SHA tracking Each OpenAPI-driven pipeline stores the SHA of the `github/rest-api-description` commit it last synced from. This is recorded in the `sha` field of each pipeline's `config.json`: * `src/webhooks/lib/config.json` * `src/github-apps/lib/config.json` * `src/rest/lib/config.json` This value is updated automatically when the pipeline runs and gives you a precise reference for the source of every generated file. ## Escalation paths | Issue | Contact | | -------------------------------- | ------------------------------ | | Pipeline failures | `#docs-engineering` Slack | | OpenAPI schema errors | `#api-platform` Slack | | Audit log / secret scanning data | Respective owning teams | | General questions | `github/docs-engineering` repo | ## Known limitations * **Shared pipeline** — Webhooks and GitHub Apps cannot be synced independently of each other or of REST. All three run together. * **Single webhook page** — All webhook events render on a single page, which can affect performance for large payloads. * **Introduction placement** — Writer-authored introductions must appear before automated content in the source Markdown file. # Introduction Source: https://www.mintlify.com/github/docs/introduction GitHub Docs is the open-source platform behind docs.github.com. Learn what it is, how the two repositories work together, and how you can contribute. GitHub Docs is the open-source content and platform that powers [docs.github.com](https://docs.github.com) — GitHub's official product documentation. The site covers everything from getting started guides to deep dives on the GitHub API, Actions, Codespaces, and more. The platform itself is a Node.js application built on Express and Next.js, and the content is written in Markdown with Liquid templating. ## Two repositories, one site The GitHub Docs project is split across two repositories that sync frequently: <Columns> <Card title="github/docs" icon="lock-open" href="https://github.com/github/docs"> **Public.** Open to external contributions. Accepts edits to Markdown content files in `/content` and select `/data` sections (reusables and variables). Infrastructure code, workflows, and site-building logic are not open for external modification. </Card> <Card title="github/docs-internal" icon="lock" href="https://github.com/github/docs-internal"> **Private.** For GitHub employees. Internal contributions — new features, platform changes, early-access content — should go here. Changes flow to `github/docs` through an automated sync. </Card> </Columns> <Note> Content changes made in either repository are reflected in the other through frequent automated syncs. If you are a GitHub employee working with a customer, you can use `github/docs`, but most internal work should go to `github/docs-internal`. </Note> ## Who can contribute <Tabs> <Tab title="Open source contributors"> Anyone outside GitHub can contribute to `github/docs`. The most common contributions are: * Fixing typos and grammatical errors * Improving clarity or accuracy of existing articles * Adding missing information to an existing topic * Updating outdated content External contributors work with `.md` files in `/content` and select files in `/data/reusables` and `/data/variables`. Pull requests to infrastructure files, CI workflows, or application source code (`/src`) will not be accepted. See the [contribution guidelines](https://docs.github.com/en/contributing) for full details, including style expectations and the review process. </Tab> <Tab title="GitHub employees (Hubbers)"> GitHub employees contribute through `github/docs-internal`. See the [CONTRIBUTING.md](https://github.com/github/docs-content/blob/main/CONTRIBUTING.md) in the `docs-content` repository for GitHub-specific processes, including how to file issues, request reviews, and work with the Docs Content team. Hubbers may also post to `github/docs` when collaborating with external contributors or community members, but internal content changes should generally target `docs-internal`. </Tab> </Tabs> ## What lives in this repo The `github/docs` repository is organized into a few key top-level directories: | Directory | Purpose | | --------------- | --------------------------------------------------------------------------------------------------------------------- | | `/content` | All English Markdown documentation, organized by product | | `/data` | Reusables, variables, learning tracks, GraphQL data, and more | | `/src` | Application source code (Node.js, Express, Next.js) organized by subject folders | | `/contributing` | Contributor guides (largely superseded by [docs.github.com/en/contributing](https://docs.github.com/en/contributing)) | ## Licensing The project is dual-licensed: * **Creative Commons Attribution 4.0** — documentation and content in `assets/`, `content/`, and `data/` * **MIT License** — application source code ## Explore further <CardGroup> <Card title="Quickstart" icon="rocket" href="/quickstart"> Set up a local development environment and make your first content edit. </Card> <Card title="Site architecture" icon="sitemap" href="/site-architecture"> Understand how the repository is structured — content, data, and application source. </Card> <Card title="Content model" icon="file-lines" href="/content/content-model"> Learn how articles are organized, typed, and connected on docs.github.com. </Card> <Card title="Pull requests" icon="code-pull-request" href="/contributing/pull-requests"> Follow the contribution workflow to get your changes reviewed and merged. </Card> </CardGroup> # Quickstart Source: https://www.mintlify.com/github/docs/quickstart Clone the github/docs repository, install dependencies, start the local dev server, make a content edit, and open a pull request — all in a few minutes. This guide walks you through setting up a local development environment for the GitHub Docs project and making your first content contribution. The full site runs locally at `localhost:4000` so you can preview changes before opening a pull request. ## Prerequisites <Columns> <Card title="Node.js v24" icon="node-js"> The site requires Node.js `^24`. Download the LTS installer from [nodejs.org](https://nodejs.org) or use a version manager like [`nodenv`](https://github.com/nodenv/nodenv). The required version is specified in `package.json`. </Card> <Card title="Git" icon="code-branch"> You'll need Git to clone the repository and manage branches. See the [Set up Git](https://docs.github.com/en/get-started/git-basics/set-up-git) guide if you're starting from scratch. </Card> </Columns> ## Set up your environment <Steps> <Step title="Fork and clone the repository"> Fork `github/docs` on GitHub, then clone your fork locally: ```bash theme={null} git clone https://github.com/YOUR-USERNAME/docs cd docs ``` If you only want to read the source without contributing, you can clone the upstream directly: ```bash theme={null} git clone https://github.com/github/docs cd docs ``` </Step> <Step title="Install dependencies"> Install all Node.js dependencies using a clean install. This does not modify `package-lock.json`: ```bash theme={null} npm ci ``` <Note> Run `npm ci` again any time you pull new changes from the remote — dependency versions may have been updated. </Note> </Step> <Step title="Build static assets"> Generate the JavaScript and CSS bundles needed by the application: ```bash theme={null} npm run build ``` You only need to run this once per branch checkout. It does not need to be re-run when you edit Markdown content. </Step> <Step title="Start the development server"> Start the local Node.js/Express server: ```bash theme={null} npm start ``` Open [http://localhost:4000](http://localhost:4000) in your browser. You should see the full docs site running locally. To stop the server, press `Ctrl+C` in your terminal. </Step> </Steps> <Tip> Prefer working in the browser? Use [GitHub Codespaces](https://docs.github.com/en/codespaces/quickstart) to get a fully configured environment in minutes — no local installation required. Open the `github/docs` repo and click **Code > Codespaces > New codespace**. </Tip> ## Make your first content edit All English documentation lives in the `/content` directory, organized by product. Files are written in Markdown and use [YAML frontmatter](https://docs.github.com/en/contributing/syntax-and-versioning-for-github-docs/using-markdown-and-liquid-in-github-docs) and [Liquid templating](https://docs.github.com/en/contributing/syntax-and-versioning-for-github-docs/using-markdown-and-liquid-in-github-docs). <Steps> <Step title="Create a new branch"> Always work on a dedicated branch, not on `main`: ```bash theme={null} git checkout -b my-content-fix ``` </Step> <Step title="Find and edit a content file"> Navigate to the relevant file under `content/`. For example, to edit the GitHub CLI overview: ``` content/ └── github-cli/ └── github-cli/ └── about-github-cli.md ``` Every content file starts with frontmatter: ```markdown theme={null} --- title: About GitHub CLI intro: 'You can use GitHub CLI to work with GitHub from the command line.' versions: fpt: '*' ghes: '*' ghec: '*' --- ``` Edit the Markdown body below the frontmatter. The dev server does **not** hot-reload content — refresh your browser at `localhost:4000` to see changes. </Step> <Step title="Run the content linter"> The content linter enforces style, structure, and quality rules across all Markdown files. Run it on your changed files before committing: ```bash theme={null} npm run lint-content -- --paths content/github-cli/github-cli/about-github-cli.md ``` To lint all changed files at once: ```bash theme={null} npm run lint-content ``` Linting errors will block your pull request's required checks. Fix them locally to save time. <Tip> The linter can auto-fix some issues. Run with `--fix` to apply safe automatic corrections: ```bash theme={null} npm run lint-content -- --fix --paths content/path/to/file.md ``` </Tip> </Step> <Step title="Commit your changes"> Stage and commit your edits: ```bash theme={null} git add content/github-cli/github-cli/about-github-cli.md git commit -m "docs: clarify GitHub CLI authentication steps" ``` </Step> </Steps> ## Open a pull request Push your branch to your fork and open a pull request against `github/docs`: ```bash theme={null} git push origin my-content-fix ``` Then go to your fork on GitHub and click **Compare & pull request**. The PR template will guide you through describing your change. <Columns> <Card title="Contribution guidelines" icon="code-pull-request" href="/contributing/pull-requests"> Learn about the review process, what reviewers look for, and how long merges take. </Card> <Card title="Translations" icon="globe" href="/contributing/translations"> Understand how merged content is translated into supported languages automatically. </Card> </Columns> ## Enabling additional languages locally By default, the local server only runs with English enabled. To run with additional languages, set `ENABLED_LANGUAGES` inline when starting the server: ```bash theme={null} ENABLED_LANGUAGES=en,ja,pt npm start ``` Or set it in your `.env` file to avoid typing it every time. Restart the server after any change to `ENABLED_LANGUAGES`. Supported language codes are defined in [`src/languages/lib/languages.ts`](https://github.com/github/docs/blob/main/src/languages/lib/languages.ts). ## Next steps <CardGroup> <Card title="Site architecture" icon="sitemap" href="/site-architecture"> Understand how the full repository is organized across content, data, and source directories. </Card> <Card title="Frontmatter reference" icon="file-code" href="/content/frontmatter"> Learn all available frontmatter fields, including versions, redirects, and layout options. </Card> <Card title="Versioning" icon="code-branch" href="/content/versioning"> Version content across GitHub.com, GitHub Enterprise Server, and GitHub Enterprise Cloud. </Card> <Card title="Liquid helpers" icon="brackets-curly" href="/content/liquid-helpers"> Use Liquid tags for conditional content, reusables, variables, and tool switching. </Card> </CardGroup> # Site architecture Source: https://www.mintlify.com/github/docs/site-architecture A map of the github/docs repository — how content, data, and application source are organized, and how the Node.js/Express/Next.js server fits together. The `github/docs` repository is a monorepo containing both the documentation content and the application that serves it. Understanding the directory structure helps you find the right place to make changes, whether you're editing an article or working on the platform itself. ## Repository overview <Tree> <Tree.Folder name="github/docs"> <Tree.Folder name="content/"> <Tree.File name="README.md" /> <Tree.Folder name="actions/"> <Tree.File name="index.md" /> </Tree.Folder> <Tree.Folder name="rest/"> <Tree.File name="index.md" /> </Tree.Folder> </Tree.Folder> <Tree.Folder name="data/"> <Tree.Folder name="reusables/" /> <Tree.Folder name="variables/" /> <Tree.Folder name="learning-tracks/" /> <Tree.Folder name="graphql/" /> <Tree.Folder name="features/" /> </Tree.Folder> <Tree.Folder name="src/"> <Tree.Folder name="frame/" /> <Tree.Folder name="content-render/" /> <Tree.Folder name="content-linter/" /> <Tree.Folder name="rest/" /> <Tree.Folder name="search/" /> <Tree.Folder name="graphql/" /> <Tree.Folder name="webhooks/" /> </Tree.Folder> <Tree.Folder name="contributing/" /> <Tree.File name="package.json" /> </Tree.Folder> </Tree> ## Content directory The `/content` directory holds all English Markdown documentation. It is organized by product, matching the URL structure of docs.github.com: ``` content/ ├── actions/ → docs.github.com/en/actions ├── codespaces/ → docs.github.com/en/codespaces ├── github-cli/ → docs.github.com/en/github-cli ├── rest/ → docs.github.com/en/rest ├── admin/ → docs.github.com/en/admin └── ... ``` Every directory has an `index.md` that acts as the landing page for that product or category. The `index.md` must include a `children` frontmatter property listing its sub-pages — the site only renders paths listed there. Pages not referenced in `children` return a 404. Content files use: * **YAML frontmatter** — metadata like `title`, `intro`, `versions`, `redirect_from`, and layout options * **Markdown** — standard CommonMark with GitHub Flavored Markdown extensions * **Liquid templating** — conditional versioning, reusables, variables, and tool-switching tags <Tip> The `/content` directory is where external contributors are welcome. Edits to `.md` files here — fixing typos, improving explanations, updating outdated content — are the most common type of contribution. </Tip> ## Data directory The `/data` directory contains structured content that is referenced from Markdown files via Liquid tags. It is not directly served as pages. | Subdirectory | Purpose | | ----------------------- | ------------------------------------------------------------------------------------------------------------------- | | `data/reusables/` | Short Markdown snippets reused across multiple articles. Referenced with `{% data reusables.topic.reusable-name %}` | | `data/variables/` | Short text strings (product names, version numbers). Referenced with `{% data variables.product.product_name %}` | | `data/learning-tracks/` | YAML definitions for learning track sequences shown on product landing pages | | `data/graphql/` | GraphQL schema data used to auto-generate the GraphQL reference docs | | `data/features/` | Feature flag definitions used to gate content by product version | <Note> External contributors may edit files in `data/reusables/` and `data/variables/`. Other subdirectories under `/data` are typically managed by automated pipelines or GitHub staff. </Note> ## Source directory The `/src` directory contains the Node.js application that serves docs.github.com. It follows a **subject folder** pattern — each subdirectory represents a distinct capability of the site, with its own `README.md`, `lib/`, `middleware/`, `pages/`, `components/`, and `tests/`. <Columns> <Card title="src/frame" icon="window-maximize"> The application shell: header, footer, global sidebar, routing, and middleware that doesn't belong to a more specific subject. Also contains `lib/frontmatter.ts`, which defines and validates all supported frontmatter fields. </Card> <Card title="src/content-render" icon="file-code"> Renders Markdown content into HTML. Handles Liquid processing, unified/remark pipeline, internal link rewriting, and mini table of contents generation. </Card> <Card title="src/content-linter" icon="circle-check"> Custom markdownlint rules that enforce style, structure, and quality across all documentation. Rules live in `src/content-linter/lib/linting-rules/`. Run via `npm run lint-content`. </Card> <Card title="src/rest" icon="plug"> REST API reference documentation pipeline. Consumes OpenAPI specs from [`github/rest-api-description`](https://github.com/github/rest-api-description) and generates Markdown pages in `content/rest/` through an automated workflow. </Card> <Card title="src/search" icon="magnifying-glass"> Full-text search infrastructure. Indexes documentation content for Elasticsearch and serves search queries from the site's search UI and API endpoints. </Card> <Card title="src/graphql" icon="diagram-project"> GraphQL reference docs pipeline. Generates reference pages from the GraphQL schema data stored in `data/graphql/`. </Card> <Card title="src/webhooks" icon="webhook"> Webhook reference documentation. Part of the same automated pipeline as REST — triggered by the same sync workflow that processes OpenAPI specs. </Card> <Card title="src/languages" icon="globe"> Language detection and internationalization support. Defines supported language codes and configures which languages are served. See `src/languages/lib/languages.ts`. </Card> </Columns> ## The server The docs.github.com site is a **dynamic Node.js web server** built on Express with Next.js for React rendering. It was not always this way: ``` Ruby on Rails → Jekyll (static) → Nanoc (static) → Node.js/Express/Next.js (current) ``` Despite the stack changes, many authoring conventions from the original Jekyll era are preserved: * Content is written in Markdown files in `/content` * Files support [Liquid templating](https://shopify.github.io/liquid/) * Data files in `/data` are available to templates via `{% data %}` tags * Markdown files use Jekyll-style frontmatter * The `redirect_from` frontmatter behavior (from the `jekyll-redirect-from` plugin) is still supported The server handles: * **HTTP redirects** — including `redirect_from` frontmatter and external site redirects * **Language detection** — via `Accept-Language` headers and URL prefixes (`/en/`, `/ja/`, etc.) * **Version routing** — URLs include the product version for GitHub Enterprise Server (e.g., `/en/enterprise-server@3.12/admin/...`) * **Dynamic content** — Liquid conditionals and versioning are evaluated at request time ## Contributing guide directory The `/contributing` directory contains guides for working on the repository. Most of its content has been superseded by the official [contributing documentation](https://docs.github.com/en/contributing) on docs.github.com, but some files (like `development.md` and `liquid-helpers.md`) remain useful references for local setup and authoring conventions. ## Explore further <CardGroup> <Card title="Local setup" icon="computer" href="/development/setup"> Step-by-step instructions for running the site on your machine. </Card> <Card title="Content model" icon="file-lines" href="/content/content-model"> How articles, categories, and map topics are structured and connected. </Card> <Card title="Server overview" icon="server" href="/engineering/server-overview"> Deep dive into the Express/Next.js application, middleware stack, and request lifecycle. </Card> <Card title="REST pipeline" icon="rotate" href="/engineering/rest-pipeline"> How OpenAPI specs become versioned REST reference docs automatically. </Card> </CardGroup>