Python & FastAPI15 min read·By Liyabona Saki·

FastAPI Microservices Architecture Explained Step by Step

How to design and build a Python microservices architecture with FastAPI — services, API gateway, async messaging, Redis, Postgres and Docker Compose.

Advertisement

Introduction

Microservices in Python are a real option in 2026. FastAPI's async runtime, Pydantic contracts and tiny memory footprint make it well-suited to running dozens of small services in containers. This tutorial walks through the architecture step by step, then ships a working multi-service stack with Docker Compose.

The Java equivalent — same architecture, different runtime — is Spring Boot Microservices Architecture Explained.

Key takeaways

  • Microservices in Python win on iteration speed and async I/O density, not raw CPU throughput.
  • Use an API gateway as the single ingress; keep auth and rate limiting there.
  • Prefer async messaging (Redis Streams, Kafka, NATS) between services over synchronous chains.
  • One schema per service in Postgres — never share tables across services.
  • Service discovery in Python world is usually DNS-based (Kubernetes services / Docker Compose names), not Eureka.

Reference architecture

text
            ┌─────────────┐
   client ─►│   Gateway   │──► auth, routing, rate limit
            └──────┬──────┘
                   │
       ┌───────────┼───────────┐
       ▼           ▼           ▼
   users-svc   orders-svc   catalog-svc
       │           │           │
       └───── Redis Streams ───┘
                   │
              Postgres (schema-per-service)

Step 1 — Per-service skeleton

Each service is a self-contained FastAPI app with its own Dockerfile, requirements.txt, schema migrations (Alembic) and tests.

text
orders-service/
  app/
    main.py
    api/orders.py
    services/order_service.py
    events/publisher.py
  Dockerfile
  alembic/

Step 2 — API Gateway

Two healthy options:

  • Traefik / Kong / Envoy as the gateway, with services mounted by host or path.
  • A thin FastAPI gateway that proxies and adds auth — good for teams that want to own the gateway code.
```python
# gateway/main.py
import httpx
from fastapi import FastAPI, Request, Response

app = FastAPI() ROUTES = {"/api/orders": "http://orders-service:8000", "/api/users": "http://users-service:8000"}

@app.api_route("/{path:path}", methods=["GET", "POST", "PUT", "DELETE"]) async def proxy(path: str, request: Request): target = next((u for p, u in ROUTES.items() if request.url.path.startswith(p)), None) if not target: return Response(status_code=404) async with httpx.AsyncClient(timeout=5) as client: r = await client.request(request.method, f"{target}/{path}", content=await request.body(), headers=dict(request.headers)) return Response(content=r.content, status_code=r.status_code, headers=dict(r.headers)) ```

Step 3 — Async messaging with Redis Streams

```python
# orders-service/app/events/publisher.py
import json, redis.asyncio as redis

r = redis.from_url("redis://redis:6379")

async def publish_order_created(order: dict): await r.xadd("orders.created", {"data": json.dumps(order)}, maxlen=10000) ```

python
# catalog-service/app/events/consumer.py
async def consume():
    last = "$"
    while True:
        resp = await r.xread({"orders.created": last}, block=5000, count=10)
        for _, messages in resp or []:
            for msg_id, fields in messages:
                await handle(json.loads(fields[b"data"]))
                last = msg_id

Step 4 — Resilience

  • Timeouts on every outbound callhttpx.AsyncClient(timeout=2).
  • Retries with backofftenacity for sync, stamina for async.
  • Circuit breakerspurgatory or pybreaker.
  • Idempotency keys for any write that an upstream might retry.

Step 5 — Docker Compose

yaml
services:
  gateway:
    build: ./gateway
    ports: ["8080:8000"]
    depends_on: [orders-service, users-service]
  orders-service:
    build: ./orders-service
    environment:
      DATABASE_URL: postgresql+asyncpg://app:app@postgres:5432/orders
      REDIS_URL: redis://redis:6379
  users-service:
    build: ./users-service
  redis:
    image: redis:7-alpine
  postgres:
    image: postgres:16
    environment: { POSTGRES_USER: app, POSTGRES_PASSWORD: app }

Production best practices

  • One bounded context per service — if two services always change together, merge them.
  • Ship a shared schemas package (Pydantic models for events) versioned in a registry.
  • Every service exposes /healthz, /readyz and /metrics (prometheus-fastapi-instrumentator).
  • Distributed tracing via OpenTelemetry — propagate traceparent through the gateway.

Common mistakes

  • Sharing a Postgres schema across services — guaranteed to recreate a distributed monolith.
  • Synchronous fan-out (service A calls B calls C calls D) — one slow node kills the chain. Use events.
  • No retries + no idempotency — duplicate writes on transient network blips.

Tools used in this tutorial

The setup below uses the following tools. Versions matter less than the role each one plays, so swap freely as long as you keep the responsibilities the same.

  • Python 3.12+
  • FastAPI
  • Uvicorn / Gunicorn
  • Pydantic v2
  • SQLAlchemy 2.x
  • Docker
  • Kubernetes

Real-world production context

In production, a Python backend like this rarely runs as a single uvicorn process on a laptop. Teams build the app into a container image, push it to a registry, and run it behind a managed load balancer with autoscaling, health checks and centralized logging. Async FastAPI services typically use multiple Uvicorn workers managed by Gunicorn, a managed Postgres for state, Redis for cache and rate-limit counters, and an object store for uploads. The reason cloud hosting becomes a hard requirement is operational: zero-downtime rollouts, log aggregation, metrics, and TLS at the edge are not optional once real users depend on the API.

Recommended tools & deployment options

Once the tutorial works on your machine, the next question is *where do I run this for real?* These are the platforms most Python backend teams reach for:

  • DigitalOcean — the simplest path from a working FastAPI container to a public URL. App Platform deploys directly from a Dockerfile, managed Postgres and Redis are one click away, and pricing is predictable. A common way to deploy the setup in this tutorial is using a cloud provider like DigitalOcean when you want to ship quickly without learning a full cloud SDK.
  • AWS — the default for enterprise workloads. ECS Fargate or EKS run containers without you managing servers, RDS handles Postgres, and CloudWatch covers logs and metrics.
  • Docker — the packaging format every modern deploy target understands. Build once, run the same image locally, in CI and in production.
  • Kubernetes (managed: EKS, DOKS, GKE) — the right choice once you have more than a handful of services, need rolling updates, autoscaling and policy-driven networking.

A VPS or managed cloud service is required to run this architecture end-to-end — uvicorn --reload is for development, not for serving traffic.

FAQ

Why not Django? Django is sync-first and heavy. For event-driven, async, container-native microservices, FastAPI is the better fit.

Service discovery in Python? In Kubernetes, use service DNS. In Docker Compose, use service names. Eureka/Consul are rare in modern Python stacks.

Next steps & related tutorials

Keep the momentum going with the next tutorial in this learning path:

Architecture

Microservices Architecture

CLIENTAPI GATEWAYSERVICESDATAEXTERNALRESTpublishsubscribeWeb AppMobile AppAPI GatewayRouting · AuthUsers ServiceOrders ServiceBilling ServiceUsers DBPostgreSQLOrders DBPostgreSQLEvent BusKafkaStripePaymentsEmail APISES / SendGrid
An API gateway routes traffic to independent services. Each service owns its data and communicates via REST or async events.

TL;DR

Key takeaways

  • Understand the core concepts behind FastAPI Microservices Architecture Explained Step by Step in a production context.
  • Apply the patterns to real Python & FastAPI systems, not just toy examples.
  • Recognize the trade-offs, failure modes, and operational concerns before adopting them.
  • Get a clear path to the next step — related tutorials, tools, and reference architectures.

Avoid these

Common mistakes

  • 1. Copy-pasting code without understanding the trade-offs

    It's tempting to ship a snippet from a blog post into production, but Python & FastAPI patterns only work when the failure modes are understood. Always reason about timeouts, retries, and consistency.

  • 2. Skipping observability from day one

    Structured logs, metrics, and traces are not optional. Wire them in before you ship — debugging Python & FastAPI systems without them is painful and expensive.

  • 3. Optimizing too early

    Premature caching, sharding, or microservice extraction adds operational cost. Validate the bottleneck with real measurements first.

  • 4. Ignoring security defaults

    Secrets in env files, open management ports, missing RBAC — these are the most common production incidents. Treat security as part of the definition of done.

Ship it safely

Production best practices

Apply these before promoting FastAPI Microservices Architecture Explained Step by Step to a real production environment.

Scalability

Design Python & FastAPI services to scale horizontally. Keep request handlers stateless, push session and cache state to external stores (Redis, the database), and benchmark p95/p99 latency under realistic load before tuning.

Monitoring & Observability

Emit metrics (RED/USE), structured JSON logs, and distributed traces from day one. Wire dashboards and alerts to SLOs you actually care about — error rate, latency, saturation — not vanity metrics.

Logging

Log with correlation IDs, never log secrets or PII, and centralize logs (ELK, Loki, CloudWatch). Use levels deliberately: INFO for state changes, WARN for recoverable issues, ERROR for incidents.

Security

Apply least-privilege IAM, rotate secrets through a vault, validate every input, and patch dependencies on a schedule. For HTTP services, enable TLS everywhere and set sensible security headers.

Testing

Layer unit, integration, and contract tests. Run them in CI on every PR, and add smoke tests post-deploy. For Python & FastAPI systems, also run chaos and load tests before a major release.

Reliability & Rollouts

Ship with health checks, readiness probes, graceful shutdown, and a rollback strategy. Prefer canary or blue/green deploys over big-bang releases.

Questions

Frequently asked questions

Is this tutorial up to date?

Yes. This tutorial was last reviewed and updated on May 26, 2026. We revisit popular Python & FastAPI tutorials regularly to keep them aligned with current best practices.

What level is this tutorial aimed at?

It is written for working developers with some backend experience. Beginners can still follow along, and senior engineers will find production-grade patterns and trade-off discussions.

Do I need to follow every step in order?

The walkthrough is sequential because each step depends on the previous one. If you only need a specific concept, the table of contents at the top of the article lets you jump straight to that section.

Where can I find the source code?

Code samples are inlined in the tutorial. When a companion repository is published it will be linked at the top of this page.

Go deeper

Further reading

#FastAPI#Microservices#Python#Docker#Redis#Architecture

More From the Channel

Follow the full tutorial series on YouTube

The MasterLabSystems channel publishes in-depth, project-based tutorials on Java, Spring Boot, microservices, Docker, Kubernetes, AWS and DevOps — the same topics covered on this site, with full code walkthroughs.

Stay in the Loop

Get the next tutorial in your inbox

next tutorial →

Dockerizing a FastAPI Application the Right Way

Related tutorials