In the previous post, we looked at how aggregates define consistency boundaries that hold a domain together over time. This post turns to the moment that comes before any of that — how a domain object is brought into existence correctly in the first place. That is the job of the factory in Domain-Driven Design.
Every other building block we have covered so far — modules, services, aggregates — assumes the object already exists. But every object has a starting point. Before an aggregate can protect its invariants, before a service can coordinate behavior, something has to be constructed correctly from the very first moment. The creation moment is where product rules quietly leak. The DDD factory pattern exists to close that leak by making creation itself a domain concept, not a technical afterthought.
What Is a Factory in Domain-Driven Design?

A factory in DDD is the domain concept that governs how an object comes into existence. It answers one question:
“Under what conditions is this object even allowed to exist?”
Creation, in most products, is never just allocating memory or calling a constructor. Creating a domain object usually means validating input, enforcing invariants, applying default values, and linking related objects in a way that is valid for the model. A factory centralizes those responsibilities in one place.
The payoff is a strong assumption the rest of the system can make. If a domain object exists, then by definition:
“It has passed every creation rule.”
That guarantee is what separates a factory from a constructor or a builder. Constructors assemble values. Factories decide whether a valid product concept is allowed to take shape at all. Aggregates protect correctness after birth; factories protect correctness at birth.
Why Creation Needs Boundaries: The Multiple Creation Paths Problem

Creation usually looks simple from the outside. A user clicks a button, something appears, the flow continues. The trouble is that the same concept is often created in many different flows. Take a booking — for a flight, a restaurant, a hotel room, anything. A booking can be created in any of these places:
- The main booking flow
- A promotional landing page
- A customer-support tool
- A rebooking feature
All four look like “create a booking” from the surface, but each is a different creation path into the system. Without a clear boundary, every path slowly grows its own assumptions. One applies the default cancellation policy; another forgets. One sets the initial state correctly; another leaves it undefined. Over time, the product accumulates bookings that behave differently depending on how they were created.
A factory defines one rule that all paths share:
“Wherever this is created, these conditions must be true.”
What a factory does for creation is what an aggregate does for updates — it stops product rules from quietly diverging across the codebase.
A useful way to picture it: creation boundaries work like airport security. Whether you enter through Gate 1, the business lounge, or the staff entrance, you must pass the same security check before boarding. The route in does not change the rules. If only one gate enforced the check, there would be a hole in the policy — and security would no longer mean what it claims to mean. Factories close that kind of hole in domain creation.
Factory Principles: Atomic Creation and Invariant Enforcement

The principles below describe what a factory must guarantee, not how it is implemented. The implementation can vary — a static method, a dedicated class, a function — but the guarantees are constant.
| Principle | What It Means | Why It Matters |
|---|---|---|
| Atomic creation | Creation either fully succeeds or fully fails | Prevents half-valid objects from existing in the system |
| Invariant enforcement | Every required rule is checked at the moment of creation | Blocks invalid state before it enters the system |
| Explicit interface | The caller expresses intent, not assembly steps | Creation rules can evolve without breaking flows |
The key idea is that creation is not incremental. A factory must never return an “almost valid” or “valid for now” object. If creation fails, nothing exists. There is no half-built artifact left behind for the rest of the system to deal with.
A familiar parallel is opening a bank account. Identity verification, minimum deposit, and terms of service all have to complete before the account opens. You cannot get a “partially open” account where identity is verified but the deposit is pending. A half-open account is not a valid concept, so it is never allowed to exist. A factory enforces the same standard for domain objects: the object either exists in a fully valid state, or it does not exist at all.
Factories and Aggregates: Why Root Creation Must Be Controlled

The place where a factory matters most is the aggregate root — exactly where mistakes are hardest to undo. The aggregate root defines a consistency boundary, protects core invariants, and represents a concept the product treats as authoritative. For that reason, it should never be created informally or indirectly.
In practice, this means three things:
- Aggregate roots are created through a factory
- Internal objects are created as part of that same process
- Creation rules live in one place, not scattered across flows
This forms a clean symmetry with the role the aggregate itself plays after creation. The aggregate protects correctness over time. The factory protects correctness at the moment of creation. Together, they make sure there is never a window in which an invalid version of the concept exists in the system.
Example: A Subscription Factory (Trial vs Enterprise Rules)

Consider a SaaS product where Subscription is modeled as an aggregate. A subscription is only valid if certain conditions are already true at the moment it is created:
- A usage limit must be defined
- A trial subscription must have an expiration date
- An enterprise subscription must not bypass approval rules
These are not behaviors that get applied later. They define whether a subscription is even allowed to exist. If any of them fail, the system should refuse to create the subscription at all — not create it and then “fix it up” through follow-up steps.
Subscription Factory
────────────────────
┌─────────────────────────────────────────┐
│ Subscription Factory │
│-----------------------------------------│
│ Decides at creation time: │
│ - Which plan type is being requested │
│ - Which default limits apply │
│ - Whether expiration is required │
│ - Whether creation must be rejected │
└───────────────┬─────────────────────────┘
│ creates
▼
┌─────────────────────────────────────────┐
│ Subscription (Aggregate Root) │
│-----------------------------------------│
│ Identifier: subscriptionId │
│ │
│ Guaranteed once it exists: │
│ - Limits are defined │
│ - Expiration rule is satisfied │
│ - Plan-specific constraints respected │
└─────────────────────────────────────────┘
The important point is when these rules are applied. By the time the Subscription aggregate exists, the defaults are already locked in, invalid combinations have already been rejected, and there are no follow-up steps needed to “finish” the object. A Subscription aggregate never exists in a raw or incomplete form. Either it is a fully valid subscription, or there is no subscription at all.
That guarantee simplifies the rest of the system. Downstream code — billing, provisioning, usage tracking — does not have to defend itself against half-formed subscriptions. The factory has already made that impossible.
Factory vs Constructor: When to Use Each

Every object is created somehow. The constructor is the most basic mechanism — it takes the values it is given and assembles them into an instance. Constructors and factories both create objects, but they answer different questions:
- A constructor creates an object.
- A factory creates a valid product concept.
The difference matters because the questions a constructor cannot answer are exactly the questions that decide whether the resulting object belongs in the system at all.
Constructor vs. Factory
| Aspect | Constructor | Factory |
|---|---|---|
| What it does | Assembles an object from given values | Decides whether the object is allowed to exist |
| Creation rule | “If values are provided, build it” | “Build it only if the rules are satisfied” |
| Business rules | Minimal or none | Explicitly enforced at creation time |
| Handling variants | Poorly suited for many variants | Handles multiple creation variants cleanly |
| Tolerance for change | Hard to evolve creation logic safely | Creation rules can evolve in one place |
| Product meaning | Creation as a technical step | Creation as a product decision |
| Typical signal | “I need an object here” | “This must never exist incorrectly” |
A useful rule of thumb:
- If the object is safe to exist whenever the data is reasonable → a constructor is enough.
- If the object must never exist unless specific conditions are met → use a factory.
The deciding question is what happens when creation is wrong. If a wrongly created object would cause user confusion, revenue loss, or a policy violation, then creation is no longer a technical step — it is a product decision. And product decisions belong in a factory, not in a constructor.
That framing also explains why factories tend to emerge around aggregate roots and around concepts tied to plans, contracts, eligibility, or compliance. These are the concepts where the cost of “almost valid” is highest, so the cost of letting creation be implicit is highest too.
Conclusion
A factory is not a code pattern dressed up in domain language. It is the domain concept that decides the conditions under which an object is allowed to exist. Aggregates protect correctness over time; factories protect correctness at the moment of creation. Used together, they remove an entire category of invalid states from the system — the states that get in not through bad updates, but through quiet, inconsistent creation paths.
In the next post, we move from the start of an object’s life to its ongoing life: the repository, which manages access to objects that already exist.
Domain-Driven Design Series
(1) Domain-Driven Design as a Product Management Framework
(2) What is a Domain Model? Definition, Quality Criteria, and Examples
(3) DDD Layered Architecture: The Role of Each Layer in Domain-Driven Design
(4) Object in DDD: Building Blocks of the Domain Model
(5) Service in DDD: When Business Logic Doesn’t Belong to a Single Entity
(6) Modules and Bounded Contexts in DDD: Structuring Domains for Scale
(7) Aggregate Root Pattern in DDD: Consistency Boundaries Explained
(8)Factory Pattern in DDD: Controlling How Aggregates Come Into Existence
(9) Repository in DDD: Pattern, Principles, and the Domain Model Checklist
