No per-service fees - one plan, unlimited appsFree tier available - start building today15% off your workspace - subscribe to our blogNo per-service fees - one plan, unlimited appsFree tier available - start building today15% off your workspace - subscribe to our blog
Miget x AIPlansEnterpriseCompareBlogDashboard
Start for Free
Blog/Engineering/Self-Hosted/
·

How to Self-Host Mintlify Docs as a Static Site

Mintlify is a good way to write documentation. The writing experience is genuinely pleasant, the API playground works, and the output looks like the docs of a company much larger than yours.

Then someone asks where the docs are hosted, and whether they can live on your own infrastructure. Mintlify's answer is that self-hosting is available on Enterprise, which is quoted per organisation. On Starter and Pro your published docs live on their infrastructure, and that is the end of the conversation unless you want to have a different one with sales.

This post is about the third option: keep writing in Mintlify, and export the rendered site to static files you host yourself.

Why anyone wants this

Three reasons come up, in roughly this order.

The docs have to be on your infrastructure. Sometimes that is a compliance requirement, sometimes it is a policy about what runs on which domain, and sometimes it is just that everything else you operate is already yours and the docs are the odd one out.

Nobody wants a second bill for HTML. Documentation is static content. Paying a per-seat subscription to serve it starts to feel strange the moment you already run a CDN.

Lock-in, but the boring kind. The MDX is yours and always was. What is not obviously yours is the rendered site: the theme, the navigation, the client-side routing, the search page, the generated API reference. If the relationship ends, you would like to keep serving the thing you already have while you decide what is next.

What we built

We hit the first reason. docs.miget.com is written in Mintlify, and we wanted it served from our own infrastructure like everything else we run.

So we wrote staticmint, a Go tool that turns a Mintlify docs repo into a directory of static files. It is MIT licensed, contains no Mintlify code, and it is what serves docs.miget.com in production today.

The approach is deliberately unclever. mint dev is a real production Next.js server rendering your docs exactly as Mintlify renders them. staticmint starts it, crawls it, and writes the result to disk. Nothing re-implements Mintlify's renderer, so nothing drifts from it.

What comes out

Running it against a docs repo produces a bundle that is more than a pile of HTML:

  • Every route as route/index.html, enumerated from the fully resolved navigation, including pages auto-generated from OpenAPI specs and hidden pages that are routable without appearing in the nav
  • route/index.rsc, the React flight payload the Next router fetches during client-side navigation, so the instant page transitions keep working
  • The whole _next/static build tree, so lazy-loaded chunks and fonts resolve
  • The styled 404 page, favicon.ico, sitemap.xml and robots.txt generated from the real exported route list
  • Each page's MDX source as a .md companion, plus llms.txt and llms-full.txt
  • docs.json redirects materialized as static stubs

Then it verifies that every internal link and asset reference in the bundle actually resolves, and exits non-zero if anything is missing. That last part is what makes it safe to gate a CI job or an image build on.

Running it

From the directory containing your docs.json:

staticmint -start-server -site-url https://docs.example.com

That starts mint dev, waits for it, exports into ./out, stops the server and verifies the result. If you already have a preview running, point it at that instead:

mint dev --no-open &
staticmint -site-url https://docs.example.com -out dist

You need the mint CLI available; logged-out local usage is fine. Prebuilt binaries exist for Linux, macOS and Windows on both architectures, or go install github.com/migetapp/staticmint@latest.

The bundle uses clean URLs, so any host that serves index.html for directory paths will work. Two things are worth configuring: serve 404.html as the custom 404, and serve route/index.rsc as text/x-component when a request carries the RSC: 1 header. Without the second one, client-side navigation degrades gracefully to full page loads. There is an nginx config in the repo that does both.

What it does not do

This is an export, not a replacement, and the honest list matters more than the feature list.

Search needs a backend. The search box posts to /api/search, and a directory of files cannot answer a POST. This is the one gap that stops the export being a drop-in, so the next section covers exactly how we closed it.

OpenAPI-generated pages have no .md companion. Those pages have no MDX source, so their .md links return 404.

It depends on Mintlify internals. The ~/.mintlify layout, generatedDocsNav.json, the flight payload behaviour. It was built against mint 4.2.800 with client 0.0.3447. Pin your mint version if you want reproducible builds. When upstream changes something, the export fails loudly rather than quietly producing a broken site, which is the behaviour you want.

The bundle is a snapshot. Re-run the export on every content change. In practice that is one CI step.

You keep none of the hosted product. The web editor, the assistant, preview deployments, insights - those are the service you were paying for, and they stay with the service.

Making search work

staticmint deliberately does not ship a search backend, because which one you want is your decision. Here is what runs behind docs.miget.com, which is about a hundred lines of glue in total.

A search engine next to the bundle. We run Meilisearch as a second process on the same host, listening on localhost only, with its database on a persistent volume. It is small, it needs no tuning for a documentation-sized corpus, and it answers in single-digit milliseconds.

One nginx location. The endpoint the docs already call gets pointed at Meilisearch's search route:

location /api/search {
    proxy_pass http://127.0.0.1:7700/indexes/docs/search;
    proxy_http_version 1.1;
    proxy_set_header Content-Type application/json;
    proxy_cache off;
}

An indexer that reads your MDX. A short Node script walks the docs repo, pulls title and description out of each file's frontmatter, strips the frontmatter, keeps the text, and pushes one document per page into a docs index:

{
  id: slug.replace(/\//g, '-'),
  slug: '/' + slug,
  title,
  description,
  content: textContent.substring(0, 10000)
}

Capping the body keeps documents small enough that the whole index stays comfortably in memory. Run it once at startup, after the engine reports healthy, and again whenever content changes.

And the part worth stealing: replace the search UI rather than emulate it. Mintlify's own search component expects its hosted API's response shape, and chasing that shape across upstream releases is a losing game. It is far less work to inject a small script that renders your own search modal and queries the endpoint directly. Ours is one injected <script> tag, a modal, and a fetch. It also means a mint upgrade cannot quietly break search, because nothing about it depends on Mintlify internals.

That last point generalises beyond search. Anywhere the static bundle needs a live backend, providing your own surface is more durable than matching theirs.

The licensing part, said plainly

staticmint is MIT and contains no Mintlify code. The bundle it produces is a different matter: it embeds Mintlify's compiled client runtime, which they license under the Elastic License 2.0.

Hosting your own documentation with it is fine. Using the export to offer Mintlify's functionality to third parties as a hosted or managed service is not, and neither is stripping the license or copyright notices out of the bundle. Read the license before you build a business on it.

staticmint is not affiliated with, sponsored by or endorsed by Mintlify, Inc. "Mintlify" is their trademark, used here to identify the software the tool works with.

When this is the wrong answer

If you are happy on Starter or Pro and nobody is asking where the docs live, there is nothing here for you. If you need the assistant and the analytics, an export removes exactly the things you are paying for. And if self-hosting is a hard organisational requirement with a budget attached, talk to Mintlify about Enterprise - that is what it exists for.

This is for the case in between: you like writing in Mintlify, you do not need the hosted extras, and you want the rendered site to be a directory you control.

Frequently asked questions

Does Mintlify support self-hosting? Yes, on the Enterprise tier, quoted per organisation. Starter and Pro publish to Mintlify's infrastructure.

Will client-side navigation still work? Yes, provided your server returns route/index.rsc as text/x-component for requests carrying the RSC: 1 header. Without that, links still work, they just do a full page load.

Can I host the bundle anywhere? Any static host or CDN that serves index.html for directory paths. There are no runtime dependencies.

Does search work? Not out of the box, and the fix is about a hundred lines. Run Meilisearch alongside the bundle, point /api/search at its /indexes/docs/search route in nginx, index your MDX into it, and inject a small search modal of your own rather than trying to satisfy Mintlify's search component. That is what runs on docs.miget.com.

Is this legal? staticmint is MIT and ships no Mintlify code. The exported bundle contains Mintlify's client runtime under the Elastic License 2.0, which permits hosting your own docs but not reselling Mintlify's functionality as a service.

Self-Host Mintlify Docs: Export to Static HTML