Smart contracts are self-executing programs that run on blockchain networks like Ethereum, enabling trustless automation of agreements and processes. In this comprehensive guide, you'll learn how to deploy and interact with smart contracts using Web3.js, one of the most widely used JavaScript libraries for Ethereum development.
We’ll walk through each step—from writing Solidity code to deploying your contract on a local development network and interacting with it programmatically. Whether you're building decentralized applications (dApps) or exploring blockchain development, mastering these fundamentals is essential.
Prerequisites for Smart Contract Development
Before diving into deployment, ensure your environment supports modern web3 development:
- Basic knowledge of JavaScript and Node.js
- Familiarity with command-line tools
- Node.js and npm installed (preferably the latest stable version)
You can verify your setup by running:
node -v
npm -vThese should return version numbers, confirming that both tools are correctly installed.
Setting Up Your Project Environment
Start by creating a dedicated project directory:
mkdir smart-contract-tutorial
cd smart-contract-tutorialInitialize a new Node.js project:
npm init -yThis generates a package.json file, which will manage your dependencies throughout the project.
👉 Learn how to securely manage blockchain interactions in real-world dApps.
Writing Your First Smart Contract in Solidity
Solidity is the most popular language for writing Ethereum smart contracts. Let’s create a simple contract that stores and updates a number.
Create a file named MyContract.sol and add the following code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract MyContract {
uint256 public myNumber;
constructor(uint256 _myNumber) {
myNumber = _myNumber;
}
function setMyNumber(uint256 _myNumber) public {
myNumber = _myNumber;
}
}This contract defines:
- A public state variable
myNumber - A constructor to initialize it
- A function to update its value
The public keyword automatically generates a getter function, allowing external access to myNumber.
Compiling the Contract: Generating ABI and Bytecode
To deploy a smart contract, you need two outputs from the compiler:
- ABI (Application Binary Interface): A JSON interface describing the contract’s methods
- Bytecode: The compiled machine-level code to be deployed on-chain
Install the Solidity compiler via npm:
npm install solcThen, create a compile.js script:
const solc = require('solc');
const path = require('path');
const fs = require('fs');
const contractName = 'MyContract';
const fileName = `${contractName}.sol`;
const contractPath = path.join(__dirname, fileName);
const sourceCode = fs.readFileSync(contractPath, 'utf8');
const input = {
language: 'Solidity',
sources: {
[fileName]: { content: sourceCode },
},
settings: {
outputSelection: {
'*': { '*': ['*'] },
},
},
};
const compiledCode = JSON.parse(solc.compile(JSON.stringify(input)));
const bytecode = compiledCode.contracts[fileName][contractName].evm.bytecode.object;
const abi = compiledCode.contracts[fileName][contractName].abi;
fs.writeFileSync(path.join(__dirname, 'MyContractBytecode.bin'), bytecode);
fs.writeFileSync(path.join(__dirname, 'MyContractAbi.json'), JSON.stringify(abi, null, '\t'));
console.log('Contract ABI:\n', abi);
console.log('Contract Bytecode:\n', bytecode);Run the script:
node compile.jsYou’ll see two new files: MyContractAbi.json and MyContractBytecode.bin.
Configuring Web3.js and Hardhat Development Network
Now set up the development environment using Hardhat, a powerful Ethereum development tool.
Install Hardhat and Web3.js:
npm install --save-dev hardhat
npm install web3Initialize Hardhat:
npx hardhatSelect default options. Then start the local network:
npx hardhat nodeThis launches a local blockchain with pre-funded test accounts at http://127.0.0.1:8545.
In a new terminal, create index.js to test connectivity:
const { Web3 } = require('web3');
const web3 = new Web3('http://127.0.0.1:8545/');
web3.eth.getChainId()
.then(id => console.log('Connected to Chain ID:', id))
.catch(console.error);Run it with:
node index.jsA successful connection confirms your environment is ready.
👉 Discover advanced tools for testing and deploying contracts securely.
Deploying the Smart Contract with Web3.js
Create deploy.js to deploy your contract:
const { Web3 } = require('web3');
const fs = require('fs');
const path = require('path');
const web3 = new Web3('http://127.0.0.1:8545/');
const bytecode = fs.readFileSync(path.join(__dirname, 'MyContractBytecode.bin'), 'utf8');
const abi = require('./MyContractAbi.json');
const myContract = new web3.eth.Contract(abi);
myContract.handleRevert = true;
async function deploy() {
const accounts = await web3.eth.getAccounts();
const deployer = accounts[0];
console.log('Deploying from account:', deployer);
const deployTx = myContract.deploy({
data: '0x' + bytecode,
arguments: [1]
});
const gas = await deployTx.estimateGas({ from: deployer });
console.log('Estimated gas:', gas);
try {
const receipt = await deployTx.send({
from: deployer,
gas,
gasPrice: '10000000000'
});
console.log('Contract deployed at:', receipt.options.address);
fs.writeFileSync('MyContractAddress.txt', receipt.options.address);
} catch (error) {
console.error('Deployment failed:', error);
}
}
deploy();Run:
node deploy.jsOn success, you’ll get a contract address saved in MyContractAddress.txt.
Interacting with the Deployed Smart Contract
Now use Web3.js to read and modify data on-chain.
Create interact.js:
const { Web3 } = require('web3');
const fs = require('fs');
const path = require('path');
const web3 = new Web3('http://127.0.0.1:8545/');
const address = fs.readFileSync(path.join(__dirname, 'MyContractAddress.txt'), 'utf8');
const abi = require('./MyContractAbi.json');
const contract = new web3.eth.Contract(abi, address);
contract.handleRevert = true;
async function interact() {
const account = (await web3.eth.getAccounts())[0];
// Read current value
let value = await contract.methods.myNumber().call();
console.log('Current value:', value.toString());
// Update value
const receipt = await contract.methods.setMyNumber(Number(value) + 1).send({
from: account,
gas: 100000,
gasPrice: '10000000000'
});
console.log('Transaction hash:', receipt.transactionHash);
// Read updated value
value = await contract.methods.myNumber().call();
console.log('Updated value:', value.toString());
}
interact();Execute:
node interact.jsYou’ll see output like:
Current value: 1
Transaction hash: 0x...
Updated value: 2Frequently Asked Questions
Q: What is an ABI in smart contracts?
A: The ABI (Application Binary Interface) is a JSON description of a contract’s functions and events. It allows Web3.js to encode and decode data when calling contract methods.
Q: Why do I need bytecode to deploy a contract?
A: Bytecode is the compiled version of your Solidity code that the Ethereum Virtual Machine (EVM) executes. Without it, the network cannot run your logic.
Q: Can I deploy to mainnet using this method?
A: Yes—just change the provider URL and use a wallet with real ETH. Always test on testnets first.
Q: What is gas estimation and why is it important?
A: Gas estimation predicts how much computational effort a transaction requires. Accurate estimates prevent failed transactions due to insufficient gas.
Q: Is Web3.js still relevant with newer alternatives?
A: Absolutely. While libraries like Ethers.js are growing in popularity, Web3.js remains widely used, well-documented, and ideal for Node.js environments.
👉 Access real-time blockchain data and build powerful dApps today.
Core Keywords
- Smart contracts
- Web3.js
- Ethereum
- Solidity
- ABI
- Bytecode
- Hardhat
- Deploy smart contract
By following this guide, you’ve gained hands-on experience in writing, compiling, deploying, and interacting with smart contracts using industry-standard tools. This foundation empowers you to build full-featured decentralized applications on Ethereum.
Remember to always test thoroughly on development networks before going live—and keep learning as the ecosystem evolves.