Build and deploy your first dApp on Base in under 60 minutes

Share This Post

Building Your First Base dApp – Deploy, Verify, and Ship in 60 Minutes

What You’ll Achieve

By the end, you’ll bridge ETH to Base, deploy and verify a smart contract on Base mainnet, and ship a minimal web UI that reads and writes on-chain.

Why This Matters

Base is an Ethereum Layer 2 built for speed, scale, and low fees. In 2025, it grew to process over 53% of all L2 transactions while keeping median fees under $0.05. “Flashblocks reduced block confirmation times from 2 seconds to 200 milliseconds,” enabling near-instant UX. With TVL surging past $4B and 18.5M active addresses, deploying on Base puts your app where users already are-and where blockspace is expanding to 250 Mgas/s by year-end.

Prerequisites

  • Wallet: MetaMask (or Coinbase Wallet). You’ll add Base mainnet manually.
  • Gas: At least 0.01 ETH on Base for deployments and a few interactions.
  • Tools: Node.js 18+, Git, and either Foundry (recommended) or Hardhat.
  • Explorer/API: BaseScan account and API key for contract verification.
  • Concepts: Basic EVM familiarity (ABI, gas, nonces), and comfort with a terminal.

Base network details you’ll use:

Useful real contracts on Base (for reference/testing):

Step-by-Step Process

1) Add Base to your wallet and fund gas

  • MetaMask → Settings → Networks → Add network, then enter:
    • Network name: Base
    • RPC: https://mainnet.base.org
    • Chain ID: 8453
    • Currency symbol: ETH
    • Block explorer: https://basescan.org
  • Fund Base ETH:
    • Fastest: Use Base official bridge. Deposit ETH from Ethereum mainnet. Deposits confirm on Base in ~2-5 minutes; L1 fee applies once.
    • Alternate: Withdraw directly to Base from Coinbase or an exchange that supports Base network.
Screenshot: MetaMask Add Base network form
MetaMask network config for Base

Cost: Expect <$2 for the initial L1 bridge deposit (varies by Ethereum gas), then <$0.05 per transaction on Base.

2) Initialize a project with Foundry

  • Install Foundry: curl -L https://foundry.paradigm.xyz | bash && foundryup
  • Scaffold: forge init base-counter && cd base-counter
  • Create .env in project root with:
    • PRIVATE_KEY=0xYOUR_PRIVATE_KEY (use a dedicated deployer wallet)
    • BASE_RPC=https://mainnet.base.org
    • ETHERSCAN_API_KEY=YOUR_BASESCAN_API_KEY

Add a simple contract at src/Counter.sol:

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

contract Counter {
uint256 public count;

event Increment(address indexed caller, uint256 newCount);

function increment() external {
unchecked { count++; }
emit Increment(msg.sender, count);
}
}

Compile: forge build. If you use optimizer settings, add to foundry.toml: optimizer = true, optimizer_runs = 200.

3) Deploy to Base mainnet

  • Ensure your deployer wallet is selected in MetaMask and funded on Base.
  • Deploy with Foundry:
    • forge create src/Counter.sol:Counter --rpc-url $BASE_RPC --private-key $PRIVATE_KEY

Note the returned contract address and open it on BaseScan to confirm: https://basescan.org/address/0xYOUR_CONTRACT.

Gas and timing: Deployment should finalize on Base in under 1 second at the UX layer thanks to Flashblocks; BaseScan indexing may take ~10-60 seconds to display details. Expect ~$0.01-$0.03 in L2 gas for this contract (varies with congestion).

4) Verify your contract on BaseScan

  • Get an API key at: basescan.org/myapikey
  • Verify via Foundry:
    • forge verify-contract --chain 8453 --watch 0xYOUR_CONTRACT src/Counter.sol:Counter $ETHERSCAN_API_KEY
  • Alternatively, use BaseScan’s UI: Contract → Code → Verify & Publish. Match compiler version (e.g., 0.8.24) and optimizer runs.
Screenshot: BaseScan verify contract form
Verifying your contract on BaseScan

If verification fails, ensure your compiler version and optimizer settings match your build, and that evmVersion isn’t mismatched.

5) Build a minimal web UI (read/write)

  • Scaffold a Next.js app: npx create-next-app@latest base-ui
  • Install ethers: cd base-ui && npm i ethers
  • Create lib/abi.js with your ABI:
    • export const COUNTER_ABI = [
      { "inputs": [], "name": "count", "outputs": [{"internalType":"uint256","name":"","type":"uint256"}], "stateMutability":"view","type":"function" },
      { "inputs": [], "name": "increment", "outputs": [], "stateMutability":"nonpayable","type":"function" }
      ];
  • Edit pages/index.js to connect, read, and increment:

import { useEffect, useState } from "react";
import { ethers } from "ethers";
import { COUNTER_ABI } from "../lib/abi";

const CONTRACT = "0xYOUR_CONTRACT";
const BASE_ID = 8453;

export default function Home() {
const [account, setAccount] = useState("");
const [count, setCount] = useState(0);
const [provider, setProvider] = useState();
const [contract, setContract] = useState();

async function connect() {
if (!window.ethereum) return alert("Install MetaMask");
const p = new ethers.BrowserProvider(window.ethereum);
const net = await p.getNetwork();
if (Number(net.chainId) !== BASE_ID) {
await window.ethereum.request({
method: "wallet_switchEthereumChain",
params: [{ chainId: "0x2105" }], // 8453 in hex
});
}
const s = await p.getSigner();
setAccount(await s.getAddress());
const c = new ethers.Contract(CONTRACT, COUNTER_ABI, s);
setProvider(p);
setContract(c);
}

async function refresh() {
if (!contract) return;
setCount(Number(await contract.count()));
}

async function increment() {
const tx = await contract.increment();
await tx.wait(); // near-instant on Base; UX updates ~<1s
refresh();
}

useEffect(() => {
if (contract) refresh();
}, [contract]);

return (
<main style={{ padding: 24 }}>
<h1>Base Counter</h1>
<button onClick={connect}>{account ? "Connected" : "Connect"}</button>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</main>
);
}

Screenshot: Minimal Base dApp UI with connect and increment buttons
Minimal UI: connect, read, write

Run locally: npm run dev. Open http://localhost:3000 and connect. Each increment() costs a few cents or less and confirms in ~200 ms from a UX standpoint.

6) Measure and confirm

  • Open your transaction on BaseScan from MetaMask’s activity feed to see exact gas used and USD cost.
  • Expect L2 gas for increment() around 21k–45k units. With typical L2 gas prices, fees are often $0.005–$0.03.
  • Batch throughput: Base regularly sustains high TPS and can exceed 1,500+ TPS during peaks, thanks to 50 Mgas/s capacity and Flashblocks. Plan your UX for rapid confirmations and low polling intervals.

Common Issues

  • Transaction stuck pending?
    • In MetaMask, use Speed up to resubmit with a higher fee. Ensure you’re on chain ID 8453.
    • If pending for >2 minutes, check status.base.org and that your RPC is https://mainnet.base.org. Consider switching to a hosted RPC (Alchemy, Infura) for WebSocket updates.
  • Bridge deposit taking long?
    • Deposits usually arrive on Base within ~2–5 minutes. If Ethereum is congested, it may take longer. Track your deposit tx on Etherscan and the corresponding L2 message on BaseScan.
    • Withdrawals via the official bridge take ~7 days (Optimistic challenge period). For faster exits, use a reputable third-party bridge/liquidity network, weighing trust and slippage.
  • Verification failed on BaseScan?
    • Use the exact compiler version (e.g., 0.8.24) and optimizer runs from your build. Mismatches cause failure.
    • If using libraries or proxies, supply constructor args and linked libraries. Foundry’s --watch helps.
  • “Insufficient liquidity” on DEX or swaps?
    • For tokens like USDC on Base, confirm the real address: USDC 0x8335…2913. If a token isn’t liquid, use ETH or USDC as routing assets.
  • Wrong network or chain ID?
    • Base mainnet is 8453. In code, ensure wallet_switchEthereumChain targets 0x2105.

Pro Tips

  • Gas optimization
    • Enable Solidity optimizer (200–400 runs) and pack storage to reduce L2 gas usage.
    • Batch calls via multicall where possible to amortize overhead.
  • UX for Flashblocks
    • Use WebSocket providers to react to ~200 ms block confirmations. Optimistically update UI after tx.hash, then reconcile on tx.wait().
  • Best time to transact
    • Off-peak UTC hours (03:00–07:00) often show the lowest fees. Base’s fee market stays stable even during spikes but timing still helps.
  • Funding paths
    • For teams, consider direct Base withdrawals from Coinbase for operational accounts to avoid L1 bridging costs.
  • Security workflow
    • Simulate transactions with Tenderly or Foundry’s forge script --dry-run. Use OpenZeppelin implementations where possible and run unit/invariant tests before mainnet.
  • Observability
    • Emit events (like Increment) and index them in a subgraph (The Graph supports Base) for fast UI state.

What’s Next

  • Productionize: Add role-based access, pause guards, and upgrade patterns (if truly needed) with transparent proxies.
  • Indexing: Create a subgraph for your events and denormalized views.
  • Frontend polish: Migrate to wagmi/viem and RainbowKit for robust wallet UX on Base.
  • CI/CD: Add automated tests, static analysis (Slither), gas snapshots, and deploy scripts with environment gates.
  • Integrations: Connect to Base-native DeFi (e.g., swap via a DEX) using real tokens like USDC 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 and WETH 0x4200...0006.
  • Scale strategy: As Base scales from 50 to 250 Mgas/s, design for higher throughput-shard state by account, minimize hot storage slots, and prefer pull-based payout patterns.

You’ve deployed, verified, and shipped a working Base dApp. From here, focus on product-market fit, robust testing, and composability with the growing Base ecosystem—where fees are low, confirmation is near-instant, and users are already active.

Reference Links

Note: Base is currently evolving its decentralization stage and fee market. Always review current docs and status pages before deploying critical systems.

Related Posts

Securely store and manage your crypto on Base: custody, bridging, and multisig in 30 minutes

What You’ll Achieve Set up a secure, operationally sound workflow to store and manage your cryptocurrency on Base: add the Base network to your...

Secure Your First Transactions on Base: A Beginner’s Blockchain Security Playbook

Secure Your First Transactions on Base: A Beginner’s Blockchain Security Playbook What You’ll Achieve In 30 minutes, you’ll securely set up Base,...

Secure Your Crypto on Base: A Step-by-Step Wallet Safety Playbook

What You’ll Achieve Lock down your assets on Base with a concrete, repeatable workflow: set up a hardened wallet, bridge safely, minimize token...

Set up and secure your first crypto wallet on Base (step-by-step)

The Ultimate Beginner’s Guide to Setting Up and Securing Your Crypto Wallet on Base Estimated time: 15-30 minutes • Difficulty: Beginner • Works with...

Onboard to Base: Bridge ETH, Set Up Your Wallet, Claim a Basename, and Make Your First Swap

What You’ll Achieve In 20-40 minutes, you’ll add the Base network to your wallet, bridge ETH to Base, claim a Basename, and complete your first

Set Up a Secure Crypto Wallet Stack on Base (Hot + Hardware + Multisig)

What You’ll Achieve: You’ll set up a secure, beginner-friendly wallet stack on Base-hot wallet for daily use, hardware wallet for cold storage, and...