Primary source
Uber Engineering, 2020
Original Adam Gluck article about Uber's architecture redesign and transition to DOMA.
DOMA (Domain-Oriented Microservice Architecture) is Uber's approach to operating a very large microservice ecosystem. The core idea is to design not a flat set of independent services but domain-oriented service collections with strict contracts, dependency layers, and explicit extension points.
Conceptually, this combines ideas from DDD and modular architecture, but applies them at the scale of thousands of engineers and services.
Uber architecture evolution
Monolithic architecture
Uber was operating two large services. As the organization grew from dozens to hundreds of engineers, availability risks, deployment risk, and change cost grew quickly.
- Availability risk: failure in a large component affected a large share of the product.
- Risky deployments with a large blast radius.
- Weak separation of concerns across business capabilities.
- Slow execution of business-logic changes.
Transition to microservices
The move improved reliability, ownership, and development speed at first. But at thousands of engineers, Uber faced a distributed monolith with high coupling.
- Too many cross-service dependencies.
- Difficult incident analysis across many teams.
- Unclear ownership boundaries and data models.
- Higher cognitive load for developers.
DOMA (Domain-Oriented Microservice Architecture)
Uber reframed its microservice system as one large distributed application and applied domain boundaries, layered dependency rules, explicit contracts, and extension mechanisms.
- Design focus moved from single services to domains as design units.
- Dependencies became controlled via layered design.
- External interactions moved to gateway contracts.
- Cross-domain integrations used extension points instead of tight direct coupling.
DOMA principles
Design around domains, not individual services
The primary design unit is a domain-level collection of services that delivers business value end-to-end. This simplifies ownership and roadmap planning.
Domains are grouped into layers
Upper layers may depend only on lower layers. This dependency rule limits cycles and reduces blast radius during changes.
Each domain exposes a clean interface via gateway
The gateway is the single entry point into the domain, stabilizing external contracts while allowing internal service evolution.
No direct cross-domain dependencies
No shared code and no shared data model between domains. Controlled extension points handle custom integrations.
DOMA layers at Uber
| Layer | Purpose | Examples |
|---|---|---|
| Infrastructure layer | Core capabilities needed in any engineering organization: storage, networking, observability, and platform primitives. | Storage APIs, network primitives, infra identity, runtime tooling |
| Business layer | Shared business capabilities Uber needs as an organization, not tied to one specific LOB. | Payment policies, fraud signals, user profile capabilities |
| Product layer | Capabilities tied to a product line but not to one consumer-facing app instance. | Ride request lifecycle, dispatch policies, driver supply logic |
| Presentation layer | Functionality directly tied to mobile/web user-facing features. | App-specific flow orchestration and UX-specific business behavior |
| Edge layer | Safe external exposure and client-aware adaptation of Uber services. | Edge gateways, auth policies, API composition, request shaping |
Core rule: services in upper layers may depend only on lower-layer services.
Contracts
Interservice communication patterns
Gateways and extension points only work when contract boundaries between teams are explicit and stable.
Gateway and extension points
Logic extension via plugins
Services inside a domain define plugin interfaces. Teams can add domain-specific checks without forking the core service flow.
Data extension via optional attributes
Core models can be enriched with domain-specific options to avoid direct schema coupling between domains.
Team-owned local extension points
Teams can define additional extension points inside their own domains while preserving contract control and lifecycle governance.
Practical gateway impact: a domain can evolve internal services without breaking consumers, as long as the external contract remains stable.
Outcomes at scale
- Lower complexity by organizing around ~70 domains instead of managing 2200 services as flat units.
- More predictable dependencies through layered design and strict dependency direction.
- Easier domain migrations and independent releases thanks to stable gateways.
- Lower developer cognitive load and faster incident localization.
When to choose monolith, microservices, and DOMA
| Organization size | Default fit | Why |
|---|---|---|
| Startup | Monolith / modular monolith | Lowest operational complexity, faster product-market fit iterations, lower change cost. |
| Mid-size company | Classic microservices | Independent delivery for multiple teams and better isolation of technical risks by subsystem. |
| Large organization | DOMA-style architecture | Needs scalable governance for thousands of engineers, domain ownership boundaries, and lower systemic coupling. |
Common DOMA adoption mistakes
Calling any random group of services a domain without clear business boundary and ownership model.
Building a gateway as a thin proxy without contract discipline, versioning, and SLA commitments.
Keeping shared database/shared schema between domains while labeling it as DOMA.
Defining layers formally but violating dependency direction (upper layers calling peers/upper layers).
Related materials
- Microservices and integration overview
- Decomposition strategies
- Learning Domain-Driven Design (short summary)
- Interservice communication patterns
- Service Discovery
- Uber Engineering: Introducing Domain-Oriented Microservice Architecture
- Book Cube: DOMA review (part 1, RU)
- Book Cube: DOMA review (part 2, RU)
