CREATE2 is an Ethereum opcode that lets you calculate a smart contract’s address before you deploy it. The address comes from a formula, not from the deployer’s transaction count, so you can know exactly where a contract will live — and even deploy it to the same address on several blockchains.
In Solidity, you reach CREATE2 through the new keyword with a salt option. The salt is a value you pick, and changing it changes the resulting address. That is what gives you control over where the contract lands.
This guide covers what CREATE2 is, how the address is derived, how to predict and deploy an address in Solidity, and what it takes to get the same address across EVM networks. It also covers the limits worth knowing before you build on it.
What Is CREATE2, and How Is It Different From CREATE?

Every contract on an EVM chain has an address, and that address is decided at deployment. The real question is what the address is derived from.
The original CREATE opcode derives the address from two things: the deployer’s address and its nonce, a counter of how many contracts or transactions that account has sent. Because the nonce increases with every deployment, you cannot reliably predict a CREATE address in advance, and you cannot reproduce it later.
EIP-1014 introduced CREATE2 in the Constantinople upgrade in early 2019. It swaps the nonce for a salt and a hash of the contract’s init code. None of those inputs depend on account history, so the address is deterministic: the same inputs always produce the same address, on any EVM chain.
Here’s the practical difference. With CREATE, the address is a side effect of when you deploy. With CREATE2, the address is something you decide up front.
How Does CREATE2 Derive the Address?
CREATE2 runs the address through a single hash. The formula from EIP-1014 is:
address = keccak256(0xff ++ deployer ++ salt ++ keccak256(init_code))[12:]
keccak256 is the hash function the EVM uses, ++ means the bytes are joined together, and [12:] means the address is the last 20 bytes of the 32-byte hash. The full input to the hash is always exactly 85 bytes.
The four inputs that decide the address
0xff— a single constant byte. It never changes, and its only job is to keep CREATE2 addresses from colliding with regularCREATEaddresses.deployer— the 20-byte address of the account or contract running CREATE2. Deploy from a different address and you get a different result.salt— a 32-byte value you choose. This is the knob you turn to produce the address you want.keccak256(init_code)— the hash of the contract’s init code, meaning the creation bytecode plus any constructor arguments. Change the code or the arguments and the address changes.
Two of these are fixed by context (the constant byte and the deployer) and two are under your control (the salt and the code). That is the entire basis for predictable addresses: fix the code, pick a salt, and the address falls out of the formula.
Why Predictable Contract Addresses Are Useful
Knowing an address before deployment solves problems that are awkward with CREATE.
You can reference a contract before it exists. A protocol can hard-code the address of a contract it will deploy later, or two contracts can be told about each other without a chicken-and-egg deployment order.
You can fund or interact with an address ahead of time. Some wallet designs send assets to a smart-account address that is only deployed on first use. The address is derived with CREATE2, so it is valid and fundable before any contract code is there. These “counterfactual” designs underpin a lot of account-abstraction work.
In practice, the heavy users are smart-account and wallet teams, DeFi protocols that deploy per-user or per-pair contracts (Uniswap-style pair contracts are the classic example), and anyone shipping the same contracts to more than one network.
How to Predict and Deploy a Contract Address in Solidity
You usually do two things: compute the address, then deploy to it. Solidity’s CREATE2 support handles both.
Compute the address before you deploy
You can compute the address off-chain or on-chain. On-chain, a helper reproduces the EIP-1014 formula directly:
solidity
function predict(bytes32 salt) public view returns (address) {
// Target is the contract you intend to deploy
bytes32 initCodeHash = keccak256(type(Target).creationCode);
bytes32 h = keccak256(
abi.encodePacked(bytes1(0xff), address(this), salt, initCodeHash)
);
return address(uint160(uint256(h)));
}
If Target‘s constructor takes arguments, append them to the creation code before hashing, because they are part of the init code. OpenZeppelin ships this logic as a reusable Create2 library with computeAddress and deploy functions, documented in its contract utilities. Off-chain, libraries such as ethers.js (getCreate2Address) and viem (getCreate2Address) run the same calculation in JavaScript.
Deploy with the salt option
To deploy, add a salt option to the new expression. This compiles down to the CREATE2 opcode:
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Factory {
event Deployed(address addr, bytes32 salt);
function deploy(bytes32 salt) external returns (address) {
Target t = new Target{salt: salt}(); // Target is any contract
emit Deployed(address(t), salt);
return address(t);
}
}
The salt option has been part of Solidity for years and behaves the same in the current 0.8.x releases — 0.8.37 at the time of writing. If a contract already exists at the computed address, the deployment reverts rather than overwriting it.
Verify the result over RPC
Once you deploy, confirm the contract landed where you predicted. The quickest check is the eth_getCode JSON-RPC method against the predicted address: it returns 0x when nothing is deployed and the contract’s runtime bytecode once it is.
bash
curl https://eth.nownodes.io/YOUR_API_KEY \
-X POST -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_getCode","params":["0xYourPredictedAddress","latest"],"id":1}'
To broadcast the deployment and run that check, you need an endpoint for each chain you are targeting. Our RPC endpoints cover Ethereum, BNB Smart Chain, Polygon, Arbitrum, and other EVM networks, so you can point the same script at one chain after another without running the underlying infrastructure yourself.
Getting the Same Address on Every EVM Chain
This is the part the title promises. Because a CREATE2 address depends only on the deployer, the salt, and the init code — and not on anything chain-specific — the same three inputs produce the same address on Ethereum, BNB Smart Chain, Polygon, and any other EVM network. Deploy with identical inputs on each chain and your contract lives at one address everywhere, which is far easier to document, integrate, and audit.
What has to match across chains
Determinism is only as good as the inputs you keep identical. To land on the same address on every chain, all of these have to match, as Foundry’s guide spells out:
- The same deployer — either the same externally owned account or the same factory contract on every chain.
- The same salt.
- Identical bytecode — no values baked in that differ per chain. A
block.chainidread in a constructor, or a chain-specific immutable, changes the init code and therefore the address. - The same compiler settings — solc version, optimizer runs, and EVM version. A different compiler can emit different bytecode from the same source.
A common way to guarantee the same deployer everywhere is a shared factory. Arachnid’s deterministic deployment proxy sits at 0x4e59b44847b379578588920ca78fbf26c0b4956c on many chains and is Foundry’s default CREATE2 deployer. It is not on every network, though — check with cast code against that address, and a 0x result means it is not deployed there.
CREATE2 vs CREATE3
CREATE2 has one catch for cross-chain work: the init code is part of the address. If the bytecode differs by even a byte between chains — a different compiler, a tweaked constructor — the addresses diverge.
CREATE3 is a deployment pattern built to remove that constraint. It combines CREATE2 with a small intermediate deployer so the final address depends only on the deployer and the salt, not on the contract’s bytecode. As 1inch’s write-up explains, that lets teams deploy different or upgraded bytecode to the same address across chains. CREATE3 is a convention implemented by libraries such as Solady and factories like CreateX, not a native opcode, so it costs more gas and adds a dependency. For most cases where you control the bytecode, plain CREATE2 is simpler; CREATE3 earns its keep when keeping bytecode byte-identical across many chains is impractical.
Limits and Risks to Know

CREATE2 is useful, but a few things trip people up.
Redeployment is mostly gone. The old trick of self-destructing a CREATE2 contract and deploying different code to the same address — the “metamorphic contract” pattern — stopped working after the Dencun upgrade (March 2024). EIP-6780 restricts SELFDESTRUCT so it only fully removes a contract when it runs in the same transaction that created the contract. Outside that case the code stays put, so you can no longer swap a deployed contract’s code by destroying and redeploying it.
Init code has a size limit. Since the Shanghai upgrade, EIP-3860 caps init code at 49,152 bytes and charges extra gas per 32-byte word of it. Very large contracts deployed via CREATE2 can run into this ceiling.
A predictable address can be front-run. Anyone who knows your deployer, salt, and bytecode can compute the address, so a third party could deploy to it first if your deployer is a public factory with a guessable salt. Use salts you control, and where it matters, tie the salt to the intended deployer.
Constructor arguments are part of the address. It is easy to forget that changing a constructor argument changes the init code hash, and therefore the address. If you expect a fixed address, keep the arguments fixed too.
Conclusion
CREATE2 turns a contract’s address from something you discover after deployment into something you decide beforehand. The address is just a hash of a constant byte, the deployer, a salt you pick, and the contract’s init code. Fix those and the address is locked in, on any EVM chain.
That makes it the standard tool for counterfactual smart accounts, per-user or per-pair contracts, and deploying the same system to one shared address across networks. The main things to get right are keeping every input identical across chains and remembering that bytecode and constructor arguments count as inputs.
When you move from computing addresses to actually deploying and verifying them across several networks, the piece you still need is a reliable connection to each chain. Our multi-chain RPC access spans Ethereum and the major EVM networks, so the same deterministic deployment runs the same way everywhere.
FAQ
Is CREATE2 the same as the Solidity new keyword?
No. new on its own compiles to the plain CREATE opcode. You only invoke CREATE2 when you add a salt, as in new Contract{salt: mySalt}().
Can I use any value as the salt?
Yes. The salt is any 32-byte value you pick — a counter, a hashed identifier, or random bytes. Randomness only matters when you need the resulting address to be hard for others to guess.
What is a vanity CREATE2 address?
It is an address with a chosen pattern, such as leading zeros or a recognizable prefix. Because the salt feeds the address formula, developers can search (“mine”) through salts until one produces an address they like, then deploy with that salt.
Is CREATE2 more expensive than CREATE?
Slightly. CREATE2 also hashes the init code to derive the address, which adds a small amount of gas proportional to the code size. Next to the cost of actually deploying the contract, the difference is usually negligible.



