Migrate from Fern
Migrate your API documentation from Fern Docs to the Stainless Docs Platform, including custom content, React components, and API reference.
Fern is a documentation platform that generates API docs from OpenAPI specifications alongside custom content.
This guide walks you through migrating your existing Fern documentation to Stainless.
Prerequisites
Section titled “Prerequisites”Before starting, make sure you have:
- An account on Stainless
- Early access to the Stainless Docs Platform (request access)
- Your existing Fern documentation project
- Node.js v22+
Set up your Stainless project
Section titled “Set up your Stainless project”If you already have a Stainless project, skip to Create your docs site.
To create a new Stainless project, you need an OpenAPI spec. Export your spec from Fern by running this command in your Fern project directory:
fern export openapi.ymlThen create your Stainless project:
- Log in to the Stainless dashboard
- Click New project
- Upload your exported
openapi.ymlfile as the spec
Create your docs site
Section titled “Create your docs site”To create a docs site for your Stainless project:
- In the Stainless dashboard, select your project
- Go to the API Docs tab
- Click Get started
Stainless creates a GitHub repository for your docs site and deploys it to a staging domain. For detailed setup instructions, see the Docs Platform quickstart.
Migrate content files
Section titled “Migrate content files”To migrate your documentation content:
- Locate your Fern content: Find your
.mdxand.mdfiles infern/docs/pages/ - Copy to Stainless: Copy these files into your Stainless site’s
src/content/docs/directory - Update frontmatter: Replace Fern frontmatter with Stainless frontmatter
Fern frontmatter:
---title: How to integratedescription: Learn how to integrate your API documentationsubtitle: Customize content using frontmatterslug: how-to-integratekeywords: integration, sdk generation, api, mcp servers, documentationog:site_name: Your Company Inc.og:title: SEO Metadata Title---Stainless frontmatter:
---title: How to integratedescription: Learn how to integrate your API documentation---The title and description fields work the same way in both platforms.
If you need custom SEO metadata (keywords, Open Graph tags, etc.), you can optionally add a head property:
---title: How to integratedescription: Learn how to integrate your API documentationhead: - tag: meta attrs: name: keywords content: integration, sdk generation, api, mcp servers, documentation - tag: meta attrs: property: og:site_name content: Your Company Inc. - tag: meta attrs: property: og:title content: SEO Metadata Title---Most pages only need title and description. The description field is used for SEO and appears in navigation previews.
Fern’s subtitle field has no direct equivalent in Stainless. Instead, add subtitle content directly in your page body after the frontmatter.
Fern’s slug field is supported but not recommended. In Stainless, file paths determine URLs, so src/content/docs/guides/quickstart.mdx becomes /docs/guides/quickstart/.
For more information about content organization, see Project structure.
Update component syntax
Section titled “Update component syntax”Fern and Stainless use different component libraries. Replace Fern components with Stainless equivalents.
Callouts
Section titled “Callouts”Fern provides multiple callout components (<Info>, <Warning>, <Note>, <Tip>, <Success>, <Error>). Stainless uses a single <Callout> component with a variant prop.
Fern:
<Info>This draws attention to important information.</Info>
<Warning>This raises a warning to watch out for.</Warning>
<Note>This highlights additional context.</Note>
<Tip>This suggests a helpful tip.</Tip>Stainless:
import { Callout } from '@stainless-api/docs/components';
<Callout variant="note"> This draws attention to important information.</Callout>
<Callout variant="warning"> This raises a warning to watch out for.</Callout>
<Callout variant="note"> This highlights additional context.</Callout>
<Callout variant="tip"> This suggests a helpful tip.</Callout>Code blocks
Section titled “Code blocks”Both Fern and Stainless use standard markdown code fences with syntax highlighting.
Fern:
```ts title="example.ts"const client = new Client();```Stainless:
```ts title="example.ts"const client = new Client();```Code block syntax is largely compatible between the two platforms, so most code examples migrate without changes.
Stainless code blocks do not support focus, startLine, or maxLines attributes.
wordWrap becomes wrap in Stainless.
For tabbed content, Fern uses <Tabs> with <Tab> children. Stainless uses <Tabs> with <TabItem> children from @astrojs/starlight/components;
Fern:
<Tabs> <Tab title="Web"> Content for Web tab. </Tab> <Tab title="Mobile"> Content for Mobile tab. </Tab></Tabs>Stainless:
import { Tabs, TabItem } from "@astrojs/starlight/components";
<Tabs> <TabItem label="Web"> Content for Web tab. </TabItem> <TabItem label="Mobile"> Content for Mobile tab. </TabItem></Tabs>Note that Fern uses title while Stainless uses label for tab headers.
Tabbed code blocks
Section titled “Tabbed code blocks”For code examples in multiple languages, Fern uses a <CodeBlocks> wrapper component. Stainless uses the standard <Tabs> component with code fences inside.
Fern:
<CodeBlocks> ```typescript title="TypeScript" const client = new Client(); ```
```python title="Python" client = Client() ```</CodeBlocks>Stainless:
import { Tabs, TabItem } from "@astrojs/starlight/components";
<Tabs> <TabItem label="TypeScript"> ```typescript const client = new Client(); ``` </TabItem> <TabItem label="Python"> ```python client = Client() ``` </TabItem></Tabs>Migrate custom React components
Section titled “Migrate custom React components”To migrate custom React components from Fern:
- Copy component files: Copy your
.tsxand.tsfiles fromfern/components/to your Stainless site’ssrc/components/directory - Update imports: Update any Fern-specific imports to use standard React or Astro imports
- Import in content: Import and use components in your MDX files
Example:
import { useState } from "react";
export default function CustomCard({ title, content }) { return ( <div className="custom-card"> <h3>{title}</h3> <p>{content}</p> </div> );}Use in content:
---title: Example Page---
import CustomCard from "/src/components/CustomCard.tsx";
<CustomCard title="My Card" content="Card content here"/>If your component needs to be interactive (uses state, event handlers, or effects), add a client directive like client:load:
<CustomCard title="My Card" content="Card content here" client:load/>Note the client:load directive is only needed for interactive components, you can omit it for most static content. For more information, see Astro’s client directives documentation.
Configure navigation
Section titled “Configure navigation”Fern uses docs.yml to configure navigation. Stainless uses astro.config.ts.
Fern navigation:
navigation: - section: Getting Started contents: - page: Quickstart path: ./docs/quickstart.mdx - page: Authentication path: ./docs/authentication.mdx - api: API ReferenceStainless navigation:
export default defineConfig({ integrations: [ stainlessDocs({ sidebar: [ { label: 'Getting Started', items: [ { label: 'Quickstart', slug: 'docs/quickstart' }, { label: 'Authentication', slug: 'docs/authentication' }, ], }, { label: 'API Reference', autogenerate: { directory: 'api' }, }, ], }), ],});The API reference section is automatically generated from your OpenAPI spec. For more information about navigation configuration, see Navigation.
Update branding
Section titled “Update branding”To migrate your branding from Fern to Stainless:
Colors
Section titled “Colors”Fern:
colors: accent-primary: '#4F46E5' background: '#FFFFFF'Stainless:
:root { --stl-color-accent: #4F46E5;}Stainless also supports the light-dark() function for different colors in light and dark mode:
:root { --stl-color-accent: light-dark(#4F46E5, #7C3AED);}For more color customization options, see Styles, fonts, and CSS.
Fern:
logo: light: ./assets/logo-light.svg dark: ./assets/logo-dark.svgStainless:
- Copy your logo files to
src/assets/ - Configure in
astro.config.ts:
export default defineConfig({ integrations: [ stainlessDocs({ logo: { light: './src/assets/logo-light.svg', dark: './src/assets/logo-dark.svg', replacesTitle: true, alt: 'Your Company', }, }), ],});For more branding options, see Logo and branding.
Search
Section titled “Search”Fern uses Algolia for search.
Stainless includes built-in search that understands the structure of your SDKs:
- Metadata-driven indexing: Search indexes are built directly from your SDK’s structural metadata, providing more relevant and precise results than HTML scraping.
- Faceted search: Users can filter results by programming language and narrow down by resources, methods, types, or properties.
- Conversational AI: An integrated AI-powered search allows users to ask questions in natural language. A RAG pipeline brings relevant SDK metadata into context for accurate answers.
- LLM-friendly Markdown: Every documentation page has an LLM-friendly Markdown representation available by adding
.mdto any URL.
API reference generation
Section titled “API reference generation”Both Fern and Stainless automatically generate API reference documentation from your OpenAPI spec.
| Feature | Fern | Stainless |
|---|---|---|
| Auto-generation | ✓ | ✓ |
| SDK code samples | Manual setup | Automatic |
| SEO control | ✓ | ✓ |
| Search indexing | ✓ | Configurable |
Deploy your site
Section titled “Deploy your site”You can host your documentation site on Stainless, or with any hosting provider that supports static sites. When you push changes to your main branch, Stainless automatically builds and deploys your site:
git add -Agit commit -m "Migrate from Fern to Stainless"git push origin mainMonitor your build status in the Stainless dashboard under your project’s API Docs tab.
Your site is initially deployed to a staging domain (a subdomain of stldocs.app). To use a custom domain, see Custom domain.
Next steps
Section titled “Next steps”Now that you have migrated from Fern to Stainless:
- Customize your site’s styles and fonts
- Configure your navigation
- Add custom components
- Set up a custom domain
If you have questions or need help with your migration, reach out to our team.