Almost 50 deploys in two weeks: what shipping this fast actually looks like

By Bergfrid Skaara Dias, Updated on 14 h, 20 m ago
push_pin
star
eco
shopping_bag

Since we cut the SuperOffice documentation site over to Mintlify on August 27, we've merged 46 changes to the live site in seven working days. That's an average of nearly seven merges every single working day, not just an occasional ship. Before Mintlify, our old pipeline shipped on a manual cadence, roughly once or twice a week.

That's the real story of this migration. It didn't just move our docs to a new platform. It changed how fast we can find and fix something.

Fast deploys mean fast fixes, not fewer bugs

A faster pipeline doesn't make bugs disappear. It changes what happens after we find one. We've closed dozens of issues since cutover, most of them small formatting or content fixes. Three keep showing up in a familiar shape, so they're worth walking through on their own.

By design: no .html, and /index is implied

Mintlify serves every page without a file extension. There is no .html on the live site at all. A source file at en/company/index.mdx doesn't serve at /en/company/index. It serves at /en/company, with index silently dropped from the URL. The same happens one level deeper: en/company/learn/index.mdx serves at /en/company/learn, not /en/company/learn/index.

That's not a bug. It's how Mintlify's routing works, and most of the time it's invisible. But it has a real side effect, and quirk 1 is where it shows up.

Quirk 1: index pages are a relative link trap

A link's target gets resolved relative to where its source file lives on disk. For most pages, that lines up with the served URL and nothing goes wrong. An index page is the exception: its file sits one directory deeper than the URL it actually serves at, because of the /index rule above. So a link like ./sibling-page, written correctly for the file's location on disk, quietly 404s once it's live.

This single bug touched 552 files and 3,491 links across the whole site (see #375#377, and #378). We fixed the links and built a dedicated check into our CI pipeline so an index page can never reintroduce this pattern.

Quirk 2: reusable snippets resolve links against the wrong page

We reuse content across languages and pages through imported snippets, small pieces of markdown pulled into a larger page. A snippet's own relative links resolve against whichever page imports it, not against the snippet's own file location.

This is the opposite of how our old DocFx setup worked, where a snippet's relative links resolved against the snippet's own location, not the importing page's (see #392 and #395). The fix wasn't to patch each snippet's relative links one at a time. It was to convert them to root-relative links, so a snippet always points to the same real destination no matter which page imports it.

Quirk 3: the same URL 404s or doesn't, depending on the language

We already knew that old bookmarked links ending in .html needed redirects on the new platform, and we added thousands of them. Even so, some .html links kept 404ing, but only for some languages. An English page worked. The exact same page in Danish, German, Dutch, Norwegian, or Swedish did not.

The cause was not a missing redirect. It was caching. English pages get visited often enough to stay cached, so a cached copy quietly served the .html request anyway. Every other language fell through to the real server and hit a 404 (see #424). One rule fixed every language at once, as long as it runs before any other redirect: strip .html from any index.html URL, first, every time. We've also registered this as a feature request with Mintlify, since a single hand-written, position-pinned redirect rule shouldn't be the only way to solve it.

An honest gap we have not closed

Not every corner of the site got the same .html redirect coverage. Our auto-generated reference documentation, the WebApi, CRMScript, and database reference trees, still does not have one-to-one .html redirects for old bookmarked links. We decided the upkeep was not worth it for content a script regenerates on every release, so an old bookmarked link into those specific trees may still 404. It is a known, accepted gap, not an oversight we are hiding.

What's next

Our API reference docs are still generated from a Swagger 2.0 spec that we convert to OpenAPI 3.0 ourselves before Mintlify can render it. There's an open request (#147) to have the backend generate native OpenAPI 3.0 specs directly. We hope reference navigation gets noticeably smoother once that's available, since a native spec removes our conversion step and the quirks it can introduce. Not promised yet, but it's the fix we're hoping for next.

Where this leaves us

All three quirks above are the same bug in different clothes. Each one assumes that where a file or a link lives, whether that's a disk path, a snippet's own location, or a cached copy, is the same place it actually gets served from. It is not. Each one now has a permanent, narrowly scoped check running in our pipeline so it cannot come back unnoticed.

We are not relying on luck to catch the next one, either. Broken-link and link-rot checks run automatically on every pull request, a sitewide automated link audit runs biweekly across the whole site, and we curl-check links by hand locally before anything ships. All three of these quirks still got past that setup before landing live. Worth saying plainly: our own checks catch a lot, but they're not unbiased, and they can share the same blind spots as the bugs they're meant to catch.

That's what continuous deployment buys you in practice: not fewer surprises, but surprises that get caught and closed in days instead of festering for months, plus an honest account of the corners we chose to leave alone.

This is the job now. If you spot the next one before we do, we'd like to hear about it.