Skip to main content

Overview

This quickstart guide will walk you through creating a compressed token mint, minting tokens, and transferring them - all with dramatically reduced storage costs compared to standard SPL tokens.
By the end of this guide, you’ll have a working compressed token application running on a local test validator.

Prerequisites

1

Install the CLI

Install the Light Protocol CLI globally:
npm install -g @lightprotocol/zk-compression-cli
Verify installation:
light --version
2

Create Project Directory

Set up a new Node.js project:
mkdir my-compressed-app
cd my-compressed-app
npm init -y
3

Install Dependencies

Install the Light Protocol SDKs:
npm install @lightprotocol/stateless.js @lightprotocol/compressed-token @solana/web3.js @solana/spl-token

Start Test Validator

Open a new terminal and start the Light Protocol test validator:
light test-validator
Keep this terminal running. The validator includes all Light Protocol programs pre-deployed and a local ZK prover service.
The test validator provides:
  • All Light Protocol programs (Account Compression, System, Compressed Token, Registry)
  • Local ZK Prover at http://127.0.0.1:3001
  • Local Photon Indexer at http://127.0.0.1:8784
  • Solana RPC at http://127.0.0.1:8899

Create Your Application

Create a new file index.ts:
index.ts
import {
  LightSystemProgram,
  Rpc,
  confirmTx,
  createRpc,
} from '@lightprotocol/stateless.js';
import { createMint, mintTo, transfer } from '@lightprotocol/compressed-token';
import { Keypair, Connection, LAMPORTS_PER_SOL } from '@solana/web3.js';

async function main() {
  // Initialize connection and RPC
  const connection = new Connection('http://127.0.0.1:8899', 'confirmed');
  const rpc: Rpc = createRpc(
    'http://127.0.0.1:8899',
    'http://127.0.0.1:8784',
    'http://127.0.0.1:3001'
  );

  // Generate keypairs
  const payer = Keypair.generate();
  const mintAuthority = Keypair.generate();
  const tokenRecipient = Keypair.generate();

  console.log('Payer:', payer.publicKey.toBase58());
  console.log('Mint Authority:', mintAuthority.publicKey.toBase58());
  console.log('Recipient:', tokenRecipient.publicKey.toBase58());

  // Airdrop SOL to payer
  console.log('\n1. Requesting airdrop...');
  const airdropSignature = await connection.requestAirdrop(
    payer.publicKey,
    2 * LAMPORTS_PER_SOL
  );
  await confirmTx(connection, airdropSignature);
  console.log('   ✓ Airdrop confirmed');

  // Create compressed token mint
  console.log('\n2. Creating compressed token mint...');
  const { mint, transactionSignature } = await createMint(
    rpc,
    payer,
    mintAuthority.publicKey,
    9 // 9 decimals
  );
  console.log('   Mint:', mint.toBase58());
  console.log('   Tx:', transactionSignature);

  // Mint tokens to recipient
  console.log('\n3. Minting 1000 tokens...');
  const mintToSignature = await mintTo(
    rpc,
    payer,
    mint,
    tokenRecipient.publicKey,
    mintAuthority,
    1000e9 // 1000 tokens with 9 decimals
  );
  console.log('   Tx:', mintToSignature);

  // Check recipient balance
  console.log('\n4. Checking balance...');
  const balance = await rpc.getCompressedTokenBalance(
    tokenRecipient.publicKey,
    mint
  );
  console.log('   Balance:', balance, 'tokens');

  // Transfer tokens
  console.log('\n5. Transferring 250 tokens...');
  const newRecipient = Keypair.generate();
  const transferSignature = await transfer(
    rpc,
    payer,
    mint,
    250e9, // 250 tokens
    tokenRecipient,
    newRecipient.publicKey
  );
  console.log('   Tx:', transferSignature);

  // Check balances after transfer
  const balance1 = await rpc.getCompressedTokenBalance(
    tokenRecipient.publicKey,
    mint
  );
  const balance2 = await rpc.getCompressedTokenBalance(
    newRecipient.publicKey,
    mint
  );
  console.log('\n6. Final balances:');
  console.log('   Original recipient:', balance1, 'tokens');
  console.log('   New recipient:', balance2, 'tokens');

  console.log('\n✓ Quickstart complete!');
}

main().catch(console.error);

Run the Application

Execute your script:
npx tsx index.ts
You should see output like:
Payer: 7xX8...Abc
Mint Authority: 9zZ9...Def
Recipient: 5yY5...Ghi

1. Requesting airdrop...
   ✓ Airdrop confirmed

2. Creating compressed token mint...
   Mint: 3wW3...Jkl
   Tx: 2vV2...Mno

3. Minting 1000 tokens...
   Tx: 4uU4...Pqr

4. Checking balance...
   Balance: 1000 tokens

5. Transferring 250 tokens...
   Tx: 6tT6...Stu

6. Final balances:
   Original recipient: 750 tokens
   New recipient: 250 tokens

✓ Quickstart complete!
Congratulations! You’ve successfully created and used compressed tokens on Solana.

What Just Happened?

Let’s break down what your application did:
Instead of creating a regular SPL Token mint (which costs rent), you created a compressed mint that stores only a small fingerprint on-chain. The full mint data is stored in the cheaper Solana ledger space.Cost Savings: ~99.8% reduction compared to SPL Token
The mintTo function created compressed token accounts stored in Merkle trees. These accounts:
  • Have no rent burden
  • Are fully composable with other programs
  • Support standard SPL Token operations
The transfer function:
  1. Generated a zero-knowledge proof of account ownership
  2. Nullified the old account state in the tree
  3. Created new account states for sender and recipient
  4. Updated the Merkle tree roots on-chain
All verified by Groth16 SNARKs for security.
The getCompressedTokenBalance RPC method queried the Photon indexer, which:
  • Indexes all compressed account state
  • Provides fast queries by owner/mint
  • Maintains Merkle proofs for transactions

Cost Comparison

Here’s what you saved compared to regular SPL tokens:
OperationSPL TokenCompressed TokenSavings
Create Mint0.00144 SOL0.000005 SOL99.7%
Create Account0.00203 SOL0.000005 SOL99.8%
Mint Tokens0.000005 SOL0.000005 SOL0%
Transfer0.000005 SOL~0.00002 SOL-300%
Transfers are slightly more expensive due to ZK proof verification, but the overall savings on account creation far outweigh this cost.

Using the CLI

You can also use the CLI for quick operations:
light create-mint --decimals 9 --mint-authority <PUBKEY>

Next Steps

Now that you’ve built your first compressed token app, explore more advanced features:

Compressed Tokens Guide

Learn about batch operations, delegation, and Token-2022 extensions

Compressed PDAs

Build custom programs with compressed state

JavaScript SDK

Explore the full SDK API

Testing

Write tests for your compressed applications

Troubleshooting

Make sure no other Solana validator is running:
killall solana-test-validator
light test-validator
The local validator may be slow to start. Wait 10 seconds and try again, or check if the validator is running:
solana cluster-version
Ensure you’re using TypeScript with tsx or compile first:
npm install -D tsx typescript @types/node
npx tsx index.ts
Verify the test validator is running and the endpoints are correct:
  • Solana RPC: http://127.0.0.1:8899
  • Photon Indexer: http://127.0.0.1:8784
  • ZK Prover: http://127.0.0.1:3001

Example Projects

Check out complete example projects:

Node.js Client

Complete Node.js example with compressed tokens

Web Client

React web application example

Program Examples

Solana program integration examples

GitHub Repo

Main Light Protocol repository

Build docs developers (and LLMs) love