back

2025-08-22

Foundry vs Hardhat: why Foundry won

Dev tooling

Foundry changed the standard for Ethereum development tooling.

It made fast feedback, Solidity-native tests, fuzzing, invariants, and cheatcodes feel like parts of one coherent workflow. Features that had previously required a mix of JavaScript tests, plugins, and specialist tools became available through a focused command-line toolkit.

That shift is why Foundry won the argument about what Solidity developers needed.

But there is an important update to this story. When this article was first published, Hardhat had already begun responding. Its EDR runtime had moved performance-critical EVM execution into Rust, and the Hardhat 3 beta had introduced Solidity tests, fuzzing, invariants, and compatible cheatcodes. Those changes were too new and too easy to underestimate at the time.

Hardhat has developed significantly since then. For the current comparison, read The comeback of Hardhat, which covers Hardhat 3, its Rust-powered runtime, the 1inch migration, and where the two tools stand today.

If you want to learn the concepts behind these tools by building rather than only comparing frameworks, try Speedrun Ethereum. As part of my DevRel work with the Ethereum Foundation, I spend a lot of time thinking about how developers move from understanding Solidity to shipping real applications. Speedrun Ethereum provides hands-on challenges covering tokens, crowdfunding, DEXs, oracles, lending, stablecoins, prediction markets, and more. Its introductory challenge also gives you practical experience with Hardhat.

The tooling environment Foundry entered

Ethereum development tooling has moved through several distinct eras.

Truffle was the original mainstream framework. Launched in 2015, it gave developers a standard way to compile, migrate, and test smart contracts. Consensys announced the sunset of Truffle and Ganache in September 2023, ending an important chapter in Ethereum's developer tooling history.

Hardhat had already become the leading successor. Built by Nomic Foundation, it offered strong debugging, Solidity stack traces, a flexible task system, a large plugin ecosystem, and natural integration with JavaScript and TypeScript applications.

For full-stack Ethereum teams, that model made sense. Contracts rarely existed in isolation. They were connected to frontends, deployment scripts, indexers, bots, and other offchain services, most of which were written in JavaScript or TypeScript.

But protocol development exposed a different set of needs. Engineers working primarily in Solidity wanted a faster and more direct loop. They wanted tests that felt like contract code, better control over EVM state, and security techniques that were easy enough to run continuously.

Enter Foundry

Foundry emerged from work by Georgios Konstantopoulos and Paradigm in 2021, building on ideas pioneered by DappTools.

The toolkit is composed of four main tools:

  • Forge for compilation, testing, fuzzing, scripting, and deployment
  • Cast for command-line blockchain interactions and onchain queries
  • Anvil for running a local Ethereum node
  • Chisel for an interactive Solidity REPL

The design was opinionated. Smart contract developers should be able to build and test contracts without first constructing a JavaScript testing stack. Tests could be written in Solidity, executed through a native Rust toolchain, and supported by a shared set of testing utilities.

That sounds obvious now. It was not obvious when Foundry appeared.

Why Foundry gained so much ground

Foundry did not succeed because of one benchmark. It improved the entire feedback loop for Solidity-focused development.

Fast feedback

Foundry quickly developed a reputation for speed. Forge is written in Rust, uses incremental compilation and caching, and executes Solidity tests directly in its EVM runner.

Early comparisons often showed dramatic advantages over JavaScript-based Hardhat test suites. One widely cited experiment measured a small Foundry suite at 1.44 seconds and its Hardhat equivalent at 5.17 seconds. With caches present, it reported 0.45 seconds for Foundry and 3.98 seconds for Hardhat.

Those results need context. They compared Foundry Solidity tests with an older, pre-EDR Hardhat JavaScript workflow. They should not be treated as a benchmark of Foundry against Hardhat 3. The test languages, execution paths, framework versions, and overhead were different.

Still, the developer experience behind those numbers was real. Foundry made it possible to run a focused Solidity test almost instantly, which encouraged developers to test more frequently and iterate in smaller steps.

Solidity-native testing

Foundry's most important contribution was making Solidity tests feel normal.

function testTransfer() public {
    token.transfer(addr1, 50);
    assertEq(token.balanceOf(addr1), 50);
}

There is no client library between the test and the contract. Developers can use Solidity's types, inheritance, interfaces, and compiler checks directly. Internal logic can be exposed through test harnesses, and contract-level behavior remains in one mental model.

JavaScript and TypeScript tests are not inherently bad. They are often better for integrations and user-level workflows. The problem was that Solidity developers previously had little choice. Foundry proved that Solidity itself could provide an excellent unit-testing environment.

Hardhat 3 has since adopted first-class Solidity testing while retaining TypeScript tests. That validates Foundry's insight, even if the frameworks now implement it differently.

Fuzz testing

Fuzz testing generates inputs automatically to search for edge cases that example-based unit tests miss.

In Foundry, a test function with parameters can become a fuzz test:

function testWithdraw(uint256 amount) public {
    amount = bound(amount, 1, balance);
    vault.withdraw(amount);
    assertEq(vault.balance(), balance - amount);
}

Forge runs the function across many generated values, shrinks a failing input into a simpler counterexample, and persists failures so they can be replayed. This made property-based testing accessible during normal development rather than reserving it for a separate security phase.

Invariant testing

Invariant testing goes further. Instead of fuzzing the inputs to one function, the runner generates sequences of calls and checks properties that should remain true throughout the resulting state changes.

For an ERC-20 token, an invariant might state that total supply must equal the sum of tracked balances. For an automated market maker, it might verify a relationship between reserves. For a lending protocol, it might assert that the system never becomes insolvent under valid operations.

Foundry made these campaigns part of the same environment as ordinary unit tests. That helped move security thinking closer to day-to-day development.

Cheatcodes

Solidity tests need ways to control their environment. Foundry's cheatcodes became one of its defining features:

  • vm.prank(address) changes the caller for the next call
  • vm.warp(timestamp) changes the block timestamp
  • vm.deal(address, amount) changes an account's ETH balance
  • vm.expectRevert() verifies that an operation fails correctly
  • vm.createSelectFork() creates and selects a live network fork

Hardhat had long offered many equivalent network controls through its JSON-RPC interface and network helpers. It was therefore inaccurate to say that this control always required multiple plugins. Foundry's advantage was primarily ergonomics and cohesion. The controls were available directly inside Solidity through one consistent interface.

Hardhat 3 now supports most commonly used Foundry cheatcodes in Solidity tests, although Foundry still has the broader cheatcode surface.

A complete Solidity command-line workflow

Foundry's appeal extends beyond testing.

Cast makes it easy to inspect storage, call contracts, send transactions, decode calldata, and query chain data without writing a script. Anvil provides a fast local node with forking support. Chisel lets developers experiment with Solidity interactively. Forge scripts let teams simulate, broadcast, and verify deployments through Solidity.

Together, these tools reduce the need to leave the terminal or switch languages for routine protocol work.

What the original Hardhat comparison missed

The first version of this article described Hardhat as if its execution architecture were still entirely JavaScript. That was already incomplete in August 2025.

Hardhat began shipping EDR in version 2.21 in March 2024. EDR replaced the old Ethereum simulation layer with a Rust runtime built on REVM. Nomic Foundation reported that most projects saw test-running improvements of at least 2x, with some reaching 10x.

Hardhat's CLI, configuration, plugins, and TypeScript tests still use Node.js. But performance-critical EVM execution does not. That makes the simple claim that Foundry is fast because it uses Rust while Hardhat is slow because it uses Node.js technically wrong.

Hardhat 3's beta arrived in August 2025 with first-class Solidity tests, fuzzing, invariants, and cheatcodes. At that point, the fair criticism was that these features were newer and less battle-tested than Foundry's, not that Hardhat lacked them entirely.

The timing matters. Foundry had already changed developer expectations, built a strong protocol community, and established mature testing conventions. Hardhat was catching up, but it was actively investing rather than standing still.

Why Foundry still won that era

Correcting the Hardhat details does not erase Foundry's impact.

Foundry identified the right workflow earlier. It treated Solidity developers as the primary users, made security testing approachable, and shipped a coherent native toolkit while the dominant ecosystem still centered JavaScript tests.

That head start mattered. Protocol teams standardized around Forge. Auditors became comfortable reproducing exploits through Foundry tests. Libraries published Foundry installation instructions. New Solidity developers learned cheatcodes, fuzzing, and invariant testing as normal parts of contract development.

Foundry also remained simpler for repositories that did not need Node.js. A Solidity-only project could install one toolkit and get compilation, testing, scripting, a local node, chain interactions, and a REPL.

Hardhat retained important strengths. Its plugin architecture, TypeScript integration, debugging, deployment ecosystem, and ability to test offchain components made it valuable for broader application development. Many teams reasonably used Foundry for contract tests and Hardhat for integrations or deployments.

The real result was not total replacement. It was a change in the industry's expectations.

The bigger lesson

Foundry won because it recognized that feedback speed, language continuity, and security tooling were not separate features. Together, they formed the daily experience of building Solidity contracts.

Hardhat's response reinforces that lesson. It rebuilt its runtime in Rust, introduced Solidity-native tests, integrated fuzzing and invariants, added compatible cheatcodes, and preserved the TypeScript and plugin workflows that made it useful in the first place.

So the conclusion needs more nuance than the original version offered.

Foundry won the argument about what Solidity developers needed. Hardhat listened, invested, and came back with a serious answer.

For how that answer looks today, continue with The comeback of Hardhat.