Trusted Certifications for 10 Years | Flat 25% OFF | Code: GROWTH
Blockchain Council
blockchain6 min read

How to Build and Deploy a Smart Contract: End-to-End Guide Using Hardhat, Foundry, and Remix

Suyash RaizadaSuyash Raizada
How to Build and Deploy a Smart Contract: End-to-End Guide Using Hardhat, Foundry, and Remix

How to build and deploy a smart contract in 2026 typically means choosing a primary framework (Hardhat or Foundry), adopting modern testing practices including fuzzing, and verifying contracts with reproducible builds. In the EVM ecosystem, Hardhat, Foundry, and Remix have become the most common tools in professional workflows because they cover the full lifecycle: development, testing, deployment, interaction, and verification.

This end-to-end guide walks through a practical workflow using all three: Hardhat for TypeScript scripting and plugin-rich automation, Foundry for fast tests and security-focused tooling, and Remix for quick deployments and hands-on debugging via a wallet.

Certified Blockchain Expert strip

Why These Three Tools Dominate Smart Contract Development

Protocol documentation and developer portals across EVM networks - including L1s and L2s - increasingly treat these toolchains as first-class options. Common reasons include:

  • Hardhat: a Node.js framework with TypeScript support, a large plugin ecosystem, and built-in local networks and forking for realistic testing.

  • Foundry: a fast Rust-based suite (Forge, Cast, Anvil) known for fuzz testing, invariant testing, and gas insights favored in security and audit workflows.

  • Remix IDE: a browser-based IDE that minimizes setup, connects to MetaMask for deployments, and supports verification workflows using Standard JSON input on many explorers.

Many teams combine all three: write contracts once, run deep tests in Foundry, deploy and verify through Hardhat or Foundry scripts, then use Remix as an interactive interface connected to a local node (Hardhat Network or Anvil) for debugging and demonstrations.

Hardhat Workflow: Develop, Deploy, and Verify with TypeScript

Hardhat is a practical choice when teams need a JavaScript or TypeScript automation layer for deployments, verification, and integrations. It is also widely referenced in structured tutorials and first-party chain documentation.

1) Initialize a Hardhat Project

Create a project directory and initialize Hardhat:

Commands:

  • mkdir hardhat-erc-721-mint

  • cd hardhat-erc-721-mint

  • npx hardhat --init

Selecting a TypeScript template is recommended in professional setups because it improves script maintainability and integrates well with modern backend tooling.

2) Install Dependencies (OpenZeppelin and Verification)

Install standardized libraries and verification support:

  • npm install @openzeppelin/contracts

  • npm install --save-dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-verify

3) Write a Contract (Example: ERC-721 Mint)

Create contracts/MyNFT.sol:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract MyNFT is ERC721, Ownable {
    uint256 private _tokenIdCounter;

    constructor(address initialOwner)
        ERC721("MyNFT", "MNFT")
        Ownable(initialOwner)
    {}

    function safeMint(address to) public onlyOwner {
        _tokenIdCounter += 1;
        _safeMint(to, _tokenIdCounter);
    }
}

4) Compile

Compile the contract with Hardhat:

  • npx hardhat build

5) Deploy with a Script

Create scripts/deploy.ts:

import { ethers } from "hardhat";

async function main() {
  const [deployer] = await ethers.getSigners();
  console.log("Deploying with:", deployer.address);

  const MyNFT = await ethers.getContractFactory("MyNFT");
  const myNft = await MyNFT.deploy(deployer.address);
  await myNft.waitForDeployment();

  console.log("MyNFT deployed to:", await myNft.getAddress());
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

Deploy to a configured network:

  • npx hardhat run scripts/deploy.ts --network testnet

6) Verify the Contract (Sourcify or Explorer APIs)

Verification is a best practice for transparency, user trust, and audit readiness. Hardhat uses @nomicfoundation/hardhat-verify and supports Sourcify verification where available.

Typical verification command:

  • npx hardhat verify --network testnet <CONTRACT_ADDRESS> <initialOwner_arg>

Tip: Ensure your compiler version, optimizer settings, and constructor arguments match exactly. Most verification failures stem from mismatches in these parameters rather than differences in contract code.

Foundry Workflow: Fast Tests, Fuzzing, and CLI Deployments

Foundry is widely adopted for its speed and depth in testing. Security-focused teams often prioritize Foundry because it makes fuzzing, invariant testing, and gas measurement straightforward through a developer-first CLI.

1) Initialize a Foundry Project

  • forge init my-foundry-project

  • cd my-foundry-project

2) Add Dependencies (OpenZeppelin)

  • forge install OpenZeppelin/openzeppelin-contracts

3) Configure foundry.toml (Optimizer Settings)

A minimal configuration includes optimizer settings for production-like bytecode:

[default]
src = "src"
out = "out"
libs = ["lib"]
optimizer = true
optimizer_runs = 200

4) Write a Contract and Tests (Including Fuzzing)

Create src/MyStorage.sol:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract MyStorage {
    uint256 private value;

    function store(uint256 newValue) public {
        value = newValue;
    }

    function retrieve() public view returns (uint256) {
        return value;
    }
}

Create test/MyStorage.t.sol using forge-std:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "forge-std/Test.sol";
import "../src/MyStorage.sol";

contract MyStorageTest is Test {
    MyStorage store;

    function setUp() public {
        store = new MyStorage();
    }

    function testStoreAndRetrieve() public {
        store.store(42);
        assertEq(store.retrieve(), 42);
    }

    function testFuzzStore(uint256 x) public {
        store.store(x);
        assertEq(store.retrieve(), x);
    }
}

Run tests with verbose logs and gas reporting:

  • forge test -vvv --gas-report

5) Deploy with Anvil and forge create

Start a local node:

  • anvil

Deploy to a local RPC:

  • forge create src/MyStorage.sol:MyStorage --rpc-url http://127.0.0.1:8545 --private-key <PRIVATE_KEY>

Deploy to a public testnet with verification:

  • forge create src/MyStorage.sol:MyStorage --rpc-url $RPC_URL --private-key $PRIVATE_KEY --verify --verifier etherscan --etherscan-api-key $ETHERSCAN_KEY

Remix Workflow: Deploy and Interact Quickly with MetaMask

Remix is a practical choice for prototyping, education, and manual operations. It also works well as a debugging front-end connected to a local chain running Hardhat Network or Anvil.

1) Create and Compile in the Browser

Open Remix at remix.ethereum.org, create Storage.sol, and compile using the Solidity compiler panel:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract Storage {
    uint256 public num;

    function set(uint256 _num) public {
        num = _num;
    }
}

2) Deploy Using Injected Provider (MetaMask)

  • In Deploy & run transactions, set Environment to Injected Provider - MetaMask.

  • Confirm the connection in MetaMask and ensure the correct network is selected.

  • Click Deploy and confirm the transaction.

3) Verify Using Standard JSON Input (Common Explorer Pattern)

A reproducible verification flow on many networks uses Remix build artifacts:

  1. In Remix, locate artifacts/build-info and open the relevant JSON file.

  2. Copy the value of the input field and save it locally as standard-json-input.json.

  3. In the block explorer, choose Verify Contract and select Standard JSON Input.

  4. Upload the JSON, then match the contract name and compiler version exactly.

Putting It Together: A Practical Multi-Tool Playbook

For an end-to-end workflow that scales from prototypes to production, a common approach is:

  • Source of truth: keep contracts in a repository that compiles under both Hardhat and Foundry, as many teams maintain support for both.

  • Testing: run Foundry tests in CI for fast feedback, fuzzing, and gas snapshots.

  • Deployment and ops: use Hardhat TypeScript scripts for repeatable deployments and plugin-driven tasks like verification.

  • Debugging and demos: connect Remix to a local Hardhat node (npx hardhat node) or Anvil and use MetaMask for interactive transaction inspection.

Checklist for Production-Grade Deployments

  • Lock compiler settings: keep Solidity version, optimizer enabled, and optimizer runs consistent across all environments.

  • Automate verification: include verification steps in deployment scripts using Hardhat verify or Foundry --verify.

  • Use multiple test styles: combine unit tests with fuzzing and invariant tests for stateful systems.

  • Secure key handling: store private keys and RPC credentials in environment variables and use separate deployer accounts per environment.

Conclusion

Building and deploying a smart contract today is less about picking a single tool and more about designing a workflow that is reliable, testable, and verifiable. Hardhat remains a strong default for TypeScript-driven deployments and plugin automation. Foundry is a leading choice for high-signal testing, fuzzing, and gas analysis. Remix continues to be the simplest way to compile, deploy, and interact with contracts through a wallet - particularly when paired with a local Hardhat or Anvil node.

For professionals and teams, the strongest results typically come from a hybrid setup: Hardhat for scripting and integrations, Foundry for deep testing, and Remix for interactive debugging. This toolchain aligns with current industry practices emphasizing reproducible builds and verification-first deployments across EVM networks.

Related Articles

View All

Trending Articles

View All