The rise of non-fungible tokens (NFTs) has transformed digital ownership, empowering creators to tokenize art, collectibles, and more on the blockchain. Whether you're an artist, developer, or enthusiast, learning how to write, deploy, and mint your own NFT opens doors to innovation and monetization in the Web3 space. This comprehensive guide walks you through every step—from setting up your development environment to viewing your freshly minted NFT in MetaMask—using industry-standard tools like Solidity, Hardhat, Alchemy, and IPFS.
By the end of this tutorial, you’ll have deployed an ERC721 smart contract on the Ropsten test network and minted your first NFT using real blockchain interactions—all without spending a single dollar in real ETH.
Core Keywords
- NFT
- ERC721
- Smart Contract
- Ethereum
- Mint NFT
- Blockchain Development
- Web3
- IPFS
These keywords naturally align with search intent for developers and creators exploring how to enter the NFT ecosystem. They are seamlessly integrated throughout the content to enhance SEO performance while maintaining readability.
Setting Up Your Development Environment
Before writing any code, you need a solid foundation. This section covers setting up essential tools: Alchemy for API access, MetaMask for wallet management, and Hardhat for local development.
Step 1: Connect to the Ethereum Network via Alchemy
To interact with Ethereum without running your own node, we’ll use Alchemy, a powerful blockchain development platform offering reliable APIs and real-time monitoring. Alchemy supports major NFT platforms like OpenSea, Dapper Labs, and MakersPlace—making it a trusted choice for serious developers.
👉 Get started with Alchemy today and unlock advanced blockchain analytics.
Sign up for a free Alchemy account at alchemy.com. Once registered, you can generate API keys to communicate with Ethereum testnets like Ropsten.
Step 2: Create Your Application and API Key
After signing in:
- Hover over "Apps" in the navigation bar and click Create App.
- Name your app (e.g., “MyNFT”), add a description, select Staging under Environment, and choose Ropsten as the network.
- Click Create App.
Your new app will appear in the dashboard with an associated HTTP API endpoint—this is what your code will use to send requests to the Ethereum blockchain.
Step 3: Set Up MetaMask Wallet
MetaMask is a browser extension and mobile app that acts as an Ethereum wallet. It allows you to manage accounts, sign transactions, and connect to decentralized applications (dApps).
Download MetaMask from metamask.io and create a new wallet. After setup, switch the network to Ropsten Test Network in the top-right corner to avoid using real funds during testing.
Step 4: Get Test ETH from a Faucet
Since we’re deploying on the Ropsten testnet, you’ll need fake ETH. Visit the FaucETH website, enter your MetaMask public address, select Ethereum Testnet Ropsten, and request funds. Within seconds, test ETH should appear in your wallet.
Step 5: Verify Your Balance Using Alchemy
To confirm receipt of test ETH, use Alchemy’s Composer Tool to send an eth_getBalance request:
- Go to composer.alchemyapi.io.
- Select
eth_getBalance. - Enter your MetaMask address and execute.
The response returns balance in Wei (1 ETH = 10¹⁸ Wei). For example:
{"jsonrpc": "2.0", "id": 0, "result": "0xde0b6b3a7640000"}Convert 0xde0b6b3a7640000 to decimal: it equals 1×10¹⁸ Wei → 1 ETH.
You're now ready to start coding!
Writing and Deploying Your NFT Smart Contract
With tools configured, let’s write a secure ERC721-compliant smart contract using Solidity and deploy it with Hardhat.
Step 6: Initialize Your Project
Open your terminal and run:
mkdir my-nft
cd my-nft
npm init -yThis creates a package.json file to manage dependencies.
Step 7: Install Hardhat
Hardhat is a development environment for compiling, testing, and deploying Ethereum software:
npm install --save-dev hardhatThen initialize Hardhat:
npx hardhatChoose Create an empty hardhat.config.js.
Step 8: Organize Project Structure
Create two folders:
mkdir contracts scriptscontracts/: Store.solfiles.scripts/: Hold deployment and interaction scripts.
Step 9: Write the NFT Smart Contract
In contracts/MyNFT.sol, paste the following Solidity code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
contract MyNFT is ERC721URIStorage, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
constructor() ERC721("MyNFT", "NFT") {}
function mintNFT(address recipient, string memory tokenURI)
public
onlyOwner
returns (uint256)
{
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(recipient, newItemId);
_setTokenURI(newItemId, tokenURI);
return newItemId;
}
}Install OpenZeppelin contracts:
npm install @openzeppelin/contractsUnderstanding the Code
- ERC721: Standard interface for NFTs; ensures compatibility across marketplaces.
- Counters: Tracks total supply and assigns unique IDs.
- Ownable: Restricts
mintNFTto the contract owner (you). - tokenURI: Points to JSON metadata stored off-chain (e.g., via IPFS).
Configuring and Deploying the Contract
Step 10: Securely Store Secrets with .env
Install dotenv:
npm install dotenv --saveCreate .env in the root:
API_URL="https://eth-ropsten.alchemyapi.io/v2/your-api-key"
PRIVATE_KEY="your-metamask-private-key"
PUBLIC_KEY="your-metamask-public-address"⚠️ Never commit .env to version control. Add it to .gitignore.
Step 11: Install Ethers.js
Ethers.js simplifies Ethereum interactions:
npm install --save-dev @nomiclabs/hardhat-ethers ethers@^5.0.0Update hardhat.config.js:
require('dotenv').config();
require("@nomiclabs/hardhat-ethers");
const { API_URL, PRIVATE_KEY } = process.env;
module.exports = {
solidity: "0.8.1",
defaultNetwork: "ropsten",
networks: {
hardhat: {},
ropsten: {
url: API_URL,
accounts: [`0x${PRIVATE_KEY}`]
}
},
};Step 12: Compile and Deploy
Compile the contract:
npx hardhat compileCreate scripts/deploy.js:
async function main() {
const MyNFT = await ethers.getContractFactory("MyNFT");
const myNFT = await MyNFT.deploy();
await myNFT.deployed();
console.log("Contract deployed to address:", myNFT.address);
}
main().catch((error) => {
console.error(error);
process.exit(1);
});Deploy:
npx hardhat --network ropsten run scripts/deploy.jsYou’ll see output like:
Contract deployed to address: 0x81c587EB0fE773404c42c1d2666b5f557C470eEDVerify deployment on Ropsten Etherscan by searching the address.
Minting Your First NFT
Now that your contract is live, let’s mint an NFT with custom metadata.
Step 13: Use IPFS for Decentralized Metadata
NFTs rely on metadata (name, image, attributes) typically stored off-chain. We’ll use Pinata, an IPFS service, for permanent storage.
- Sign up at pinata.cloud.
- Upload an image file (e.g.,
nft-image.png) under Files. - Copy its CID and form the URL:
https://gateway.pinata.cloud/ipfs/Qm...image-hash
Create nft-metadata.json:
{
"name": "Ramses",
"description": "The world's most adorable pup.",
"image": "https://gateway.pinata.cloud/ipfs/QmWmvTJmJU3pozR9ZHFmQC2DNDwi2XJtf3QGyYiiagFSWb",
"attributes": [
{ "trait_type": "Breed", "value": "Maltipoo" },
{ "trait_type": "Eye color", "value": "Mocha" }
]
}Upload this JSON to Pinata and copy its gateway URL.
👉 Discover how blockchain storage powers true digital ownership.
Step 14: Mint Using a Script
Install Alchemy Web3:
npm install @alch/alchemy-web3Create scripts/mint-nft.js:
require("dotenv").config();
const API_URL = process.env.API_URL;
const PUBLIC_KEY = process.env.PUBLIC_KEY;
const PRIVATE_KEY = process.env.PRIVATE_KEY;
const { createAlchemyWeb3 } = require("@alch/alchemy-web3");
const web3 = createAlchemyWeb3(API_URL);
const contract = require("../artifacts/contracts/MyNFT.sol/MyNFT.json");
const contractAddress = "0x81c587EB0fE773404c42c1d2666b5f557C470eED";
const nftContract = new web3.eth.Contract(contract.abi, contractAddress);
async function mintNFT(tokenURI) {
const nonce = await web3.eth.getTransactionCount(PUBLIC_KEY, "latest");
const tx = {
from: PUBLIC_KEY,
to: contractAddress,
nonce: nonce,
gas: 500000,
data: nftContract.methods.mintNFT(PUBLIC_KEY, tokenURI).encodeABI(),
};
const signPromise = web3.eth.accounts.signTransaction(tx, PRIVATE_KEY);
signPromise
.then((signedTx) => {
web3.eth.sendSignedTransaction(
signedTx.rawTransaction,
function (err, hash) {
if (!err) {
console.log("The hash of your transaction is:", hash);
} else {
console.log("Error submitting transaction:", err);
}
}
);
})
.catch((err) => {
console.log("Promise failed:", err);
});
}
mintNFT("https://gateway.pinata.cloud/ipfs/QmYueiuRNmL4MiA2GwtVMm6ZagknXnSpQnB3z2gWbz36hP");Run:
node scripts/mint-nft.jsCheck status via Alchemy Mempool or Ropsten Etherscan.
Viewing Your NFT in MetaMask
Step 15: Add NFT to MetaMask
- Open MetaMask mobile app.
- Switch network to Ropsten.
- Tap Collectibles > Import NFTs.
Enter:
- Contract Address:
0x81c587EB... - Token ID: Check transaction details on Etherscan (likely
1).
- Contract Address:
- Confirm import.
After a refresh, your NFT will appear in your collection.
Frequently Asked Questions
Q: What is an NFT?
An NFT (non-fungible token) is a unique digital asset verified on a blockchain. Unlike cryptocurrencies, each NFT has distinct value and cannot be exchanged one-to-one.
Q: Why use the Ropsten testnet?
Ropsten lets you test smart contracts with free ETH before deploying on mainnet, reducing risk and cost.
Q: Can anyone mint my NFT?
By default, only the contract owner can mint due to the onlyOwner modifier. Remove it if you want public minting.
Q: Where is my NFT metadata stored?
Metadata is stored off-chain via IPFS using a tokenURI. This keeps data decentralized and tamper-proof.
Q: Is this ERC721 standard compliant?
Yes. The contract inherits from OpenZeppelin’s ERC721 implementation, ensuring full compliance with EIP-721 standards.
Q: How do I deploy on Ethereum mainnet?
Replace ropsten with mainnet in hardhat.config.js, connect to a mainnet Alchemy endpoint, and fund your wallet with real ETH.
👉 Start building the future of digital ownership—explore Web3 tools now.