Foundry and Hardhat are the two development frameworks most Solidity teams choose between. They overlap heavily — compile contracts, run tests, fork a live network, deploy — but they come from different worlds. Hardhat is a JavaScript and TypeScript tool that grew out of the Node.js ecosystem. Foundry is a Rust-built toolchain in which you write tests in Solidity itself.
At Rivix Systems we use both, chosen per project, as part of our wider Solidity smart contract development practice. This note explains the differences that actually matter when you are choosing, and the cases where the best answer is to use them together. For the bigger picture of how testing fits into contract security, start with our note on building production smart contracts in Solidity.
The short answer
- Choose Foundry when the contracts are the product and you want the strongest testing story: fuzzing, stateful invariant testing and fork tests are built in, and tests are written in the same language as the code under test.
- Choose Hardhat when the team lives in TypeScript, when contract tests are entangled with a JavaScript application or deployment pipeline, or when you depend on the Hardhat plugin ecosystem.
- Use both when you want Foundry for contract-level testing and TypeScript for deployment scripts, integration tests and the application layer. This is common and works well.
Neither choice is permanent. Both compile the same Solidity, both work with OpenZeppelin, and a well-structured project can move between them or run them side by side.
Side by side
| Area | Foundry | Hardhat |
|---|---|---|
| Language of tests | Solidity | JavaScript / TypeScript (Solidity tests are also supported in newer releases) |
| Built on | Rust toolchain: forge, cast, anvil, chisel | Node.js, with an npm plugin ecosystem |
| Fuzz testing | Built in: any test function with parameters is fuzzed | Not built in for JS tests; typically added through Solidity tests or external fuzzers |
| Invariant testing | Built in, with handler contracts | Typically via external tools such as Echidna or Medusa |
| Mainnet forking | Built in: --fork-url or cheatcodes | Built in through network configuration |
| Manipulating state in tests | Cheatcodes: vm.prank, vm.warp, vm.deal, vm.expectRevert | Helper libraries and network helpers such as time and balance manipulation |
| Deployment scripts | Solidity scripts with forge script | TypeScript scripts, or a declarative deployment module system |
| Dependencies | Git submodules by default, plus remappings | npm packages |
| Front-end integration | Separate: you generate ABIs and wire them up yourself | Natural fit: same language and package manager as the app |
| Gas reporting and coverage | Built in: gas reports, gas snapshots, coverage | Available through plugins |
Check current documentation before deciding on any row of this table. Both projects move quickly, and the gaps between them have narrowed over time.
Where Foundry is stronger
Tests in Solidity
Writing tests in Solidity removes a whole layer of translation. You call contracts directly, use the same types and custom errors, and there is no encoding of big integers between two languages. It also means the engineers reading a test are reading the language they are auditing.
Fuzzing and invariants are first-class
In Foundry, a test function that takes parameters is automatically fuzzed with generated inputs. Functions prefixed with invariant_ are run against random sequences of calls to your contracts, so you can assert properties that must always hold — for example, that a vault never owes more than it holds. This is the layer that finds the bugs example-based tests miss — reentrancy paths are a classic example (see Solidity reentrancy attacks) — which is why it is central to how we test contracts that hold value.
Cheatcodes make hard scenarios easy
Impersonating an account, jumping the block timestamp, setting balances and asserting specific reverts are one-line calls. That makes it cheap to write the awkward tests — time-locked upgrades, role checks, edge cases around deadlines — that teams otherwise skip.
A compact toolchain
Compile, test, gas-report, format, script deployments, run a local node and query a chain from the command line all come from one install. There is less to configure, and less that can drift between developers' machines.
Where Hardhat is stronger
One language across contracts and application
If your team already writes TypeScript for the front end and the backend, Hardhat keeps contract tests, deployment scripts and application code in a single language, package manager and editor setup. Sharing types and configuration with the rest of the codebase is straightforward.
Ecosystem and plugins
Hardhat has a long-established plugin ecosystem: contract verification on block explorers, gas reporting, coverage, type generation for TypeScript bindings and upgrade tooling. Many existing tutorials, templates and protocol repositories are Hardhat-based, which matters when you are joining or auditing an existing codebase.
Integration-style tests
When a test needs to exercise the same client library your application uses — for example ethers or viem — or run alongside backend code, doing it in TypeScript is more natural than reproducing the setup in Solidity.
The same test in both
A small check that a non-owner cannot pause a contract. In Foundry:
function test_NonOwnerCannotPause() public {
vm.prank(alice);
vm.expectRevert();
vault.pause();
}
In Hardhat with TypeScript:
it("non-owner cannot pause", async () => {
await expect(vault.connect(alice).pause()).to.be.reverted;
});
Both are readable. The difference shows up as tests get more complex: Foundry's advantage grows with the amount of state manipulation and property testing, and Hardhat's grows with the amount of application-level integration.
How to decide
- What is the team fluent in? A team of TypeScript engineers will be productive in Hardhat sooner; a team of contract specialists will usually prefer Solidity tests.
- How much value will the contracts hold? The more value at risk, the more built-in fuzzing and invariant testing is worth. That points to Foundry, or to Hardhat plus dedicated fuzzing tools.
- Is there an existing codebase? Migrating a working Hardhat project purely for taste is rarely worth it. Adding Foundry tests alongside it often is.
- Where do deployments and integration tests live? If they are part of a TypeScript pipeline, keep them there.
- Who else must read the tests? Auditors are used to both, but tests in the contract language lower the barrier for security reviewers.
Using both
A layout that works well: Foundry for unit, fuzz, invariant and fork tests inside the contracts package; TypeScript for deployment scripts, integration tests and the application. Contracts compile once, ABIs are shared, and each tool does what it is best at. Keep static analysis such as Slither and upgrade-safety checks in CI regardless of which framework runs the tests.
What a framework does not do for you
Neither tool makes a contract safe. A framework runs the tests you write; it does not decide which properties matter. Threat modeling, a written specification, well-chosen invariants, review and, for contracts that hold meaningful value, an independent audit are what actually reduce risk. Choose the framework that makes those practices cheapest for your team to follow consistently.
Common questions
Is Foundry better than Hardhat?
Neither is better in every case. Foundry is stronger for contract-focused testing, with built-in fuzzing, invariant testing and Solidity tests. Hardhat is stronger when the team works in TypeScript and needs the plugin ecosystem or close integration with application code.
Can you use Foundry and Hardhat together?
Yes. A common setup uses Foundry for contract unit, fuzz, invariant and fork tests, and Hardhat or TypeScript for deployment scripts and integration tests. Both compile the same Solidity source.
Does Hardhat support fuzzing and invariant testing?
Classic JavaScript tests in Hardhat do not include fuzzing or invariant testing on their own. Teams add them through Solidity-based tests or external tools such as Echidna and Medusa. Check the current Hardhat documentation, as its Solidity testing support has been evolving.
Which framework should a new Solidity project use?
For a project where the contracts hold value and the team is comfortable with Solidity, Foundry is a strong default. For a project driven by a TypeScript team or an existing Hardhat codebase, Hardhat is the pragmatic choice. Either can be complemented with the other later.
