Structural pattern
Flyweight
When you need thousands of similar objects, stop letting every instance carry its own copy of the same heavy data — share it instead.
✗ The problem
A forest of 1,000,000 heavy trees
Each Tree stores its own mesh, texture and color — even though most trees
share the same handful of species.
class Tree {
constructor(x, y, name, color) {
this.x = x; this.y = y;
this.name = name;
this.color = color;
// duplicated on EVERY instance:
this.mesh = loadMesh(name); // ~1.5MB
this.texture = loadTexture(name); // ~1.5MB
}
}
// 1,000,000 × its own mesh+texture → 💥
Tree #1
+mesh +texture
Tree #2
+mesh +texture
Tree #3
+mesh +texture
Tree #…
+mesh +texture
Duplicated intrinsic data (mesh, texture, color) repeats per
instance — memory scales with tree count, not with the number of unique species.
✓ The pattern
↓ all reference →
Split intrinsic (shared) from extrinsic (per-instance)
A TreeType flyweight holds the heavy, shared state. A factory hands out
one instance per unique species. Each Tree keeps only its own x/y + a reference.
class TreeType { // shared
constructor(name, color) {
this.name = name; this.color = color;
this.mesh = loadMesh(name); // heavy, once
}
}
class TreeFactory {
static cache = new Map();
static get(name, color) {
const key = name + color;
if (!this.cache.has(key))
this.cache.set(key, new TreeType(name, color));
return this.cache.get(key); // reuse!
}
}
class Tree { // per-instance
constructor(x, y, type) {
this.x = x; this.y = y; this.type = type;
}
}
Tree
12,45
Tree
88,3
Tree
50,50
Tree …
x,y
TreeType
Oak 🌳
TreeType
Pine 🌲
TreeType
Birch 🌴
✓ See it live
Plant 1,000 trees — count the flyweights
Only 3 species exist, so the factory ever creates 3 TreeType flyweights,
no matter how many Tree instances reference them.
Tree instances 0
Unique TreeType flyweights 0
✓ Takeaway
Share state, slash memory
- Intrinsic state (shared, immutable) lives in the flyweight; extrinsic state (unique, contextual) is passed in by the caller.
- A factory guarantees one flyweight per unique key — new callers reuse, they never duplicate.
- You already see it: font glyphs, game sprites/particles, table-cell styles.
- Caution: it adds a layer of indirection — reach for it only when object count or memory pressure genuinely hurts (YAGNI otherwise).
🎯 Principle applied: Flyweight is DRY for memory — one shared copy of common state — with a clean SRP split between shared (intrinsic) and per-object (extrinsic) data.
Back to all topics →