← All guides
beginner May 16, 2026

Deploy your first smart contract on Sepolia with Foundry

Step-by-step guide to writing, testing and deploying a Solidity smart contract to Ethereum Sepolia using Foundry — the fastest dev toolchain in 2026.


Foundry has become the standard toolchain for Solidity development. It is faster than Hardhat, runs tests in Solidity instead of JavaScript, and has first-class support for forking and fuzzing.

Prerequisites

  • Basic Solidity knowledge
  • Sepolia ETH in your wallet — see the How to get Sepolia ETH guide
  • A wallet private key for deployment (use a dedicated dev wallet, never your mainnet key)

1. Install Foundry

curl -L https://foundry.paradigm.xyz | bash
foundryup

Verify the installation:

forge --version
cast --version

2. Create a new project

forge init hello-sepolia
cd hello-sepolia

Foundry creates the following structure:

hello-sepolia/
├── src/
│   └── Counter.sol       # sample contract
├── test/
│   └── Counter.t.sol     # sample test
├── script/
│   └── Counter.s.sol     # deployment script
└── foundry.toml

3. Write the contract

Replace src/Counter.sol with a simple storage contract:

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

contract HelloSepolia {
    string public message;
    address public owner;

    event MessageUpdated(string newMessage, address updatedBy);

    constructor(string memory _message) {
        message = _message;
        owner = msg.sender;
    }

    function setMessage(string calldata _message) external {
        message = _message;
        emit MessageUpdated(_message, msg.sender);
    }
}

4. Write a test

Replace test/Counter.t.sol:

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

import {Test} from "forge-std/Test.sol";
import {HelloSepolia} from "../src/HelloSepolia.sol";

contract HelloSepoliaTest is Test {
    HelloSepolia public hello;

    function setUp() public {
        hello = new HelloSepolia("Hello, testnet!");
    }

    function test_InitialMessage() public view {
        assertEq(hello.message(), "Hello, testnet!");
    }

    function test_SetMessage() public {
        hello.setMessage("Updated");
        assertEq(hello.message(), "Updated");
    }

    function test_OwnerIsDeployer() public view {
        assertEq(hello.owner(), address(this));
    }
}

Run the tests:

forge test -vv

5. Configure the network

Create a .env file (never commit this):

SEPOLIA_RPC_URL=https://rpc.sepolia.org
PRIVATE_KEY=0xYOUR_DEV_WALLET_PRIVATE_KEY
ETHERSCAN_API_KEY=YOUR_ETHERSCAN_API_KEY

Add to foundry.toml:

[profile.default]
src = "src"
out = "out"
libs = ["lib"]

[rpc_endpoints]
sepolia = "${SEPOLIA_RPC_URL}"

[etherscan]
sepolia = { key = "${ETHERSCAN_API_KEY}", url = "https://api-sepolia.etherscan.io/api" }

6. Write the deployment script

Replace script/Counter.s.sol with script/Deploy.s.sol:

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

import {Script} from "forge-std/Script.sol";
import {HelloSepolia} from "../src/HelloSepolia.sol";

contract Deploy is Script {
    function run() external returns (HelloSepolia) {
        vm.startBroadcast();
        HelloSepolia hello = new HelloSepolia("Hello from Sepolia!");
        vm.stopBroadcast();
        return hello;
    }
}

7. Deploy

Load environment variables and deploy:

source .env

forge script script/Deploy.s.sol \
  --rpc-url sepolia \
  --private-key $PRIVATE_KEY \
  --broadcast \
  --verify

The --verify flag automatically verifies the contract on Sepolia Etherscan.

8. Verify the deployment

cast call <DEPLOYED_ADDRESS> "message()(string)" --rpc-url sepolia

Or visit sepolia.etherscan.io/address/<DEPLOYED_ADDRESS> and interact via the Read Contract tab.

Send a transaction

cast send <DEPLOYED_ADDRESS> \
  "setMessage(string)" "Hello from CLI!" \
  --private-key $PRIVATE_KEY \
  --rpc-url sepolia

Common errors

Error Cause Fix
insufficient funds Not enough Sepolia ETH Get ETH from a faucet
nonce too low Pending transaction Wait or reset nonce with cast nonce
execution reverted Contract logic error Check the revert reason with cast run <txhash>