Skip to main content

Create a Solana SPL Token with Metaplex

Updated on
Jun 30, 2025

11 min read

Overview

Looking to create a token on Solana? Metaplex’s Token Metadata Standard and Umi make it easier and more secure than ever. In this guide, we’ll walk you through how to create a fungible SPL token on Solana using this modern framework—in just 6 steps.

Prefer a video walkthrough? Follow along with Sahil and learn how to create a fungible token on Solana.
Subscribe to our YouTube channel for more videos!

What You Will Do

In this guide, you’ll learn how to create a Solana SPL token using Metaplex’s Token Standard and the Umi client. You will create a wallet (and airdrop some SOL), upload token metadata to IPFS, and mint your token—all using best practices for a Solana dev environment.

What You Will Need

Step 1: Set Up Your Environment

Before you can create an SPL token, you need to set up your environment. To start, create a new project directory in your terminal with:

mkdir mint-fungible-spl
cd mint-fungible-spl
Logs for Simplified Debugging

You can now access Logs for your RPC endpoints, helping you troubleshoot issues more effectively. If you encounter an issue with your RPC calls, simply check the logs in your QuickNode dashboard to identify and resolve problems quickly. Learn more about log history limits on our pricing page.

Create two files, wallet.ts and mint.ts. We will use wallet.ts to create a new dev wallet and airdrop some Solana for testing. We'll use mint.ts to mint a new SPL token and upload our token metadata. 

echo > {wallet,mint}.ts

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

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

Create a tsconfig.json file: 

tsc --init

Open tsconfig.json and uncomment (or add) this to your file: 

"resolveJsonModule": true

This will allow us to import .json files into our repository, which will be important later when we want to generate a Keypair from a PrivateKey.

Also double check that esModuleInterop is set to true to allow for us to use imports. 

Install Solana Web3 dependencies:

yarn add @solana/web3.js@1 @metaplex-foundation/umi @metaplex-foundation/mpl-token-metadata @metaplex-foundation/umi-bundle-defaults bs58
#or
npm i @solana/web3.js@1 @metaplex-foundation/umi @metaplex-foundation/mpl-token-metadata @metaplex-foundation/umi-bundle-defaults bs58

Your environment should look something like this: 

Ready Solana Environment

Alright! We're all ready to go. 

Step 2: Set Up a Solana Devnet Endpoint on QuickNode

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. Sign up for a free account here.

Once you’ve created your account, deploy a Solana Devnet node. From there, copy the HTTP Provider link:

New Solana Endpoint

Step 3: Create a Wallet and Airdrop SOL

In order to mint a fungible SPL token, we'll first want to create a Devnet wallet and airdrop SOL into it. If you already have a paper wallet, save it to your project directory as guideSecret.json. If it needs some devnet SOL, you can request some with the form below or from QuickNode's Solana faucet:

🪂Request Devnet SOL

If you don't have a paper wallet, we'll programmatically generate a new one. Open wallet.ts and paste the following code in. We'll break it down in the next section.

wallet.ts
import { Keypair, LAMPORTS_PER_SOL, Connection } from "@solana/web3.js";
import * as fs from 'fs';
import bs58 from 'bs58';

//STEP 1 - Connect to Solana Network
const endpoint = 'https://example.solana-devnet.quiknode.pro/000000/'; //Replace with your QuickNode RPC Endpoint
const solanaConnection = new Connection(endpoint);

//STEP 2 - Generate a New Solana Wallet
const keypair = Keypair.generate();
console.log(`Generated new KeyPair. Wallet PublicKey: `, keypair.publicKey.toString());

//STEP 3 - Convert Private key to Base58
const privateKey = bs58.encode(keypair.secretKey);
console.log(`Wallet PrivateKey:`, privateKey);

//STEP 4 - Write Wallet Secret Key to a .JSON
const secret_array = keypair.secretKey
.toString() //convert secret key to string
.split(',') //delimit string by commas and convert to an array of strings
.map(value=>Number(value)); //convert string values to numbers inside the array

const secret = JSON.stringify(secret_array); //Covert to JSON string

fs.writeFile('guideSecret.json', secret, 'utf8', function(err) {
if (err) throw err;
console.log('Wrote secret key to guideSecret.json.');
});

//STEP 5 - Airdrop 1 SOL to new wallet
(async()=>{
const airdropSignature = solanaConnection.requestAirdrop(
keypair.publicKey,
LAMPORTS_PER_SOL,
);
try{
const txId = await airdropSignature;
console.log(`Airdrop Transaction Id: ${txId}`);
console.log(`https://explorer.solana.com/tx/${txId}?cluster=devnet`)
}
catch(err){
console.log(err);
}
})()

This script will perform 5 tasks: 

  1. Connect to the Solana Network (Make sure you replace the example URL on Line 6 with your actual QuickNode Endpoint URL that you saved in the previous step).

  2. Generate a new Wallet Keypair.

  3. Convert the Private key to Base58 and print it to the console.

  4. Write the Secret Key to a .json file that we'll use in the next step. Lines 16-22 are necessary to format the key as an array of numbers. Lines 24-27 use fs to export the array to a .json file.

  5. Airdrop 1 SOL to the new Wallet. 

Go ahead and run this script to create a new wallet and airdrop it 1 SOL: 

ts-node wallet.ts

You should see a new file, guideSecret.json in your project folder and a terminal log like this:

Generated new KeyPair. Wallet PublicKey:  G7ugoBpckgiL13KZMzWgQ751G27moDR9yVckQERrNnvj
Wallet PrivateKey: 3A4b34ob9hqUaTjR52eBLjQCLova1jqAG1zT59ypXSJvjh1cQzEExpBBbQLWT7gfbcS4KuYddBDiAaYrFCPE55Tu
Wrote secret key to guideSecret.json.
Airdrop Transaction Id: 58uYUd8PeimjWxf12dZRdqmURoMg1Q15SaaWwEET8U4VXU2pystyUsL9s2sq3cp2JTsUugPY7SUwW82S71SUo6Sj
https://explorer.solana.com/tx/58uYUd8PeimjWxf12dZRdqmURoMg1Q15SaaWwEET8U4VXU2pystyUsL9s2sq3cp2JTsUugPY7SUwW82S71SUo6Sj?cluster=devnet

Now, let's add the private key to the wallet of our choice (Phantom in this case):

Do not share Private Keys

We are printing the private keys just so that we can add the new wallet in Phantom. Never share your private keys with anyone; always store them securely and in environment files (.env) when using them in code, and make sure to add the environment files to .gitignore before publishing them on GitHub.

Adding Wallet in Phantom

Let's upload the Token icon and metadata.

Step 4: Upload the Token Icon and Metadata using the Metaplex Token Standard

We will need a token icon (image) and metadata (JSON file) that are publicly accessible so that our token metadata can be properly displayed on block explorers, wallets, and exchanges.

To stay true to the ethos of decentralization, we will use IPFS to upload our token icon and metadata.

Although we recommend using QuickNode's IPFS tool to pin and serve data, we'll demonstrate both methods below:

  1. Using QuickNode's managed IPFS service
  2. Running a local IPFS node

tip

To use IPFS on QuickNode, a Build plan or higher is required. View our feature breakdown by plan on our pricing page.

Navigate to the QuickNode Dashboard and click the IPFS tab on the left-sidebar.

Then, click on the Files tab and either click the New button and select Upload a file or simply drag the file you want to pin. We'll first upload the image below and then the metadata JSON file.

Token icon

Once the image is uploaded, click on the ellipses menu next to the file then click on Copy IPFS URL. We'll need to add this in the metadata file.

Now let's define our metadata using Metaplex's Fungible Token Standard, which requires a name, symbol, description, and image (all are string values). Using the standard with your token mint will enable major platforms like Phantom Wallet or Solana Explorer to easily recognize your token and make it viewable by their users. Create a new metadata JSON file (token.json in this case).

token.json
{
"name": "Best Token Ever",
"symbol": "BTE",
"description": "This is the best token ever!",
"image": "IPFS_URL_OF_IMAGE"
}

Update IPFS_URL_OF_IMAGE with the IPFS URL of the image we got earlier, save the file and upload it. Once pinned, you'll see the file's name, along with other data such as the files CID, whether they're pinned, and the date they were pinned. Copy the IPFS URL of the metadata file too. We will need this URL later while minting our token.

Screenshot of dashboard with Token icon and metadata upload to IPFS

That was easy! Plus, we don't have to worry about running and managing our own IPFS node. You can click the ellipses next to the file and click Copy IPFS URL to get the URL where your file is hosted. Additionally, you can re-download or view your files details under this ellipses menu. Take a moment to try it.

Now that we have our files pinned on IPFS via QuickNode. Let's mint our token!

Step 5: Build a Token Minting Tool

To mint your SPL token, you’ll first need to build a mint tool. Here’s how:

Import Dependencies

Open up mint.ts and import the following dependencies on line 1

import { percentAmount, generateSigner, signerIdentity, createSignerFromKeypair } from '@metaplex-foundation/umi'
import { TokenStandard, createAndMint, mplTokenMetadata } from '@metaplex-foundation/mpl-token-metadata'
import { createUmi } from '@metaplex-foundation/umi-bundle-defaults';
import secret from './guideSecret.json';

We'll cover these as we get to them in the guide, but we do want to note that final import, secret, which is importing the .json we created in early steps.

Establish Solana Connection

Create a Connection to the Solana network by replacing the example URL with your QuickNode Endpoint URL in the code below and pasting it just below your imports:

const umi = createUmi('https://example.solana-devnet.quiknode.pro/000000/'); //Replace with your QuickNode RPC Endpoint

Initialize the Signer wallet

We are initializing the wallet from the secret and making it the signer for transactions.

const userWallet = umi.eddsa.createKeypairFromSecretKey(new Uint8Array(secret));
const userWalletSigner = createSignerFromKeypair(umi, userWallet);

*Note: setting numDecimals to 0 results in a token that cannot be subdivided. This might be relevant for something like a membership or whitelist mint token.

Create the Metadata variable

Create a metadata variable like below and fill in your token details. Replace IPFS_URL_OF_METADATA with the actual IPFS URL of your metadata (token.json) file.

const metadata = {
name: "Best Token Ever",
symbol: "BTE",
uri: "IPFS_URL_OF_METADATA",
};

Creating the Mint PDA

We'll need to create a Mint Program Derived Address for our token. Learn about what are PDAs in Solana and what is Mint PDA for Tokens on Solana.

Below, we are creating a new Mint PDA and asking the umi client to use our wallet initialized earlier from secret as a signer and use the MPL Token Metadata to mint token metadata.

const mint = generateSigner(umi);
umi.use(signerIdentity(userWalletSigner));
umi.use(mplTokenMetadata())

Deploy Mint PDA and Mint Tokens

In the below function, we send a transaction to deploy the Mint PDA and mint 1 million of our tokens. You can change the amount of tokens and console message according to whatever suits best for you.

createAndMint(umi, {
mint,
authority: umi.identity,
name: metadata.name,
symbol: metadata.symbol,
uri: metadata.uri,
sellerFeeBasisPoints: percentAmount(0),
decimals: 8,
amount: 1000000_00000000,
tokenOwner: userWallet.publicKey,
tokenStandard: TokenStandard.Fungible,
}).sendAndConfirm(umi)
.then(() => {
console.log("Successfully minted 1 million tokens (", mint.publicKey, ")");
})
.catch((err) => {
console.error("Error minting tokens:", err);
});
Why do we add decimals?

Decimals are added to tokens to make them divisible to the smallest parts for simpler transactions and better liquidity. For example, in the above example, we are saying that our token's decimal would be 8, which means that our one token will be divisible to the 8th decimal value. Thus, while minting 1 million tokens, we have to add eight zeros ahead of the 1 million number (1000000_00000000).

Pull it All Together

Alright, the complete mint.ts should look like this:

mint.ts
import { percentAmount, generateSigner, signerIdentity, createSignerFromKeypair } from '@metaplex-foundation/umi'
import { TokenStandard, createAndMint, mplTokenMetadata } from '@metaplex-foundation/mpl-token-metadata'
import { createUmi } from '@metaplex-foundation/umi-bundle-defaults';
import secret from './guideSecret.json';

const umi = createUmi('https://example.solana-devnet.quiknode.pro/000000/'); //Replace with your QuickNode RPC Endpoint

const userWallet = umi.eddsa.createKeypairFromSecretKey(new Uint8Array(secret));
const userWalletSigner = createSignerFromKeypair(umi, userWallet);

const metadata = {
name: "Best Token Ever",
symbol: "BTE",
uri: "IPFS_URL_OF_METADATA",
};

const mint = generateSigner(umi);
umi.use(signerIdentity(userWalletSigner));
umi.use(mplTokenMetadata())

createAndMint(umi, {
mint,
authority: umi.identity,
name: metadata.name,
symbol: metadata.symbol,
uri: metadata.uri,
sellerFeeBasisPoints: percentAmount(0),
decimals: 8,
amount: 1000000_00000000,
tokenOwner: userWallet.publicKey,
tokenStandard: TokenStandard.Fungible,
}).sendAndConfirm(umi)
.then(() => {
console.log("Successfully minted 1 million tokens (", mint.publicKey, ")");
})
.catch((err) => {
console.error("Error minting tokens:", err);
});

Step 6: Create Your Solana Token

In your Terminal, type: 

ts-node mint.ts

Upon successful execution you should see an output like this:

Final results terminal output

You have now successfully created your Solana token. You can view it on the Solana Devnet Explorer as well as in your Phantom wallet:


Token account on Solana devnet explorerToken being displayed in Phantom wallet

Note: If you've minted a fungible token in the past, you've probably submitted your token to the Solana Token Program Registry. That registry is now deprecated and no longer a necessary step. You've already uploaded the metadata on chain, so you're good to go!

Party Time! 🎉

Congrats! You just minted your own token on Solana using the Metaplex fungible token standard and Umi. Have some fun with this--we're excited to see what tokens you're creating! To learn more, check out some of our other Solana tutorials here

We ❤️ Feedback!

Let us know if you have any feedback or requests for new topics. We'd love to hear from you.

Share this guide