Building a microservice with servo

A step-by-step, from-scratch build of a real order-management service — HTTP API, JWT auth, Postgres, Redis, NATS, Prometheus metrics, OpenTelemetry tracing, a circuit breaker, a full test suite, CI/CD, and a Docker deployment — using servo to wire and run all of it.

Every chapter’s code lives in examples/tutorial, a real, separate Go module you can cd into and run at every step. Nothing in these pages is invented: every code block is copied from that module, and every command’s output shown here was actually run.

Why this exists

servo’s own README and examples/basic show the mechanics — how one constructor gets wired to another, what a spec file looks like, what servo generate produces. What they don’t show is what it’s like to build something with real weight to it: a service with a database, a cache, an event to publish, a login flow, tests at three different levels, and a pipeline that ships it. That gap — “I understand what servo does” to “I could build a real service with it” — is what this tutorial is for. Every chapter adds one layer or concern to the same running service, in the order you’d actually add them, so by the last chapter nothing is hypothetical: it’s a service you’ve built, one working piece at a time, that happens to also be a complete reference for how the pieces fit together.

How to read this

Each chapter follows the same shape: what problem this layer solves and why it exists, the real code that solves it (with enough surrounding explanation that you’re not just staring at syntax), a diagram where the shape of something is easier to see than to describe, a “try it yourself” section with commands you can actually run, then diagnostics, do’s and don’ts, and pointers to alternatives. Read chapters in order the first time — each one builds on code the previous ones already wrote. After that, they hold up fine as standalone reference.

Who this is for

You should be comfortable writing Go and using go test, but this tutorial assumes nothing about prior exposure to dependency injection, microservice architecture, or any of the specific libraries used (Postgres, Redis, NATS, JWT, Prometheus, OpenTelemetry). Each is introduced when it’s first needed, with a short “what and why” before the code.

Prerequisites

  • Go 1.27 or newer (go version)
  • Docker with the docker compose plugin, for running Postgres, Redis, and NATS locally
  • curl (or any HTTP client) for the “try it yourself” sections
  • No cloud account of any kind is required — everything runs on your machine

What you’ll build

flowchart TB
    Client(["HTTP client"])

    subgraph api["API layer"]
        Router["Router + middleware<br/>(auth, logging, recovery, rate limit)"]
    end

    subgraph svc["Service layer"]
        OrderService
    end

    subgraph data["Data"]
        PG[("Postgres")]
        Redis[("Redis")]
    end

    subgraph msg["Messaging"]
        NATS[("NATS")]
        Notifier["notifier<br/>(subscriber)"]
    end

    Client -->|"Bearer JWT"| Router
    Router --> OrderService
    OrderService -->|"read/write orders"| PG
    OrderService -->|"cache-aside reads"| Redis
    OrderService -->|"publish OrderPlaced"| NATS
    NATS -->|"consume"| Notifier

A user logs in, gets a JWT, and can place and view orders. Placing an order writes to Postgres, invalidates the cache, and publishes an OrderPlaced event; a separate notifier component consumes that event to show the “other side” of an event-driven system without needing an actual second service. Every arrow in that diagram is a real dependency servo resolves and wires for you — nothing here is assembled by hand.

Chapters

# Chapter What it covers
1 Architecture overview Layers, why layered, where servo fits
2 Project setup Module layout, tools, the Makefile
3 Configuration Typed env config, validation, secrets
4 Domain layer Core types, framework-free
5 Repository layer Postgres, migrations, connection pooling
6 Caching layer Redis, cache-aside, invalidation
7 Messaging layer NATS, publish/subscribe, delivery guarantees
8 Service layer Business logic, orchestration, domain errors
9 Authentication JWT issue/verify, password hashing, middleware
10 API layer Routing, DTOs, validation, error mapping
11 Gin as the transport The same API in Gin, and what the swap costs
12 gRPC as the transport The same API over gRPC, on one port with REST
13 Wiring with servo The spec file, capabilities, servo generate
14 Scoped instances One session per user, instead of one per process
15 Observability Structured logs, metrics, tracing, health checks
16 Resilience Circuit breaker, rate limiting, graceful shutdown
17 Testing strategy Unit, integration, and API-level tests
18 CI/CD GitHub Actions: lint, test, build, servo check
19 Running and deployment Docker Compose, Dockerfile, env reference
20 Troubleshooting Every diagnostic from every chapter, organized by symptom
21 Alternatives and further reading Other valid choices at every layer

Read them in order the first time through — each one assumes the code from the previous chapters already exists. After that, they stand alone well enough to use as reference.