Knowledge baseIntegrationsThis article

The Composable Services Approach

Building software as a collection of small, focused services rather than a single monolith changes the trajectory of every project that comes after. Each service makes the next one faster to build.

When you build an authentication system into a monolith, you build it once for that product. When you build an authentication service with a clean HTTP API, you build it once for every product that comes after. The first approach is faster on day one. The second is faster on every subsequent day.

This is the composable services principle. It takes discipline to apply correctly, but the payoff compounds in a way that monolithic development does not.

What a service is

A service in this context is a small, focused piece of functionality with a well-defined HTTP API, its own database, and the ability to be deployed independently. It does one thing. It does not do adjacent things.

An email service sends emails. It has endpoints for sending a message, queuing a message, and checking delivery status. It does not know about users, products, or anything specific to the application calling it. That specificity lives in the caller.

The hard part is the discipline to keep services focused. The temptation is always to add one more thing. “The email service already knows about messages, it should handle notifications too.” But notifications involve user preferences, event triggers, and display logic that have nothing to do with sending email. Adding them creates coupling that defeats the purpose.

The compounding effect

The time to build the first application using a set of services is roughly the same as building a monolith. You build the services, then you wire them together. The wiring is fast, but the service construction takes time.

The time to build the second application is significantly less, because you already have services for the common concerns: authentication, email, file storage, payments. You wire those existing services to the new application-specific logic.

By the third application, the services are mature, well-tested, and cover most of what you need. The new application is almost entirely composition work: wiring existing services to new application logic. You are building faster than a team that has to implement authentication from scratch every time.

Why this pairs well with AI development

AI agents work best within a well-defined scope. A service specification is exactly that: a precise description of one concern, the data model, the API surface, and the behavior. An agent can read that specification and implement the service correctly, because the scope is clear.

Building a monolith with an AI agent requires the agent to hold the entire application in context and reason about how every change might affect everything else. That is harder and produces more errors.

Services are also rebuildable. If a service has a well-written spec, it can be rebuilt from scratch in an afternoon. That makes the composable approach particularly resilient to the technical debt that accumulates over time.

Practical patterns

Every service we build follows the same structure: Express API with SQLite, an OpenAPI spec describing the endpoints, a health check at GET /health, and a clear scope statement in the architecture document.

Services communicate only through their HTTP APIs. No shared databases. No direct imports between service codebases. This constraint feels limiting at first and is liberating over time. You can redeploy a service, change its implementation, or move it to a different server without affecting any other part of the system.

Application layers (the thing users see) are kept thin. They handle routing, UI, and orchestration. The business logic lives in the services. A new frontend for an existing application is a matter of calling the same service APIs with a different UI.

When not to use services

Services add overhead in the early stages of a product. When you are building the first version and do not yet know what the boundaries should be, starting with a monolith and extracting services later is often the right call.

Extract a service when a concern is well-understood, when it would be useful across multiple projects, or when the monolith is growing in ways that make the boundary clear. Extracting too early, before the boundaries are obvious, creates services with poor abstractions that are worse than the original monolith.

The goal is not services for their own sake. The goal is the compound effect: a catalog of well-scoped, well-specced services that make every new project faster than the last. That effect only materializes if the services are actually well-scoped.

Read next