Solana NFTs
An NFT is just an SPL Token with three constraints
A Solana NFT is not a separate kind of object. It is an SPL Token, the same token program that runs USDC and Bonk and your project's reward token. What makes it "non-fungible" is configuration:
- Supply is 1. There is exactly one of them.
- Decimals is 0. No fractional units exist.
- Mint authority is permanently renounced. Nobody can ever mint more.
That's it. The token program doesn't know or care that this particular mint represents a JPEG of a cartoon lizard. It enforces the supply constraint, blocks attempts to mint after the authority is renounced, and tracks ownership through token accounts the way it would for any other token. Transferring an NFT is just calling the SPL Token transfer instruction on a token account whose balance is 1. The same instruction that moves USDC moves NFTs.
What's missing from "an SPL Token with supply 1" is the descriptive information. The token program tracks how many of the token exist and who owns each one. It doesn't store a name, a symbol, an image, a list of attributes, or which collection the NFT belongs to. That information lives elsewhere.
Metadata lives in a separate account, attached by convention
Metaplex's Token Metadata program is the de facto standard for attaching descriptive information to a mint. When someone says "an NFT," they almost always mean an SPL Token mint plus a Metaplex metadata account that points at it. The two are paired so consistently that wallets, marketplaces, and explorers expect every NFT to have both.
The metadata account is a PDA owned by the Token Metadata program, with seeds derived from the mint's pubkey. This is what makes the pairing automatic: given any mint address, anyone can compute where its metadata account should live and look up whether one exists. The metadata account stores the name, symbol, URI pointing at off-chain JSON, the list of creators with royalty shares, the collection the NFT belongs to, and various flags.
The URI is where the actual image lives. The metadata account is too small and too expensive to hold image bytes. Instead, the URI points at a JSON file on Arweave or IPFS, which describes the NFT and includes another link to the actual image asset. The chain doesn't store the picture. The chain stores a pointer to a pointer to the picture. This is fine in practice because Arweave promises permanent storage and IPFS is pinned by enough services that NFT images stay accessible.
Metaplex also defines other related accounts that show up in production:
- Master Edition marks the mint as the original, prevents future mints, and is what cryptographically locks the supply to 1.
- Collection NFT is a special NFT that other NFTs reference as their "collection," which is how marketplaces group items together.
- Edition accounts let one original NFT be printed in numbered copies. Less common but real.
Reading metadata on chain means deserializing the Metaplex account at the right PDA. Wallets and SDKs do this for you. As a developer, you mostly care about recognizing the pattern: a mint, a metadata PDA, an off-chain URI, and the Metaplex program owning everything that isn't the mint.
How collections actually get minted
Most production NFT collections didn't have someone individually creating 10,000 mints with custom code. They used Metaplex's Candy Machine, a program that automates the mint process for an entire collection. The creator uploads the images and metadata to Arweave, configures the Candy Machine with the collection size, mint price, royalties, and any guards such as mint windows, allowlists, or payment tokens, and the program handles minting one NFT per buyer call.
The Candy Machine model produced most of the major Solana collections. A user clicks "mint" on a launch page, sends some SOL, the Candy Machine creates a fresh mint account, a metadata account, and an Edition account for them, and the buyer walks away with one NFT from the collection. The randomization of which item the buyer gets happens through a reveal mechanism: the metadata can be hidden until the mint completes, then "revealed" by updating the URI to point at the actual asset.
After the mint, secondary trading happens on marketplaces. Magic Eden and Tensor are the two dominant ones. They work by indexing every Metaplex metadata account on chain, building a queryable database, and providing listing and offer functionality through their own programs. When someone lists an NFT for sale, they create a listing account that holds the NFT in escrow or grants the marketplace transfer authority. When a buyer purchases, the marketplace program runs the transfer and distributes royalties to the creators recorded in the metadata account.
Royalty enforcement has been a contentious topic on Solana. Originally, royalties were a social contract: marketplaces honored them because creators expected it and the community shamed marketplaces that didn't. Then some marketplaces started skipping royalties to compete on fees. Metaplex responded with the Token Metadata standard's "programmable NFT" extension, which makes royalties enforceable at the program level by gating transfers through a ruleset. Programmable NFTs add cost and complexity. Most collections don't use them. The debate isn't fully settled.
Compressed NFTs and the rent math
The single biggest economic problem with regular Solana NFTs is rent. Every NFT is at least two new accounts on chain. At about 0.007 SOL of rent per NFT, a 10,000-item collection locks up around 70 SOL just to exist, before anyone buys anything. That's been paid by the creator at mint time and is recoverable only if NFTs are burned, which essentially never happens in practice. For collections that are minted for free or as rewards, the rent cost becomes prohibitive.
Compressed NFTs, or cNFTs, solve this with state compression. Instead of storing each NFT's data in its own account, the entire collection is represented as a Merkle tree. Only the tree's root hash lives on chain, in a single account that can hold up to millions of leaves depending on its configured depth. The actual NFT data, names, URIs, owners, lives off chain in indexers. When you want to prove you own a specific cNFT, you provide a Merkle proof against the on-chain root.
The math works because Merkle trees compress logarithmically. A tree of depth 14 can hold 16,384 NFTs in one account. A tree of depth 20 can hold over a million. The account size grows with the tree's depth rather than with the number of items in it. Rent for the tree account is typically under 1 SOL for collection sizes that would cost dozens or hundreds of SOL as regular NFTs.
The trade-off is that cNFTs cannot be read trivially from chain state alone. Reading a regular NFT means fetching two accounts and decoding them. Reading a cNFT means querying an indexer that maintains the off-chain leaf data and the proofs. Helius, Triton, and others provide cNFT-aware RPC endpoints that let you query a wallet's cNFTs as if they were regular NFTs. The indexer is doing the work behind the scenes.
cNFTs are common for use cases that would have been impossible with regular NFTs at scale. Game items that get distributed to every player. Achievement badges minted on action. Loyalty tokens that an airline gives out by the million. Anything where you want NFT semantics, meaning each one is distinct, transferable, and identifiable, but couldn't justify the rent of millions of full accounts. They're less common for art collections in the traditional sense, where the rent is a small fraction of the mint price and the indexer dependency is a friction.
Where you'll encounter NFTs as a developer
Even if you never build an NFT-centric protocol, NFTs will show up in your work. A few common patterns to recognize:
NFTs as access tokens. Many Solana products gate features behind ownership of a specific collection. Your program reads a Metaplex metadata account, checks the collection field, and grants access based on what the user holds. This is how DAOs gate voting to collection holders, how games unlock features for certain NFT owners, and how alpha groups verify membership.
NFTs as in-game items. Game programs treat NFTs as inventory. The player's wallet holds the NFT, the game's program checks ownership through the user's token accounts, and item-specific logic reads the metadata for stats and properties. cNFTs are common here because games often distribute many items per player.
NFTs as receipts. Some protocols issue an NFT to represent a position. Your stake in a pool, your loan in a lending market, your liquidity position in a CLMM. The NFT is the transferable handle on the position. Burn it to redeem. Sell it to transfer the position to someone else. Raydium's CLMM positions work this way.
NFTs as marketplace listings. Programs that interact with NFT marketplaces need to recognize listing accounts, escrow tokens, and royalty calculations. If you're building a tool that touches NFT inventory, you'll likely interact with Tensor or Magic Eden's APIs and the corresponding on-chain programs.
Recognizing these in the wild is mostly about reading account ownership. When you see an SPL Token with supply 1 and decimals 0, it's almost certainly an NFT. When you see an account owned by the Metaplex Token Metadata program, it's almost certainly an NFT's metadata. When you see an account that's a Merkle tree owned by the Account Compression program, it's almost certainly a cNFT collection. The patterns are consistent enough that you can identify them just from the program IDs and account shapes.
NFTs aren't going away on Solana. The peak hype cycle has passed, the cultural moment around PFP collections has cooled, but the underlying mechanism of a small on-chain identity attached to an off-chain asset, transferable through the standard token program, is too useful to lose. Whatever the next wave of products on Solana looks like, NFTs will be in the toolkit, and you'll want to be able to read them when you encounter them.