Skip to content
FollowtheDamnCode

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.
Proxy and real subject share an interface
A request through the proxy

In code

Lazy, protected, and cached — and the dashboard can't tell
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: 1

Run 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

ProsCons
Control access without touching the subject or clientsExtra latency and indirection
Lazy creation saves startup costHidden costs: a call may connect, load, or block
Caching and auth in one reusable placeCaches 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.