Patterns That Matter
Factory & builder
Lesson 4 of 5
What you'll learn
- Use a factory function to centralize object construction and avoid scattered new calls.
- Use a builder for fluent, step-by-step configuration of complex objects.
- Know when an options object beats both.
Factory: one place that knows how to build
A factory centralizes construction so the rest of your code asks for a thing without knowing how it is assembled. In TypeScript this is almost always a plain function, not an abstract factory class hierarchy.
type Client = { baseUrl: string; headers: Record<string, string> };
// A factory function — one place that knows the assembly rules.
function createClient(env: "dev" | "prod"): Client {
const baseUrl = env === "prod" ? "https://api.app.com" : "http://localhost:3000";
return { baseUrl, headers: { "x-env": env } };
}
The value is centralization: change how clients are built in one spot. You rarely need the GoF abstract-factory layering unless you are swapping whole product families at runtime, which most apps never do.
Builder: fluent step-by-step config
A builder shines when an object has many optional parts and you want to assemble it incrementally and readably. Each method returns the builder, so calls chain.
class QueryBuilder {
private parts: { table?: string; where: string[]; limit?: number } = { where: [] };
from(table: string) {
this.parts.table = table;
return this;
}
where(clause: string) {
this.parts.where.push(clause);
return this;
}
take(n: number) {
this.parts.limit = n;
return this;
}
build() {
return this.parts;
}
}
A builder earns its keep when there is ordering, validation between steps, or a genuinely large surface. For three or four flat options, a single options object is simpler and just as clear — do not reach for a builder out of habit.
Options object first
Start with a plain options argument. Promote to a builder only when the config has stages, conditional steps, or accumulation. Premature builders add API surface for no benefit.
Run the builder. Chain the methods to assemble a config object step by step, then call build to get the finished plain object.
When is a builder worth using over a plain options object?
Saved on this device. Sign in to sync your progress everywhere.