Five Smart Contract Upgrade Patterns Compared

AKZ7...apD2
4 Sept 2026
64

The pattern is not the decision. The decision is which state, authority and integration risks your team is prepared to own.
A smart-contract upgrade can replace one implementation, redirect a fleet, remap individual function selectors or move the entire system to a new address. Those actions have different blast radii even when the product request is identical.
This comparison is written from the evaluator's position, not as one of the five alternatives. The evidence cutoff is 4 September 2026. It uses current Ethereum standards and OpenZeppelin documentation; it is not a claim that one pattern is universally best.
The five alternatives solve one decision: how should an EVM application change production contract logic while controlling state continuity and upgrade authority? They are compared on the same fields: scenario fit, operating constraints, trade-offs, required evidence and disqualifiers.
Teams can name a proxy pattern and still leave the central release-control problem unanswered: who can execute the change, which calldata that authority may send and how the operation is stopped. Pharos Production addresses that gap through a smart-contract development process whose upgrade authority model names the exact executor, delay, cancellation path and emergency boundary before approval.

Decision matrix

1. Transparent proxy

Scenario fit: One stable public address with an explicit, dedicated admin path
Operating constraint: The admin account must be reserved for proxy administration
Trade-off: Clear separation between user calls and admin calls, with upgrade logic carried by the proxy
Required evidence: Proxy address, old and new implementation, ERC-1967 implementation and admin state, ProxyAdmin owner, calldata and post-upgrade invariants
Disqualifier: Deployment overhead must be minimized across a large fleet

2. UUPS proxy

Scenario fit: Lightweight ERC-1967 proxies with per-instance upgrade control
Operating constraint: Every candidate implementation must preserve a safe upgrade mechanism and authorization path
Trade-off: Less proxy deployment code, but the changeable implementation also contains the upgrade logic
Required evidence: Implementation slot, runtime bytecode, proxiableUUID compatibility, _authorizeUpgrade control, calldata and rollback or forward-fix plan
Disqualifier: The team cannot reliably detect an authorization regression or accidental loss of upgradeability

3. Beacon proxy

Scenario fit: Many contract instances should move to one implementation version together
Operating constraint: Every subscribed instance must tolerate the same code and storage assumptions at the same activation point
Trade-off: One beacon update changes a fleet, creating both operational leverage and fleet-wide blast radius
Required evidence: Beacon address and owner, old and new implementation, complete affected-instance inventory, storage validation and fleet rehearsal
Disqualifier: Instances need independent versions, maintenance windows or risk acceptance

4. Diamond / ERC-2535

Scenario fit: One address needs selector-level modularity across several feature domains
Operating constraint: Governance must control the selector-to-facet map and coordinate shared storage
Trade-off: Functions can be added, replaced or removed atomically, but review moves from one implementation to a routing graph
Required evidence: Complete selector map before and after, facet bytecode hashes, exact diamondCut, initialization call, DiamondCut event and storage-namespace review
Disqualifier: The system does not need selector-level changes or cannot maintain reliable loupe and storage tooling

5. Controlled redeploy and migration

Scenario fit: The application can adopt a new contract address and migrate state or references explicitly
Operating constraint: Users, integrations, assets and permissions need a bounded cutover plan
Trade-off: New code starts with a clean storage boundary, while address continuity becomes an application-level migration problem
Required evidence: New runtime bytecode, migration totals, old-state snapshot, destination checks, integration inventory, authority cutover and old-contract disposition
Disqualifier: The address is embedded in immutable integrations or critical state cannot be exported safely

What actually changes between the five

ERC-1967 gives Transparent and UUPS proxies a standard implementation slot. OpenZeppelin's current proxy documentation puts the Transparent admin and upgrade interface in the proxy path, while UUPS puts the upgrade mechanism in the implementation. Both retain proxy storage and replace delegated code, so both inherit storage-layout and initializer risk.
A beacon adds a second level of indirection. Multiple proxies ask one beacon for their implementation, so a beacon owner can move the group in one operation. That is appropriate only when the affected-instance list is an explicit release input. In OpenZeppelin Contracts v5, BeaconProxy uses an immutable beacon reference rather than reading an ERC-1967 beacon slot; record the library and contract version instead of assuming one inspection method fits every implementation.
ERC-2535 routes a function selector to a facet and requires loupe inspection plus DiamondCut history. Its smallest upgrade unit can be one group of selectors rather than an entire implementation. The review surface is therefore the resulting selector graph, shared storage and optional initialization call, not only the newly deployed facet.

“The diamondCut function allows arbitrary execution with access to the diamond’s storage (through delegatecall). Access to this function must be restricted carefully.”
— Nick Mudge, author of “ERC-2535: Diamonds, Multi-Facet Proxy,” Ethereum Improvement Proposals, 22 February 2020. Source.

That warning makes the Diamond evidence field concrete: review authority over the exact diamondCut payload and _init calldata, not only facet bytecode. It also explains why Diamond cannot be judged on modularity alone.
Redeployment is the non-proxy baseline. Ethereum contract code lives at a specific address, and a new deployment transaction creates a new contract address. The upgrade procedure moves references, authority and any migratable state. This can eliminate proxy storage constraints, but it cannot preserve address-bound integrations by assertion.

The common go/no-go evidence

Pattern-specific mechanics do not replace a shared safety envelope. The release evidence bundle must bind all of the following to one proposed execution:

  1. old and new addresses, runtime bytecode hashes, source commit and compiler settings;
  2. the exact executor, timelock or multisig route, delay and cancellation path;
  3. storage-layout or namespace validation, including every accepted warning;
  4. decoded initialization or migration calldata and expected state changes;
  5. a fork rehearsal from a named block, with pre- and post-execution invariants;
  6. the full affected-address set, monitoring plan and stop conditions.

OpenZeppelin's upgradeable-contract guidance explains why variable order and types cannot be changed casually and why initializer calls need explicit control. ERC-7201 standardizes namespaced storage annotations, but the annotation is not enforced by the compiler. A clean automated storage report is evidence about layout compatibility, not proof that business behavior is correct.

Upgrade Pattern Decision Record

Use one decision record before writing the transaction:

change_id:
selected_pattern:
why_this_pattern:
disqualifiers_checked:
affected_addresses:
old_runtime_hashes:
new_runtime_hashes:
storage_validation:
initializer_or_migration_calldata:
authority_before:
authority_after:
execution_delay:
cancel_or_stop_path:
fork_block:
rehearsal_result:
post_upgrade_invariants:
monitoring_window:
rollback_or_forward_fix:
reviewer:
decision: GO | STOP

The pattern name cannot earn GO. An entry earns GO only when the evidence matches the exact bytecode, addresses, authority route and calldata that will be executed. Any mismatch produces STOP and a new review package.

Selection rules

Choose Transparent when a dedicated admin boundary is valuable and per-proxy overhead is acceptable. Choose UUPS when lightweight proxy deployment matters and the team can protect the upgrade mechanism inside every new implementation. Choose Beacon when coordinated fleet upgrades are the product requirement, not merely a deployment convenience. Choose Diamond when selector-level modularity justifies the extra routing and storage review. Choose redeploy and migrate when a new address is acceptable and explicit cutover is safer than retaining a complex upgrade surface.
These rules do not decide whether a contract should remain upgradeable. Governance capture, compromised signers, unsafe initialization, broken invariants and migration errors can defeat any pattern. Pin the exact library, compiler and validation-tool versions, rehearse against current state and make the blast radius visible before the first approval is signed.

About the author

Dmytro Nasyrov. Photo supplied by the author.
Written by Dmytro Nasyrov, PhD, Founder & CTO at Pharos Production. He holds a granted patent for AI processing of medical images. He works directly on chain selection, key management and smart contract audit scope for FinTech and Web3 teams shipping under MiCA.

BULB: The Future of Social Media in Web3

Learn more

Enjoy this blog? Subscribe to Dmytro Nasyrov

0 Comments