# Quickstart
> Start building beautiful documentation in under 5 minutes
With Fern, you can build beautiful developer documentation that matches your brand. Fern supports writing pages (written in Markdown) and generating API Reference documentation (from an OpenAPI Specification).
In this guide, we'll show you how to get started with Fern in under 5 minutes.
### Initialize your `fern` folder
All the configuration for your docs lives in the `fern` folder. Inside you'll
find a `docs.yml` file that contains all the settings for your documentation.
Get started by cloning the [starter template](https://github.com/fern-api/docs-starter-openapi).
```bash
git clone git@github.com:fern-api/docs-starter-openapi.git
```
Next, please update the template settings to use your organization.
Please edit the details `fern.config.json` and `docs.yml` with your organization
name.
```json {2}
{
"organization": "{{YOUR_ORGANIZATION}}",
"version": "0.x.x"
}
```
```yml {2}
instances:
- url: {{YOUR_ORGANIZATION}}.docs.buildwithfern.com
```
Finally, run `fern generate --docs` to generate your documentation.
If you prefer, you can use our CLI to create a new project. Install the CLI
by running
```bash
npm install -g fern-api
```
Then run
```bash
fern init --docs
```
You will see a new `fern` folder in your project with the following structure:
```bash
fern
├─ docs.yml
└─ fern.config.json
```
Finally, run `fern generate --docs` to generate your documentation.
### Update your docs
We provide a white-glove migration service as part of our Enterprise plan. Interested? Request it
[here](https://buildwithfern.com/contact).
Add content with MDX files.
```markdown
---
title: "Page Title"
description: "Subtitle (optional)"
---
Hello world!
```
Fern supports [GitHub flavored Markdown (GFM)](https://github.github.com/gfm/) within MDX files, no plugin required.
In order for the Markdown page to show up, you'll need to reference them from your `docs.yml` file. You
can reference the Markdown page within a section or as a standalone page.
```yml
navigation:
- page: "Hello World"
path: "pages/hello-world.mdx"
- section: Overview
content:
- page: QuickStart
path: pages/hello-world.mdx
```
Add an API Reference by adding an OpenAPI Specification to your project.
```bash
fern init --openapi /path/to/openapi.yml
```
This will create an `openapi.yml` file in your project. You can reference this file in your
`docs.yml` file by adding an api block.
```yml
navigation:
- api: "API Reference"
```
All of the branding for your docs can be configured in the `docs.yml` file.
For example, to set the logos, colors, and fonts for your docs, you can
add the following to your `docs.yml` file:
```yml
colors:
accentPrimary:
dark: "#f0c193"
light: "#af5f1b"
logo:
dark: ./docs/assets/logo-dark.svg
light: ./docs/assets/logo-light.svg
height: 40
href: https://buildwithfern.com/
favicon: ./docs/assets/favicon.png
```
### Publish to production
Fern supports hosting your docs website on a custom domain or on a
custom subpath (e.g. [https://domain.com/docs](https://domain.com/docs)).
Please reach out to the Fern team at [support@buildwithfern.com](mailto:support@buildwithfern.com) to configure this.
Fern supports integrations with a variety of providers such as PostHog, Segment, Intercom,
Google Tag Manager, etc.
Find out more on this [page](/learn/docs/integrations/overview).
Below are some examples of documentation websites that have been published using Fern:
} />
}
/>
} />
} />
} />
}
/>
}
/>
}
/>
# Global Configuration
> Customize your documentation using the docs.yml file
Not all of the properties in `docs.yml` are documented here. If you'd like to see all properties, please check out the
the raw [schema](https://github.com/fern-api/fern/blob/69e74d9c27dc031ec2e84e70b878c40e9e9678a5/packages/cli/configuration/fern/definition/docs.yml#L110-L153)
## Top-level properties
Every Fern documentation website needs a `docs.yml` file with the core configuration settings.
```yaml docs.yml
title: My Docs
logo:
href: mydomain.com
dark: path/to/logo.png
light: path/to/logo.png
favicon: path/to/favicon.ico
```
A string that is used as the tab bar title.
Learn more about the `logo` configuration [here](/learn/docs/getting-started/global-configuration#logo-configuration).
Relative filepath to the favicon.
Configure the `primaryAccent` and `background` colors. Learn more about the `colors` configuration
[here](/learn/docs/getting-started/global-configuration#colors-configuration).
An array of paths you want to configure to permanently redirect to another path. Learn more about the
`redirects` configuration [here](/learn/docs/getting-started/global-configuration#redirects-configuration).
Array of names and urls of links you want to include as a call to action. Learn more about the
`navbar-links` configuration [here](/learn/docs/getting-started/global-configuration#navbar-links-configuration).
Set a custom background image to be displayed behind every page. Learn more about the
`background-image` configuration [here](/learn/docs/getting-started/global-configuration#background-image-configuration).
Customize the fonts used in your documentation website. Learn more about the
`typography` configuration [here](/learn/docs/getting-started/global-configuration#typography-configuration).
Customize the layout of your documentation website. Learn more about the
`layout` configuration [here](/learn/docs/getting-started/global-configuration#layout-configuration).
Creates a landing page for your documentation website. Learn more about the
`landing-page` configuration [here](/learn/docs/getting-started/global-configuration#landing-page-configuration).
Sets the default language displayed by code snippets in the API Reference.
Options include: `typescript`, `python`, `java`, `go`, `ruby`, `csharp`, `curl`
## Instances configuration
An `instance` is the backend of a distinct docs website. Each instance is published to a unique domain using the `--instance` flag. It is most common to use instances to configure staging and production docs which publish to separate URLs.
```yaml docs.yml
instances:
- url: plantstore.docs.buildwithfern.com
custom-domain: docs.plantstore.com
edit-this-page:
github:
owner: fern
repo: plant-store-docs
branch: main
```
The URL where your Fern documentation is deployed. Must contain the suffix `docs.buildwithfern.com`
The custom domain where your documentation is hosted. Learn more about setting up a custom domain [here](/learn/docs/building-your-docs/custom-domain).
If `edit-this-page` is set, Fern will add an "Edit this page" link to the bottom of each page that links to the given public GitHub repository.
Learn more about the `edit-this-page` object [here](#github-configuration).
## Colors configuration
```yaml docs.yml
colors:
accent-primary:
light: "#418326"
dark: "#ADFF8C"
background:
light: "#ffffff"
dark: "#0d0e11"
```
The configured accent primary color for light and dark mode.
The configured background colors for light and dark mode.
The border color is used for the borders of cards and other elements.
If `sidebarBackground` is set, the sidebar will also render a 1px border on the right side.
By default, the sidebar will render with a transparent background without a border.
If `headerBackground` is set, the header will render with a solid background, with a 1px solid border on the bottom.
By default, the header will render with a transparent background, with a 1px faded border on the bottom.
The background color of cards and code blocks.
## Logo configuration
```yaml docs.yml
logo:
href: mydomain.com
dark: path/to/logo.png
light: path/to/logo.png
```
Where clicking on the logo links you to.
Path to the image for the dark mode logo. You can exclude this if you don't have dark mode enabled. SVG format is recommended.
Path to the image for the light mode logo. You can exclude this if you don't have light mode enabled. SVG format is recommended.
## Redirects configuration
```yaml docs.yml
redirects:
- source: "/old-path"
destination: "/new-path"
- source: "/old-folder/*"
destination: "/new-folder/*"
```
The path that you want to redirect from.
The path that you want to redirect to.
Toggle between **permanent** and **temporary** redirect (default `false`). When true, the status code is 308. When false the status code is 307.
## NavBar links configuration
```yaml docs.yml
navbar-links:
- type: minimal
text: Contact support
href: https://example.com/support
- type: filled
text: Login
href: https://example.com/login
rounded: false
```
One of `outlined`, `minimal`, or `filled`. This value controls the styling of the button.
The url once you click on the button. Example: [https://buildwithfern.com/contact](https://buildwithfern.com/contact)
Text inside the button.
When `true`, the border radius of the button will be fully rounded.
The [Font Awesome icon](https://fontawesome.com/icons) to be used in the button. This icon will appear to the **left** of the text content. Pro and Brand Icons from Font Awesome are supported.
The [Font Awesome icon](https://fontawesome.com/icons) to be used in the button. This icon will appear to the **right** of the text content. Pro and Brand Icons from Font Awesome are supported.
By default, the `rightIcon` for a `filled` button is set to `arrow-right`.
## Background image configuration
```yaml docs.yml
background-image:
light: ./path/to/bg-light.svg
dark: ./path/to/bg-dark.svg
```
Relative filepath to the light-mode background image.
Relative filepath to the dark-mode background image.
## Typography configuration
```yaml docs.yml {2-16}
typography:
bodyFont:
name: Inter-Regular
path: ./fonts/Inter-Regular.woff2
headingsFont:
name: Inter-Bold
paths:
- path: ./fonts/Inter-Bold.woff2
weight: "400"
style: normal
- path: ./fonts/Inter-Bold.woff2
weight: 500 900 # <-- indicates a range of weights
style: normal
codeFont:
name: Roboto-Mono-Regular
path: ./fonts/Roboto-Mono-Regular.woff2
```
Customize page and section titles. If not supplied, defaults to the body font.
Learn more about font configuration [here](/learn/docs/getting-started/global-configuration#font-configuration).
Customize paragraph text and other body text.
Learn more about font configuration [here](/learn/docs/getting-started/global-configuration#font-configuration).
Customize code blocks and inline code snippets.
Learn more about font configuration [here](/learn/docs/getting-started/global-configuration#font-configuration).
### Font configuration
```yaml title="Basic" {3-4}
typography:
bodyFont:
name: Inter-Regular
path: ./fonts/Inter-Regular.woff2
```
```yaml title="Variable Font" {3-10}
typography:
bodyFont:
name: Inter-Regular
paths:
- path: ./fonts/Inter-Bold.woff2
weight: "400"
style: normal
- path: ./fonts/Inter-Bold.woff2
weight: 500 900 # <-- indicates a range of weights
style: normal
```
The name of the font. Defaults to a generated name that will be used to reference your custom font in the eventually injected CSS.
Relative filepath to a variable font file. If the font file is not variable, use `paths` instead.
Supported font file types are `.woff` and `woff2`.
A list of font files for particular weights. Each element in the list includes a `path`, `weight`, and `style` property.
## Layout configuration
```yaml docs.yml
layout:
header-height: 70px
page-width: 1344px
content-width: 672px
sidebar-width: 336px
searchbar-placement: header
tabs-placement: header
content-alignment: left
```
Sets the height of the header. Defaults to `4rem` (`64px`). Valid options are `{number}rem` or `{number}px`.
Sets the maximum width of the docs layout, including the sidebar and content. Defaults to `88rem` (`1408px`).
Valid options are `{number}rem`, `{number}px`, or `full`.
Sets the maximum width of the Markdown article content. Defaults to `44rem` (`704px`).
Valid options are `{number}rem` or `{number}px`.
Sets the width of the sidebar in desktop mode. Defaults to `18rem` (`288px`). Valid options are `{number}rem` or `{number}px`.
Sets the placement of the searchbar. Can be one of `header`, `sidebar` or `header_tabs` (places the searchbar in the header but on the tabs row).
Defaults to `sidebar`.
This setting is ignored when
`disable-header`
is set to true.
Set the placement of the tabs. Can be one of `header` or `sidebar`.
Defaults to `sidebar`.
This setting is ignored when
`disable-header`
is set to true.
Set the alignment of the Markdown content. Can be one of `center` or `left`.
Defaults to `center`.
If set to true, the header will not be rendered. Instead, the logo will be rendered as part of the sidebar,
and a 1px border will separate the sidebar from the content.
## GitHub configuration
```yaml docs.yml
edit-this-page:
github:
owner: fern
repo: plant-store-docs
branch: main
```
Be sure the repository is set to **public** visibility.
The owner of the GitHub repository where you host your documentation.
The name of the GitHub repository where you host your documentation.
The branch of the repository you would like the GitHub editor to open a PR to. Default is `main`.
## Landing page configuration
```yaml docs.yml
landing-page:
page: Page Title
path: path/to/landing-page.mdx
```
The name of the landing page.
Relative filepath to the desired landing page Markdown file.
See [VapiAI's landing page live](https://docs.vapi.ai/welcome) and the associated [Markdown file](https://github.com/VapiAI/docs/blob/main/fern/welcome.mdx?plain=1).
# Project Structure
> An overview of the file and folder structure of a Fern Docs project
This page provides an overview of the file and folder structure of a Fern Docs project. The following structure is recommended for organizing your documentation content, but is customizable to fit your needs.
## Top-level folders
```bash
fern
├─ pages
├─ assets
├─ docs.yml
├─ openapi
└─ fern.config.json
```
A Fern Docs project has the following top-level folders:
* `pages`: Contains the Markdown (MDX) files that make up your documentation.
* `assets`: Contains any images or videos used in your documentation.
* `docs.yml`: The configuration file that defines the navigation, theme, and hosting details of your documentation.
* `openapi`: Contains the OpenAPI Specification file (if you have an API Reference section in your documentation).
* `fern.config.json`: The configuration file specifying your organization name and CLI version.
## Pages folder
The `pages` folder contains the Markdown (MDX) files that make up your documentation. Each MDX file represents a page in your documentation.
```bash
pages
├─ introduction
│ ├─ quickstart.mdx
│ ├─ project-structure.mdx
│ └─ showcase.mdx
├─ building-your-docs
│ ├─ navigation
│ ├─ sections.mdx
│ ├─ tabs.mdx
│ └─ versions.mdx
└─ └─ configuration.mdx
```
The `pages` folder is organized into subfolders based on the sections of your documentation. Each subfolder contains the MDX files for the pages in that section.
## Assets folder
The `assets` folder contains any images or videos used in your documentation. You can reference these assets in your MDX files using relative paths.
```bash
assets
├─ favicon.ico
├─ product-screenshot.svg
├─ demo-video.mp4
├─ logo-dark-mode.png
└─ logo-light-mode.png
```
## `docs.yml`
The `docs.yml` file is the configuration file that defines the navigation, theme, and hosting details of your documentation. You can customize the appearance and behavior of your documentation by editing this file.
```yml
instances:
- url: fern.docs.buildwithfern.com/learn
custom-domain: buildwithfern.com/learn
navigation:
- section: Introduction
layout:
- page: QuickStart
path: pages/introduction/quickstart.mdx
- page: Project Structure
path: pages/introduction/project-structure.mdx
- page: Showcase
path: pages/introduction/showcase.mdx
navbar-links:
- type: filled
text: Book a demo
url: https://buildwithfern.com/contact
logo:
light: ./images/logo-primary.svg
dark: ./images/logo-white.svg
colors:
accentPrimary:
dark: "#ADFF8C"
light: "#209d63"
favicon: ./images/favicon.ico
title: Fern's Documentation
```
## API Definitions
The `openapi` folder contains the OpenAPI Specification file for your API Reference section. Fern will read either a YAML or JSON file from this folder to generate the API Reference documentation. If you don't have an API Reference section, you can skip this folder.
```bash
openapi
└─ openapi.yaml # OR openapi.json
```
To see what this looks like in practice, check out [Vellum's Fern configuration](https://github.com/vellum-ai/vellum-client-generator/tree/main/fern/openapi).
The `definition` folder contains the Fern Definition YAML files used to generate the API Reference section. If you don't have an API Reference section, you can skip this folder.
```bash
definition
├─ pets.yaml
├─ owners.yaml
├─ stores.yaml
└─ api.yaml
```
To see what this looks like in practice, check out [Pier's Fern configuration](https://github.com/pierdeveloper/pier-fern-def/tree/main/fern/definition).
If you have multiple APIs, you can organize them into separate folders within the `apis` folder. Each API should have its own API definition. For example:
```bash
apis
├─ admin
│ └─ openapi.json
├─ user
│ └─ openapi.yaml
```
To see what this looks like in practice, check out [OctoAI's Fern configuration](https://github.com/octoml/fern-config/tree/main/fern/apis).
## `fern.config.json`
The `fern.config.json` file specifies your organization name and the version of the Fern CLI used to generate the documentation. You can customize this file to reflect your organization's details.
```json
{
"organization": "my-organization",
"version": "0.24.0"
}
```
# Preview changes locally
> View and share updates to your documentation
Fern offers two ways to preview changes to your documentation: a [local development environment](#local-development) and [unique preview links](#generate-a-preview-link).
## Local development
Fern allows you to view changes to your documentation in a locally-hosted environment.
**Prerequisite**
: Please install Node.js (version 18 or higher) before proceeding.
Follow these steps to install and run the Fern CLI:
**Step 1**: Install the Fern CLI:
```bash npm
npm i -g fern-api
```
```bash yarn
yarn global add fern-api
```
**Step 2**: Navigate to the docs directory (where the `fern` folder is located) and execute the following command:
```bash
fern docs dev
```
A local preview of your documentation will be available at `http://localhost:3000`. The functionality is available offline if you have run local development mode online at least once.
Some features (e.g. search) are disabled in the local development environment.
### Custom ports
By default, Fern uses port 3000. You can customize the port Fern runs on by using the `--port` flag. For example, to run Fern on port 3002,
use this command:
```bash
fern docs dev --port 3333
```
If you attempt to run Fern on a port that's already in use, it will use the next available port:
## Generate a preview link
Fern allows you to generate a shareable preview link displaying the current state of your docs. Each preview link is appended with a UUID and is not indexed. Currently, these links do not expire (this behavior is subject to change in the future).
**Usage**:
```bash
fern generate --docs --preview
```
**Example**:
```bash
fern generate --docs --preview
[docs]: Found 0 errors and 1 warnings. Run fern check --warnings to print out the warnings.
[docs]: Published docs to https://fern-preview-a1da0157-93ca-4b1f-b310-8dd34fb891ca.docs.buildwithfern.com
┌─
│ ✓ docs.example.com
└─
```
# Publishing your docs
When you are ready for your docs to be publicly accessible, you can publish them using the Fern CLI.
## Usage
```bash
fern generate --docs
```
### Example
```bash
fern generate --docs
[docs]: Found 0 errors and 1 warnings. Run fern check --warnings to print out the warnings.
[docs]: ✓ All checks passed
[docs]: Published docs to https://plantstore.docs.buildwithfern.com
┌─
│ ✓ https://plantstore.docs.buildwithfern.com
└─
```
### Usage in GitHub Actions
To automate the publishing process, you can use a GitHub Action workflow to publish your docs when a push is made to the `main` branch. [Be sure to add the `FERN_TOKEN` for your organization to the repository](/learn/cli-api/cli-reference/commands#fern-token).
```yaml .github/workflows/publish-docs.yml
name: Publish Docs
on:
push:
branches:
- main
jobs:
run:
runs-on: ubuntu-latest
if: ${{ github.event_name == 'push' && contains(github.ref, 'refs/heads/main') && github.run_number > 1 }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Fern
run: npm install -g fern-api
- name: Publish Docs
env:
FERN_TOKEN: ${{ secrets.FERN_TOKEN }}
run: fern generate --docs
```
## Hosting
When you publish your docs, Fern takes care of hosting them for you. To publish your docs to a custom domain, check out our docs [here](/learn/docs/building-your-docs/custom-domain).
### Self-hosting your docs
This feature is available on the Enterprise plan. [Contact us](https://buildwithfern.com/contact) to learn more.
If you need access to your docs offline or would like to host your docs on your own server, Fern offers that option as well. Self-hosted docs have limited access to certain features (including search).
# Configure your site navigation
> Set up the navigation for your documentation site built with Fern Docs using the docs.yml file, including tabs, sections, pages, and more.
## Use `docs.yml`
Every Fern Docs website has a special configuration file called `docs.yml`. Use this file to configure the navigation for your documentation site.
```yaml
navigation:
- section: Home
contents:
- page: Introduction
path: ./intro.mdx
- page: Authentication
path: ./auth.mdx
- api: API Reference
navbar-links:
- type: secondary
text: Contact support
url: https://example.com/support
- type: primary
text: Login
url: https://example.com/login
```
## Sections, contents, and pages
The navigation organizes your documentation in the left-side nav bar. You can create sections for grouping related content. Each `section` has a name and a list of `contents`. The sections appear in the left-side nav bar in the order that they are listed in `docs.yml`.
In `contents`, list your pages with names and corresponding file paths. The supported file types for pages are `.md` or `.mdx`.
A basic navigation configuration with two sections is shown below. The first section is called `Introduction` and contains a single page called `My Page`. The second section is called **API Reference**. This is a special type of section that's automatically generated by Fern, and you do not need to add any pages to it by hand. For more information, see the [Generate API Reference](/learn/docs/api-references/generate-api-ref) page.
```yaml Example navigation config
navigation:
- section: Introduction
contents:
- page: My Page
path: ./pages/my-page.mdx
- api: API Reference
```
If you want to add another page to an existing section, create an `.md` or `.mdx` file. Then in `docs.yml`, create a new `page` in the `contents` list for that section, providing the path to the `.md` or `.mdx` file you created. Example:
```yaml Example navigation config
navigation:
- section: Introduction
contents:
- page: My Page
path: ./pages/my-page.mdx
- page: Another Page
path: ./pages/another-page.mdx
- api: API Reference
```
To add another section, add another `section` to the `navigation`. Example:
```yaml Example navigation config with additional section
navigation:
- section: Introduction
contents:
- page: My Page
path: ./pages/my-page.mdx
- api: API Reference
- section: Help Center
contents:
- page: Contact Us
path: contact-us.mdx
```
### Hiding content
To hide a page or an entire section of your docs, add `hidden: true`. A hidden page or section will still be discoverable using the exact URL, but it will be excluded from search and will not be indexed.
```yaml Example navigation config with additional section {7, 10}
navigation:
- section: Introduction
contents:
- page: My Page
path: ./pages/my-page.mdx
- page: Hidden Page
hidden: true
path: ./pages/my-hidden-page.mdx
- section: Hidden Sections
hidden: true
contents:
- page: Another Hidden Page
path: ./pages/also-hidden.mdx
```
## Section overviews
To add an overview page to a section, add a `path` property to the section.
```yaml Example section with an overview {7}
navigation:
- section: Introduction
contents:
- page: My Page
path: ./pages/my-page.mdx
- section: Guides
path: ./pages/guide-overview.mdx
contents:
- page: Simple Guide
path: ./pages/guides/simple.mdx
- page: Complex Guide
path: ./pages/guides/complex.mdx
```
## Nested sections
If you'd like a section to toggle into more sections and pages, you can nest sections within sections. Here's an example:
```yaml Example navigation config with nested sections
navigation:
- tab: guides
layout:
- section: Learn
contents:
- section: Key Concepts
contents:
- page: Embeddings
path: ./docs/pages/embeddings.mdx
- page: Prompt Engineering
path: ./docs/pages/prompts.mdx
- section: Generation
contents:
- page: Command Nightly
path: ./docs/pages/command.mdx
- page: Likelihood
path: ./docs/pages/likelihood.mdx
```
![Result of above docs.yml example](https://fern-image-hosting.s3.amazonaws.com/fern/nested-sections.png)
## Sidebar icons
For icons to appear next to sections and pages, add the `icon` key. The value should be a valid [Font Awesome icon](https://fontawesome.com/icons) name. Pro and Brand Icons from Font Awesome are supported.
```yaml Example navigation config with icons
navigation:
- section: Home
icon: fa-regular fa-home
contents:
- page: My Page
icon: fa-regular fa-file
path: ./pages/my-page.mdx
- api: API Reference
icon: fa-regular fa-puzzle
```
## Links
You can add a link to an external page within your sidebar navigation with the following configuration:
```yaml title="docs.yml"
navigation:
- section: Home
contents:
- page: Introduction
path: ./intro.mdx
- link: Our YouTube Channel
href: https://www.youtube.com/
```
## Tabs
Within the navigation, you can add `tabs`. Tabs are used to group sections together. The example below shows tabs for `Help Center`, `API Reference`, and an external link to `Github`. Each tab has a `title` and `icon`. [Browse the icons available](https://fontawesome.com/icons) from Font Awesome. Pro and Brand Icons are supported.
```yaml
tabs:
api:
display-name: API Reference
icon: puzzle
help:
display-name: Help Center
icon: home
github:
display-name: GitHub
icon: brands github
href: https://github.com/fern-api/fern
navigation:
- tab: api
layout:
- section: Introduction
contents:
- page: My Page
path: my-page.mdx
- api: API Reference
- tab: help
layout:
- section: Help Center
contents:
- page: Contact Us
path: contact-us.mdx
- tab: github
```
Here's an example of what the Tabs implementation looks like:
![Screenshot showing two vertically stacked tabs labeled API Reference and Help
Center](https://fern-image-hosting.s3.amazonaws.com/fern/tabs.png)
## Versions
If you have multiple versions of your documentation, you can introduce a dropdown version selector by specifying the `versions`. For more information, check out our [documentation on versioning](/learn/docs/building-your-docs/versioning).
# Versioning
> Allow users to navigate between different versions of your docs.
![A dropdown of the available versions](file:9cd760a4-1a46-4816-bf37-7471aed3bf39)
Each version of your docs can contain its own distinct tabs, sections, pages, and API references. Versions can share content, as well.
**To add versions to your docs:**
### Define your versions
Create a `versions` folder inside of your `fern` folder. TO specify the contents of each version, add a `.yml` file to the `versions` folder to define the navigational structure of that version. Make sure to include the `navigation` and `tabs` properties, if applicable.
```bash
fern/
├─ fern.config.json
├─ generators.yml
├─ docs.yml
├─ pages/
├─ ...
└─ versions/
├─ v2-1/pages/...
├─ v2-1.yml
├─ v2-2/pages/...
└─ v2-2.yml
```
```yaml
navigation:
- section: Introduction
contents:
- page: My Page
path: ./v2-1/pages/my-page.mdx # relative path to the file
- page: Shared Resource
path: ../shared-pages/shared-resource.mdx
- api: API Reference
```
```yaml
tabs:
api:
title: API Reference
icon: puzzle
help:
title: Help Center
icon: home
navigation:
- tab: api
contents:
- section: Introduction
contents:
- page: My Page
path: ./v2-2/pages/my-page.mdx # relative path to the file
- page: Shared Resource
path: ../shared-pages/shared-resource.mdx
- api: API Reference
- tab: help
contents:
- section: Help Center
contents:
- page: Contact Us
path: contact-us.mdx
```
### Add your version configuration
To define a version, in `docs.yml`, add an item to the `versions` list, specifying the `display-name` and `path`.
```bash
fern/
├─ fern.config.json
├─ generators.yml
├─ docs.yml
└─ versions/
├─ ...
├─ v2-1.yml
└─ v2-2.yml
```
```yaml
versions:
- display-name: v2.2 # shown in the dropdown
path: ./versions/v2-2.yml # relative path to the version file
- display-name: v2.1
path: ./versions/v2-1.yml
```
### Remove extra `navigation` from `docs.yml`
If your `docs.yml` file includes a `navigation` field or a `tabs` field, be sure to remove. Those fields should now belong in the version-specific `.yml` files.
# Add an announcement banner to your docs
> Prominently highlight new features, updates, or important information
An announcement banner is a great way to draw attention to new features and product launches. When configured, the announcement bar appears at the top of your docs site. After the user dismisses the bar, it will reappear the next time you update the announcement.
```yaml docs.yml
announcement:
message: "🚀 New feature: Announcements are available! (Learn more) 🚀"
```
Markdown and HTML is supported in the announcement message. You can include links, images, and other formatting. [Custom css](/learn/docs/building-your-docs/custom-css-global-js#custom-css) can be used to customize the style of the announcement.
Another docs change
# Configure links and redirects for your site
> Set up the navigation for your documentation site built with Fern Docs using the docs.yml file
## Redirects
The `redirects` object allows you to redirect traffic from one path to another. You can also use [`regex`](https://www.npmjs.com/package/path-to-regexp) within redirects.
```yml
redirects:
- source: "/old-path"
destination: "/new-path"
- source: "/incorrect/path"
destination: "/correct/path"
- source: "/old-folder/:slug" # <- using regex
destination: "/new-folder/:slug"
```
By default, the redirects implement temporary (302) redirects. If you would like to implement permanent (301) redirects, you can set `permanent: true`.
```yml
redirects:
- source: "/old-subdomain"
destination: "/new-subdomain"
permanent: true
```
If your docs are hosted on a subpath (like `buildwithfern.com/learn`), be sure to include the subpath in the redirect.
## Links
You can add a link to an external page within your sidebar navigation with the following configuration:
```yaml title="docs.yml"
navigation:
- section: Home
contents:
- page: Introduction
path: ./intro.mdx
- link: Our YouTube Channel
href: https://www.youtube.com/
```
# Customizing slugs within your site
By default, Fern generates the slug of a page based on the navigation structure in the `docs.yml` file.
```yaml docs.yml {5, 7}
instances:
- url: plantstore.docs.buildwithfern.com
navigation:
- section: Get Started
contents:
- page: Welcome
path: ./docs/pages/welcome.mdx
```
In the example above, the **Welcome** page would be hosted at `plantstore.docs.buildwithfern.com/get-started/welcome`.
```yaml docs.yml {5, 13, 15}
instances:
- url: plantstore.docs.buildwithfern.com
tabs:
docs:
display-name: Docs
reference:
display-name: API Reference
navigation:
- tab: docs
layout:
- section: Get Started
contents:
- page: Welcome
path: ./docs/pages/welcome.mdx
```
In the example above, the **Welcome** page would be hosted at `plantstore.docs.buildwithfern.com/docs/get-started/welcome`.
### Renaming slugs
#### Modify a page or section slug
To modify the slug used for a page or section, you can set the `slug` within the `navigation` object.
```yaml {3, 6}
navigation:
- section: Get Started
slug: start
contents:
- page: Welcome
slug: intro
path: ./docs/pages/welcome.mdx
```
In the example above, the **Welcome** page would be hosted at `plantstore.docs.buildwithfern.com/start/intro`.
#### Modify a tab slug
To modify the slug used for a tab, you can set the `slug` within the `tabs` object.
```yaml {4}
tabs:
docs:
display-name: Docs
slug: guides
reference:
display-name: API Reference
navigation:
- tab: docs
layout:
- section: Get Started
contents:
- page: Welcome
path: ./docs/pages/welcome.mdx
```
In the example above, the **Welcome** page would be hosted at `plantstore.docs.buildwithfern.com/guides/get-started/welcome`.
#### Override a page's slug
You can set the exact slug of a page within its frontmatter. [You can read more about the frontmatter configuration here](/learn/docs/content/frontmatter#slug).
```yaml title="docs.yml"
navigation:
- section: Get Started
slug: start
contents:
- page: Quick Start
path: ./docs/pages/quick-start.mdx
```
You can set the slug in the frontmatter of `./docs/pages/quick-start.mdx` to `start-up`:
```markdown title="quick-start.mdx" {2}
---
slug: start-up
---
```
The page then becomes available at `plantstore.docs.buildwithfern.com/start-up`.
#### Renaming slugs for subheadings
By default, deep links to subheadings are generated by appending a `#` and the subheading title (converted to `kebab-casing-convention`) onto the page URl.
```yaml docs.yml
navigation:
- section: Get Started
contents:
- page: Welcome
path: ./docs/pages/welcome.mdx
```
```markdown welcome.mdx
...
## Frequently Asked Questions
...
```
The link to this section will be available at `plantstore.docs.buildwithfern.com/get-started/welcome#frequently-asked-questions`.
To rename the slug of the subheading, add the desired slug
```markdown welcome.mdx
## Frequently Asked Questions [#faqs]
```
The link to this section will now be available at `plantstore.docs.buildwithfern.com/get-started/welcome#faqs`.
### Skipping slugs
To ignore a tab or section when generating the slug, simply indicate `skip-slug: true`.
```yaml docs.yml {6}
instances:
- url: plantstore.docs.buildwithfern.com
navigation:
- section: Get Started
skip-slug: true
contents:
- page: Welcome
path: ./docs/pages/welcome.mdx
```
In the example above, the **Welcome** page would be hosted at `plantstore.docs.buildwithfern.com/welcome`.
```yaml docs.yml {7, 15}
instances:
- url: plantstore.docs.buildwithfern.com
tabs:
docs:
display-name: Docs
skip-slug: true
reference:
display-name: API Reference
navigation:
- tab: docs
layout:
- section: Get Started
skip-slug: true
contents:
- page: Welcome
path: ./docs/pages/welcome.mdx
```
In the example above, the **Welcome** page would be hosted at `plantstore.docs.buildwithfern.com/welcome`.
# Hiding content in your site
If you would like to *hide* a section or a page, you can add `hidden: true` to its configuration. Hidden sections and pages are accessible by URL only.
```yaml title="docs.yml"
navigation:
- section: Introduction
contents:
- page: My Page
path: ./pages/my-page.mdx
- page: Hide and Seek
hidden: true
path: ./pages/hide-and-seek.mdx
- api: API Reference
```
```yaml title="docs.yml"
navigation:
- section: Introduction
contents:
- page: My Page
path: ./pages/my-page.mdx
- api: API Reference
- section: Hidden Section
hidden: true
contents:
- page: Hide and Seek
path: ./pages/hide-and-seek.mdx
```
# Fully customize your docs
> Add brand-specific styling, user interactions. and components to make your docs your own.
Custom CSS & JS are available on the Basic plan.
Adding Custom Components is available on the Pro plan.
## Custom CSS
You can add custom CSS to your docs to further customize the look and feel. The defined class names are applied across all MDX files.
Here's an example of what you can do with custom CSS:
```css maxLines=10
.petstore-table {
background-color: white;
border: 1px solid #DEDEE1;
border-radius: 4px;
}
.dark .petstore-table {
background-color: #1e1e1e;
border: 1px solid #2e2e2e;
}
.petstore-table thead {
position: sticky;
top: 0;
}
.petstore-table thead tr {
background-color: #edecee;
border: 1px solid #DEDEE1;
border-radius: 4px 4px 0px 0px;
}
.dark .petstore-table thead tr {
background-color: #2e2e2e;
border: 1px solid #2e2e2e;
}
.petstore-table th {
padding: 6px;
}
.petstore-table tbody td {
padding: 6px;
}
.petstore-table tbody tr:nth-child(odd) {
border: 1px solid #DEDEE1;
}
.petstore-table tbody tr:nth-child(even) {
border: 1px solid #DEDEE1;
background-color: #f7f6f8;
}
.dark .petstore-table tbody tr:nth-child(odd) {
border: 1px solid #2e2e2e;
}
.dark .petstore-table tbody tr:nth-child(even) {
border: 1px solid #2e2e2e;
background-color: #2e2e2e;
}
```
### Create `styles.css`
Add a `styles.css` file and include it in your `fern/` project:
```bash {5}
fern/
├─ openapi/
├─ pages/
├─ images/
├─ styles.css
├─ docs.yml
└─ fern.config.json
```
### Edit `docs.yml`
In `docs.yml`, specify the path to the `styles.css` file:
```yaml
css: ./styles.css
```
### Add multiple custom CSS files (optional)
You can specify any number of custom CSS files:
```yaml
css:
- ./css/header-styles.css
- ./css/footer-styles.css
```
For customizing the background, logo, font, and layout of your Docs via Fern's built-in styling,
check out the [Global Configuration](/learn/docs/getting-started/global-configuration).
## Custom JavaScript
Customize the behavior of your Docs site by injecting custom JavaScript globally. Add a `custom.js` file and include it in your `fern/` project:
```bash {5}
fern/
├─ openapi/
├─ pages/
├─ images/
├─ custom.js
├─ docs.yml
└─ fern.config.json
```
In `docs.yml`, specify the path to the `custom.js` file:
```yaml
js: ./custom.js
```
You can also specify multiple custom JS files stored locally and remote:
```yaml
js:
- path/to/js/file.js
- path: path/to/another/js/file.js
strategy: beforeInteractive
- url: https://example.com/path/to/js/file.js
```
### Strategy
Optionally, specify the strategy for each custom JavaScript file. Choose from `beforeInteractive`, `afterInteractive` (default), and `lazyOnload`.
```yaml
js:
- path: path/to/another/js/file.js
strategy: beforeInteractive
```
## Custom components
You can use custom CSS and JS to replace Fern's default UI components with your own. The `header` and `footer`
are the most commonly replaced components. You can replace any component in the docs,
including the sidebar, tabs, search bar, and more.
To implement your own components in Fern Docs, write JavaScript to render your
custom components in the DOM. Build to CSS and JavaScript files that
are stored in `fern/` and referenced in `docs.yml`:
```bash {5-7}
fern/
├─ openapi/
├─ pages/
├─ images/
├─ dist/
└─ output.css
└─ output.js
├─ docs.yml
└─ fern.config.json
```
```yaml
css: ./dist/output.css
js: ./dist/output.js
```
### Example custom components
See this [GitHub repo](https://github.com/fern-api/docs-custom-js-example)
and its [generated docs page](https://custom-js-example.docs.buildwithfern.com/get-started/welcome)
for an example of how to replace the Fern `header` and `footer` with custom React components.
#### Example custom header
```JavaScript
ReactDOM.render(
React.createElement(NavHeader),
document.getElementById('fern-header'),
)
```
#### Example custom footer
```JavaScript
ReactDOM.render(
React.createElement(NavFooter),
document.getElementById('fern-footer'),
)
```
### Important notes
* `ReactDOM.render()` may need to be called multiple times to prevent it from unmounting (this side-effect will be removed in the future).
* `yarn build` or `npm build` must generate files with deterministic names to be referenced in `docs.yml`. The above example uses a [`vite` config](https://github.com/fern-api/docs-custom-js-example/blob/main/custom-app/vite.config.ts) to accomplish this.
* For your hosted Docs site, you may need to update your CD steps to include building the react-app.
This approach is subject to change, with notice, as we make improvements to the plugin architecture.
# Pull request previews
> Fern's PR previews feature lets you preview changes to your docs from pull requests before merging to the live docs site. Use manually or in GitHub Actions.
`PR previews` offer a way to preview changes from pull requests (PRs) before merging code to a production branch. This is useful for reviewing documentation changes before publishing them to your live documentation site. Use manually or in GitHub Actions.
## Usage
```bash
fern generate --docs --preview
```
## Example
```bash
fern generate --docs --preview
[docs]: Found 0 errors and 1 warnings. Run fern check --warnings to print out the warnings.
[docs]: Published docs to https://fern-preview-a1da0157-93ca-4b1f-b310-8dd34fb891ca.docs.buildwithfern.com
┌─
│ ✓ docs.example.com
└─
```
## Usage in GitHub Actions
The following is a GitHub Action workflow that generates a preview URL for every pull request. [Be sure to add the `FERN_TOKEN` for your organization to the repository](/learn/cli-api/cli-reference/commands#fern-token).
```yaml
name: preview-docs
on:
pull_request
jobs:
run:
runs-on: ubuntu-latest
permissions: write-all
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Fern
run: npm install -g fern-api
- name: Generate preview URL
id: generate-docs
env:
FERN_TOKEN: ${{ secrets.FERN_TOKEN }}
run: |
OUTPUT=$(fern generate --docs --preview 2>&1) || true
echo "$OUTPUT"
URL=$(echo "$OUTPUT" | grep -oP 'Published docs to \K.*(?= \()')
echo "Preview URL: $URL"
echo "🌿 Preview your docs: $URL" > preview_url.txt
- name: Comment URL in PR
uses: thollander/actions-comment-pull-request@v2.4.3
with:
filePath: preview_url.txt
```
Fern's PR previews GitHub Action requires a Fern token to run. Depending on your repository's permissions, you may need to use the following workflow to allow PR previews from forks to access this token.
```yaml .github/workflows/preview-docs.yml
name: preview-docs
on:
pull_request_target:
branches:
- main
jobs:
run:
runs-on: ubuntu-latest
permissions:
pull-requests: write # Only for commenting
contents: read # For checking out code
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Fern
run: npm install -g fern-api
- name: Checkout PR
if: github.event_name == 'pull_request_target'
run: |
git fetch origin pull/${{ github.event.pull_request.number }}/head:pr-${{ github.event.pull_request.number }}
git checkout pr-${{ github.event.pull_request.number }}
- name: Generate preview URL
id: generate-docs
env:
FERN_TOKEN: ${{ secrets.FERN_TOKEN }}
run: |
OUTPUT=$(fern generate --docs --preview 2>&1) || true
echo "$OUTPUT"
URL=$(echo "$OUTPUT" | grep -oP 'Published docs to \K.*(?= \()')
echo "Preview URL: $URL"
echo "🌿 Preview your docs: $URL" > preview_url.txt
- name: Comment URL in PR
uses: thollander/actions-comment-pull-request@v2.4.3
with:
filePath: preview_url.txt
```
## Link expiration
Preview links do not expire. However, the time to live (TTL) is subject to change in the future.
# Bring your custom domain
> Learn how to set up your Fern-generated documentation site to use a custom subdomain or subpath.
Bring Fern Docs to your custom domain.
You can use:
* A subdomain on your custom domain, such as `docs.example.com`
* A subpath on your custom domain, such as `example.com/docs`
This feature is available on the Basic plan and above.
[Contact us](https://buildwithfern.com/contact)
to get set up.
To host your documentation on a subdomain, i.e. `docs.mydomain.com`, you need to create a CNAME record in your DNS settings.
### Update the domain in `docs.yml`
```yaml
instances:
- url: example.docs.buildwithfern.com
custom-domain: docs.mydomain.com
```
Merge your changes into `main`. [Here's an example](https://github.com/octoml/fern-config/blob/389b67679953856ba0716537981a6d749635556f/fern/docs.yml#L1-L3).
### Create a CNAME record
1. Log in to your domain registrar's dashboard.
2. Navigate to the DNS settings for your domain.
3. Add a new CNAME record with the following details:
* **Type**: `CNAME`
* **Name**: `docs` (or any subdomain you want to use)
* **Value**: `cname.vercel-dns.com.`
### Reach out to us
Once you've completed the steps above, reach out via your dedicated Slack channel or [email](mailto:support@buildwithfern.com).
You may need to create a TXT record to verify your domain. If you do, we'll provide you with the record to add.
### Verify the setup
Once we've completed the setup on our end, you should be able to access your documentation at `docs.mydomain.com`. SSL will be automatically provisioned for your domain, but it may take a few minutes to propagate globally.
It's helpful to check that you can access your new docs site from a mobile device or incognito browser.
To host your documentation on a subpath, i.e. `mydomain.com/docs`, you need to edit your `docs.yml` configuration and then get provider-specific instructions for setting up the subpath. Common providers include Cloudflare, AWS Route53 and Cloudfront, Netlify, and Vercel.
### Configure the `url` in `docs.yml`
Append that subpath to the end of the `url`. This example use `docs` for the subpath, but you can use any word you like, such as `reference` or `developer`.
```yaml
instances:
- url: example.docs.buildwithfern.com/docs
```
### Configure the `custom-domain`
Below the `url`, add a `custom-domain` key as shown in the examples below.
```yaml
instances:
- url: example.docs.buildwithfern.com/docs
custom-domain: example.com/docs
```
[Here's an example.](https://github.com/fern-api/fern/blob/7d8631c6119787a8aaccb4ba49837e73c985db28/fern/docs.yml#L1-L3)
### Update the Fern Docs site
If you created your Fern Docs site using one of our [Docs Quickstarts](/learn/docs/getting-started/quickstart), push the changes you made to your GitHub repository. This runs a GitHub Action to update the site with your new configuration.
If you need to update your Fern Docs site manually, run `fern generate --docs`.
### Reach out to us
This feature is available on the Fern Docs Basic plan and above. Reach out to [sales@buildwithfern.com](mailto:sales@buildwithfern.com) to set up your subscription and obtain the configuration for setting up your custom subpath.
# Collecting feedback and suggestions from users
Fern offers a variety of ways to track feedback and suggested improvements from users.
## On-page feedback
By default, every Markdown page of your docs contains a feedback component at the bottom of the page:
This feature is available on the Basic plan and above.
[Contact us](https://buildwithfern.com/contact)
to get set up.
The feedback can be sent to you in real-time via the method of your choosing (e.g. Slack, email).
To disable this feature on a page, set `hide-feedback: true` in the frontmatter of that page. You can read more about the frontmatter configuration [here](/learn/docs/content/frontmatter#on-page-feedback).
## Edit this page
Allow users to open directly to the current page in your GitHub repository and suggest changes.
You can configure this feature for the entire site in the [global configuration](/learn/docs/getting-started/global-configuration#instances-configuration), or for an individual page in the [frontmatter of that page](/learn/docs/content/frontmatter#edit-this-page).
# Write docs content using Markdown
> Use Markdown and MDX to add content to your Fern documentation site, including Fern's built-in component library.
## Add Markdown or MDX pages
Add pages manually to your documentation by creating Markdown (`.md`) or MDX (`.mdx`) files. New to Markdown? See [Markdown Guide: Getting started](https://www.markdownguide.org/getting-started/).
NOTE: Throughout our documentation, we refer to both Markdown and MDX as Markdown. [MDX](https://mdxjs.com/) is a version of Markdown, extended to allow the use of JSX components.
Place your pages inside your `fern/` folder and link to them from your [navigation settings](/learn/docs/building-your-docs/navigation) in the `docs.yml` file.
In the example below, the MDX files are inside a folder named `pages/`.
```bash
fern/
├─ fern.config.json
├─ docs.yml
└─ pages/
├─ welcome.mdx
└─ quickstart.mdx
```
```yml
navigation:
- section: Overview
contents:
- page: Welcome
path: ./pages/welcome.mdx
- page: Quickstart
path: ./pages/quickstart.mdx
```
## Page header
Fern automatically generates the `
` page header for each page from `docs.yml`. For example, here's the `docs.yml` entry that maps the page you are reading now:
```yml
- page: Write Markdown content
path: ./docs/pages/fern-docs/content/write-markdown.mdx
```
The value for `page` is used as the content of the top `
` element of this page. Thus, when adding content to your Markdown pages, begin with `
` instead of `
`.
## Fern components
Fern has a built-in component library you can use in Markdown. [Explore the components.](/learn/docs/content/components/overview)
## Links in Markdown
### Link target
When clicked, links to relative URLs open in the same tab, whereas links to absolute URLs open in a new browser tab.
### Link format
Use a `/` character to begin a relative URL to another page on your docs site. This routes to the `url` defined in your `docs.yml` file, such as `example-docs.buildwithfern.com`. For example, if you want to link to `https://example-docs.buildwithfern.com/overview/introduction`, you can write the link in Markdown as follows:
```mdx
Read the [Introduction](/learn/overview/introduction).
```
## Images
You can use locally stored images or URLs to include images in your Markdown pages. Use either [Markdown syntax](https://www.markdownguide.org/basic-syntax/#images-1) or the [`` HTML tag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img) to insert the image.
## LaTeX
Fern supports [LaTeX](https://www.latex-project.org/) math equations. To use LaTeX, wrap your inline math equations in `$`. For example, `$(x^2 + y^2 = z^2)$` will render $x^2 + y^2 = z^2$.
For display math equations, wrap the equation in `$$`. For example:
```latex
$$
% \f is defined as #1f(#2) using the macro
\f\relax{x} = \int_{-\infty}^\infty
\f\hat\xi\,e^{2 \pi i \xi x}
\,d\xi
$$
```
## Diagrams
Fern supports creating diagrams within your Markdown using [Mermaid](https://mermaid.js.org/). Mermaid offers a variety of diagrams, including flowcharts, entity-relationship models, and Gantt charts. To include a Mermaid diagram in your Markdown file, create a codeblock marked with `mermaid`.
````markdown
```mermaid
erDiagram
CUSTOMER ||--o{ PLANT-ORDER : places
PLANT-ORDER ||--|{ PLANT-ID : contains
CUSTOMER }|..|{ DELIVERY-ADDRESS : uses
```
````
```mermaid
erDiagram
CUSTOMER ||--o{ PLANT-ORDER : places
PLANT-ORDER ||--|{ PLANT-ID : contains
CUSTOMER }|..|{ DELIVERY-ADDRESS : uses
```
# Components Overview
> Enhance your docs with Fern's built-in component library. Use components to create interactive and engaging documentation.
Fern provides a library of 15+ built-in-components to make your documentation more interactive and engaging. Components are building blocks that you can add to any MDX page.
## Usage
Specify a component in your MDX file while writing content. For example, to add a `Card` component, use the following syntax:
```mdx
Give us a star! Fern's CLI & docs source code is available on GitHub.
```
This will automatically render a card with the title, icon, and content you specified.
Give us a star! The source code to Fern's CLI is available on GitHub.
## Bring your own components
Want to bring your own UI components, such as a custom header and footer? You can on the Enterprise plan. [Contact us](https://buildwithfern.com/contact) to learn more.
## Requests for new components
Have a component in mind that you'd like to see in Fern? Let us know by filing a [GitHub Issue](https://github.com/fern-api/fern/issues/new?assignees=\&labels=\&projects=\&template=feature-request.md\&title=%5BFeature%5D).
# Accordions
> Expand or collapse to reveal more information
Standalone content
# Accordion Groups
> Display expandable/collapsible options that can reveal more information
You can put other components inside Accordions.
```ts index.ts
export function generateRandomNumber() {
return Math.random();
}
```
This is a second option.
This is a third option.
# Aside
> Push any content inside the Aside component to the right of the page in a sticky container
```jsx
```
# Callouts
> A built-in component to show important information to the reader
## Callout properties
Customize your Callouts using the `title` and `icon` properties.
The title of your Callout
The icon of your Callout. Can be a [Font Awesome](https://fontawesome.com/icons) icon name or an HTML element.
This Callout uses a title and a custom icon.
```markdown
This Callout uses a title and a custom icon.
```
## Callout varieties
### Note callouts
This adds a note in the content
```jsx
This adds a note in the content
```
### Warning callouts
This raises a warning to watch out for
```jsx
This raises a warning to watch out for
```
### Error callouts
This indicates a potential error
```jsx
This indicates a potential error
```
### Info callouts
This draws attention to important information
```jsx
This draws attention to important information
```
### Tip callouts
This suggests a helpful tip
```jsx
This suggests a helpful tip
```
### Check callouts
This brings us a checked status
```jsx
This brings us a checked status
```
# Cards
> Use cards to display content in a box
### Basic
The icon field references a Font Awesome icon.
### Custom icon
} href="https://github.com/fern-api/fern/tree/main/generators/python">
Pass in an image tag to use a custom icon.
### Icon position
You can set the icon positon as `left` or `top`. Default is `top`.
# Card Groups
> Show cards side by side in a grid format
The `CardGroup` component lets you group multiple `Card` components together. It's most often used to put multiple cards on the same column.
This is the first card.
This is the second card.
This is the third card.
This is the fourth and final card.
# Code Blocks
> Write beautiful code snippets in your documentation
Fern uses [Shiki](https://shiki.matsu.io/) to do syntax highlighting.
It's very reliable and performant. Below are examples of how you can configure syntax highlighting in code snippets.
## Basic
To create a code snippet, you need to wrap your code in three backticks.
You can also specify the language for syntax highlighting after the opening backticks.
```js
console.log("hello world")
```
````mdx
```js
console.log("hello world")
```
````
## Titles
You can add a title to your code snippet by adding a title after the language identifier.
```js Hello World Snippet
console.log("hello world")
```
````mdx
```js Hello World Snippet
console.log("hello world")
```
````
You may also use a `title` prop or `filename` prop to achieve the same result.
For example, `title="Hello World Snippet"` or `filename="Hello World Snippet"`.
## Line highlighting
You can highlight specific lines in your code snippet by placing a numeric range inside `{}`
after the language identifier.
```js {2-4}
console.log("Line 1");
console.log("Line 2");
console.log("Line 3");
console.log("Line 4");
console.log("Line 5");
```
````markdown
```javascript {2-4}
console.log("Line 1");
console.log("Line 2");
console.log("Line 3");
console.log("Line 4");
console.log("Line 5");
```
````
The range is inclusive and can be a single number, a comma-separated list of numbers, or ranges.
For example, `{1,3,5-7}` will highlight lines 1, 3, 5, 6, and 7.
## Line focusing
Instead of highlighting lines, you can focus on specific lines by adding a comment `[!code focus]` or by adding a
`focus` attribute after the language identifier. The `focus` attribute works the same way as the `highlight` attribute.
```javascript focus={2-4}
console.log("Line 1");
console.log("Line 2");
console.log("Line 3");
console.log("Line 4");
console.log("Line 5");
```
````markdown
```javascript focus={2-4}
console.log("Line 1");
console.log("Line 2");
console.log("Line 3");
console.log("Line 4");
console.log("Line 5");
```
````
## Max height
You can control the max height of the code block by adding
a `maxLines` attribute after the language identifier. The
`maxLines` attribute should be a number representing the maximum
number of lines to display. By default, the code block will display up to 20 lines.
```python maxLines=10
def is_prime(num):
"""Check if a number is prime."""
if num <= 1:
return False
for i in range(2, num):
if num % i == 0:
return False
return True
start = 10
end = 50
print(f"Prime numbers between {start} and {end} are:")
prime_numbers = []
for num in range(start, end+1):
if is_prime(num):
prime_numbers.append(num)
for prime in prime_numbers:
print(prime)
```
````markdown maxLines=10
```python maxLines=10
def is_prime(num):
"""Check if a number is prime."""
if num <= 1:
return False
for i in range(2, num):
if num % i == 0:
return False
return True
start = 10
end = 50
print(f"Prime numbers between {start} and {end} are:")
prime_numbers = []
for num in range(start, end+1):
if is_prime(num):
prime_numbers.append(num)
for prime in prime_numbers:
print(prime)
```
````
To disable the default 20 lines limit, you can set `maxLines` to `0`.
## Wrap overflow
By default, long lines that exceed the width of the code block become scrollable:
```txt title="Without Word Wrap"
A very very very long line of text that may cause the codeblock to overflow and scroll as a result.
```
````markdown
```txt title="Without Word Wrap"
A very very very long line of text that may cause the codeblock to overflow and scroll as a result.
```
````
To disable scrolling and wrap overflow onto the next line, use the `wordWrap` prop:
```txt title="With Word Wrap" wordWrap
A very very very long line of text that may cause the codeblock to overflow and scroll as a result.
```
````markdown
```txt title="With Word Wrap" wordWrap
A very very very long line of text that may cause the codeblock to overflow and scroll as a result.
```
````
## Combining props
You can combine the `title`, `highlight`, `focus`, `maxLines`, and `wordWrap`
props to create a code block with a title, highlighted lines,
and a maximum height.
```javascript title="Hello, World!" {2-4} maxLines=5
console.log("Line 1");
console.log("Line 2");
console.log("Line 3");
console.log("Line 4");
console.log("Line 5");
console.log("Line 6");
console.log("Line 7");
console.log("Line 8");
console.log("Line 9");
console.log("Line 10");
```
````markdown maxLines=5
```javascript title="Hello, World!" {2-4} maxLines=5
console.log("Line 1");
console.log("Line 2");
console.log("Line 3");
console.log("Line 4");
console.log("Line 5");
console.log("Line 6");
console.log("Line 7");
console.log("Line 8");
console.log("Line 9");
console.log("Line 10");
```
````
## Tabbed CodeBlocks
The `CodeBlocks` component is used to display multiple code snippets in a tabbed view. It does not take any props.
```javascript title="helloWorld.js"
console.log("Hello World");
```
```python title="hello_world.py"
print('Hello World!')
```
```java title="HelloWorld.java"
class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
```
````jsx maxLines=0
```javascript title="helloWorld.js"
console.log("Hello World");
```
```python title="hello_world.py"
print('Hello World!')
```
```java title="HelloWorld.java"
class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
```
````
# Steps
> The Steps component helps you display a set of instructions to the user.
The `Steps` component is used when you want to display a set of instructions for the user to follow.
### First Step
Initial instructions.
### Second Step
More instructions.
### Third Step
Final Instructions
# Frames
> Wrap images in a container with the frame component
### Adding a subtle background
In the scenario where you want to draw more attention to your framed images or your content blends with the main background of your documentation, you can use the `background="subtle"` prop to add a subtle background to the frame.
```jsx title="Subtle background" {3}
```
# Tabs
> The Tabs component allows you to display related content in a tabbed view.
You can add any number of tabs.
☝️ Welcome to the content that you can only see inside the first Tab.
✌️ Here's content that's only inside the second Tab.
💪 Here's content that's only inside the third Tab.
# Endpoint Request Snippet
> Reference an endpoint request from your API Reference
The `EndpointRequestSnippet` component is used to reference an endpoint request from
your API Reference. Below is an example of referencing the request for the `POST /snippets` endpoint.
```jsx
```
will be rendered as:
### Reference particular examples
If you want to reference a particular example in the request snippet, you can set `example` prop
to the name of the example. See the steps below:
### Define named examples
The highlighted lines show how to set the example name.
```yaml {12}
paths:
/pet:
put:
summary: Update an existing pet
operationId: pets_update
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
examples:
ExampleWithMarkley:
summary: This is an example of a Pet
value:
name: Markley
id: 44
```
```yaml {11}
service:
auth: true
base-path: ""
endpoints:
update:
docs: Update an existing pet
method: PUT
path: /pet
request: Pet
examples:
- name: ExampleWithMarkley
docs: This is an example of a Pet
request:
name: Markley
id: 44
```
### Reference the example
In the API Definition, the example had a name `ExampleWithMarkley`. You can reference
the example directly:
```jsx {3}
```
{/* ### Props
Below is a description of all the supported props for the `EndpointRequestSnippet` component.
```fern
EndpointRequestSnippetProps:
properties:
endpoint:
type: string
docs: The endpoint using `METHOD /path` format.
example:
type: optional
docs: The name of the example to display, defaults to the first example.
``` */}
# Endpoint Response Snippet
> Reference an endpoint response from your API Reference
The `EndpointResponseSnippet` component is used to reference an endpoint
response from your API Reference. Below is an example of referencing the
response for the `POST /snippets` endpoint.
```jsx
```
will be rendered as
### Reference particular examples
If you want to reference a particular example in the response snippet, you can set `example` prop
to the name of the example. See the steps below:
### Define named examples
The highlighted lines show how to set the example name.
```yaml {13}
paths:
/pet/{petId}:
put:
summary: Get a pet
operationId: pets_get
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
examples:
ExampleWithMarkley:
summary: This is an example of a Pet
value:
name: Markley
id: 44
```
```yaml {11}
service:
auth: true
base-path: ""
endpoints:
update:
docs: Get a pet
method: GET
path: /pet/{petId}
response: Pet
examples:
- name: ExampleWithMarkley
docs: This is an example of a Pet
response:
body:
name: Markley
id: 44
```
### Reference the example
In the API Definition, the example had a name `ExampleWithMarkley`. You can reference
the example directly:
```jsx {3}
```
{/* ### Props
Below is a description of all the supported props for the `EndpointResponseSnippet` component.
```fern
EndpointResponseSnippetProps:
properties:
endpoint:
type: string
docs: The endpoint using `METHOD /path` format.
example:
type: optional
docs: The name of the example to display, defaults to the first example.
``` */}
# Customize content using frontmatter
> Use frontmatter to set a variety of page properties and metadata.
You can optionally use frontmatter to set each page's title, full slug override, meta description, a URL to suggest edits to the page, and its OpenGraph image. You can also use frontmatter to disable certain page element like the table of contents and on-page feedback.
Frontmatter must be added to the top of a `.md` or `.mdx` file, before the rest of the content. Use sets of three dashes to indicate the beginning and end of your frontmatter, as shown:
```mdx
---
title: Customize content using frontmatter
subtitle: Set titles, add meta descriptions, and more
slug: frontmatter
description: Use frontmatter to set the page title, subtitle, slug, meta description, its OpenGraph image, and a URL to suggest edits.
---
```
## Title
**Name**: `title`
**Type**: string
**Default**: The name of the page as specified in `docs.yml`
Set the content for the [`` element](https://web.dev/learn/html/document-structure#document_title) for a page. This title is displayed in browser tabs, history, and bookmarks, as well as in search engine results. Having a unique and informative title for each page benefits your site's SEO (Search Engine Optimization).
For more information, see [Google's guidelines for useful
titles](https://developers.google.com/search/docs/appearance/title-link#page-titles).
If no `title` is provided in the frontmatter of a page, Fern uses the value for that page in `docs.yml`.
For example, if a page is defined like this in `docs.yml`:
```yaml
- page: Overview
path: ./docs/pages/api-overview.mdx
```
Then, if Fern does not find a `title` in that page's frontmatter, `Overview` is used for the default title.
### Site-wide title text
You can set a field named `title` in `docs.yml` like this:
```yaml
instances:
- url: fern.docs.buildwithfern.com
title: Fern | Documentation # <-- set site-wide
```
The value you enter for this field is appended to every page's title across your docs site, as ` - TITLE_VALUE`.
For example, with the above setting in `docs.yml`, the `Overview` page's title becomes `Overview - Fern | Documentation`.
## Subtitle
**Name**: `subtitle`
**Type**: string
**Default**: None
Renders as a subtitle on the page. If `description` is not set, `subtitle` is also used as the meta description tag.
## Slug
**Name**: `slug`
**Type**: string
**Default**: None
The `slug` you set in a page's frontmatter overrides the URL for that page derived from `docs.yml`. This slug begins from the root of your docs site, ignoring the tab or section that the page is under. This allows you to set a custom full slug for any page.
As an example, consider this navigation setup in `docs.yml`:
```yaml
navigation:
- tab: overview
layout:
- section: Support
contents:
- page: Email Us
path: ./pages/emailus.mdx
slug: email
```
The `slug` set in `docs.yml` affects only the final part of the URL, so the `emailus.mdx` page is available at `/overview/support/email`.
In contrast, the `slug` that you set in frontmatter affects the full URL. For example, you can set the frontmatter `slug` to `email`, as shown:
```mdx
---
slug: email
---
```
The page then becomes available at `/email`.
## Meta description
**Name**: `description`
**Type**: string
**Default**: None
Set the [meta description](https://web.dev/learn/html/metadata#description) for a page. Like the page title, the meta description is important for SEO. It impacts the text that search engines display about your page in search results snippets. It can also influence search engine indexing and ranking. For more information, see [Google's guidelines for meta descriptions](https://developers.google.com/search/docs/appearance/snippet#meta-descriptions).
## Edit this page
**Name**: `edit-this-page-url`
**Type**: string (absolute URL)
**Default**: None
Provide the absolute link to the source `.md` or `.mdx` file in GitHub. Fern uses it to add an `Edit this page` link to the page, which users of your documentation can use to suggest corrections or additions.
## Meta image
**Name**: `image`
**Type**: string (absolute URL)
**Default**: None
Configure the `` metadata for a page using an absolute path to an image hosted online. This provides an image to show next to a link to your documentation when the link is shared on social media, using a metadata protocol called [OpenGraph](https://ogp.me/). For more information, see the [web.dev explanation of OpenGraph](https://web.dev/learn/html/metadata#open_graph).
## Table of contents
**Name**: `hide-toc`
**Type**: boolean
**Default**: false
Controls the conditional rendering of the table of contents feature on the right-side of the page. Set to true to disable this feature.
By default, Fern will center the contents of a page when the table of contents is hidden. To control the layout of the page, see the [layout documentation](#layout).
## Navigation links
**Name**: `hide-nav-links`
**Type**: boolean
**Default**: false
Controls the conditional rendering of the navigation links (previous, next) at the bottom of the page. Set to true to disable this feature.
## On-page feedback
**Name**: `hide-feedback`
**Type**: boolean
**Default**: false
Controls the conditional rendering of the on-page feedback form at the bottom of the page. Set to true to disable this feature.
## Page logo
**Name**: `logo`
**Type**: object
**Default**: None
You can override the site-wide logo for a page by setting a field named `logo` in any page's frontmatter like this:
```mdx
---
logo:
light: /path/to/page-logo.png
dark: /path/to/page-logo.png
---
```
This field specifies the logo for this page. If no logo is set, the site-wide [logo configuration](/learn/docs/getting-started/global-configuration#logo-configuration) is used.
## Layout
**Name**: `layout`
**Type**: `overview`, `guide`, `reference`, `page`, or `custom`
**Default**: `guide`
Sets the page layout.
* `overview`: A spacious, full-width layout without a table of contents. Perfect for landing pages, section overviews, and content that benefits from maximum horizontal space. Navigation sidebar remains visible.
* `guide`: The default documentation layout featuring a table of contents on the right side. Ideal for tutorials, how-to guides, and any content that benefits from easy navigation through sections.
* `reference`: A full-width layout optimized for an API or SDK reference. Removes the table of contents so you can add another column, such as code examples. Navigation sidebar remains visible.
* `page`: A distraction-free, full-screen layout that hides both the table of contents and navigation sidebar. Best for standalone content that benefits from focused reading experiences.
* `custom`: A blank canvas layout that removes all default styling constraints. Hides both the table of contents and navigation sidebar, allowing complete control over the page layout.
## SEO metadata
Fern supports adding SEO metadata in the frontmatter.
| Property | Description | Type |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- |
| `headline` | When set, the `` tag in the document head will use this value rather than the `title` property. This property changes the title that search engines see when crawling this page, and can be used to address Duplicate Title issues in your SEO report. | string |
| `canonical-url` | Overrides the canonical url for this page. Must be a full URL including the protocol (i.e. `https://buildwithfern.com/learn/docs/content/frontmatter`) | string |
| `og:site_name` | The name of your website as it should appear when your content is shared. | string |
| `og:title` | The title of your page as it should appear when your content is shared. | string |
| `og:description` | The description of your page as it should appear when your content is shared. | string |
| `og:url` | The URL of your page. | string |
| `og:image` | The URL or identifier of the image that will be displayed when your content is shared. | URL or relative path to file |
| `og:image:width` | The width of the image in pixels. | number |
| `og:image:height` | The height of the image in pixels. | number |
| `og:locale` | The locale of the page, typically in the format `language_TERRITORY` (e.g., `en_US`). | string |
| `og:logo` | The URL or identifier of the logo image of your website that will be displayed when your content is shared. | URL or relative path to file |
| `twitter:title` | The title of your page as it should appear in a tweet. | string |
| `twitter:description` | The description of your page as it should appear in a tweet. | string |
| `twitter:handle` | The Twitter handle of the page creator or site. | string |
| `twitter:image` | The URL or identifier of the image that will be displayed in a tweet. | URL or relative path to file |
| `twitter:site` | The name of your website as it should appear in a tweet. | string |
| `twitter:url` | The URL of your page. | string |
| `twitter:card` | The type of card to be used for sharing on Twitter. | `summary`, `summary_large_image`, `app`, `player` |
| `noindex` | If set to `true`, the page will not be indexed by search engines. Defaults to `false`. | boolean |
| `nofollow` | If set to `true`, a search engine will not follow any links present on the page. Defaults to `false`. | boolean |
# Reusable Snippets
> Reusable, custom snippets to keep content in sync. Edit once, update everywhere.
Keep your documentation DRY (Don't Repeat Yourself) by defining a reusable snippet once, and then referencing it in multiple places. This way, you only need to update the snippet in one place to keep all references in sync.
## Create a reusable snippet
To use reusable snippets, start by creating a new folder in your `fern` project called `snippets`. Inside the `snippets` folder, create a new file for each snippet you want to define.
For example:
```bash
fern
└─ pages
└─ my-tutorial.mdx
└─ assets
└─ snippets
├─ herbs.mdx
├─ peace-lily.mdx
└─ trees.mdx
```
In each snippet file, define the content you want to reuse. For example, `peace-lily.mdx` might contain:
```mdx snippets/peace-lily.mdx
Remember to water your plant at least twice a week.
```
## Use a reusable snippet
To use a snippet in your documentation, reference it by its file path (including the `.mdx` extension) in your content. For example, to include the `peace-lily` snippet in your content, use:
```mdx pages/my-tutorial.mdx
---
title: Getting started with your peace lily
description: Peace lily care tips for beginners
---
## Caring for your new plant
Peace lilies are easy to grow and relatively trouble-free.
```
# Keep a Changelog
> Record the notable changes to your project
Keep a record of how your project has changed by writing changelog entries. The changelog will automatically populate with the files contained within the `changelog` folder.
## Configure your Changelog
Configure a changelog for your project by creating a changelog folder.
```yaml {4-6}
fern/
├─ fern.config.json
├─ docs.yml
├─ changelog/
├─ 07-08-24.md
└─ 08-21-24.mdx
```
Once you've configured your changelog, specify where it should appear within your docs in your `docs.yml`.
```yaml {8-11}
tabs:
guides:
display-name: Guides
icon: light book-open
api:
display-name: API Reference
icon: light code
changelog:
display-name: Changelog
icon: light clock
changelog: ./changelog
```
[View an example](https://github.com/humanloop/humanloop-docs/blob/30ddedaf6d2779361e8ee1f373f722364e5dd71d/fern/versions/v5.yml#L10-L13) in GitHub of Humanloop's `docs.yml` which powers [their Changelog](https://humanloop.com/docs/changelog).
Configure a changelog at the API-level by creating a changelog folder specific to an API.
```yaml {6-8}
fern/
├─ fern.config.json
├─ docs.yml
└─ openapi/
├─ openapi.yml
└─ changelog/
├─ 07-15-24.md
└─ 08-23-24.mdx
```
```yaml {7-9}
fern/
├─ fern.config.json
├─ docs.yml
└─ definition/
├─ api.yml
├─ imdb.yml
└─ changelog/
├─ 07-15-24.md
└─ 08-23-24.mdx
```
```yaml {8-10,14-17}
fern/
├─ fern.config.json
├─ docs.yml
└─ apis/
├─ user-api/
└─ openapi/
├─ openapi.yml
├─ openapi-overrides.yml
└─ changelog
├─ 07-15-24.md
└─ 08-23-24.mdx
└─ admin-api/
└─ openapi/
├─ openapi.yml
└─ changelog
├─ 06-29-24.md
└─ 08-02-24.md
└─ 08-15-24.md
```
Changelogs contained within your API folder will automatically be displayed at the bottom of your API reference. You do not need to configure your changelog(s) within `docs.yml`.
View an example of a changelog per API in [Astronomer's docs](https://www.astronomer.io/docs/api/iam-api-reference/changelog).
Configure a changelog for your project by creating a changelog folder.
```yaml {4-6}
fern/
├─ fern.config.json
├─ docs.yml
├─ pages/
├─ changelog/
├─ 07-08-24.md
└─ 08-21-24.mdx
```
Once you've configured your changelog, specify where it should appear within your navigation in your `docs.yml`.
```yaml {9-11}
navigation:
- section: Introduction
contents:
- page: Authentication
path: ./pages/authentication.mdx
- page: Versioning
path: ./pages/versioning.mdx
- api: API Reference
- changelog: ./changelog
title: Release Notes
slug: api-release-notes
```
## Write a Changelog Entry
Create a new changelog entry by writing a Markdown file. You can use `.md` or `.mdx` files. The benefit of using `.mdx` is that you can leverage the built-in [component library](/learn/docs/content/components/overview) within an entry.
```mdx
## Summary
In the latest release, we've added endpoints to create a new Plant.
### What's new?
New endpoints:
- `POST /plant` add a new plant to inventory.
New object schemas:
- `CreatePlantRequest`
Have questions? Reach out to your local botanist.
```
### Entry date
Changelog entries are automatically sorted chronologically by the date specific in the file name. Specify the date of your entry using one of the following formats:
* MM-DD-YYYY (e.g., 10-06-2024)
* MM-DD-YY (e.g., 10-06-24)
* YYYY-MM-DD (e.g., 2024-04-21)
### Linking to an Entry
Each changelog entry has a unique URL you can direct users to. For example, `https://humanloop.com/docs/v5/changelog/2024/8/16`
# Generate your API Reference
> Use Fern Docs to generate your API Reference documentation from your API definition, using your choice of either OpenAPI or Fern Definition.
A key benefit of using Fern Docs is that once you've defined your API, you get your API Reference documentation with just one line.
Add `- api: API Reference` to your navigation in `docs.yml` and Fern takes care of the rest! You'll see your endpoints, types,
and cURL snippets automatically populated from your [OpenAPI Specification](/learn/api-definition/openapi/overview) or [Fern Definition](/learn/api-definition/fern/overview).
Example:
```yml docs.yml
navigation:
- api: API Reference
```
### API Reference configuration options
| Property | Value |
| ---------------- | ------------------------------------------------------------------------------------------------------ |
| `api` (required) | Title of the API Reference Section |
| `api-name` | Name of the API we are referencing, if there are [multiple APIs](#include-more-than-one-api-reference) |
| `audiences` | List of [audiences](/learn/api-definition/fern/audiences) to filter the API Reference for |
| `display-errors` | Displays error schemas in the API References |
| `snippets` | Enable [generated SDK code snippets](/learn/cli-api/api-reference/snippets/get) in your API Reference |
| `summary` | Relative path to the Markdown file; the summary is displayed at the top of the API section |
| `layout` | Customize the order that your API endpoints are displayed in the docs site |
| `icon` | Icon to display next to the API section in the navigation |
| `slug` | Customize the slug for the API section (by default, the slug is generated from the API title) |
| `skip-slug` | When `true`, skips the slug generation for the API section |
| `alphabetized` | When `true`, organizes all sections and endpoints in alphabetically order |
| `flattened` | Display all endpoints at the top level (hides the API Reference Section's title) |
| `paginated` | Display all endpoints on separate pages (by default, endpoints are displayed on one single, long page) |
More on customizing your API Reference [here](/learn/docs/api-references/customize-api-reference-layout).
### Include more than one API Reference
To include multiple, distinct API definitions in your documentation, you can indicate which to include using the `api-name` property. The `api-name` corresponds to the name of the folder where your API definition is housed.
```yaml title="docs.yml"
navigation:
- api: Plant Store
api-name: plant-api
- api: Garden
api-name: garden-api
```
# Display SDK snippets
> Enable SDK code examples in TypeScript, Python, Go, and more from the request and response examples documented in your API definition. Once enabled, Fern Docs will automatically populate the snippets within your API Reference.
If you use Fern's SDK Generator, you can automatically show SDK code snippets in your API Reference. SDK languages appear in a drop-down. By default, cURL snippets will be displayed to users.
![SDK code snippet selector](https://fern-image-hosting.s3.amazonaws.com/sdk-code-snippets.png)
## Configuring SDK Snippets
To configure SDK snippets, you'll need to name your SDKs in `generators.yml` and then reference that name in `docs.yml`. In the following example, We'll use `your-organization` as the package name because it is a common practice. For example, Stripe calls their npm package `stripe` and Twilio calls their PyPI package `twilio`.
### Add examples to your API definition
In order to generate code snippets, Fern needs to read request examples from your API definition. If you're using a Fern Definition, you can follow [these instructions](/learn/api-definition/fern/examples). If you're using an OpenAPI Specification, you can follow [these instructions](https://swagger.io/docs/specification/adding-examples/).
### Define a package name for your SDK(s)
```yaml
groups:
production:
generators:
- name: fernapi/fern-python-sdk
version: 2.8.0
output:
location: pypi
token: ${PYPI_TOKEN}
package-name: your-package-name # <--- add this field
...
- name: fernapi/fern-typescript-node-sdk
version: 0.20.9
output:
location: npm
token: ${NPM_TOKEN}
package-name: your-package-name # <--- add this field
- name: fernapi/fern-ruby-sdk
version: 0.6.3
output:
location: rubygems
token: ${RUBYGEMS_TOKEN}
package-name: your-package-name # <--- add this field
- name: fernapi/fern-go-sdk
version: 0.22.0
github:
repository: your-organization/your-repository # <--- add this field
...
```
SDK snippets automatically populated in your Fern Docs is a paid feature included
in the [SDK Starter plan](https://buildwithfern.com/pricing).
### Add the package name to your docs configuration
Add the package name for the corresponding SDK to your `docs.yml` file. For Go, use the exact URL where the SDK repository is located.
```yaml
navigation:
- api: API Reference
snippets:
python: your-package-name # <--- needs to match the naming in generators.yml
typescript: your-package-name
go: https://github.com/your-organization/your-repository # <--- needs the https://github.com/ prefix
```
### Trigger generation
As the final step, trigger your docs generation by running `fern generate --docs` locally or in CI/CD (i.e., GitHub Actions). The SDK snippets will now appear via a drop-down!
### Set default snippet
To set the default snippet shown in the API Reference drop-down, specify the `default-language` in your `docs.yml`.
```yaml {1}
default-language: typescript
navigation:
- api: API Reference
snippets:
python: your-package-name
typescript: your-package-name
```
## Language support
TypeScript, Python, Go, and Ruby are the supported SDK code snippet languages. Our development work is driven by customer requests, so please request support for another language by [opening an issue](https://github.com/fern-api/fern/issues/new/choose).
## Access via API
If you'd like to bring SDK snippets into your own documentation, you can use the [Snippets API](/learn/cli-api/api-reference/snippets/get). API access requires a [SDK Business plan](https://buildwithfern.com/pricing) or above.
Merge.dev is an example of a Fern customer that uses the Snippets API to bring Python code samples [into their API Reference](https://docs.merge.dev/hris/employees/#employees_list).
## Endpoint request and response snippets
Looking for information on generating API endpoint request and response snippets? See our documentation on [Endpoint Request Snippets](/learn/docs/content/components/request-snippet) and [Endpoint Response Snippets](/learn/docs/content/components/response-snippet).
# API Playground
> Reduce "time to 200" by allowing users to make real calls to your API from right within the API Reference.
This feature is available on the Basic plan and above.
[Contact us](https://buildwithfern.com/contact)
to get set up.
Fern's API Playground allows users to make authenticated requests to your API without ever leaving your documentation.
### Auto-populate with examples
Fern will automatically populate the fields of the endpoint with the values set in your API specification.
### Authenticated sessions
Once a user sets their authentication credentials once, their credentials persist throughout their entire exploration.
Authentication credentials are only stored client-side using cookies. No sensitive user information is collected or stored.
### Multiple environments
Allow users to test their calls in a sandbox environment or select the environment relevant to them. Users can switch between multiple environments. Once they've selected their environment, it persists throughout their entire exploration.
### WebSocket Playground
For APIs that support WebSocket connections, the API Playground includes a **WebSocket**-specific Playground. The WebSocket Playground also allows users to establish a connection with the API, and send/receive messages in real-time.
# Auto-populate API keys
> Make integrating with your API frictionless by adding your login flow to the API Playground.
This feature is available on the Enterprise plan. [Contact us](https://buildwithfern.com/contact) to learn more.
Fern can integrate with your authentication flow, allowing users to login and have their API key automatically populated with the click of a button.
With this feature, you can **create new users of your API** directly from within your documentation.
# Advanced configuration
> Configure advanced settings like the server URLs reachable by the API playground and authentication with OAuth.
If you subscribe to Fern's Pro or Enterprise Plans, you can customize your API Playground settings to suit your customers needs.
All configuration settings are defined in the `docs.yml` file, under API Reference navigation configuration, in a `Playground` object.
### Filtering Server Urls
If you have multiple environments for your API, you can filter the server URLs that are displayed in the API Playground.
To filter server URLs, add the `environments` property to the `PlaygroundSettings` object in your `docs.yml`, like so:
```yaml
navigation:
api:
playground:
environments:
- Staging-A
- Staging-B
```
### Enabling OAuth 2.0 Authorization Injection
If you have defined an endpoint that executes OAuth 2.0 Client Credentials Authorization in your API definition, you can enable OAuth 2.0 Authorization Injection in your API Playground.
More information on enabling OAuth 2.0 Authorization Injection can be found [here](/learn/api-definition/fern/authentication#oauth-client-credentials).
To enable OAuth 2.0 Authorization Injection, simply add the `oauth` feature flag to the `PlaygroundSettings` object in your `docs.yml`, like so:
```yaml
navigation:
api:
playground:
oauth: true
```
# Endpoint errors configuration
> Enable errors to show up on the endpoint pages of your documentation, from the error names, codes, and objects returned configured in your API definition.
This configuration enables errors to show up on the endpoint pages of your documentation. The error names, codes, and objects returned are configured in your API definition.
## Configuration
```yaml
navigation:
- api: API Reference
display-errors: true #<--- add this line
```
## Example
![Endpoint errors](https://fern-image-hosting.s3.amazonaws.com/fern/errors.png)
By clicking on an error, you can see the error name, code, and object returned. The response also updates to show the error object.
![Endpoint errors when expanded](https://fern-image-hosting.s3.amazonaws.com/fern/errors-expanded.png)
# Audiences
> Use audiences to filter the endpoints, schemas, and properties that are displayed in your API Reference.
Audiences are a useful tool for segmenting your API for different consumers. Common examples of audiences include `public`
and `beta`. You can configure audiences in both [the OpenAPI Specification](/learn/api-definition/openapi/audiences) as well as [the Fern Definition](/learn/api-definition/fern/audiences).
Once you've added audiences to your API Specification, you can filter to that audience by adding the `audience` property to the `api` object in your `docs.yml` navigation.
```yaml title="docs.yml" {3-4}
navigation:
- api: API Reference
audiences:
- public
```
Here's [an example from Schematic](https://github.com/SchematicHQ/schematic-fern-config/blob/e19f5ea69a343727ed018e79127bf4fd20ad0f7b/fern/docs.yml#L128-L129) in production.
# Customize API Reference layout
> Customize your API Reference's naming, ordering, and structure.
When you [include an API in your `docs.yml` file](/learn/docs/api-references/generate-api-ref), you can customize how the endpoints and sections are displayed in the sidebar navigation. By default, the reference will generate a navigation hierarchy based on the structure of the API spec, but several customizations can be configured.
If you are using an OpenAPI Specification, sections are created based on the `tags` property, converted to `lowerCamelCase` convention (e.g., createUser). If you are using a Fern Definition, sections are created based on the [`service`](/learn/api-definition/fern/endpoints#service-definition) file names.
If you would like to only display a subset of endpoints, read more about the Audiences property for [OpenAPI Specifications](/learn/api-definition/openapi/audiences) or [Fern Definitions](/learn/api-definition/fern/audiences).
## Ordering the API Reference
### Alphabetizing endpoints and sections
To sort all sections and endpoints alphabetically, unless explicitly ordered in `layout`, set `alphabetized` to `true`.
```yaml title="docs.yml"
navigation:
- api: API Reference
alphabetized: true
```
### Ordering top-level sections
The `layout` option allows you to specify the order of sub-packages, sections, endpoints, and pages at the top level of your API Reference.
```yaml title="docs.yml"
navigation:
- api: API Reference
layout:
- POST /user
- user
- store
- plant
```
```yaml title="docs.yml"
navigation:
- api: API Reference
layout:
- user.create
- user
- store
- plant
```
### Ordering section contents
Adding a `:` after the section name allows you to specify the order of its nested sub-packages and endpoints.
To reference an endpoint, you can use either:
* `METHOD /path/name` (best for OpenAPI Specification)
* `serviceName.endpointName` (best for Fern Definition)
You can reference an endpoint using the format `METHOD /path`.
```yaml title="docs.yml"
navigation:
- api: API Reference
layout:
- user:
- POST /user
- PUT /user/{username}
- DELETE /user/{username}
```
You can reference an endpoint using the format `serviceName.endpointName`.
```yaml title="docs.yml"
navigation:
- api: API Reference
layout:
- user:
- user.create
- user.update
- user.delete
```
## Customizing the API Reference
### Flattening sections
To remove the API Reference title and display the section contents, set `flattened` to `true`.
```yaml title="docs.yml"
navigation:
- api: API Reference
flattened: true
```
### Styling endpoints
To customize the display of an endpoint, you can expand the endpoint description to include a `title` and `slug`, or set the endpoint as `hidden`.
```yaml title="docs.yml"
navigation:
- api: API Reference
layout:
- user:
- endpoint: POST /user
title: Create a User
slug: user-creation
- DELETE /user/{username}
```
```yaml title="docs.yml"
navigation:
- api: API Reference
layout:
- user:
- endpoint: user.create
title: Create a User
slug: user-creation
- user.delete
```
### Adding custom sections
You can add arbitrary folders in the sidebar by adding a `section` to your API Reference layout. A section can comprise entire groups of endpoints, individual endpoints, or even just Markdown pages. Sections can be customized by adding properties like a `icon`, `summary`, `slug` (or `skip-slug`), and `contents`.
```yaml title="docs.yml"
navigation:
- api: API Reference
layout:
- section: My Section
icon: flower
contents:
- PUT /user/{username}
- plant
```
```yaml title="docs.yml"
navigation:
- api: API Reference
layout:
- section: My Section
icon: flower
contents:
- user.update
- plant
```
### Adding a section overview
The `summary` property allows you to add an `.md` or `.mdx` page as an overview of the API Reference or a section.
```yaml title="docs.yml"
navigation:
- api: API Reference
summary: pages/api-overview.mdx
layout:
- user:
summary: pages/user-overview.mdx
```
### Adding pages and links
You can add regular pages and external links within your API Reference.
```yaml title="docs.yml"
navigation:
- api: API Reference
layout:
- user:
contents:
- page: User Guide
path: ./docs/pages/user-guide.mdx
- link: Link Title
href: http://google.com
```
### Disable long-scrolling
By default, the API Reference renders all endpoints on a single page (long-scrolling). To create separate pages for each endpoint, set `paginated: true`.
```yaml title="docs.yml"
navigation:
- api: API Reference
paginated: true
```
# Write Markdown content in your API Reference
> Add Markdown content to your API Reference including summary pages and content between endpoints.
Fern Docs allows you to write Markdown content in your API Reference documentation. This feature is useful for providing additional context, examples, or explanations for your API endpoints. There are a few ways to accomplish this:
## In OpenAPI
If you're using OpenAPI to define your API, you can include Markdown content in your OpenAPI Specification.
For example, you can include a [callout](/learn/docs/content/components/callouts#note-callouts) in the `description` field of an endpoint:
```yaml title="api/openapi.yml"
paths:
/pets:
get:
summary: List all pets
description: |
Get a list of all pets in the system.
This endpoint requires authentication.
```
## In Fern Definition
If you're using Fern's simpler API definition format, you can include Markdown content in your API definition.
For example, you can include a [callout](/learn/docs/content/components/callouts#note-callouts) in the `docs` field of an endpoint:
```yaml title="api/service.yml"
service:
endpoints:
get:
path: /pets
docs: |
Get a list of all pets in the system.
This endpoint requires authentication.
```
## Adding a summary page
You can also create a Markdown page that provides an overview of your API Reference. This page can include general information about your API, such as authentication requirements, rate limits, or other important details.
To add a summary page, create a Markdown file in your `fern/` folder and link to it in your `docs.yml` file:
```yaml title="docs.yml"
navigation:
- api: API Reference
summary: ./pages/api-summary.mdx
```
By including the `summary` field, the `API Reference` section title will link to the `api-summary.mdx` page.
## Adding Markdown content between endpoints
In addition to adding Markdown content to individual endpoints, you can also include Markdown content between endpoints in your API Reference. This content can provide context or explanations that apply to multiple endpoints.
This feature requires you to use the `layout` field in your `docs.yml` file, which is described in the [Customize your API Reference](/learn/docs/api-references/customize-api-reference-layout) guide.
To add Markdown content between endpoints, create a Markdown file in your `fern/` folder and link to it in your `docs.yml` file:
```yaml title="docs.yml"
navigation:
- api: API Reference
layout:
- pet:
- page: Pet CRUD
path: ./pages/pet-crud.mdx
- addPet
- updatePet
- deletePet
- page: Pet Search
path: ./pages/pet-search.mdx
- findPets
- findPetsByStatus
- findPetsByTags
- findPetsByType
- findPetsByBreed
```
# Integrations
> Integrate with third party platforms for analytics, support, etc.
} iconSize={12} />
}
iconSize={12}
/>
} iconSize={12} />
} iconSize={12} />
} iconSize={12} />
## Enabling Analytics
You can define your analytics configuration in `docs.yml`. You only need to include entries for the platforms you want to connect.
```yaml docs.yml
analytics:
posthog:
api-key: ${POSTOHG_API_KEY}
endpoint: https://self.hosted.posthog.com/
segment:
write-key: ${SEGMENT_WRITE_KEY}
intercom:
app-id: ${INTERCOM_APP_ID}
endpoint: https://intercom.custom-instance.com/
fullstory:
org-id: ${FULLSTORY_ORG_ID}
```
### Environment Variables
If your docs configuration is public, then we do not advise adding secret values directly to `docs.yml`.
Instead, you can reference an environment variable by using the syntax `${VARIABLE_NAME}`.
If you are using GitHub Workflows to trigger docs generation, you must make sure that the environment variables
are available during the workflow run.
```yaml {4}
- name: Publish Docs
env:
FERN_TOKEN: ${{ secrets.FERN_TOKEN }}
POSTHOG_API_KEY: ${{ secrets.POSTHOG_PROJECT_API_KEY }}
run: |
npm install -g fern-api
fern generate --docs
```
## Postman
The Postman integration is not configured in `docs.yml`. Check out this [page](/learn/docs/integrations/postman) to
learn more.
# Google Analytics
> Add Google Analytics to your Docs with Fern.
Fern supports integrating with both [Google Analytics 4](https://developers.google.com/analytics) and [Google Tag Manager](https://tagmanager.google.com/).
This feature is available on the Fern Basic plan and above. Reach out to [support@buildwithfern.com](mailto:support@buildwithfern.com) to set up your Google Analytics.
# PostHog
> Learn how to integrate PostHog with Fern Docs!
## Add Posthog to your Docs
To integrate PostHog, you'll need a Posthog API Key, and optionally, you can configure a custom Posthog host.
### Integrate Posthog
You can find your PostHog API Key under your [project settings.](https://us.posthog.com/settings/project)
Then, in your `docs.yml` file, add your Posthog configuration:
```yaml
analytics:
posthog:
api-key: ${POSTHOG_API_KEY} # reads your api key from environment variables
# Optional
endpoint: ${POSTHOG_API_HOST} # e.g. https://analytics.example.com or https://eu.i.posthog.com
```
# Fullstory
> Learn how to integrate Fern Docs with Fullstory to track user behavior and analytics.
## Add Fullstory to your Docs
To add Fullstory to your Docs, you need to add your Fullstory `orgId` to your `docs.yml` file.
### Get your Fullstory Org ID
When you login to your Fullstory account, your Org ID can be found in the URL of your browser.
```
https://app.fullstory.com/ui//home
```
Additionally, you can find your Org ID in [Settings > Data Capture and Privacy > Fullstory Setup](https://help.fullstory.com/hc/en-us/articles/360047075853-How-do-I-find-my-Fullstory-Org-Id#:~:text=You%20can%20find%20your%20Org,embedded%20in%20the%20Fullstory%20snippet.\&text=More%20information%20about%20installation%20and,the%20URL%20of%20your%20browser.)
inside the Fullstory snippet:
1. Log in to your Fullstory account.
2. Find **Settings** in a dropdown by clicking your organization's name or logo in the top left.
3. Navigate the sidebar to the Data Capture and Privacy section. Click on "Fullstory Setup", located under the heading.
4. Retrieve the Org Id from the snippet, where it is assigned to `window['_fs_org']`. It will appear as `window['_fs_org'] = ''`.
You can find visual instructions in [Fullstory's guide](https://help.fullstory.com/hc/en-us/articles/360047075853-How-do-I-find-my-Fullstory-Org-Id#:~:text=You%20can%20find%20your%20Org,embedded%20in%20the%20Fullstory%20snippet.\&text=More%20information%20about%20installation%20and,the%20URL%20of%20your%20browser.)
about this topic.
### Integrate Fullstory with your Docs
In your `docs.yml` file, add your Fullstory Org ID:
```yaml
analytics:
fullstory:
org-id: ${FULLSTORY_ORG_ID} # reads your org id from environment variables
```
# Segment
> Learn how to integrate Fern Docs with Segment to track user behavior and analytics.
Currently we only support Segment via a custom writeKey in the docs.yml file, however you can add other providers to your docs page through [Custom Javascript](/learn/docs/building-your-docs/custom-css-global-js).
We are also working on adding support for additional analytics tools via the docs.yml file analytics block!
## Add Segment to your Docs
To add Segment to your Docs, you need to add the Segment writeKey to your `docs.yml` file.
### Get your Segment writeKey
1. Log in to your Segment account.
2. Go to the workspace where you want to add the Docs integration.
3. Click on the Source you want to track.'
4. Click on the `Settings` tab.
5. Copy the `Write Key` from the `API Keys` section.
### Add the Segment writeKey to your Docs
In your `docs.yml` file, add the Segment writeKey:
```yaml
analytics:
segment:
write-key: ${SEGMENT_WRITE_KEY} # scans environment variable
```
# Intercom
> Learn how to integrate Intercom with Fern Docs!
## Add Intercom to your Docs
To add Intercom to your Docs, you need to your Intercom `app_id`, also known as the Intercom workspace ID.
This is a unique code assigned to your app when you create it in Intercom.
Additionally, you may configure a custom Intercom endpoint.
### Get your Intercom App Id
Your app ID is available under [Settings > Workspace > General](https://app.intercom.com/a/apps/_/settings/workspace/general)
in the "Workspace name & time zone" tab.
See [Intercom's FAQ](https://www.intercom.com/help/en/articles/8771110-getting-started-faqs#h_c12f89cf9d) for visual instructions.
### Integrate Intercom with your Docs
In your `docs.yml` file, add your Intercom config:
```yaml
analytics:
intercom:
app-id: ${INTERCOM_APP_ID} # reads your org id from environment variables
# Optional
endpoint: ${INTERCOM_ENDPOINT} # e.g. https://intercom.custom-instance.com
```
# Postman Integeration
> Generate a postman collection full of example requests and responses
## Showcase
} iconSize={12} />
} iconSize={12} />
## Getting started
The configuration for the postman generator lives in your fern folder, in a file
called [`generators.yml`](/learn/api-definition/introduction/what-is-the-fern-folder#generatorsyml).
### **Step 1**: Configure your `generators.yml`
Start by running the following command:
```sh
fern add fern-postman --group postman
```
Once the command completes, you will see the following configuration added:
```yaml title="generators.yml" {2-8}
groups:
postman:
generators:
- name: fernapi/fern-postman
version: 0.0.45
output:
location: local-file-system
path: ../postman
```
### **Step 2**: Generate a `collection.json`
Start by running the following command
```sh
fern generate --group postman
```
This will trigger postman collection on Fern's cloud. Once complete, you'll see a `collection.json`:
```bash {4-5}
fern/
├─ fern.config.json
├─ generators.yml
postman
├─ collection.json
```
## Publishing
If you'd like Fern to publish the collection directly to Postman instead, you can modify your `generators.yml` configuration
in the following way:
```yaml title="generators.yml" {6-9}
generators:
postman:
generators:
- name: fernapi/fern-postman
version: 0.4.0
output:
location: postman
api-key: ${POSTMAN_API_KEY}
workspace-id: 07e228e5-3f91-4223-8e27-bbfe4a81a601
config:
collection-name: My collection name
```
If you'd like to publish to a particular collection, just specify the collection ID.
```yaml title="generators.yml" {10}
generators:
postman:
generators:
- name: fernapi/fern-postman
version: 0.4.0
output:
location: postman
api-key: ${POSTMAN_API_KEY}
workspace-id: 07e228e5-3f91-4223-8e27-bbfe4a81a601
collection-id: 21510182-14b07230-46e2-431e-8153-d5c7d217b214
config:
collection-name: My collection name
```
# Hosting with GitLab
To host your Fern docs using GitLab, you will need to [add a Fern token to your repository variables](/learn/docs/developer-tools/gitlab#add-a-token-to-gitlab).
The following GitLab CI/CD workflow will generate a preview link of your docs on merge request and publish your docs when updates are made to `main`.
To add this to your GitLab Fern project, create a `.gitlab-ci.yml` file in the root of your repository.
```yaml .gitlab-ci.yml
stages:
- check
- preview_docs
- publish_docs
- publish_sdks
before_script:
- apt-get update -y
- apt-get install -y curl
- curl -sL https://deb.nodesource.com/setup_current.x | bash -
- apt-get install -y nodejs
- npm install -g fern-api
check:
stage: check
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH == "main"'
script:
- echo "Checking API is valid"
- fern check
preview_docs:
stage: preview_docs
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
script:
- echo "Running fern generate --docs --preview..."
- |
OUTPUT=$(fern generate --docs --preview) || true
echo "$OUTPUT"
DEMO_URL=$(echo "$OUTPUT" | grep -oP -m1 '(https://[^\s]+-preview-[^\s]+)(?: )')
echo "Preview URL: $DEMO_URL"
- |
if [ -z "$DEMO_URL" ]; then
echo "No DEMO_URL found"
exit 1
fi
curl --location --request POST \
--header "PRIVATE-TOKEN: $REPO_TOKEN" \
--header "Content-Type: application/json" \
--url "https://gitlab.com/api/v4/projects/$CI_MERGE_REQUEST_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID/notes" \
--data-raw "{ \"body\": \"🌿 Preview your docs [here]($DEMO_URL)\" }"
publish_docs:
stage: publish_docs
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
script:
- echo "Publishing Docs"
- fern generate --docs
publish_sdks:
stage: publish_sdks
rules:
- if: '$CI_PIPELINE_SOURCE == "web"'
script:
- echo "Publishing SDKs"
- fern generate --group ts-sdk --version $VERSION --log-level debug
```
## Add a token to GitLab
### Log in
Log into [GitLab](https://gitlab.com/users/sign_in).
### Navigate to CI/CD in settings
Click on the **Settings** tab in your repository. Then, click on **CI/CD**.
### Add variable
Scroll to the **Variables** section and select **Expand** > **Add variable**. Add your key and value, *deselect* **Protect variable**, and then click **Save changes**.
## Preview docs with GitLab
### Contact us
To get set up with a GitLab pipeline to preview your docs automatically, reach out via your dedicated Slack channel or [email](mailto:support@buildwithfern.com).
### Log in
Log into [GitLab](https://gitlab.com/users/sign_in).
### Navigate to Access Tokens
Click on the **Settings** tab in your repository. Then, click on **Access Tokens**.
### Generate project access token
Click on **Add new token**. You then need to:
* Add your token name
* Select an expiry date (note: once the token expires, you will need to generate a new one)
* Set role to **Reporter**
* Set scope to **api**
When finished, click **Create project access token**.
Be sure to save the generated token - it won't be displayed after you leave the page.
### Add token to repository variables
You can do this using [the steps listed above](/learn/docs/developer-tools/gitlab#add-a-token-to-gitlab).
# Using Vale
## What is Vale?
[Vale](https://vale.sh/) is an open-source tool for linting content from a variety of different file types, including Markdown.
## Using Vale with MDX
Once installed, you can use Vale with MDX files by adding a `.vale.ini` file to your Fern repo.
Be sure to add
```txt
[formats]
mdx = md
```
to your `.vale.ini` configuration so the MDX format is recognized.
To use Vale's HTML-style comments (``) in an MDX file, wrap within an MDX-styled comment (`{/* comment */}`). For example:
* **disable Vale**: `{/* */}`
* **enable Vale**: `{/* */}`
```markdown title='Example Vale Usage'
Vale will check this text.
{/* */}
Vale won't check this text.
{/* */}
Vale will start checking this text again.
```