Marketplace has launched, further enabling blockchain developers! Learn more

How to Mint an NFT on Solana using Typescript

October 18, 2022

Overview

Minting 10,000 NFTs with a Candy Machine is fun, but there are many instances where we might need to mint a single NFT (e.g., 1 of 1 art, music, etc.). Metaplex, the organization that created the Solana metadata standard, has recently developed some handy JS SDKs that make creating an NFT from your terminal easy.

What You Will Do

In this guide, you will mint an NFT with metadata to Solana's devnet from your terminal using the Solana Web3 library and Metaplex JS SDKs. We will cover three key steps to NFT minting: 

  1. Upload an Image
  2. Upload Metadata
  3. Mint NFT

What You Will Need

  • Nodejs (version 16.15 or higher) installed
  • Typescript experience and ts-node installed

Solana NFT Background Info

Before building our app, let's talk about NFTs and Solana's NFT architecture. So what the heck is an NFT? A non-fungible token is effectively a set of data stored on chain that is unique from any other. In short, there's just one of them. On Solana, we achieve this by using the SPL Token Program and creating a token with a supply of 1. Further, NFTs cannot be subdivided, meaning you cannot have a third of an NFT (note: there are some advanced NFT protocols around fractionalization, but typically an NFT cannot be broken into smaller units). On Solana, we also achieve this using the SPL Token Program by setting decimals to 0 (meaning it cannot be fractionalized).

Though creating an SPL token with a supply of 1 and decimals of 0 is technically an NFT defined by its unique Mint ID, the SPL token program is limited regarding some of the types and amount of data that can be stored. Enter Metaplex. The Metaplex Metadata program sets a standard for on and off-chain metadata. Through a Program Derived Address associated with the Mint account, Metaplex allows users to assign more detailed metadata to a mint (e.g., name, description, mutability, seller fees, etc.). One notable field in the Metaplex metadata is called "URI." This is an address that points to specific off-chain metadata. Due to rent fees and speed constraints, Metaplex expects certain data to be stored off-chain (e.g., image/image URI, NFT traits/characteristics). The following figure from Metaplex visualizes the relationships between these fields:
Source: https://docs.metaplex.com/programs/token-metadata/overview

In this guide, we will first upload our image to Arweave and fetch its URI, then we will create the off-chain metadata and upload it to Arweave, and finally, we will mint our token and define on-chain metadata that points to our off-chain metadata.

Set Up Your Project

Create a new project directory in your terminal with:

set up your project

Copy
mkdir mint-nft
cd mint-nft

Create a file for your app, app.ts:

set up your project

Copy
echo > app.ts

Initialize your project with the "yes" flag to use default values for your new package:

set up your project

Copy
yarn init --yes
#or
npm init --yes

Create a tsconfig.json with .json importing enabled:

set up your project

Copy
tsc -init --resolveJsonModule true

Finally, create a folder for your uploads:

set up your project

Copy
mkdir uploads

Save an image (.png or .jpg) to this folder as image.png. We will be using this pixelated beauty:


Install Solana Web3 Dependency

We will need to add the Solana Web3 and SPL Token libraries for this exercise. Additionally, we will use Metaplex's JS SDK and MPL Token Metadata libraries. In your terminal type:

set up your project

Copy
yarn add @solana/web3.js @metaplex-foundation/js
#or
npm install @solana/web3.js @metaplex-foundation/js

Create a Wallet and Airdrop SOL

You'll need to create a Solana File System Wallet (keypair written to a guideSecret.json file) and airdrop some SOL to it. You can do this using Solana CLI or use this script we have created for you.

Make sure you save your wallet to your project directory as guideSecret.json.

After set up, your environment should look something like this:

Set Up Your App

Import Necessary Dependencies

Open app.ts, and paste the following imports on line 1:

set up your app

Copy
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
import { Metaplex, keypairIdentity, bundlrStorage, toMetaplexFile, toBigNumber } from "@metaplex-foundation/js";
import * as fs from 'fs';
import secret from './guideSecret.json';

In addition to the wallet we created in the previous step, we are also importing a few essential methods and classes from the Solana Web3 and Metaplex JS libraries. Also, since we will be uploading files from our system, we need to import fs, the file system library.

Set Up Your QuickNode Endpoint

To build on Solana, you'll need an API endpoint to connect with the network. You're welcome to use public nodes or deploy and manage your own infrastructure; however, if you'd like 8x faster response times, you can leave the heavy lifting to us. See why over 50% of projects on Solana choose QuickNode and sign up for a free account here. We're going to use a Solana Devnet node.

Copy the HTTP Provider link:



Inside app.ts under your import statements, declare your RPC and establish your Connection to Solana:

set up your app

Copy
const QUICKNODE_RPC = 'https://example.solana-devnet.quiknode.pro/0123456/';
const SOLANA_CONNECTION = new Connection(QUICKNODE_RPC);

Declare Variables

You will need to declare a few variables to run your script: 
  • Your source wallet (a keypair derived from your secret key). 
  • A Metaplex instance. 
  • A CONFIG file (we will use this to store information about the NFT we're going to mint).

Add the following declarations below SOLANA_CONNECTION to establish the wallet we will be using:

set up your app

Copy
const WALLET = Keypair.fromSecretKey(new Uint8Array(secret));

Establish a new Metaplex instance by calling our SOLANA_CONNECTION in Metaplex.make(). Our instance will use the Keypair we just created and bundlrStorage (an option for uploading files to Arweave using Solana):

set up your app

Copy
const METAPLEX = Metaplex.make(SOLANA_CONNECTION)
    .use(keypairIdentity(WALLET))
    .use(bundlrStorage({
        address: 'https://devnet.bundlr.network',
        providerUrl: QUICKNODE_RPC,
        timeout: 60000,
    }));

By including our network connection, wallet, and storage route, the API will make it easy for us to submit transactions to the Solana network.

Define NFT Characteristics

We will create a CONFIG object containing some metadata that we want to include in our NFT. Create a new const, CONFIG, and include the following attributes:

set up your app

Copy
const CONFIG = {
    uploadPath: 'uploads/',
    imgFileName: 'image.png',
    imgType: 'image/png',
    imgName: 'QuickNode Pixel',
    description: 'Pixel infrastructure for everyone!',
    attributes: [
        {trait_type: 'Speed', value: 'Quick'},
        {trait_type: 'Type', value: 'Pixelated'},
        {trait_type: 'Background', value: 'QuickNode Blue'}
    ],
    sellerFeeBasisPoints: 500,//500 bp = 5%
    symbol: 'QNPIX',
    creators: [
        {address: WALLET.publicKey, share: 100}
    ]
};

Feel free to use your own values here. Just make sure if you add your own creators to use PublicKeys for the address, and double check that the total share equals 100.

Create and Call Main Function

Create an async function, main, that we will use to execute all of the steps of our code:

set up your app

Copy
async function main() {
    console.log(`Minting ${CONFIG.imgName} to an NFT in Wallet ${WALLET.publicKey.toBase58()}.`);
}

main();

This won't do much, but you should be able to run your code to make sure there are no errors at this point:

set up your app

Copy
ts-node app

You should see a log in your console that you're about to mint an NFT--so let's do it already! If you're getting an error or have questions, shoot us a line on Discord, and we will be happy to help.

Upload Your Image

Before doing anything, we will need to upload the image we will use for our NFT to a decentralized storage platform. This is because we must pass the URI of the NFT image into the NFT's metadata. If you already have an image hosted with a URI, feel free to define that in your CONFIG file and skip to step 2. Otherwise, let's create a new async function, uploadImage before our main function. The function should accept a filePath and a fileName and return a promise of a string (the URI pointing to our uploaded image).

upload your image

Copy
async function uploadImage(filePath: string,fileName: string): Promise<string>  {
    console.log(`Step 1 - Uploading Image`);

}

To upload our image, we must first use the File System program to create a Buffer. We can do this using the fs.readFileSync method. Inside uploadImage, add:

upload your image

Copy
    const imgBuffer = fs.readFileSync(filePath+fileName);

To use the Metaplex uploader, we will need to convert the returned Buffer to a MetaplexFile using toMetaplexFile. On the following line, add:

upload your image

Copy
    const imgMetaplexFile = toMetaplexFile(imgBuffer,fileName);

Use the Metaplex storage().upload() method to upload your file. Because we have set bundlr as our storage provider in our Metaplex instance, the upload function will use Bundlr to upload the file to Arweave. Log and return your results:

upload your image

Copy
    const imgUri = await METAPLEX.storage().upload(imgMetaplexFile);
    console.log(`   Image URI:`,imgUri);
    return imgUri;

Finally, add this step inside of your main() function by calling uploadImage and passing uploadPath and imgFileName from your CONFIG file:

upload your image

Copy
    //Step 1 - Upload Image
    const imgUri = await uploadImage(CONFIG.uploadPath, CONFIG.imgFileName);

You should be able to test your function by running your script in the terminal:

upload your image

Copy
ts-node app

After a few seconds, you should see an Arweave link for your image in your terminal. Nice job!

Now let's add that URI to our metadata and upload our metadata.

Upload Metadata

Metadata is more or less what makes your NFT special. It includes the image, any defining traits, assigns it to a collection, etc. Metaplex makes uploading metadata easy--just a single call of nfts().uploadMetadata(). Let's start by creating a new function, uploadMetadata that accepts 5 parameters: imgUri, imgType, nftName, description, and attributes:

upload metadata

Copy
async function uploadMetadata(imgUri: string, imgType: string, nftName: string, description: string, attributes: {trait_type: string, value: string}[]) {
    console.log(`Step 2 - Uploading Metadata`);
  
}

Next, call nfts().uploadMetadata(). We will need to pass our parameters as follows:

upload metadata

Copy
    const { uri } = await METAPLEX
    .nfts()
    .uploadMetadata({
        name: nftName,
        description: description,
        image: imgUri,
        attributes: attributes,
        properties: {
            files: [
                {
                    type: imgType,
                    uri: imgUri,
                },
            ]
        }
    });
    console.log('   Metadata URI:',uri);
    return uri;  

There's not a lot to this--but you may want to add extra elements to your metadata. A complete list of Metaplex's token standards is available here.

Let's go ahead and call our function in main(). After uploadImage, call uploadMetadata using our CONFIG to populate the parameters:

upload metadata

Copy
    //Step 2 - Upload Metadata
    const metadataUri = await uploadMetadata(imgUri, CONFIG.imgType, CONFIG.imgName, CONFIG.description, CONFIG.attributes); 

If you want to test your function, you'll need to log metadataUri and then run ts-node app. Whenever you're ready, let's mint this to a token on Solana!

Mint NFT

Like our previous functions, the Metaplex API simplifies this process and allows us to mint our NFT with a single method, nfts().create(). Unlike the metadata in the previous step, in this final step, we must pass in some metadata that will be stored on the Solana chain directly.

After your uploadMetadata() function and before main(), create a new async function, mintNft():

mint nft

Copy
async function mintNft(metadataUri: string, name: string, sellerFee: number, symbol: string, creators: {address: PublicKey, share: number}[]) {
    console.log(`Step 3 - Minting NFT`);
}

Finally, inside of our function, call nfts().create() passing our metadataUri and other function parameters and log the results:

mint nft

Copy
    const { nft } = await METAPLEX
    .nfts()
    .create({
        uri: metadataUri,
        name: name,
        sellerFeeBasisPoints: sellerFee,
        symbol: symbol,
        creators: creators,
        isMutable: false,
        maxSupply: toBigNumber(1)
    });
    console.log(`   Success!🎉`);
    console.log(`   Minted NFT: https://explorer.solana.com/address/${nft.address}?cluster=devnet`);

This function will mint a token on-chain that links to our metadata using the Metaplex Metadata Program.

Now all you need to do is call this function inside of main(), passing parameters from CONFIG:

mint nft

Copy
    //Step 3 - Mint NFT
    mintNft(metadataUri, CONFIG.imgName, CONFIG.sellerFeeBasisPoints, CONFIG.symbol, CONFIG.creators);

Run Your Code💨

You're all set! If you would like to double-check your code against ours, our entire workbook is available on GitHub here.

When you're ready, in terminal type:

run your code

Copy
ts-node app

YES! Do you see something like this?



Go ahead and follow the link in your console to Solana Explorer. You should be able to see your NFT on the page:



If you scroll down, you should be able to see the on-chain metadata with a link to our uploaded metadata:



And the attributes from our CONFIG file:




You should also be able to see your NFT in your wallet (make sure you have selected Devnet in your wallet's developer settings):



Great job.

Next Steps and Wrap Up

You now have a handy and reusable script to mint NFTs right from your terminal! Pretty handy, right? Want to keep building? Here are a couple of ideas to keep building off what you just learned:

  1. Use an SPL token transfer to send this NFT to another wallet. (Guide: How to Transfer SPL Tokens on Solana)
  2. Use the Solana dApp Scaffold to create an NFT minting widget. (Guide: How to Connect Users to Your dApp with the Solana Wallet Adapter and Scaffold) Note: You'll have to use a Wallet Adapter Identity instead of keypairIdentity to create your instance of Metaplex in a front end with Solana Wallet Adapter.
If you give either a shot or have any questions for us, let us know! Find us on Discord and Twitter!

We <3 Feedback!

If you have any feedback or questions on this guide, let us know. We'd love to hear from you!

Related articles 33

Como crear un NFT en SOLANA
Published: Dec 27, 2021
Updated: Sep 23, 2022

¡Hola querido lector! Bienvenidos a una nueva guía de Solana.Solana es una blockchain que promete mucho a la hora de intentar resolver los problemas de escalabilidad que...

Continue reading
How to Get Transaction Logs on Solana
Published: Jun 24, 2022
Updated: Oct 27, 2022

Ever need to pull all the transactions associated with a Wallet? Want to see all of the mint transactions associated with a Candy Machine? Or maybe see transaction history of an NFT? Solana's...

Continue reading
How to Transfer SPL Tokens on Solana
Published: Sep 23, 2022
Updated: Sep 23, 2022

Sending Solana Program Library (SPL) Tokens is a critical mechanism for Solana development. Whether you are airdropping whitelist tokens to your community, bulk sending NFTs to another wallet,...

Continue reading
How to Mint an NFT on Solana
Published: Aug 27, 2021
Updated: Sep 23, 2022

Updated at: April 10, 2022Welcome to another QuickNode guide on Solana - the up-and-coming blockchain that seeks to solve the scalability issues of Ethereum. We will be walking through...

Continue reading
How to Send Bulk Transactions on Solana
Published: Aug 31, 2022
Updated: Oct 3, 2022

Are you running a batch process that has many transactions? Perhaps an airdrop to your community's NFT holders or a token distribution to early users of your dApp. Solana transaction...

Continue reading
Solana Fundamentals Reference Guide
Published: Oct 27, 2022
Updated: Oct 27, 2022

The Solana blockchain is a powerful tool, delivering thousands of transactions per second with almost no-cost transaction fees. If you are new to Web3 or have developed on EVM-based...

Continue reading