blockchainsv
Developer Tools & Infrastructure·July 16, 2026·18 min read

Web3 development tools: monolithic suites vs modular stacks

A frontend integration fails in a very familiar way: the contract is fine, the wallet flow is fine, the RPC provider is fine — until the local test suite takes 25 seconds to tell us that one stale fixture broke state sync. We rerun it. We wait again.

Web3 development tools: monolithic suites vs modular stacks

Then a second problem appears: deployment scripts, indexer configuration, and the UI’s typed contract bindings all depend on one toolchain decision made months ago.

This is where the comparison between monolithic suites and modular Web3 development tools stops being a matter of developer taste. It becomes a product decision. Tooling shapes feedback loops, deployment confidence, team onboarding, and, eventually, the amount of friction a user feels when a transaction takes an unexpected path.

The old question was “Hardhat or Truffle?” Truffle and Ganache were officially sunset by Consensys in December 2023, and the practical question has moved on. Today, many teams are deciding whether to center their stack around an integrated runtime such as Hardhat 3 or assemble a modular workflow around Foundry’s Forge, Cast, Anvil, Chisel, plus whichever SDKs, indexers, and deployment services fit the application.

Neither architecture wins by default. Let’s look at where each one helps, where it creates hidden coupling, and how the same choice reappears inside the contracts we ship.

The best stack is not the one with the fewest commands. It is the one that keeps the team’s feedback loop short when production behaves differently from local development.

The shift from monolithic suites to modular toolchains

A monolithic Web3 dev stack gives us a coherent center of gravity. The project starts in one environment, with one configuration model and a predictable path through compilation, testing, local execution, deployment, and verification. That coherence is valuable, particularly when a team includes Solidity developers, frontend engineers, and protocol contributors who do not all want to become EVM runtime specialists before they can ship a feature.

Historically, Truffle embodied this approach. It paired migrations, compilation, testing, and local chains under a familiar Node.js workflow. That was useful in the period when the industry needed a common baseline more than it needed raw speed. But a maintained toolchain is part of production infrastructure, not a nostalgic dependency. With Truffle Suite sunset, continuing to build new workflows around it means accepting migration work later, under less pleasant conditions.

Hardhat became the default successor for many teams because it retained the integrated-project feeling while fitting naturally into JavaScript and TypeScript applications. Contract artifacts, deployment scripts, plugin ecosystems, test runners, frontend package management — these can live close together. For a DApp team, that often reduces handoff friction.

Modular Web3 development tools take a different position. They treat compilation, testing, chain simulation, command-line interaction, and experimentation as components rather than a single application.

Foundry is the clearest example:

  • Forge compiles, tests, fuzzes, and runs Solidity-oriented workflows.
  • Anvil provides a local Ethereum node for deterministic development and integration work.
  • Cast gives us a direct CLI interface to EVM data, transactions, calldata, storage, and RPC endpoints.
  • Chisel is a REPL for trying Solidity and EVM ideas without first creating a full project structure.

That separation can sound cosmetic until we hit a debugging session that crosses boundaries. Perhaps the frontend reads an incorrect struct after an upgrade. We may not need to run the full deployment framework again. We may need Cast to inspect storage on a fork, Anvil to replay a state transition locally, Forge to write a regression test, and our existing TypeScript client to confirm the UI decodes the result correctly.

A modular workflow lets us reach for the right instrument. The trade-off is that we must decide how the instruments fit together.

“Integrated” does not mean outdated, and “modular” does not mean mature by itself

The web3 framework vs modular tools debate gets noisy when it turns into identity. JavaScript is not obsolete because Rust-backed tooling is fast. A CLI-first workflow is not more serious because it looks closer to the chain. And a project with eight carefully selected tools is not necessarily flexible; it may just be carrying eight upgrade paths.

What matters is where the boundaries actually are:

QuestionMonolithic suiteModular stack
Primary developer experienceOne runtime and project conventionSeparate tools composed around a workflow
OnboardingFaster for teams already in TypeScript/NodeFaster for Solidity- and CLI-heavy teams after initial setup
DebuggingStrong in-context workflow, often plugin-ledPrecise tools for isolated EVM, RPC, and test tasks
CustomizationOften follows the framework’s extension modelComponents can be swapped independently
Configuration riskCentral configuration can become a bottleneckIntegration contracts between tools must be maintained
Best fitProduct teams seeking a shared default pathProtocol teams and performance-sensitive workflows

The table is not a scorecard. It is a way to expose where complexity lands. Monolithic suites concentrate it. Modular stacks distribute it.

For a small team, concentrated complexity is often a gift. For a protocol with multiple deployment targets, custom forks, independent audit tooling, and a long-lived contract surface, distributed complexity can be easier to live with — provided we document it as a real system rather than a collection of shell aliases.

Hardhat 3 is a monolithic runtime that learned from the performance problem

Calling Hardhat “monolithic” can be misleading if we mean slow, rigid, or closed. Hardhat’s value has always been its ability to make an Ethereum project feel like an application project. It gives teams a central runtime where tests, scripts, artifacts, network configuration, and plugins have shared context.

Hardhat 3 pushes this further with the Ethereum Development Runtime, or EDR: a performant Rust-powered runtime beneath the developer-facing framework. Its stable release introduced first-class Solidity tests and multichain support, two changes that matter beyond the release notes.

First-class Solidity tests reduce a recurring mismatch. When tests are expressed in JavaScript, a frontend-oriented team gets familiar tooling, but the test environment can be one translation layer away from the contract’s own language and assumptions. Solidity tests keep some invariants, helper contracts, and adversarial scenarios closer to the code they validate. That is particularly helpful for protocols whose bugs live in state transitions rather than in API wiring.

Multichain support answers another practical reality. Many DApps now have a user journey that crosses more than one network, even if the core contract does not. A bridge route, a settlement layer, an L2-specific deployment, or chain-aware feature flags can turn “the network config” into an application concern. A framework that treats this as a first-class condition can remove a lot of improvised glue.

Hardhat also remains compelling for teams whose frontend and contract code need to share types, scripts, and release conventions. If our DApp is built in TypeScript, and the same engineers touch React components, server-side relayers, event processors, and Solidity tests, a unified environment may be the lower-friction choice.

That does not mean we should let the runtime own every part of the stack. There is a meaningful difference between using Hardhat as the project’s orchestrator and allowing its conventions to leak into every operational task. RPC diagnostics, production event indexing, contract monitoring, and user-facing transaction state belong to their own layers.

Where Hardhat’s integration helps the user, not merely the developer

It is tempting to evaluate tooling through compiler time alone. Users never see our compiler. They do see the consequences of a weak deployment workflow:

  • a frontend displaying an ABI from the previous release;
  • a transaction composer calling a function on the wrong chain address;
  • an indexer lagging behind after a proxy upgrade;
  • a wallet prompt appearing before the app has simulated a reverting call;
  • a long-running state sync that shows “pending” after the transaction is already final.

An integrated suite can reduce these failures when it gives us a single place to define networks, deployment artifacts, contract interfaces, and test assumptions. The benefit is not that every concern becomes one concern. The benefit is that the team is less likely to silently run two incompatible versions of reality.

Hardhat 3 is also a reminder that framework architecture is not fixed. A monolithic runtime can adopt a faster execution core without giving up the workflow conventions that made it useful. For teams comparing Hardhat vs custom Web3 scripts, that is the central point: custom scripts should earn their maintenance cost. We do not write them merely to prove we can.

Foundry makes modularity feel fast because its pieces are usable alone

Foundry’s rise is partly a performance story, but performance is not the whole story. It is a composability story.

A medium-sized suite of roughly 50 tests can run in about 2–4 seconds in Foundry, compared with roughly 18–25 seconds in Hardhat in the cited comparison. Foundry compilation is also reported as up to five times faster in that context. Those numbers will vary with project structure, caching, hardware, compiler versions, and test design. Still, the direction is familiar to teams working on contracts all day: shorter runs change behavior.

When tests complete in a few seconds, we write smaller regression tests. We use fuzzing more freely. We stop batching ten unrelated changes before validation because rerunning the suite feels expensive. The difference is not only saved minutes. It is a different engineering rhythm.

Forge is particularly strong when the contract is the center of the work. Solidity-native tests can express access-control boundaries, token accounting, upgrade paths, storage collisions, reentrancy attempts, and invariant properties with less ceremony around the test itself. Cheatcodes make it practical to alter callers, balances, timestamps, block numbers, and fork state in controlled ways.

Anvil then brings a local node into the same workflow. We can fork a live network state, impersonate an address in a controlled test setting, inspect a failure, and hand the relevant transaction details to frontend teammates without asking them to recreate an entire remote environment.

Cast is where a lot of day-to-day friction disappears. A production incident may not need a new script or a dashboard click-through. We may need to decode calldata, query a mapping, estimate gas against a specific RPC endpoint, compare code at two addresses, or inspect an event topic. Direct EVM access from the terminal is not glamorous. It is often the shortest route from “the UI says this is broken” to “we know which state assumption failed.”

And Chisel is useful precisely because not every question deserves a repository branch. Testing an ABI encoding edge case, checking a type conversion, or trying a storage layout idea can happen in a small interactive loop.

Modular tools earn their keep when they shorten investigation, not when they make the setup diagram more impressive.

The modular stack needs explicit seams

Foundry is not an all-or-nothing replacement for Hardhat. We can use Forge for testing while retaining a TypeScript deployment flow. We can run Anvil locally while a team’s existing indexing pipeline continues to consume deployed contract events. We can use Cast for production debugging even if the main repository uses another framework.

This mixed approach is often the most honest one. It acknowledges the existing product instead of treating a tooling migration as a rewrite ritual.

But modularity introduces seams, and seams need owners. Before adopting a modular stack, let’s agree on a few concrete contracts inside the team:

1. Artifact ownership: Decide which tool produces the ABI, bytecode, source maps, and deployment metadata that the frontend and backend consume. Two artifact directories are manageable for a week and painful for a year.

2. Network definitions: Keep chain IDs, RPC endpoints, deployed addresses, and explorer settings in a source-controlled model with environment-specific overrides. A local Anvil fork and a staging L2 should not be inferred from somebody’s terminal history.

3. Stateful integration tests: Fast Solidity unit tests are not a substitute for user-journey tests. We still need to validate the path from wallet connection through transaction submission, receipt handling, indexer ingestion, and UI state sync.

4. Tool versioning: Pin compiler versions, Foundry versions, Node versions where relevant, and CI images. “Works on my machine” often means two developers are testing different EVM behavior.

5. Failure reproduction: Write down the command sequence for replaying a mainnet or L2 incident on a fork. The value of a modular stack is highest when another teammate can reproduce the diagnosis without us sitting beside them.

This is the unglamorous part. It is also the part that determines whether modular tooling feels liberating or fragile.

Architectural trade-offs: deployment speed, gas, and maintenance are different currencies

The phrase “monolithic versus modular” appears twice in a Web3 project. First, in the development environment. Then, in the contracts themselves.

These are related choices, but they should not be collapsed into one. A team can use Foundry while deploying a monolithic contract. Another can use Hardhat while operating a facet-based Diamond architecture. Tool architecture and contract architecture influence each other, but they solve different problems.

At the contract level, monolithic designs often have clear efficiency advantages. An empirical comparison of monolithic and modular smart contract architectures found monolithic contracts reduced transaction costs by 36.7% and deployment times by 75%. This aligns with the mechanics: a direct internal call inside one contract is cheaper and less operationally complex than routing execution through a proxy and delegatecalls across facets.

That matters. If an interaction happens frequently — swaps, claims, mints, votes, liquidation checks, or repeated account actions — an architectural abstraction can become a permanent cost paid by users. We should never wave that away as an implementation detail.

But a monolith has another boundary: the EVM contract size limit of 24KB. As logic accumulates, a contract can hit the limit before the product is finished. At that point, teams face choices that are all real engineering work: remove features, refactor libraries, move some logic off-chain, split contracts by domain, or adopt a proxy-based modular architecture.

The relevant comparison looks like this:

DimensionMonolithic contractFacet-based modular contract
Execution pathMore directProxy routing and delegatecall add overhead
DeploymentUsually faster and cheaperMore contracts and setup increase initial cost
Size constraintBound by the 24KB EVM contract limitLogic can be distributed across facets
UpgradesBroad upgrades can be harder to isolateFacets can be upgraded independently
Audit surfaceOne codebase, but potentially large and denseMore moving parts, selector and storage coordination
Long-term maintenanceStraightforward until size and coupling growBetter separation, but only with disciplined governance

The word “modular” can hide significant risks. Facets do not erase complexity; they make its boundaries explicit. Storage layout must remain compatible. Function selectors must map correctly. Upgrade authority must be guarded. Monitoring needs to identify not only a proxy address but the facet implementation currently handling each function.

For the frontend, this can introduce another class of friction. A user does not care whether an action passed through a Diamond proxy. They care whether their transaction status is accurate, whether the app shows the right error, and whether the feature they used yesterday still works after an upgrade. That means our integration layer must treat upgrade events and implementation changes as product-relevant state.

A fast test suite does not justify a gas-heavy architecture

There is a subtle trap here. Foundry can make a modular smart contract architecture easier to test. Hardhat 3 can make an integrated deployment flow easier to manage. Neither fact means our on-chain design should become more elaborate than the problem requires.

Let’s separate three decisions:

  • How do we build and test contracts?
  • How do we deploy, verify, monitor, and index them?
  • How do we divide execution logic on-chain?

When these are decided independently, teams tend to make calmer trade-offs. A compact contract can be tested with Forge. A Diamond can be deployed through a TypeScript-oriented application workflow. A production indexer can follow proxy upgrades regardless of which local runtime created the deployment artifact.

That separation is also good for graceful degradation. If our rich SDK layer is temporarily unavailable, can operations still query a contract through standard RPC calls and ABI artifacts? If the indexer is catching up, can the UI reconcile a wallet’s transaction receipt directly rather than presenting stale application state? Tool boundaries become safer when the user journey does not rely on every layer being healthy at once.

Diamonds and ERC-8153: modularity needs a better selector story

The Diamond Standard, EIP-2535, is one of the established answers to the 24KB contract-size constraint. It organizes business logic into separate implementation contracts, called facets, behind a shared proxy. The proxy routes function selectors to the appropriate facet, allowing the overall system to grow beyond the bytecode limit imposed on a single contract.

This is useful for large protocols with clearly separable domains: governance, token operations, marketplace execution, access management, settlement, and so on. It can also support targeted upgrades. Rather than redeploying or changing an entire large implementation, a team can replace one facet.

But EIP-2535 has a practical maintenance cost: selector management. Somebody needs to know which facet owns which selector, which selectors are added or removed in an upgrade, and whether the off-chain deployment tooling matches what is actually registered on-chain. That “somebody” is often an increasingly complicated script.

ERC-8153, proposed in February 2026, addresses this design pressure with facet-based Diamonds that move selector discovery on-chain. The proposal requires an exportSelectors() function, allowing a facet to declare its supported selectors rather than relying entirely on off-chain selector coordination.

The potential improvement is less about novelty and more about reducing mismatched sources of truth. If deployment tooling has one view of selector ownership and a facet has another, upgrades become a nerve-racking operation. On-chain export can create a more inspectable contract between the facet and the proxy-management workflow.

We should still treat a proposal as a proposal. Its exact adoption rate in production relative to EIP-2535 is not established. Teams choosing it need to evaluate ecosystem support, audit expectations, tooling maturity, and the migration path from existing Diamond implementations.

For a new protocol, the question is not “should we use Diamonds?” It is more specific:

  • Are we close enough to the 24KB limit that architectural change is unavoidable?
  • Do our domains have genuine upgrade independence, or are we splitting a tightly coupled monolith into pieces that will always change together?
  • Can we maintain storage discipline and selector governance over several years, not only through the first deployment?
  • Do the expected maintenance benefits outweigh higher deployment costs and execution overhead?
  • Can our client, indexer, and monitoring systems reliably understand proxy and facet changes?

If the answers are vague, a well-scoped monolith is often the safer starting point. We can preserve internal boundaries in the codebase, test them rigorously, and introduce an on-chain modular design when constraints make it necessary rather than fashionable.

Choosing a stack around the team’s actual bottleneck

A comparison of web3 development tools is only useful if it ends with a decision we can act on. Here is the pattern we see most often.

Choose an integrated Hardhat-centered setup when the product team is TypeScript-heavy, developers need a common project workflow, plugin-based integration is valuable, and the main risk is coordination across contracts, frontend code, deployment scripts, and application services. Hardhat 3’s Rust-powered runtime means this no longer has to imply accepting older performance assumptions.

Choose a Foundry-centered modular stack when contract iteration is the dominant loop, test speed is holding back disciplined validation, the team spends substantial time on forks and EVM-level debugging, or the protocol needs tools that can be adopted independently. Forge, Anvil, Cast, and Chisel are strong precisely because we can bring them into an existing stack one by one.

Choose a hybrid when the project already has a working TypeScript application workflow but the Solidity feedback loop is too slow. This is not indecision. It is often the cleanest migration path: introduce Forge for contract tests, Anvil for local and forked integration environments, and Cast for incident investigation. Keep the pieces that still serve the team.

And if we are considering a custom stack, let’s be strict with ourselves. Custom scripts are warranted when our deployment topology, chain support, security process, or operational model is truly outside the framework’s assumptions. They are not warranted because a framework has opinions. Every script we own becomes a future debugging session, a versioning responsibility, and a potential source of inconsistent artifacts.

The end user will never congratulate us for selecting a monolithic suite or a modular toolkit. They will notice something more basic: transactions fail less mysteriously, balances refresh when they should, network switches do not corrupt the session, and the app can explain what happened when a contract call reverts.

That is the standard worth optimizing for. Let’s choose the tools that leave us more time to build that experience — and fewer 25-second waits to discover that a fixture was stale.

FAQ

Should I choose Hardhat or Foundry for my project?
Choose Hardhat if your team is TypeScript-heavy and benefits from a unified environment for frontend and contract code. Choose Foundry if your primary bottleneck is contract iteration speed and you require deep, CLI-based EVM debugging tools.
Can I use both Hardhat and Foundry in the same project?
Yes, a hybrid approach is often effective. You can introduce Foundry tools like Forge for faster contract testing and Anvil for local forks while maintaining a Hardhat-based deployment and TypeScript workflow.
What are the main risks of using a modular development stack?
The primary risk is increased complexity in managing the 'seams' between tools. You must explicitly define ownership for artifacts, network configurations, and versioning to avoid inconsistent states across the team.
Are monolithic smart contracts always better than modular ones?
Monolithic contracts are generally more gas-efficient and simpler to deploy, but they are constrained by the 24KB EVM bytecode limit. Modular, facet-based architectures allow for larger systems but introduce overhead in proxy routing and storage management.
What is the benefit of Hardhat 3's new Rust-powered runtime?
The EDR (Ethereum Development Runtime) provides a more performant execution core, allowing teams to retain the convenience of an integrated framework while achieving faster test execution and better multichain support.

By Chloe Redfern