Sitemap

Builder Design Pattern

5 min readMay 12, 2026

--

Builder is a Creational Design Pattern that lets you construct complex objects step by step. Instead of creating huge constructors with endless parameters, the Builder pattern separates the construction process from the final representation of the object.

Press enter or click to view image in full size

It is one of the most commonly used patterns in enterprise applications, SDKs, ORMs, query builders, UI frameworks, and configuration-heavy systems.

Real-World Analogy

Imagine ordering a burger.

You don’t tell the chef:

new Burger(true, true, false, true, 2, "large", true);

Instead, you say:

  • Add cheese
  • Double patty
  • Extra sauce
  • Large fries

The chef builds the burger step by step.

That’s exactly what the Builder pattern does.

Problem

Suppose you have a User class.

class User
{
public function __construct(
string $name,
string $email,
string $password,
?string $phone = null,
?string $address = null,
?string $company = null,
?string $website = null,
bool $isAdmin = false,
bool $isVerified = false,
bool $newsletter = false
) {}
}

Now imagine using it:

$user = new User(
"Hassan",
"hassan@example.com",
"secret",
null,
null,
"Acme Inc",
null,
false,
true,
true
);

Problems:

  • Constructor becomes unreadable
  • Parameter order becomes dangerous
  • Too many optional arguments
  • Hard to maintain
  • Hard to scale
  • Easy to introduce bugs

This problem is commonly known as the Telescoping Constructor Problem.

Solution

The Builder pattern moves object construction into a separate builder class.

Instead of passing everything into a constructor, you build the object gradually.

$user = UserBuilder::make()
->name("Hassan")
->email("hassan@example.com")
->company("Acme Inc")
->verified()
->subscribedToNewsletter()
->build();

Now the code is:

  • Readable
  • Flexible
  • Self-documenting
  • Easy to extend
  • Safer

Structure

The Builder pattern usually contains these components:

| Component           | Responsibility                 |
| ------------------- | ------------------------------ |
| Builder Interface | Defines building steps |
| Concrete Builder | Implements actual construction |
| Product | Final object being created |
| Director (Optional) | Controls build order |
| Client | Uses builder to create object |

Basic UML Flow

Client
|
v
Director ------> Builder Interface
|
v
Concrete Builder
|
v
Product

Simple PHP Example

Product

class Burger
{
public array $items = [];

public function show(): void
{
echo implode(', ', $this->items);
}
}

Builder Interface

interface BurgerBuilder
{
public function addBun(): self;

public function addPatty(): self;

public function addCheese(): self;

public function addSauce(): self;

public function build(): Burger;
}

Concrete Builder

class ZingerBurgerBuilder implements BurgerBuilder
{
private Burger $burger;

public function __construct()
{
$this->burger = new Burger();
}

public function addBun(): self
{
$this->burger->items[] = "Sesame Bun";

return $this;
}

public function addPatty(): self
{
$this->burger->items[] = "Zinger Patty";

return $this;
}

public function addCheese(): self
{
$this->burger->items[] = "Cheddar Cheese";

return $this;
}

public function addSauce(): self
{
$this->burger->items[] = "Mayo Sauce";

return $this;
}

public function build(): Burger
{
return $this->burger;
}
}

Client Code

$burger = (new ZingerBurgerBuilder())
->addBun()
->addPatty()
->addCheese()
->addSauce()
->build();

$burger->show();

Director Class (Optional)

A Director defines predefined build flows.

class BurgerDirector
{
public function makeZingerMeal(BurgerBuilder $builder): Burger
{
return $builder
->addBun()
->addPatty()
->addCheese()
->addSauce()
->build();
}
}

Usage:

$director = new BurgerDirector();

$burger = $director->makeZingerMeal(
new ZingerBurgerBuilder()
);

Fluent Builder

Modern applications usually use Fluent Builders.

Get Syed Hassan Hashmi’s stories in your inbox

Join Medium for free to get updates from this writer.

This enables method chaining.

$user = UserBuilder::make()
->name("Hassan")
->email("hassan@example.com")
->isAdmin()
->verified()
->build();

Laravel itself heavily uses fluent builders:

User::query()
->where('active', true)
->latest()
->limit(10)
->get();

Query Builder is actually one of the most famous real-world Builder implementations.

Real Industry Examples

1. Laravel Query Builder

User::query()
->where('status', 'active')
->orderBy('created_at')
->limit(5)
->get();

Every chained method progressively builds the SQL query.

2. HTTP Request Builders

Http::withHeaders([
'Authorization' => 'Bearer token'
])
->timeout(30)
->retry(3)
->post('/api/users');

3. Docker Image Builders

Dockerfiles are essentially builder patterns.

FROM php:8.3
RUN composer install
COPY . /app
CMD ["php", "artisan", "serve"]

Each instruction builds the final image step by step.

When to Use Builder Pattern

Use Builder when:

  • Objects contain many optional parameters
  • Object creation has multiple steps
  • Constructors become too large
  • You need immutable objects
  • Different representations share the same construction logic
  • You want fluent APIs
  • You want cleaner object initialization

When NOT to Use Builder

Avoid Builder when:

  • Object creation is simple
  • Only 2–3 parameters exist
  • Additional abstraction adds unnecessary complexity
  • A simple factory is enough

Overengineering is still bad architecture.

Builder vs Factory

| Builder                              | Factory                    |
| ------------------------------------ | -------------------------- |
| Builds step by step | Creates object immediately |
| Focuses on construction process | Focuses on object type |
| Supports complex configuration | Simpler object creation |
| Usually fluent | Usually one method call |
| Can create different representations | Returns a ready object |

Advantages

1. Cleaner Constructors

No more massive parameter lists.

2. Better Readability

->verified()
->isAdmin()
->withPhone()

is much clearer than:

true, true, "123"

3. Flexible Object Creation

You only configure what you need.

4. Easier Maintenance

Adding a new field doesn’t break existing constructor calls.

5. Supports Immutable Objects

Builder allows constructing immutable objects safely.

Disadvantages

1. More Classes

Builder introduces additional abstraction layers.

2. Increased Complexity

For small objects, Builder becomes unnecessary overhead.

3. Boilerplate Code

Without language support, builders can become repetitive.

Advanced Builder Example

A production-level builder usually contains:

  • Validation
  • Defaults
  • Immutable objects
  • Reset functionality
  • Nested builders

Example:

$user = UserBuilder::make()
->name("Hassan")
->email("hassan@example.com")
->validate()
->build();

Common Mistakes

1. Using Builder for Simple Objects

Not every class needs a builder.

2. God Builders

If the builder has 100 methods, your domain model is probably broken.

3. Skipping Validation

Builder should validate required fields before build.

if (!$this->email) {
throw new Exception("Email required");
}

Builder Pattern in Modern Languages

Modern languages already support Builder-like features.

Examples:

  • Named parameters
  • Optional parameters
  • Data classes
  • Records
  • Object literals

That’s why Builder is less necessary in some ecosystems.

However, in enterprise systems with large domain models, Builder is still heavily used.

Best Practices

Prefer Fluent APIs

->withEmail()
->withRole()
->verified()

Validate Before Build

Never return incomplete objects.

Keep Builders Focused

One builder should build one responsibility.

Use Immutability

Builder works extremely well with immutable objects.

Final Thoughts

Builder is one of the most practical design patterns used in real-world applications.

It solves a very common engineering problem:

“How do we create complex objects without destroying readability and maintainability?”

When used correctly, Builder gives you:

  • Cleaner APIs
  • Better readability
  • Flexible object construction
  • Easier maintenance
  • More expressive code

But like every design pattern, Builder is a tool — not a rule.

Good engineers don’t use patterns everywhere.

They use them where complexity actually exists.

--

--

Syed Hassan Hashmi
Syed Hassan Hashmi

I'm a passionate and results-driven Full-Stack Developer with more than 3 years of experience in web development, specializing in PHP, Laravel, and JavaScript.