Migrating from Truffle to Hardhat: A Practical Guide
As the Ethereum development ecosystem evolves, Hardhat has emerged as a powerful alternative to Truffle, offering enhanced performance, extensibility, and a modern plugin system. This guide will walk you through a thorough, step-by-step migration of an existing Truffle project to Hardhat, complete with configuration tweaks, test adaptation, deployment scripts, and best practices.
1. Prerequisites
- Node.js v14 and npm or Yarn installed
- An existing Truffle project with contracts/, migrations/, and test/ directories
- Familiarity with JavaScript/TypeScript and basic CLI usage
- API keys for networks (Infura, Alchemy, etc.)
2. Overview: Truffle vs Hardhat
| Feature | Truffle | Hardhat |
|---|---|---|
| Development Network | Built-in Ganache | Hardhat Network (in-process, fast) |
| Testing | Mocha Chai | Mocha Chai Waffle |
| Plugins | Truffle plugins | 70 official/community plugins |
| Debugging | Limited console logs | Console.sol stack traces |
3. Initial Setup
- Navigate to your project root and remove Truffle artifacts:
rm -rf build/ contracts/Migrations.sol - Install Hardhat:
npm install --save-dev hardhat - Initialize Hardhat in interactive mode:
npx hardhatSelect “Create a basic sample project” to scaffold config, scripts/, contracts/, and test/ folders.
4. Configuring hardhat.config.js
Replace the generated config with:
require(@nomiclabs/hardhat-waffle)
require(@nomiclabs/hardhat-etherscan)
require(dotenv).config()
module.exports = {
solidity: 0.8.9,
defaultNetwork: hardhat,
networks: {
hardhat: {},
ropsten: {
url: process.env.ROPSTEN_RPC_URL,
accounts: [process.env.DEPLOYER_PRIVATE_KEY]
}
},
etherscan: {
apiKey: process.env.ETHERSCAN_API_KEY
}
}
Tip: Use dotenv to manage secrets.
5. Migrating Contracts
- Move contracts/ from Truffle to Hardhat project.
- Ensure each contract imports
hardhat/console.solfor debugging:
import hardhat/console.sol
artifacts.require).6. Adapting Tests
Hardhat defaults to Waffle matchers, but you can continue with Chai assertions.
- Update imports:
const { ethers } = require(hardhat) - Replace:
const instance = await MyContract.deployed()with:
const MyContract = await ethers.getContractFactory(MyContract) const instance = await MyContract.deploy()
7. Deployment Scripts
Hardhat uses scripts/ instead of migrations/. Example deploy.js:
async function main() {
const [deployer] = await ethers.getSigners()
console.log(Deploying contracts with:, deployer.address)
const Token = await ethers.getContractFactory(Token)
const token = await Token.deploy(My Token, MTK, 18, ethers.utils.parseEther(1000000))
console.log(Token deployed to:, token.address)
}
main()
.then(() => process.exit(0))
.catch(error => {
console.error(error)
process.exit(1)
})
8. Plugins Integrations
- hardhat-gas-reporter – Gas usage reports.
- hardhat-etherscan – Verify contracts automatically.
- hardhat-truffle5 – Optional Truffle compatibility.
9. Front-End Integration
If you use Truffle Contract, switch to @ethersproject or ethers.js:
import { ethers } from ethers
const provider = new ethers.providers.Web3Provider(window.ethereum)
const contract = new ethers.Contract(address, abi, provider.getSigner())
10. Continuous Integration
Add in your CI config (GitHub Actions example):
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install
run: npm install
- name: Compile Test
run: npx hardhat test
11. Troubleshooting Tips
- Stack traces: Enable via
--verboseor Hardhat’ssolidity.debugsetting. - Forking Mainnet: Use
hardhat.networks.hardhat.forking.urlfor live state tests. - Cache issues: Run
npx hardhat cleanto reset artifacts.
Conclusion
Migrating from Truffle to Hardhat unlocks improved performance, superior debugging, and an ever-growing plugin ecosystem. By following this guide, you’ll modernize your workflow, reduce gas costs, and streamline contract development and deployment.
Leave a Reply