Skip to content

Microservice Chassis

Every service you build needs the same unglamorous machinery before it can do anything useful. It must load its configuration, set up structured logging with request correlation, expose metrics in the format your monitoring expects, answer health and readiness probes for the orchestrator, and register itself for discovery. None of this is business logic, yet it is a precondition for the business logic to run safely.

When you wrote one service, you assembled this plumbing once. By the tenth service you notice the same hundreds of lines being copied, pasted, and quietly diverging: one service exposes /healthz, another /health; one logs JSON, another plain text; metrics are named inconsistently. The cross-cutting baseline is reimplemented, slightly differently, in every service.

You want every new service to start life with configuration, logging, metrics, health checks, and discovery already wired in and consistent across the fleet — so that a service exposes the same health endpoint, emits logs in the same shape, and reports metrics with the same names as every other service. You want a developer creating a new service to write business logic on day one, not spend a week reassembling boilerplate. And you want to upgrade that baseline in one place rather than in twenty repositories.

So the forces are: a consistent, ready-made operational baseline in every service, with minimal per-service effort and a single place to evolve it.

Build a microservice chassis: a framework, library, or base that bundles the cross-cutting concerns so a new service inherits them. The chassis owns the plumbing — it reads configuration, configures structured logging, registers a metrics endpoint, mounts health and readiness probes, and handles discovery registration — and exposes a small surface where you plug in the business logic.

The developer’s job shrinks to: start from the chassis, add the routes and domain logic, and ship. Everything operational is already present and identical to every other service built on the chassis. Often the chassis is paired with a service template — a starter repository, generator, or skeleton — so creating a new service means generating from the template and filling in the business code.

Because the baseline lives in one shared component, improving it (a new metrics field, a tightened log format, a better health check) is one change you roll out by bumping the chassis version across services, rather than editing each repository by hand.

flowchart TB
  subgraph Service[A service built on the chassis]
    direction TB
    Biz[Business logic: routes and domain rules]
    subgraph Chassis[Microservice chassis]
      Cfg[Config loading]
      Log[Structured logging]
      Met[Metrics endpoint]
      Health[Health and readiness probes]
      Disc[Service discovery registration]
    end
    Biz --> Chassis
  end
  Chassis --> Plat[Platform: orchestrator, monitoring, registry]
The chassis wraps the business logic, providing config, logging, metrics, health, and discovery; the developer adds only the domain code

Here a service is created on the chassis. The single bootstrap call wires up config, logging, metrics, health, and discovery; the only thing the developer adds is the route that carries business meaning. Each example is idiomatic to its language.

import { createService } from '@acme/chassis';
// The chassis loads config, sets up logging, metrics,
// /health, /ready, and registers the service for discovery.
const app = createService({ name: 'order-service' });
// Developer adds only the business logic.
app.get('/orders/:id', async (req, res) => {
const order = await orderRepo.find(req.params.id);
res.json(order);
});
app.start();

What you gain:

  • Consistency for free. Every service exposes the same health endpoint, log shape, and metric names, because one shared component provides them — observability and operability stop being per-team guesswork.
  • Faster service creation. A new service starts with the operational baseline already present, so developers write domain code instead of reassembling plumbing.
  • One place to evolve the baseline. Improvements to logging, metrics, or health land in the chassis and roll out by version bump, not by editing every repository.

What it costs you:

  • Per-language effort. A polyglot fleet needs a chassis per language, and keeping them feature-equivalent is real, ongoing work.
  • Coupling and versioning friction. Every service depends on the chassis; a breaking change forces a coordinated upgrade, and a stale chassis can hold a service back.
  • Risk of bloat. A chassis that tries to do everything becomes heavy and opinionated. Keep it focused on genuinely cross-cutting concerns, not business helpers.

A practical note: a chassis handles in-process concerns (config, logging, metrics, health), while a Service Mesh handles between-process networking. Many teams use both.

  • Externalized Configuration — the chassis is usually what reads and applies the externalized config.
  • Service Mesh — handles the networking cross-cutting concerns the chassis leaves to the sidecar.
  • Service per Container — a chassis-built service is still packaged and run as one service per container.
What is a microservice chassis?
What problem does the chassis primarily solve?
How does a chassis differ from a service mesh?
Which is a genuine cost of the chassis pattern?