Ethereum-Solidity Quiz Q14: Why constructors can't be used in upgradeable contracts?

Published: (January 5, 2026 at 02:42 PM EST)
1 min read
Source: Dev.to

Source: Dev.to

Constructor behavior in upgradeable contracts

In Solidity, code placed inside a constructor or in a global variable declaration is not part of a deployed contract’s runtime bytecode. This code runs only once, at the moment the contract instance is deployed.

When a logic contract is used behind a proxy, the constructor of the logic contract is never executed in the context of the proxy’s storage. Proxies are completely oblivious to any storage changes performed by the constructor.

Solution: use an initializer function

To make a contract upgrade‑compatible, move the constructor logic into a regular initializer function and call this function after the proxy is linked to the logic contract. The initializer must be protected so it can be called only once—mirroring the one‑time execution guarantee that constructors provide.

OpenZeppelin Upgrades lets you specify the name of the initializer function (and its parameters) when deploying a proxy.

Example with OpenZeppelin Initializable

// contracts/MyContract.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

contract MyContract is Initializable {
    function initialize(
        address arg1,
        uint256 arg2,
        bytes memory arg3
    ) public payable initializer {
        // "constructor" code...
    }
}

The contract inherits from Initializable, which provides the initializer modifier that ensures the initialize function can be executed only once.

Extract from OpenZeppelin Docs

Back to Blog

Related posts

Read more »