In different blockchains, multiple patterns have been developed for making a contract upgradeable including the widely adopted proxy patterns.

Starknet has native upgradeability through a syscall that updates the contract source code, removing the need for proxies.

Replacing contract classes

To better comprehend how upgradeability works in Starknet, it’s important to understand the difference between a contract and its contract class.

Contract Classes represent the source code of a program. All contracts are associated to a class, and many contracts can be instances of the same one. Classes are usually represented by a class hash, and before a contract of a class can be deployed, the class hash needs to be declared.


The replace_class syscall allows a contract to update its source code by replacing its class hash once deployed.

/// Upgrades the contract source code to the new contract class.
fn _upgrade(new_class_hash: ClassHash) {
    assert(!new_class_hash.is_zero(), 'Class hash cannot be zero');
If a contract is deployed without this mechanism, its class hash can still be replaced through library calls.

Upgradeable component

OpenZeppelin Contracts for Cairo provides Upgradeable to add upgradeability support to your contracts.


Upgrades are often very sensitive operations, and some form of access control is usually required to avoid unauthorized upgrades. The Ownable module is used in this example.

We will be using the following module to implement the IUpgradeable interface described in the API Reference section.
mod UpgradeableContract {
    use openzeppelin::access::ownable::Ownable as ownable_component;
    use openzeppelin::upgrades::Upgradeable as upgradeable_component;
    use openzeppelin::upgrades::interface::IUpgradeable;
    use starknet::ClassHash;
    use starknet::ContractAddress;

    component!(path: ownable_component, storage: ownable, event: OwnableEvent);
    component!(path: upgradeable_component, storage: upgradeable, event: UpgradeableEvent);

    /// Ownable
    impl OwnableImpl = ownable_component::OwnableImpl<ContractState>;
    impl OwnableInternalImpl = ownable_component::InternalImpl<ContractState>;

    /// Upgradeable
    impl UpgradeableInternalImpl = upgradeable_component::InternalImpl<ContractState>;

    struct Storage {
        ownable: ownable_component::Storage,
        upgradeable: upgradeable_component::Storage

    #[derive(Drop, starknet::Event)]
    enum Event {
        OwnableEvent: ownable_component::Event,
        UpgradeableEvent: upgradeable_component::Event

    fn constructor(ref self: ContractState, owner: ContractAddress) {

    impl UpgradeableImpl of IUpgradeable<ContractState> {
        fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {
            // This function can only be called by the owner

            // Replace the class hash upgrading the contract

Proxies and Starknet

Proxies enable different patterns such as upgrades and clones. But since Starknet achieves the same in different ways is that there’s no support to implement them.

In the case of contract upgrades, it is achieved by simply changing the contract’s class hash. As of clones, contracts already are like clones of the class they implement.

Implementing a proxy pattern in Starknet has an important limitation: there is no fallback mechanism to be used for redirecting every potential function call to the implementation. This means that a generic proxy contract can’t be implemented. Instead, a limited proxy contract can implement specific functions that forward their execution to another contract class. This can still be useful for example to upgrade the logic of some functions.