# Where Should Your OpenAPI Spec Live? — Routebase

> Repo or hosted is the wrong question. What decides whether your API has one contract or several is which copy the others derive from, and who runs that step.

Canonical page: https://routebase.dev/blog/where-should-your-openapi-spec-live/
Published: 2026-09-15 · The Routebase Team · OpenAPI, API Design, Documentation

Every corporate lobby has the same wall, with four identical clocks in a row, one
per office. It works because each clock is labelled with a different city.

Now imagine the same four clocks, all labelled with the same city, showing four
different times. Nobody standing in front of that wall asks which clock is
broken. They ask which one is *right*. There is no way to tell from
looking, because all four are running, all four look official, and each one was
correct on the day somebody set it.

That is the state of the API contract at most companies, and it is not fixed by
deciding where the spec file goes.

## The argument everyone has instead

Ask where an OpenAPI spec should live and you get a storage answer. It belongs
in the repo, next to the code, in version control, like every other artefact.
Or it belongs in a tool, where people who do not have a Git client can reach it.

Teams argue this for an afternoon, pick the repo, and consider the matter
settled. Then someone counts, and the spec turns out to live in four places.
There is the YAML in the repo and the docs portal that was generated from it in March.
There is the Confluence page a solutions engineer maintains by hand, and the PDF a partner
was emailed at integration time and has been building against ever since.

All four are real. All four are being read. None of them is labelled with the
version it came from. The storage question was answered. The contract still has
four values.

## What the repo is genuinely good at

It is worth being precise about this, because the case for keeping the spec in
Git is strong and mostly correct.

The spec becomes a build artefact. It moves with the branch, so a feature that
changes the API changes the contract in the same commit, and the two cannot be
merged apart from each other. Review happens where review already happens, in
a pull request with the same reviewers, the same threads and the same
approval rules the team already agreed on. It does not happen in a second tool with a
second set of permissions nobody audits.

CI can gate on it, so it can lint the document, diff it against the previous version, and
fail the build on a breaking change before it reaches anyone. `git blame` on a
schema line answers "who changed this and why" better than any audit log,
because it lands you in the commit, the pull request and the discussion in one
step.

And there is no lock-in worth the name. It is a text file in a directory. If
the tooling around it disappoints you, you keep the file.

Anyone who tells you this is a bad setup is selling something. It is a good
setup. It just does not answer the question the four clocks are asking.

## The moment a copy is born

Watch where a spec-in-the-repo actually breaks, and it is never at the repo. It
is at the first reader who cannot get to it.

A support engineer needs to know whether `status` can still return `pending`. A
partner integrating next month wants the current contract. A QA lead is writing
a regression plan, product is scoping the next quarter, and a customer's
developer, who will never have access to your repository under any
circumstances, is building against your API today. Increasingly the reader is
not a person at all but an agent that reads the contract and calls the endpoint
without asking anyone first.

Every one of them gets served the same way. Somebody exports the file, or
pastes it into a wiki, or attaches it to an email, or publishes a portal and
does not publish it again. That is the moment the copy is born, and from that
second on it is a *statement about the past* that looks exactly like a
statement about the present.

The copies are not the failure. Copies are how a contract reaches the people
who need it. The failure is that none of them carries the one piece of
information that would make it safe to read, namely which version of the source it
came from.

_Figure: Four surfaces derived from the same spec, none of them stamped with the version it came from, so the question 'which one is current?' has no answer you can look up. Stamping them does not stop two of them from falling behind. It just means you can see which two._

## The question worth arguing about

Replace "where should the spec live" with three questions that actually have
consequences.

**Can someone without repository access read the current contract without
being sent it?** If the honest answer is "they ask us and we export it", you do
not have one contract. You have one contract and an unbounded number of
snapshots in other people's inboxes, with no way to recall them.

**When the spec changes, is there a named step that brings the derived surfaces
forward, or does somebody have to remember?** A portal, a mock, a test suite
and a generated client are all downstream of the same document. "We regenerate
when we think of it" is not a process. It is a person, and that person will be
on holiday during your next breaking change.

**Can you tell, by looking at a copy, which version it came from?** This is the
cheapest of the three and the one most often skipped. An unstamped copy cannot
be triaged. A stamped one can be, in seconds, by someone who was not involved.

Notice that none of these is a hosting question. A disciplined Git-first setup
answers all three. The spec in the repo is the source, CI regenerates the
portal and the clients on every merge and publishes them, and each artefact
carries the commit it was built from. That works. It is a pipeline you build
and then maintain, and the maintenance is the part teams underestimate, because
it is invisible right up until the day it silently stops running.

The hosted answer moves the same responsibility into a tool, where the source sits
somewhere non-developers can reach without asking, and publishing is an act
with a record. That works too, and it also has a cost, because it is one more system,
with credentials, and a place where the spec can be edited outside your review
process if you let it.

Both need discipline. They just need it in different places, and the useful
comparison is which kind of discipline your team actually sustains, not which
architecture reads better in a blog post.

## How we treat it, and what we deliberately do not do

Routebase keeps the spec in a system rather than a file, so the second and
third questions have structural answers. But it is worth being exact about
what that does and does not mean, because this is the area where API tooling
routinely overpromises.

A version is `draft`, `review`, `published` or `deprecated`. While it is a
draft, it moves. Once it is published, it is frozen on purpose, because a
version that changes underneath a reader is not a version. The whole point
of stamping a copy is defeated if the thing it points at is a moving target.

What we do **not** claim is that everything downstream stays in sync by itself.
It does not. When a published spec moves on, a mock or a test suite pinned to
the older version stays where it is, and the honest description of what the
product gives you is *detection*. It compares what the surface was built from
against the current contract and shows you the gap, and pulling it forward is a
step someone takes. The clocks still drift. You can see which ones.

And the repo stays in the picture rather than being replaced. The spec exports
as YAML, JSON, Postman or Insomnia, which is the file you would have had, when you want
it. Documentation is genuinely docs-as-code in both directions. The CLI pulls a
version down to Markdown files and pushes edits back, and it exits with a
conflict code rather than overwriting when a page moved remotely in the
meantime. And after a deploy, CI can pin the version an environment is running
with a single command. That is how the environment stops being folklore and
starts being a fact you can assert in a test.

If you are working out how the pieces fit together, from design and review to mock,
test, and publish, we lay out that shape in more detail on our
[API design](/api-design/) page.

## The wall of clocks

The reason the lobby wall works is not that the clocks are accurate. Clocks
drift, because that is what clocks do. It works because each one is labelled, so a
wrong clock is a visibly wrong clock rather than a plausible one.

Your spec does not need to live in any particular place. It needs one location
that everybody agrees is the source, and a way for people without repository access
to read it without being sent a copy. It also needs a stamp on everything derived from it
saying where it came from. Get those three right and the storage argument
answers itself, in either direction, which is the honest conclusion.

Get them wrong and it does not matter how good your YAML is. There will be four
clocks on the wall, all of them running, and the next person who needs the
right time will pick one.

---

[Routebase](https://routebase.dev/) — [Sign up](https://app.routebase.dev/): Every account starts with a 14-day Pro trial — no credit card required.
