You want to create your own NFT? Here’s how you do it on the Cardano blockchain

by Silas Stulz

With the current hype around NFTs, you may think about creating your own. For those who are new to the crypto space, an NFT is a non-fungible token, this means unlike bitcoin (or other cryptocurrencies) those tokens are not mutually interchangeable. This results in a digital scarcity which creates a natural value for the token.

You may have heard of the Cardano blockchain and its native asset token ada. Cardano calls itself a third-generation blockchain and solves a lot of problems, ethereum or bitcoin are struggling with. Since the 2nd of March 2021, it’s officially possible to create NFTs and other assets on the Cardano blockchain! That’s why I will show you how to create your NFT on the Cardano blockchain! Enough theory, let’s get going.

First, this tutorial will assume the following:

  • You own (or have access to) a full Cardano-node
  • You are at least a little bit familiar with the Cardano-CLI and its concepts
  • You have an ada wallet with at least 2 ada.

Alright, I will show you how I create two brand new NFTs for our project at bitPhant where we are trying to conserve biodiversity with NFTs and our own staking pool.

First, create a new payment address. You'll need two keys for this. Generate them using:

cardano-cli address key-gen \
--verification-key-file payment.vkey \
--signing-key-file payment.skey

Then, generate the payment address:

cardano-cli address build \
--payment-verification-key-file payment.vkey \
--out-file payment.addr \

Display the content of the file with:

cat payment.addr

Check the current UTXo of your address:

cardano-cli query utxo --address $(cat payment.addr) \
--mainnet --mary-era

This means you did not have any transactions on your address. In the next step, you need to fund your address. Copy your address, e.g.


Go to your wallet of choice and transfer the amount you like to this address, you need at least 1 ada to create your NFT. Depending on how many you want to create, you may want to transfer more ada. Later, if you want to send your NFTs to your friends, you need at least 1.7 ada per transaction you are creating. This is because it is currently not possible to only send custom tokens, with every transaction you have to send a minimum amount of ada with it.

After funding, check your UTXO again:

cardano-cli query utxo --address $(cat payment.addr) \
--mainnet --mary-era

You might see something like:

TxHash                                 TxIx        Amount
7211b05ef3cbe067b36469af2a81a63de5612b6a449cf8db47504ccc82726015     0        5000000 lovelace

I transferred 5 ada to my address. The amount is always displayed in lovelace. 1 ada = 1'000'000 lovelace.

Export the current network parameters:

cardano-cli  query protocol-parameters \
--mainnet \
--out-file protocol.json

Awesome! Now comes the good part, you have to create your own policy. A policy can create and burn tokens. A token is always identified by the policy id and a token name. The token name is unique for the policy id but can be used with another policy id.

Again, you will need two keys two create your policy, so let’s do that:

cardano-cli address key-gen \
--verification-key-file policy.vkey \
--signing-key-file policy.skey

Now you are able to create your policy script, your script indicates the type of signing that is required to issue tokens.

touch policy.script && echo "" > policy.script

echo "{" >> policy.script
echo "  \"keyHash\": \"$(cardano-cli address key-hash --payment-verification-key-file policy.vkey)\"," >> policy.script
echo "  \"type\": \"sig\"" >> policy.script
echo "}" >> policy.script

cat policy.script
  "keyHash": "5805823e303fb28231a736a3eb4420261bb42019dc3605dd83cccd04",
  "type": "sig"

Here you indicate with “sig” that only a single signature is needed to issue new tokens, meaning the policy key signing. Now, let’s get the policy id out of your policy script:

cardano-cli transaction policyid --script-file policy.script
> 677d3bbe3e01eeab498cd8786f7d261d92bd6ecea12109a332e86374

Create the transaction. You have one output (your own address), where you send all your ada, which you have to calculate first, that is why it’s currently zero, and all the tokens you mint with this transaction. Remember that the inputs and outputs always need to be equal, this is also true for custom tokens!

cardano-cli transaction build-raw \
--mary-era \
--fee 0 \
--tx-in  7211b05ef3cbe067b36469af2a81a63de5612b6a449cf8db47504ccc82726015#0 \
--tx-out $(cat payment.addr)+0+"1 677d3bbe3e01eeab498cd8786f7d261d92bd6ecea12109a332e86374.MountainGorilla + 1 677d3bbe3e01eeab498cd8786f7d261d92bd6ecea12109a332e86374.BrownBear"\
--mint="1 677d3bbe3e01eeab498cd8786f7d261d92bd6ecea12109a332e86374.MountainGorilla + 1 677d3bbe3e01eeab498cd8786f7d261d92bd6ecea12109a332e86374.BrownBear"\
--out-file matx.raw

Now you have the raw transaction, the next step is to calculate the transaction fees:

cardano-cli transaction calculate-min-fee \
--tx-body-file matx.raw \
--tx-in-count 1 \
--tx-out-count 1 \
--witness-count 2 \
--mainnet \
--protocol-params-file protocol.json

195509 Lovelace

The calculation needs the raw transaction, the number of transaction inputs, the number of transaction outputs, the number of keys needed to sign the transaction, and the network parameters. Now you can build the transaction again, but this time with the fee:

cardano-cli transaction build-raw \
--mary-era \
--fee 195509 \
--tx-in b1ddb0347fed2aecc7f00caabaaf2634f8e2d17541f6237bbed78e2092e1c414#0 \
--tx-out $(cat payment.addr)+4804491+"1 677d3bbe3e01eeab498cd8786f7d261d92bd6ecea12109a332e86374.MountainGorilla + 1 677d3bbe3e01eeab498cd8786f7d261d92bd6ecea12109a332e86374.BrownBear"\
--mint="1 677d3bbe3e01eeab498cd8786f7d261d92bd6ecea12109a332e86374.MountainGorilla + 1 677d3bbe3e01eeab498cd8786f7d261d92bd6ecea12109a332e86374.BrownBear"\
--out-file matx.raw

Almost done, now sign the transaction:

cardano-cli transaction sign \
--signing-key-file payment.skey \
--signing-key-file policy.skey \
--script-file policy.script \
--mainnet \
--tx-body-file matx.raw \
--out-file matx.signed

And finally submit the transaction, if you don’t get any response, that is usually a sign that everything worked.

cardano-cli transaction submit --tx-file matx.signed --mainnet

Go ahead and query your UTXo again, you should now see your newly minted tokens!

cardano-cli query utxo --address $(cat payment.addr) \
--mainnet --mary-era

TxHash                                 TxIx        Amount
fd0790f3984348f65ee22f35480b873b4eb9862065514f3e3a9c0f04d0a6ad63     0        4804491 lovelace + 1 677d3bbe3e01eeab498cd8786f7d261d92bd6ecea12109a332e86374.MountainGorilla + 1 677d3bbe3e01eeab498cd8786f7d261d92bd6ecea12109a332e86374.BrownBear

Congratulations you just created your first NFT on the Cardano blockchain!

If this guide was helpful, consider supporting our cause by delegating some ada to our stake pool or check out our custom NFTs which represent a species on the IUCN Redlist. BitPhant is a non-profit that leverages blockchain technology to conserve biodiversity.

More articles

Improve your Psycopg2 executions for PostgreSQL in Python

Speeding up your PostgreSQL execute statements!

Read more

Using Azure Functions with Python, a quick intro with a Blobtrigger

A quick introduction on how to create an Azure Blobtrigger Function on Microsoft Azure using Python.

Read more

Let's talk about your project