So you're wanna mint some compressed NFTs on Solana? Smart move. Regular NFTs? They eat up SOL like crazy on storage rent. But compressed ones? Basically free. We're talking 0.0000005 SOL per NFT. Mint a billion? Around 11k bucks total. I usually do this on devnet first to test without burning real cash.
Why bother? Collections of thousands or millions become doable. Games, art drops, whatever. No more "oh crap, that's 12k SOL for a mil NFTs" nightmare. Sound familiar? Yeah, thought so.
Compressed NFTs stash most data off chain in a Merkle tree. Only the root hash lives on Solana. Indexers handle the rest. Super cheap storage. But it's verified on chain, so no funny business. The thing is, you need a Merkle tree first. That's your NFT home base.
In my experience, start with Metaplex's Bubblegum program. It's the go to. Powers everything. Or no code if you're lazy like me sometimes.
| Scale | Regular NFT Cost | Compressed Cost |
|---|---|---|
| 1,000 NFTs | ~12 SOL | Negligible |
| 1 Million | ~12,000 SOL | ~5 SOL |
| 100 Million | Insane | ~50 SOL |
| 1 Billion | Impossible | ~11,000 USD |
Pretty much 99.9% savings. Fees? Tiny transaction costs only. No rent.
Okay, hate code? Use Crossmint Console. Super quick.
Takes 2 minutes. Perfect for testing. But for real projects? Code it. More control.
Grab your terminal. Let's build a script. I do this all the time. Uses Metaplex Umi and DAS API. Devnet first, obvs.
Setup? Node.js, TypeScript. QuickNode or Helius RPC. Free tiers work.
mkdir compressed nft && cd compressed nftnpm init -y && npm i @metaplex foundation/umi @metaplex foundation/mpl bubblegum @metaplex foundation/digital asset standard api @solana/web3.js ts node typescriptnpx tsc --init. Tweak tsconfig if picky.app.ts. Paste this bad boy.Here's the script I use. Tweaked for 10k tree capacity. Change nums as needed.
import { publicKey, signerIdentity, createSignerFromKeypair, generateSigner, percentAmount, LAMPORTSPERSOL
} from '@metaplex foundation/umi';
import { mplBubblegum, ConcurrentMerkleTreeAccount, createMerkleTreeIx, mintV1Ix, findLeafAssetIdPda
} from '@metaplex foundation/mpl bubblegum';
import { dasApi, fetchDigitalAssetWithAssetsByOwner } from '@metaplex foundation/digital asset standard api';
import { createUmi } from '@metaplex foundation/umi bundle defaults';
import { fromWeb3JsKeypairToUmi } from '@metaplex foundation/umi web3js adapters';
import { Keypair } from '@solana/web3.js';
import * as fs from 'fs'; // Your wallet keypair - DANGER: devnet only! Use env vars IRL.
const keypair = Keypair.fromSecretKey( Uint8Array.from([/ your 64 bytes here /])
); // Metadata JSON for your NFT. Upload image to IPFS first.
const metadata = { name: "My First cNFT", symbol: "CNFT", uri: "https://your ipfs gateway.io/metadata.json", // Must point to valid JSON sellerFeeBasisPoints: percentAmount(500), // 5%
}; // Helper to calc tree params
function calculateMerkleTreeParams(maxDepth: number, maxBufferSize: number) { return { treeCreator: keypair.publicKey, maxDepth, maxBufferSize, canopyDepth: maxDepth - 3 // Common setup };
} async function main() { const umi = createUmi('https://api.devnet.solana.com') // Swap for your RPC .use(signerIdentity(createSignerFromKeypair(umi, fromWeb3JsKeypairToUmi(keypair)))) .use(mplBubblegum()); const das = dasApi(umi); console.log('Wallet balance:', await umi.rpc.getBalance(keypair.publicKey) / LAMPORTSPERSOL, 'SOL'); // For 10k NFTs: depth 14 (2^14 = 16k leaves) const merkleStructure = calculateMerkleTreeParams(14, 64); console.log(Initializing Merkle Tree for ~${Math.pow(2, merkleStructure.maxDepth)} NFTs.); // Create tree const merkleTree = generateSigner(umi); await createMerkleTreeIx(umi, { merkleTree, ..merkleStructure }).sendAndConfirm(umi); console.log('Merkle Tree created:', merkleTree.publicKey); // Mint leaf const leafOwner = umi.identity.publicKey; // Your wallet const leafId = generateSigner(umi); await mintV1Ix(umi, { leafOwner, merkleTree: merkleTree.publicKey, metadata, leafId }).sendAndConfirm(umi); console.log('cNFT minted! Fetching..'); // Fetch it const assetId = publicKey(findLeafAssetIdPda(umi, { merkleTree: merkleTree.publicKey, leafId: leafId.publicKey })); let asset; for (let i = 0; i < 10; i++) { // Retry try { asset = await das.getAsset(assetId); break; } catch { await new Promise(r => setTimeout(r, 1000)); } } if (asset) { console.log('Compressed:', asset.compression?.eligible); console.log('Name:', asset.content?.metadata?.name); console.log('URI:', asset.content?.jsonUri); console.log('Image:', asset.content?.files?.?.uri); }
} main().catch(console.error);
Run it: ts node app.ts. Watch magic. Tree creates (~0.03 SOL), mints leaf (micro fee). Fetches via DAS. Boom, your cNFT details print out.
solana airdrop 2.Honestly, first time I forgot canopy depth. Tree failed. Docs say maxDepth - 3 usually. Why? Proof efficiency. Deeper canopy = fewer on chain proofs later.
Loop the mintV1. Batch 'em. Umi handles concurrency fine. For 100? Parallel promises. Costs? Still pennies.
In my experience, for a 10k drop: Create one tree once. Mint all leaves to it. Transfer later cheap too. Bubblegum has transferIx.
Skip? Lone wolf NFTs. Fine for tests.
Fetched via DAS API. getAsset(assetId). Checks compressed: true. Grabs metadata off indexer.
Transfer? Another script.
Apps? Helius has mobile minter tuts. Snap photo, mint cNFT. Wild.
Look, RPC matters. Public devnet lags. Paid endpoint? Smooth.
Buffer size: 64 default. Bigger for heavy writes.
Canopy: Tradeoff. More = verify faster, but tree create costs more compute.
Games? Billions viable now. MMORPG loot? cNFTs.
What's next? Burn one? delegate? Bubblegum docs got it. Or hit me up, we'll tweak.
| No code (Crossmint) | Code (Umi) | |
|---|---|---|
| Speed | Minutes | Hours first time |
| Cost | Service fee | Raw SOL |
| Scale | Limited | Unlimited |
| Control | Basic | Full |
Start no code. Graduate to code. That's my path.
One more: Validators dig it. Fast confirms. No congestion like old drops.
Artists? Drop 10k editions free. Supply chain? Tag millions cheap.
Energy? Less on chain data = greener.
Go mint. Tweak the script. Share your tree pubkey. Let's see what you build.