Proxy
A stand-in with the same interface as the real object, controlling access to it — lazily, remotely, cautiously, or with a cache.
Big idea
A Proxy stands in for another object with exactly the same interface and decides when and whether the real object is reached. Clients can't tell the difference; the proxy adds control — creating the subject lazily, checking permissions, caching answers, or talking to it over the network.
The problem it solves
A ReportService.generate(month) takes ten seconds and reads sensitive salary data. You want: don't even connect to the warehouse until someone asks for a report; don't let interns run salary reports; don't recompute March's report every time someone opens the dashboard. Putting all that inside ReportService mixes infrastructure concerns into the report logic; putting it in every caller duplicates it.
Think of it like
A company's reception desk. Visitors ask for someone by name. Reception checks you're expected (protection), may say "she's in a meeting, here's the summary she left" (cache), and only calls the person down when it's truly needed (lazy). To the visitor, reception is how you reach that person.
Kinds of proxy
- Virtual proxy — creates the expensive real object only on first use.
- Protection proxy — checks the caller's rights before forwarding.
- Caching proxy — remembers results for repeated requests.
- Remote proxy — a local object that forwards calls over a network (RPC stubs, API clients).
- Logging / smart reference — counts uses, logs calls, cleans up when unused.
In code
class WarehouseReports: # the real subject: slow and sensitive
instances = 0
def __init__(self):
WarehouseReports.instances += 1
print(" (connecting to warehouse...)")
def generate(self, user, month):
return f"payroll report {month}"
class ReportsProxy:
def __init__(self, allowed_roles):
self._real = None
self._cache = {}
self._allowed = allowed_roles
def generate(self, user, month):
if user["role"] not in self._allowed: # protection
raise PermissionError(f"{user['name']} may not run reports")
if month not in self._cache: # caching
if self._real is None: # virtual (lazy)
self._real = WarehouseReports()
self._cache[month] = self._real.generate(user, month)
return self._cache[month]
reports = ReportsProxy({"finance", "admin"})
print("proxy ready, warehouse connections:", WarehouseReports.instances)
alice, ivan = {"name": "Alice", "role": "finance"}, {"name": "Ivan", "role": "intern"}
print(reports.generate(alice, "2026-03"))
print(reports.generate(alice, "2026-03"))
try:
reports.generate(ivan, "2026-03")
except PermissionError as err:
print("denied:", err)
print("warehouse connections:", WarehouseReports.instances)output
proxy ready, warehouse connections: 0
(connecting to warehouse...)
payroll report 2026-03
payroll report 2026-03
denied: Ivan may not run reports
warehouse connections: 1Run and edit it in the app.
An image viewer shows a placeholder and loads the full image file only when it scrolls into view. Which proxy is that?
Watch it
When to use it — and when not to
Use it when access to an object needs control the object itself shouldn't care about: expensive initialisation, permissions, caching, remote calls, auditing. Be wary when the proxy changes timing callers rely on — a "cheap" call that suddenly blocks on a network connection — and don't stack proxies where a single explicit service would be clearer.
Pros and cons
| Pros | Cons |
|---|---|
| Control access without touching the subject or clients | Extra latency and indirection |
| Lazy creation saves startup cost | Hidden costs: a call may connect, load, or block |
| Caching and auth in one reusable place | Caches need invalidation rules |
How it relates
- Decorator has the same shape; a decorator adds features the client asks for, a proxy manages the subject's access and lifecycle.
- Adapter changes the interface; a proxy keeps it identical.
- Facade simplifies many objects; a proxy stands in for one.
- The system-design Proxy and Caching lessons are the same ideas at network scale.
What must be true of a proxy's interface?
Key terms
- Proxy — An object with the same interface as another that controls access to it.
- Real subject — The object the proxy stands in for.
- Virtual proxy — Delays creating an expensive object until it's first needed.
- Protection proxy — Checks permissions before forwarding a request.
- Remote proxy — A local stand-in that forwards calls to an object in another process or machine.