How to Deploy an NFT Smart Contract on the Sui Blockchain

Daniel Uhlík
on Mar 14, 2023

Non-fungible tokens (NFTs) are digital assets that are becoming increasingly popular in the blockchain world. They allow creators to sell unique, digital items like artwork, music, and even tweets as one-of-a-kind assets that cannot be replicated or duplicated. In this tutorial, we'll walk through how to create an NFT smart contract in Sui Blockchain using the Move programming language.


Before we start, there are a few things you'll need:

  • A basic understanding of blockchain technology
  • Familiarity with the programming
  • A text editor or integrated development environment (IDE) for writing Move code
  • Sui browser wallet 
  • Install Sui

Create sources/contract.move

Sui uses Move as a programming language for smart contracts. Smart contracts are stateless and the state is stored in an object. An object either has an owner or is a shared object and thus anyone can read and update the object. To create an NFT collection on the Sui blockchain, you will need to write a Move smart contract. The Move smart contract should define the NFTs that you want to create and how they will be stored. You will also need to define the rules governing the minting of the NFTs.

  1. Open a text editor or IDE that supports Move language. Some popular options are Visual Studio Code with the Move Language Support extension or the Diem IDE.
  2. Start by opening the desired folder in a terminal and create a new project by command:
    sui move new some_dog_nft
  3. Create a new file in the sources folder with a .move extension. This file will contain the code for your smart contract. Begin your code by defining the module name and import statements. In this case, we're defining the module name as some_dog_nft::DogNFT and importing necessary modules using the use keyword. Here's what it should look like:
module some_dog_nft::DogNFT {
 use sui::object::{Self, UID};
 use sui::transfer;
 use sui::url::{Self, Url};
 use sui::tx_context::{Self, TxContext};
 // code goes here

 Define a constant called MAX_SUPPLY to set the maximum number of tokens that can be minted. In this case, we're setting the value to 10. Here's what it should look like:

const MAX_SUPPLY: u64 = 10;

Define a constant called ELimitExceeded to represent an error code that will be thrown if the maximum supply is exceeded. In this case, we're setting the value to 1. Here's what it should look like:

const ELimitExceeded: u64 = 1;

Define a struct called SomeDogNFT to represent the attributes of the token. In this case, we're including id, n (the token number), and url (the URL of the token's image). You can add additional attributes as necessary. Here's what it should look like:

struct SomeDogNFT has key, store {
      id: UID,
      n: u64,
      url: Url
      // Add attributes

Define another struct called NftCap to represent the number of tokens that have been minted and issued. This will be used to enforce the maximum supply. Here's what it should look like:

struct NftCap has key {
      id: UID,
      issued_counter: u64,

Define a function called init to initialize the smart contract. The init function takes in a mutable reference to TxContext, which is a context object that contains information about the current transaction.

Inside the init function, we define a local variable called minting_cap which is an instance of the NftCap struct. This struct has two fields: id and issued_counter. id is a unique identifier for the NftCap instance, and issued_counter is initialized to 0.

To create a new NftCap object, we call the object::new function and pass in the ctx parameter. This function generates a new UID value, which is assigned to the id field of the NftCap instance.

Finally, we call the transfer::transfer function to transfer ownership of the minting_cap object to the sender of the transaction. The tx_context::sender function is used to retrieve the sender address from the transaction context, which is then passed as the second parameter to transfer::transfer. This effectively assigns ownership of the minting_cap object to the sender of the transaction.

Here's what it should look like:

fun init(ctx: &mut TxContext) {
      let minting_cap = NftCap {
          id: object::new(ctx),
          issued_counter: 0,
      transfer::transfer(minting_cap, tx_context::sender(ctx))

In the last step, define a public entry function called mint to mint a new NFT. The function takes in four parameters: a mutable reference to an NftCap object, a vector of bytes representing the URL of the NFT image, an address representing the receiver of the NFT, and a mutable reference to TxContext, which is a context object that contains information about the current transaction.

The first line of the mint function retrieves the current value of issued_counter from the NftCap object passed in as a parameter and assigns it to a local variable n. The next line increments the issued_counter field of the NftCap object by 1 to indicate that a new NFT has been minted.

The assert! macro on the next line is used to ensure that the total number of NFTs minted does not exceed the maximum supply limit, which is defined as MAX_SUPPLY and set to 10 in this case. If the assert! condition is not true, the execution of the function will be aborted and an error code ELimitExceeded will be returned.

If the assert! condition passes, the function creates a new SomeDogNFT object with a unique ID generated using the object::new function and assigns the n value to its n field. The URL of the NFT image is passed as a parameter to the url::new_unsafe_from_bytes function to create a new Url object, which is then assigned to the url field of the SomeDogNFT object.

Finally, the transfer::transfer function is called to transfer ownership of the newly minted SomeDogNFT object to the receiver specified in the function parameters. This completes the process of minting and transferring a new NFT.

Here's what it should look like:

public entry fun mint(cap: &mut NftCap, url: vector, receiver: address, ctx: &mut TxContext) {
      let n = cap.issued_counter;
cap.issued_counter = n + 1; assert!(n <= MAX_SUPPLY, ELimitExceeded); let nft = SomeDogNFT { id: object::new(ctx), n: n, url: url::new_unsafe_from_bytes(url) }; transfer::transfer(nft, receiver); } }

How to deploy smart contract

Create a wallet via the Sui extension:
The SUI extension can be downloaded and installed from the Google Chrome Web Store. Once installed, open the extension and create a new wallet by following the on-screen instructions. Remember to store your recovery phrase in a safe and secure location.

Use the faucet to get Sui tokens:
Next, you will need to obtain some SUI tokens to deploy your smart contract. The SUI faucet allows you to request some tokens for free. Open the Sui wallet and follow the instructions to request tokens.

Get the wallet address via Sui client addresses:
Once you have received your SUI tokens, you will need to retrieve your wallet address. This can be done using the SUI client by running the following command:

sui client addresses

This will display a list of all addresses associated with your SUI wallet. Copy the address you wish to use for deploying your smart contract.

Transfer the Sui tokens to the cli wallet:
Now that you have obtained your wallet address and received your SUI tokens in-browser wallet, you will need to transfer the tokens to your cli wallet using the extension:

Publish command:
Finally, you are ready to deploy your smart contract. Use the following command in the project root folder to publish your smart contract on the SUI blockchain:

sui client publish –gas-budget 3000

The -gas-budget flag sets the maximum amount of gas you are willing to spend on the deployment. You can adjust this value as needed.

And that's it! Your SUI smart contract should now be deployed and ready to use on the SUI blockchain. From the output, you can get a transaction hash to check your smart contract in Sui explorer . In the output you can see something like this:
Created Objects:
 - ID: 0x0da258d968f90acace4fcbe18acd7535bd870ee8 , Owner: Account Address ( 0x18d30ad5fca75b39de034d3b7442fb5d4ab44f3c )
 - ID: 0xa0afddabe3fecf4fed9e78b28af9f008c934a968 , Owner: Immutable

The first ID is created NFTCap object and the second one is the packageId of the smart contract. We can transfer ownership of the NFTCap object to the browser wallet for easier NFT minting. You can execute the following command:

sui client transfer --object-id {YOUR_NFTCAP_ID} --to {YOUR_WALLET_ADDRESS} --gas-budget 3000

Now you can find your packageID in Sui explorer.

Connect your wallet using the button Connect Wallet and fill in all fields. In the first one enter NFTCap object id, in the second enter the image URL and finally in the third one set the receiver address of the NFT and hit execute. Approve the transaction and NFT should be minted on the receiver address.

You can also mint NFT directly from cli wallet using this command:

sui client call --function mint --module DogNFT --package {YOUR_PACKAGE_ID} --args {YOUR_NFTCAP_ID} {IMAGE_URL} {RECEIVER_ADDRESS} --gas-budget 10000

Happy coding!


Let's change the Web3 experience together.

We build stellar products with elite blockchain engineers for global Web3 startups.

Get in touch

Cleevio ventures

Are you looking for a business partner?

We collaborate with founding teams at the earliest stages, and invest broadly across all categories within the blockchain economy.

Get investment