How to create and deploy a basic NFT smart contract

In this post we will learn how to create and deploy a basic NFT smart contract on the Ethereum blockchain. We will use MetaMask, Solidity and Hardhat to create and deploy our smart contract. The smart contract will be deployed on the Goerli testnet.


You will need to have an Alchemy API Key, and some ehters on the Goerli testnet. You can get the API key here. You can get testnet ethers from the Goerli faucet here.

Setting up the project

First we need to create a new directory for our project and initialize it with npm.

mkdir my-nft
cd my-nft
npm init -y

Then we install Hardhat a development environment to compile, deploy, test, and debug your Ethereum software and a create new project.

yarn add --dev hardhat && npx hardhat

When running npx hardhat you will be prompted with the following options:

Create a JavaScript project
Create a TypeScript project
Create an empty hardhat.config.js

Select the third option and Hardhat will create an empty hardhat.config.js file for you. Nex to finish the setup we create this two folders contracts and scripts.

mkdir contracts
mkdir scripts
  • contracts/ will contain smart contracts files
  • scripts/ will contain scripts to deploy with our smart contract.

Now we are ready to start coding our smart contract.

Coding and compiling the contract

Create a new file in the contracts/ folder named MyFirstNFT.sol.

// 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 MyFirstNFT is ERC721URIStorage, Ownable  {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    constructor() ERC721("MyFirstNFT", "NFT") {}

    function mintNFT(address recipient, string memory tokenURI)
        public onlyOwner
        returns (uint256)

        uint256 newItemId = _tokenIds.current();
        _mint(recipient, newItemId);
        _setTokenURI(newItemId, tokenURI);

        return newItemId;

This is a basic NFT smart contract that is derived from the OpenZeppelin ERC721 contract. Notice this contract will only allow you to mint. It uses the Counters library to keep track of the tokenIds.

In the constructor we set the name of our NFT to MyFirstNFT and the symbol to NFT. The mintNFT function is the function that will be called to mint new NFTs.

Because we are using the multiple OpenZeppelin contracts we need to add them in our project.

yarn add @openzeppelin/contracts

Now we need to install dotenv and ethers packages to be able to read the environment variables and to interact with the blockchain.

yarn add dotenv @nomiclabs/hardhat-ethers ethers@^5.0.0

To be able to deploy our smart contract we will need the Alchmey API Url and our metamask account private key. We will use dotenv to read the environment variables from a .env file.


Then we update the hardhat.config.js file to include the following:

 * @type import('hardhat/config').HardhatUserConfig
const { API_URL, PRIVATE_KEY } = process.env
module.exports = {
  solidity: '0.8.1',
  defaultNetwork: 'goerli',
  networks: {
    hardhat: {},
    goerli: {
      url: API_URL,
      accounts: [`0x${PRIVATE_KEY}`],

After that you will be able to run npx hardhat compile to compile your smart contract.

Deploying the contract

To be able to deploy our smart contract we need to create a new script in the scripts/ folder named deploy.js.

async function main() {
  const MyFirstNFT = await ethers.getContractFactory('MyFirstNFT')
  // Start deployment, returning a promise that resolves to a contract object
  const myNFT = await MyFirstNFT.deploy()
  await myNFT.deployed()
  console.log('Contract deployed to address:', myNFT.address)
  .then(() => process.exit(0))
  .catch((error) => {

After that you will be able to run npx hardhat run scripts/deploy.js --network goerli to deploy your smart contract.

If everything goes well you should see the following output:

Contract deployed to address: 0xyour-contract-address

You can also verify your contract on Etherscan by adding the contract address to the end of the url


In this post we learned how to create and deploy a basic NFT smart contract.

But here is a few considerations to take into account :

  • This is a very basic smart contract don't use it in production.
  • If you want to deploy a contract to production you could use the Open zeppelin wizard to generate a production ready smart contract.

In a futur post we will see how to deply a production ready NFT smart contract.

You can get the code here.