ZK Compression: cheaper accounts on Solana (and why it's not cNFTs)
State compression gave Solana cheap NFTs. ZK Compression generalises the idea to arbitrary accounts and tokens — ~100× cheaper, secured by a constant-size validity proof verified on-chain. The catch is compute. A developer's-eye view, and the cNFT distinction everyone gets wrong.
devrels.xyz/a/31ZK Compression (by Light Protocol, with indexer infra from Helius) stores account and token state as hashes in a Merkle tree, keeping the full data in the ledger rather than in rent-funded account space. A zero-knowledge validity proof proves the state is correct — so you get ~100× lower storage cost while keeping L1 security and composability.
First, the distinction everyone gets wrong
It is not the same as the state compression behind cNFTs:
- State compression (cNFTs) — concurrent Merkle trees, essentially NFT-only, data off-chain, no general on-chain read/write of arbitrary state.
- ZK Compression — the generalized successor: arbitrary account data (tokens, PDAs, program state) behaves like native accounts, with a ZK validity proof verified on-chain.
How it works
- Only a hash (commitment) of each account lives on-chain, inside a state Merkle tree. The full data is emitted as calldata in the transaction.
- A constant 128-byte Groth16 proof proves the touched accounts exist in the tree — regardless of how many accounts the tx reads/writes. Verified on-chain (~100k CU).
- The Photon indexer (Helius) indexes Light programs so clients can read compressed state; a prover generates the proofs; forester nodes maintain the trees.
The cost win, concretely
ZK-compressed regular SPL/account ~saving
token account 0.000017 SOL ~0.0029 SOL ~100×
token mint 0.000091 SOL ~0.0015 SOL ~200×
100-byte PDA ~0.000015 SOL ~0.0016 SOL ~100×Reading it client-side uses the ZK Compression RPC (a superset of standard Solana RPC):
import { createRpc } from "@lightprotocol/stateless.js"
const rpc = createRpc(HELIUS_RPC_URL) // Photon-enabled endpoint
// compressed-state read methods:
await rpc.getCompressedAccount(hashOrAddress)
await rpc.getCompressedTokenAccountsByOwner(owner)
await rpc.getCompressedBalanceByOwner(owner)
await rpc.getValidityProof([accountHash]) // the 128-byte proof for a txThe honest read
ZK Compression trades rent for compute. A compressed token transfer runs ≈292k CU (proof verification + system hashing + per- account costs), and 128 bytes of every transaction are reserved for the proof against the 1,232-byte limit. You also depend on a Photon indexer and a prover (added latency). It shines for many cheap, rarely-written accounts — airdrops to millions of wallets, long-tail token accounts, large PDA sets. Avoid it for hot accounts written every block, data >~1kB accessed frequently, or anything where the extra CU and RPC dependency outweigh the rent saved.
Live on mainnet-beta since September 2024; Photon endpoints are available from Helius, Triton, and Alchemy.
References
- zkcompression.com — docs & core concepts
- Lightprotocol/light-protocol (GitHub)
- State compression & cNFTs — the NFT-only predecessor
cNFTs proved Solana could put millions of assets on-chain for pennies. ZK Compression is the same bet, generalised to everything that isn't an NFT.
Keep reading
Token Metadata spreads an NFT across three-plus accounts. Metaplex Core puts the whole thing in one — ~0.0037 SOL to mint vs ~0.022, ~17k CU vs ~205k — with a modular plugin system for royalties, freezing, and on-chain data. The catch: a Core asset isn't an SPL token.
Passage is the embed. Ondo is the catalog. Users get price exposure, not title. Checkout is Ethereum for now. Solana is where the token can live after.
The builder product did not vanish with the rename. poof.new still ships. Bounded is where your own agent writes, with boundaries that survive a bad prompt.
Get new articles in your inbox
Technical deep-dives on Solana tooling, infrastructure, and ecosystem. No noise.
