m@ksim.pro
Back to all posts
IT 3 min read

API-first for internal systems: why it matters before you have many of them

Building internal tools and systems with an API-first approach is not extra work. It is the discipline that prevents the integration mess most companies spend years untangling.

API-first design is associated with public-facing products: platforms, SaaS tools, developer ecosystems. The discipline is less commonly applied to internal systems - the custom tools, internal portals, and operational software that most companies build or configure. That is a mistake, and the cost shows up several years later.

The typical result of not thinking API-first internally is a set of systems that can only talk to each other through brittle point-to-point integrations, file exports, or manual re-entry. When you need to connect a new system, you discover that every integration has to be built from scratch. When you need to replace one system, you find its interfaces are undefined and every consumer has encoded assumptions about its internals.

What API-first means in practice

API-first does not mean building a REST API for everything before building anything else. It means deciding, early, that every system exposes its capabilities through a defined, versioned interface - and that nothing outside the system bypasses that interface to read or write data directly.

The interface can be a REST API, a message queue, a file exchange protocol, or an event stream, depending on what fits the use case. What matters is that it is explicit, documented, and treated as a contract.

The most common violation I see is direct database access between systems. One system writes to a database table. Another system reads from that same table. There is no contract. When the first system changes its schema, the second system breaks without warning. Multiply this by five or ten systems over several years and you have the classic integration nightmare.

The internal platforms that get this right

Companies that avoid this problem share a pattern. They treat each internal system as a service with an owner. The owner controls the interface and is responsible for backward compatibility when it changes. Consumers declare their dependency on the interface, not on the system's internals. And there is a lightweight process for negotiating breaking changes rather than discovering them in production.

This does not require a formal API management platform. For small teams, it can be as simple as an OpenAPI spec checked into a repository and a norm that nobody reads the database directly. The point is the discipline, not the tooling.

Why the investment makes sense even for small internal tools

The objection I hear most often is that small internal tools do not justify the overhead of defining APIs. My experience is the opposite. Small internal tools tend to grow. They get more users, more integrations, more data flowing through them. The cost of retrofitting an API onto a tool that was built without one is always higher than building one in from the start.

The other argument is that you are buying future optionality. If every internal system has a defined interface, you can replace the implementation - the database, the framework, the hosting - without changing every consumer. That is a meaningful degree of freedom over a five-year horizon.

A practical starting point

If you are building something new, the minimum viable commitment is this: define the interface before you build the implementation. Write out what data comes in, what comes out, what the error cases are, and who is the owner. Keep that definition in version control. Do not allow direct database access from outside the system.

If you are working with existing systems, start by mapping the undeclared dependencies. Which systems read which databases directly? Which integrations have no documented contract? Making the implicit explicit is the first step toward replacing it with something maintainable.

Back to all posts
Contact

If this resonated, write to me. I reply personally.

WhatsApp