A production microservices architecture is more than a collection of small APIs.
A complete system needs clear domain boundaries, a client entry point, service-owned data, synchronous and asynchronous communication, distributed workflow handling, deployment automation, observability, security, and infrastructure that lets each service scale without accidentally overwhelming shared dependencies.
A useful architecture blueprint therefore looks closer to this:
Clients
↓
Edge / API Gateway
↓
┌─────────────┬─────────────┬─────────────┐
│ Orders │ Payments │ Inventory │
│ Service │ Service │ Service │
└──────┬──────┴──────┬──────┴──────┬──────┘
│ │ │
own data own data own data
│ │ │
└──────── events / messaging ───────┐
↓
Async consumers
Cross-cutting platform:
service discovery • observability • CI/CD • secrets • autoscaling
This article explains why each layer exists and where teams commonly get the boundaries wrong.
1. Start With the Domain, Not the Deployment Topology
The architecture begins with business capabilities.
For an e-commerce system, reasonable bounded contexts might include:
catalog
orders
payments
inventory
shipping
identity
Microsoft's current microservices guidance recommends using domain analysis and bounded contexts to determine service boundaries instead of decomposing the application arbitrarily.
The goal is high cohesion inside a service and loose coupling between services.
If two services constantly change together and call each other for every operation, they may belong inside the same boundary.
2. A Service Is an Ownership Boundary
A microservice should own more than a URL.
It should normally own:
- business rules
- code
- API/event contracts
- persistent data
- deployment lifecycle
- telemetry
- operational responsibility
That ownership is what allows one team to change and deploy the service independently.
A collection of tiny APIs maintained from one shared codebase and one shared schema may be distributed at runtime without being meaningfully autonomous.
3. The Edge Layer Protects Internal Topology
Clients should not need to know every internal service hostname.
A typical edge path is:
Web / Mobile / Partners
↓
Load Balancer / WAF
↓
API Gateway
↓
Domain services / BFFs
The edge/gateway layer can handle:
- TLS
- authentication integration
- rate limiting
- routing
- request limits
- public API versioning
- telemetry
Keep domain rules out of the gateway. Microsoft explicitly warns that putting business knowledge in the gateway creates coupling between services.
4. Use a BFF When Different Clients Need Different Shapes
A mobile application and an admin dashboard often need different data compositions.
Instead of forcing the shared gateway to understand every screen, use a Backend for Frontend where justified:
Mobile → Mobile BFF ─┐
├→ domain services
Web → Web BFF ────┘
This is especially useful when clients otherwise need many high-latency calls to build one view.
The BFF can compose application-facing data while domain services remain client-agnostic.
5. Services Should Own Their Data
Microsoft's data guidance is explicit: two microservices should not share and directly manipulate the same schema.
Prefer:
Orders Service → order schema/data
Payments Service → payment schema/data
Inventory Service → inventory schema/data
This does not mean every service needs its own physical database server.
Several services can share one PostgreSQL/MySQL cluster while using isolated schemas/tables, credentials, migration ownership, and access boundaries.
The key principle is:
> Another service cannot bypass the owning service and silently become dependent on its database implementation.
6. Polyglot Persistence Is an Option, Not a Goal
Microservices allow different services to use different storage technologies.
For example:
Orders → PostgreSQL
Search → Elasticsearch
Sessions → Redis
Analytics → ClickHouse
Documents → Object Storage
This can be powerful when workloads genuinely differ.
But every new database adds:
- operational knowledge
- backups
- monitoring
- upgrades
- security
- connection management
Do not give every service a different database because microservices technically permit it.
Standardize by default; diverge when workload requirements justify it.
7. Cross-Service Reads Need an Explicit Pattern
If Orders owns order data and Customers owns customer data, how does a dashboard display both?
Several options exist.
API composition
Dashboard/BFF
├→ Orders
└→ Customers
Simple, but latency and availability depend on both services.
Replicated read model
Customer information needed frequently by Orders may be replicated asynchronously into an Orders-owned read model.
This reduces runtime coupling but introduces eventual consistency.
CQRS/materialized view
For complex read-heavy views, build a query model from events.
Use the simplest approach that meets consistency and latency requirements.
8. Strong Consistency Should Stay Local Where Possible
A service can use normal ACID transactions inside its own data boundary.
Across services, trying to recreate one global transaction often creates tight coupling and availability problems.
Microsoft's guidance recommends explicitly deciding which operations require strong consistency and where eventual consistency is acceptable.
Example:
Payment ledger update
→ strong local transaction
Analytics dashboard refresh
→ eventual consistency acceptable
Do not demand global immediate consistency from data that does not need it.
9. Distributed Business Transactions Need Workflow State
Consider checkout:
1. create order
2. reserve inventory
3. authorize payment
4. schedule fulfillment
Each service commits a local transaction.
If step 3 fails, previously completed work may need compensating actions.
This is commonly modeled as a saga.
Two common styles:
Orchestration
A workflow controller coordinates steps and compensation.
Choreography
Services react to events without a central coordinator.
Use orchestration when the workflow has complex ordering, branching, or compensation. Use choreography when reactions remain loosely coupled and understandable.
10. Synchronous Communication Belongs on the Immediate Path
REST or gRPC is appropriate when the caller truly needs the response now.
Orders → Pricing → price result
But avoid deep chains:
API → A → B → C → D → E
Every hop adds latency and another failure dependency.
Microservice architecture does not require microservice-to-microservice RPC for every business event.
11. Asynchronous Messaging Handles Independent Work Better
Events and queues are useful when the producer should not wait for downstream work.
OrderConfirmed
↓
Message Broker
├→ Email
├→ Analytics
└→ Warehouse
AWS describes API-driven, event-driven, and data-streaming patterns as common microservice integration styles.
Messaging can reduce coupling and absorb traffic spikes, but requires:
- idempotent consumers
- retry/dead-letter strategy
- schema evolution
- ordering decisions
- tracing across async boundaries
12. The Message Broker Is Infrastructure, Not the Business Source of Truth
A broker transports or retains messages according to its model.
The owning service should still define the authoritative business state.
For example:
Orders database → source of truth for order status
Order events → integration facts for consumers
Do not make consumers infer current business state by hoping they observed every event unless event sourcing is a deliberate architecture choice.
13. Service Discovery Handles Ephemeral Instances
Autoscaled containers do not keep stable IP addresses.
Applications should call logical identities:
inventory-service
instead of:
10.2.7.19
Kubernetes Services/DNS, service registries, or a service mesh can map logical service identity to healthy instances.
Use platform-native discovery when it already solves the problem.
14. The Platform Layer Should Standardize Cross-Cutting Concerns
Microservice teams need autonomy, but unlimited infrastructure diversity becomes expensive.
A platform team can provide standard building blocks for:
- service templates
- CI/CD
- telemetry
- secrets
- networking
- identity
- deployment
- health checks
This creates a paved road without forcing every service to use identical domain technology.
Standardize boring infrastructure. Let domain teams spend autonomy where it creates product value.
15. Container Orchestration Solves Runtime Placement, Not Service Design
Kubernetes can:
- schedule containers
- restart failed workloads
- expose services
- scale replicas
- roll deployments
It cannot decide:
- whether Orders and Payments should be separate services
- which data each service owns
- whether a workflow requires strong consistency
- which events are domain facts
Do not confuse orchestration maturity with architecture quality.
16. Autoscaling Must Include Downstream Capacity
Suppose Orders scales from 10 replicas to 100.
If each replica opens 40 database connections:
100 × 40 = 4,000 potential connections
The service layer may scale perfectly while the database collapses.
Scaling design must include:
- DB connection budgets
- cache/broker connections
- upstream/downstream quotas
- queue capacity
- network capacity
Scale the system, not just the container count.
17. Failure Isolation Is a First-Class Architecture Goal
A failure in Recommendations should not necessarily stop checkout.
Use domain-aware resilience:
optional recommendation service down
→ return catalog without recommendations
But do not hide critical failures:
payment authorization unknown
→ do not pretend order is paid
Tools include:
- timeouts
- bounded retries
- circuit breakers
- bulkheads
- load shedding
- queues
The architecture should define which failures can degrade and which must fail closed.
18. Observability Is Part of the Architecture Diagram
In a monolith, one stack trace may explain a request.
In microservices, one request may cross:
Gateway → Orders → Payments → Broker → Fulfillment
A production platform needs:
- centralized structured logs
- metrics
- distributed traces
- correlation IDs
- service/dependency dashboards
Microsoft's current architecture guidance explicitly includes observability and OpenTelemetry-style distributed tracing as foundational microservice infrastructure.
If operators cannot follow one request through the system, the architecture is not production-ready.
19. Every Service Needs a Deployment Contract
Independent deployment requires:
- backward-compatible API/event changes
- readiness checks
- automated migrations
- safe rollout
- rollback
Database schema changes should generally tolerate old and new application versions during rolling deployments.
A service that can only deploy when six consumers deploy simultaneously is not independently deployable in practice.
20. Security Must Exist Between Services Too
The internal network is not automatically trusted.
Depending on risk, use:
- workload/service identity
- mTLS
- short-lived credentials
- scoped authorization
- network policy
- secret management
The gateway can authenticate external users, but internal services still need to enforce resource and tenant boundaries relevant to their data.
21. Multi-Tenant Systems Need Tenant Context Across Every Boundary
For SaaS systems, tenant identity must survive:
request
→ gateway
→ service
→ async event
→ consumer
→ database query
A tenant ID supplied by the client should not automatically become trusted identity.
Resolve tenant scope from authenticated context and propagate it in a controlled way.
Queues, caches, logs, read models, and analytics pipelines can all become data-leak paths if tenant boundaries are forgotten outside the primary API.
22. Architecture Must Include Operations and Ownership
A box on a diagram needs an owner.
For every service define:
- owning team
- repository
- on-call responsibility
- dashboard
- alerts
- SLO
- runbook
- deployment pipeline
- dependencies
Microservices scale organizations partly by distributing ownership. Without that operational ownership, they only distribute code.
23. A Reference Production Blueprint
Internet
↓
CDN / WAF / LB
↓
API Gateway
↓
┌─────────┴─────────┐
▼ ▼
Web BFF Mobile BFF
│ │
┌──────────┼──────────┐ │
▼ ▼ ▼ ▼
Orders Catalog Identity Search
│ │ │ │
Postgres Postgres Postgres Search DB
│
└──────── domain events ────────┐
▼
Message Broker
┌───────────┬──────────┐
▼ ▼ ▼
Notifications Analytics Fulfillment
Platform plane:
CI/CD • service discovery • secrets • telemetry • autoscaling • policy
This is not a template to copy literally.
The value is the separation of responsibilities:
- edge traffic
- client composition
- domain ownership
- private data
- async integration
- platform capabilities
24. When a Modular Monolith Is the Better Architecture
Microservices are not always the correct starting point.
A modular monolith is often better when:
- one small team owns the product
- domain boundaries are still changing rapidly
- modules have similar scaling needs
- operational maturity is limited
- distributed consistency would add little value
Microsoft and AWS both explicitly describe microservices as a trade-off, not a universal upgrade over monoliths.
Extract services when independent scaling, ownership, security, or deployment becomes valuable enough to justify the distributed-system cost.
Production Architecture Checklist
Domain
- Service boundaries follow business capabilities
- Highly coupled functions are kept together
- Every service has an owner
Data
- Each service owns its schema/data
- Cross-service direct database writes are blocked
- Strong vs eventual consistency is explicit
- Cross-service reads use an intentional composition/read-model pattern
Communication
- Synchronous call chains are short
- Independent work uses durable async messaging where useful
- Event contracts are stable/versioned
- Consumers are idempotent
- Multi-step distributed workflows have explicit state/compensation
Platform
- Edge gateway responsibilities are bounded
- Service discovery handles instance churn
- Autoscaling respects downstream limits
- Cross-cutting infrastructure is standardized
- Security exists between workloads where required
Operations
- Logs, metrics, and traces cross service boundaries
- Every service has SLOs/runbooks
- Deployments are independently safe
- API/event/database changes tolerate mixed versions
Final Takeaway
A strong microservices architecture is not defined by the number of boxes in the diagram.
It is defined by whether those boxes represent real boundaries of business ownership, data, deployment, and failure.
Keep domain state private. Keep synchronous dependencies short. Use messaging where delayed independent work genuinely helps. Treat distributed workflows and consistency explicitly. Standardize the platform concerns every team would otherwise reinvent. Make observability and ownership part of the architecture from day one.
And if those requirements can still be met cleanly inside a modular monolith, do not split the system just to look distributed.

Discussion (0)