QuickNode Raises $60M Series B!
Read the Letter from our CEO.

How to Mint an NFT on Solana using Typescript

October 18, 2022

Before you start this guide

This guide will give you an in-depth walkthrough of How to Mint an NFT on Solana using Typescript - but if you’d like to leave the heavy lifting to us - we recommend the Crossmint NFT Mint API add-on. By using Crossmint NFT Mint API, you can avoid wasting time writing typescript, deploying contracts or anything else. Use the NFT Mint API to create collections and mint NFTs easily! Try Crossmint NFT Mint API


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

mkdir mint-nft
cd mint-nft

Create a file for your app, app.ts:

set up your project

echo > app.ts

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

set up your project

yarn init --yes
npm init --yes

Create a tsconfig.json with .json importing enabled:

set up your project

tsc -init --resolveJsonModule true

Finally, create a folder for your uploads:

set up your project

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

yarn add @solana/web3.js @metaplex-foundation/js
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

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

const QUICKNODE_RPC = 'https://example.solana-devnet.quiknode.pro/0123456/';

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

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

        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

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

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


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

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

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

    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

    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

    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

    //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

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

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

    const { uri } = await METAPLEX
        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

    //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

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

    const { nft } = await METAPLEX
        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

    //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

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 41

Solana NFT Metadata Deep Dive
Published: Dec 16, 2022
Updated: Dec 16, 2022

Even in the 2022 bear market, Solana NFTs are showing no signs of slowing down. If you are building with Solana NFTs, understanding your NFTs' metadata will make it easier for you to deploy...

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
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 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
How to Burn SPL Tokens on Solana
Published: Jan 13, 2023
Updated: Jan 13, 2023

🔥🔥🔥Building a deflationary token protocol? Want to destroy a rugged NFT? Just want to have some fun with your community? The Solana SPL Token Program's Burn feature is what...

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 Use Priority Fees on Solana
Published: Jan 13, 2023
Updated: Jan 17, 2023

Are you looking to get your transactions confirmed as quickly as possible on Solana? This guide will show you how to use priority fees to bid for priority in the leader's queue and confirm...

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