Today is August 26, 2025, and Hardhat 3 has been officially stable since August 13.
I've spent the past month migrating six production De
Fi protocols from Hardhat 2 to 3, and if you're still running Hardhat 2, you're voluntarily choosing to waste your time.
The Numbers That Matter
The performance improvements are real, and they're fucking dramatic. The EDR runtime rewrite in Rust isn't marketing bullshit:
- Test execution: 2-10x faster than Hardhat 2
- Memory usage: 50% reduction for large projects
- Compilation time: 3x faster for complex contract suites
- Network simulation:
Near-instant blockchain state changes
These aren't synthetic benchmarks. Our DeFi protocol tests went from 15 minutes to 3-4 minutes. That's the difference between running tests during development vs. grabbing coffee and losing your train of thought.
What's Actually New (Beyond the Performance Hype)
Solidity-native testing changes everything.
You can now write unit tests directly in Solidity using Foundry-compatible syntax:
import { Test } from "forge-std/Test.sol";
contract Token
Test is Test {
Token token;
function setUp() public {
token = new Token();
}
function testInitialSupply() public {
assertEq(token.totalSupply(), 1000000 * 10**18);
}
function testFuzz_Transfer(uint256 amount) public {
vm.assume(amount <= token.balanceOf(address(this)));
token.transfer(address(0x1), amount);
assertEq(token.balanceOf(address(0x1)), amount);
}
}
Configuration Variables solve the private key management nightmare.
The new encrypted keystore means no more .env
files with mainnet private keys:
## Store secrets encrypted on disk
npx hardhat keystore set MAINNET_PRIVATE_KEY
## Use in config without exposing values
import { configVariable } from "hardhat/config";
export default {
networks: {
mainnet: {
url: config
Variable("MAINNET_RPC_URL"),
// No raw private keys in config files!
}
}
};
Multichain support is built-in, not bolted-on.
You can simulate OP Stack networks, Polygon, or any EVM-compatible chain locally:
networks: {
hardhat: {
chainId: 8453, // Base
forking: {
url: "https://mainnet.base.org"
}
},
optimism: {
chainId: 10,
url: "https://mainnet.optimism.io"
}
}
The Migration Will Break Your Shit (But It's Worth It)
This migration will break your existing project in ways you don't expect.
The biggest pain in the ass is ESM-only configuration
- your CommonJS setup is fucked.
Your hardhat.config.js
dies and becomes hardhat.config.ts
:
// Hardhat 2 (CommonJS)
const { task } = require("hardhat/config");
require("@nomicfoundation/hardhat-toolbox");
module.exports = {
solidity: "0.8.19",
networks: { /* config */ }
};
// Hardhat 3 (ESM)
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";
const config:
HardhatUserConfig = {
solidity: "0.8.28",
networks: { /* config */ }
};
export default config;
Plugin compatibility is hit-or-miss.
The important ones work:
@nomicfoundation/hardhat-toolbox
- works out of the box
hardhat-gas-reporter
- compatible as of v2.0+
@openzeppelin/hardhat-upgrades
- requires v3.0+ for Hardhat 3
hardhat-deploy
- still catching up, use Hardhat Ignition instead
The Test Runner Revolution
Hardhat 3's test runner plugin system means you're not locked into Mocha anymore.
The default Node.js test runner is faster and has zero dependencies:
// package.json
- no test framework dependencies needed!
{
"scripts": {
"test": "hardhat test"
},
"devDependencies": {
"hardhat": "^3.0.0"
// That's it
- no mocha, chai, etc.
}
}
Built-in code coverage works without additional setup:
npx hardhat test --coverage
No more wrestling with solidity-coverage
plugin configurations or mysterious coverage gaps.
Where This Migration Will Fuck You Over
TypeScript strict mode breaks shit that worked in Hardhat 2.
The type checker actually gives a damn now:
// This breaks in Hardhat 3
const signer = await ethers.getSigner(); // Type error!
// Fix: be explicit about signer selection
const [deployer] = await ethers.getSigners();
const signer = await ethers.getSigner(deployer.address);
Network manager changes require updates to scripts that manage multiple connections:
// Hardhat 2 pattern
await network.provider.request({
method: "hardhat_reset"
});
// Hardhat 3 pattern
- more explicit connection handling
const networkConnection = await hre.network.getProvider();
await networkConnection.request({
method: "hardhat_reset"
});
When Migration Makes Sense (Decision Framework)
Migrate immediately if:
- Your test suite takes more than 2 minutes to run
- You're deploying to multiple networks regularly
- Security matters (you need encrypted secret management)
- You're starting a new project
Consider waiting if:
- You have complex custom tasks that rely on Hardhat 2 internals
- Critical plugins haven't been updated yet
- Your team is already overwhelmed with other migrations
Never migrate if:
- Your project is in maintenance mode with no active development
- You're using unsupported legacy Node.js versions (<18)
Everyone Else Already Did This Migration
The big DeFi protocols aren't waiting around. Uniswap, Aave, and Compound are all running Hardhat 3 in production.
The ecosystem caught up:
- IDE support: Hardhat for VSCode works perfectly
- CI/CD:
GitHub Actions templates available
- Docker: Official images support Hardhat 3
- Documentation:
Comprehensive migration guide exists
The Performance Impact You'll Actually Feel
Forget synthetic benchmarks.
Here's what changes day-to-day:
Before Hardhat 3:
Running tests during development means grabbing coffee. Large projects with 500+ tests take 8-12 minutes. Memory usage creeps up, eventually requiring restarts.
After Hardhat 3: Tests finish while you're still thinking about what to change next. The same 500 tests complete in 2-3 minutes. Memory stays stable across long development sessions.
This isn't just convenience – it changes how you work. You'll run tests more frequently, catch bugs earlier, and iterate faster on complex smart contract logic.
Look, if you're building anything serious on Ethereum in 2025, this migration isn't optional. The performance difference alone will save you hours every week, and the security improvements mean you can actually deploy to mainnet without shitting yourself about leaked private keys.