# Migrating from Mintlify

Most Mintlify pages build in writedocs with no changes: the components, props, code-block syntax, and frontmatter below are accepted under Mintlify's own names. Copy your MDX files over, then check the [known differences](#known-differences).

## Converting docs.json

In your Mintlify project's folder, run:

```bash
writedocs convert --mintlify
```

It writes `writedocs.json` from `docs.json` and lists everything that couldn't be carried over as-is, then checks your pages - see [`writedocs convert`](/docs/cli/#writedocs-convert). Pass `--dry-run` first to review the result without writing anything.

What it converts:

| docs.json | writedocs.json |
| --- | --- |
| `name`, `description` | Same fields. |
| `colors.primary`, `colors.light` | `styles.colors.primary`, `styles.colors.dark.primary`. |
| `logo`, `favicon`, `fonts`, `background`, `styling.codeblocks` | The matching `styles` fields. |
| `navigation` - pages, groups, tabs, dropdowns, products, versions, languages | The same structure. A group's `root` becomes its `page`. |
| `navigation` anchors | Tabs. |
| A tab's or product's `menu` | Dropdowns inside it. |
| `navigation.global` anchors, tabs and dropdowns | Global dropdowns - or topbar links, when the navigation is a plain list of pages. |
| Groups with an `openapi` spec | OpenAPI groups. A group that listed individual endpoints now shows every endpoint in its spec. |
| `navbar.links`, `navbar.primary` | Topbar links. |
| `footer.socials`, `footer.links` | `socials`, `footer.columns`. |
| `banner`, `errors.404`, `redirects`, `variables` | `banner`, `notFound`, `redirects`, `variables`. |
| `seo.metatags` (`og:image`, `og:type`, `twitter:card`, `keywords`) | `seo`. |
| `contextual.options` | `contextMenu`. |
| `integrations` - GA4, Google Tag Manager, Plausible, Fathom, PostHog | `integrations`. |
| `api.playground.proxy` | `api.proxy`. |

Everything else is listed in the report, with the field it came from. Hidden tabs and groups are left out of the navigation - their pages still build, reachable by URL. After converting, set `domain` in `writedocs.json` to your site's address: Mintlify sets it in its dashboard, not `docs.json`.

## CLI commands

| Mintlify | writedocs |
| --- | --- |
| `mint dev` | [`writedocs dev`](/docs/cli/#writedocs-dev) |
| `mint broken-links` | [`writedocs broken-links`](/docs/cli/#writedocs-broken-links) - also checks `#anchors`. |
| `mint openapi-check` | [`writedocs validate`](/docs/cli/#writedocs-validate) - checks every spec in the navigation, and every page's `openapi` operation, with the rest of the project. |
| `mint a11y` | [`writedocs a11y`](/docs/cli/#writedocs-a11y) |

## Components

| Mintlify | In writedocs |
| --- | --- |
| `Note`, `Info`, `Tip`, `Warning`, `Danger`, `Check` | Same names. See [Callout](/docs/content/components/callout/). |
| `Callout` with `icon` / `color` | Same props. |
| `Card` with `icon`, `img`, `href`, `color`, `horizontal`, `cta`, `arrow` | Same props. See [Card](/docs/content/components/card/). |
| `Columns`, `Column`, `CardGroup` | Same names. |
| `Tabs` / `Tab` with `defaultTabIndex`, `icon` | Same props. See [Tabs](/docs/content/components/tabs/). |
| `CodeGroup` | Same name. Tab labels come from each block's title. |
| `Accordion` / `AccordionGroup` with `icon`, `description`, `defaultOpen` | Same props. See [Accordion](/docs/content/components/accordion/). |
| `Steps` / `Step` with `icon`, `stepNumber`, `titleSize` | Same props. See [Steps](/docs/content/components/steps/). |
| `Frame` with `caption`, `hint` | Same props. See [Frame](/docs/content/components/frame/). |
| `Tooltip` with `tip`, `headline`, `cta`, `href` | Same props. Also available as `Hint`. See [Hint](/docs/content/components/hint/). |
| `ParamField` (`path` / `query` / `body` / `header`), `ResponseField` | Same props, including `deprecated`, `pre`, `post`. See [Parameter](/docs/content/components/parameter/). |
| `Expandable`, `RequestExample`, `ResponseExample`, `Badge`, `Icon` | Same names. |
| `Update` | Same props. See [Update](/docs/content/components/update/). |
| `Tree` / `FileTree`, `Tree.Folder`, `Tree.File` - component or Markdown-list form | Same props and keyboard navigation. See [Tree](/docs/content/components/tree/). |
| `Tile` | Same props. See [Tile](/docs/content/components/tile/). |
| `Panel` | Same behavior. See [Panel](/docs/content/components/panel/). |
| `Prompt` with `description`, `icon`, `actions` | Same props. See [Prompt](/docs/content/components/prompt/). |
| `View` with `title`, `icon` | Same props, and the table of contents follows the selected view. See [View](/docs/content/components/view/). |
| `Color`, `Color.Row`, `Color.Item` | Same props, including light/dark values. See [Color](/docs/content/components/color/). |
| `GitHub.Repo` | Same props. See [GitHub repository](/docs/content/components/github/). |
| `Visibility` | Same behavior on the site and in the page's Markdown version. See [Visibility](/docs/content/components/visibility/). |
| `className` on any component | Same - added to the component's outermost element. |
| `CodeBlock` | Same props. See [Code blocks](/docs/content/code-blocks/#codeblock-component). |
| Snippets imported from `/snippets/...` | Same path. See [Snippets](/docs/content/snippets/). |
| React hooks without imports, components defined in a page | Work as on Mintlify, interactive. See [Snippets](/docs/content/snippets/#components-defined-in-a-page). |
| `openapi: "/spec.json GET /path"` page frontmatter | Same form - the page shows that operation. See [OpenAPI](/docs/openapi/multi-spec-and-overrides/#naming-the-spec-on-the-page). |

## Icons

A bare icon name is looked up in Lucide first, then Font Awesome Solid, then Font Awesome Brands. Mintlify's default library is Font Awesome, so names like `gear`, `circle-info`, or `discord` work as-is. See [Icons](/docs/content/components/icon/#icons).

## Code blocks

Mintlify's code-block options work as written: an inline title (` ```bash Install `), `title="..."`, `highlight={1,3-5}`, `focus={2}`, `icon="..."`, `lines`, `wrap`, `expandable`, and `nocopy`. See [Code blocks](/docs/content/code-blocks/).

## Frontmatter

`title`, `description`, and `openapi` mean the same thing, and a page without a `title` gets one from its file name, as on Mintlify. A page doesn't need frontmatter at all if the navigation lists it. These Mintlify fields are also accepted:

- `sidebarTitle`, `icon`, `tag`, and `deprecated` - how the page appears in the sidebar.
- `hidden` - leaves the page out of navigation but keeps its URL working, and noindexes it.
- `url` - makes the sidebar entry an external link, and redirects the page's URL there.
- `hideFooterPagination` and `hideApiMarker` - hide the previous/next links, or the sidebar's HTTP method badge.
- `noindex`, `keywords`, `og:image`, `og:type`, `twitter:card` - the same as writedocs' `seo` fields.

See [Frontmatter](/docs/content/frontmatter/) for each one.
- `mode: wide` and `mode: custom` - the same modes. `mode: center` renders as writedocs' `frame` mode (no sidebar, no table of contents). `mode: assistant` renders as a normal page.

## Tailwind classes

Tailwind utility classes in your MDX are generated as they are on Mintlify, and `dark:` follows the site's light/dark toggle. Mintlify's light/dark image pair works unchanged:

```mdx
<img className="block dark:hidden" src="/images/light.png" />
<img className="hidden dark:block" src="/images/dark.png" />
```

## Known differences

<Tip title="Run writedocs validate first">
  After copying your pages over, run [`writedocs validate`](/docs/cli/#writedocs-validate). It lists everything that needs attention in one pass, with file and line - pages that would fail the build, and components or icons writedocs doesn't have. Then run [`writedocs broken-links`](/docs/cli/#writedocs-broken-links) to find links that don't lead anywhere.
</Tip>

- **Components writedocs doesn't have** - every component in Mintlify's documentation is available. Anything else, like a custom React component from your Mintlify project, doesn't fail the build: it shows only the content inside it, with a warning naming the file and line. Move it into a [snippet](/docs/content/snippets/), or remove it.

- **`mode: frame`** - Mintlify's `frame` is a blank canvas that keeps the sidebar. writedocs' `frame` has no sidebar and keeps the page's title and normal layout. The page builds, but looks different - a custom landing page with its own hero shows writedocs' title above it.
- **Components inside a page's own React component** - in a page component that uses React hooks or is passed to a snippet, `Card`, `Callout` and the other writedocs components render just their content, `Icon` renders nothing, and `CodeBlock` renders unhighlighted. `writedocs validate` lists each one. A component passed to a snippet as a prop renders, but isn't interactive.
- **Font Awesome Pro and `iconType`** - only the free Font Awesome Solid and Brands sets are installed. `iconType` is ignored, so the icon renders from whichever set has the name (Lucide first), and a Pro-only icon name is left out, with a warning.
- **Frontmatter with no equivalent** - `searchable`, `boost`, `related`, `contextual`, `groups`, `timestamp`, `lastUpdatedDate`, and SEO keys other than the five above (for example `"twitter:image"`) are ignored for now.
- **`Update` and RSS** - writedocs doesn't generate an RSS feed from `Update` entries, so their `rss` prop does nothing. The tag filters appear above the first entry, not in a side panel.
- **`Panel` outside the default mode** - on Mintlify, a page mode without a table of contents also hides its `Panel`. In writedocs, the `Panel` stays in the page instead.
- **Variables** - `{{name}}` works for names made of letters, digits and underscores. A name with a hyphen isn't valid in MDX - write it as `[[name]]`.
- **Relative links** - writedocs page URLs end in a slash (`/docs/guides/setup/`), so a relative link resolves one level deeper than on Mintlify: `[Install](install)` on that page points to `/docs/guides/setup/install/`. Write links from the site root instead (`/docs/guides/install/`). [`writedocs broken-links`](/docs/cli/#writedocs-broken-links) finds each one and says what to write.
- **Redirects with a pattern** - Mintlify's `/old/:slug` and `/old/*` redirects aren't supported; writedocs redirects match one exact path. `convert` leaves them out and says how many.
- **`noindex` and on-site search** - on Mintlify, `noindex` (and `hidden`) also removes the page from the site's own search. In writedocs, the page still shows up in on-site search.