> ## Documentation Index
> Fetch the complete documentation index at: https://www.zkcompression.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Compress Complete SPL Token Accounts

> Compress the entire balance of an SPL token account to reclaim rent. Optionally leave some tokens in SPL format.

<CodeGroup>
  ```typescript compressSplTokenAccount() theme={null}
  // Compress entire SPL token account balance
  const transactionSignature = await compressSplTokenAccount(
      rpc,
      payer,
      mint, // SPL mint with interface PDA for compression
      owner,
      tokenAccount, // SPL token account to compress
  );
  ```

  ```typescript partialCompression() theme={null}
  // Compress account while keeping some tokens in SPL format
  const transactionSignature = await compressSplTokenAccount(
      rpc,
      payer,
      mint, // SPL mint with interface PDA for compression
      owner,
      tokenAccount, // SPL token account to compress
      remainingAmount, // amount to keep in SPL format
  );
  ```
</CodeGroup>

<Note>
  After compression, empty token accounts can now be closed to reclaim rent with [`closeAccount()`](https://solana.com/developers/cookbook/tokens/close-token-accounts).
</Note>

<Tip>
  **Function Difference and Best Practice:**

  * `compressSplTokenAccount(tokenAccount, remainingAmount)` compresses the entire SPL token account balance minus optional remaining amount only to the same owner. Use to migrate complete token accounts with optional partial retention.
  * `compress(amount, sourceTokenAccount, toAddress)` compresses specific amounts from source to a specified recipient. Use for transfers and precise amounts. [Here is how](/compressed-tokens/guides/compress-decompress).
</Tip>

## Get Started

<Steps>
  <Step>
    ### Compress SPL Token Accounts

    <Accordion title="Installation">
      <Tabs>
        <Tab title="npm">
          Install packages in your working directory:

          ```bash theme={null}
          npm install @lightprotocol/stateless.js@^0.23.0 \
                      @lightprotocol/compressed-token@^0.23.0
          ```

          Install the CLI globally:

          ```bash theme={null}
          npm install -g @lightprotocol/zk-compression-cli
          ```
        </Tab>

        <Tab title="yarn">
          Install packages in your working directory:

          ```bash theme={null}
          yarn add @lightprotocol/stateless.js@^0.23.0 \
                   @lightprotocol/compressed-token@^0.23.0
          ```

          Install the CLI globally:

          ```bash theme={null}
          yarn global add @lightprotocol/zk-compression-cli
          ```
        </Tab>

        <Tab title="pnpm">
          Install packages in your working directory:

          ```bash theme={null}
          pnpm add @lightprotocol/stateless.js@^0.23.0 \
                   @lightprotocol/compressed-token@^0.23.0
          ```

          Install the CLI globally:

          ```bash theme={null}
          pnpm add -g @lightprotocol/zk-compression-cli
          ```
        </Tab>

        <Tab title="SDK 2.0 (token-interface)">
          Install packages in your working directory:

          ```bash theme={null}
          # npm
          npm install @lightprotocol/stateless.js@^0.23.0 \
                      @lightprotocol/token-interface@^0.1.2

          # yarn
          yarn add @lightprotocol/stateless.js@^0.23.0 \
                   @lightprotocol/token-interface@^0.1.2

          # pnpm
          pnpm add @lightprotocol/stateless.js@^0.23.0 \
                   @lightprotocol/token-interface@^0.1.2
          ```

          Install the CLI globally:

          ```bash theme={null}
          npm install -g @lightprotocol/zk-compression-cli
          ```
        </Tab>
      </Tabs>
    </Accordion>

    <Tabs>
      <Tab title="Localnet">
        ```bash theme={null}
        # start local test-validator in a separate terminal
        light test-validator
        ```

        <Note>
          In the code examples, use `createRpc()` without arguments for localnet.
        </Note>
      </Tab>

      <Tab title="Devnet">
        Get an API key from [Helius](https://helius.dev) and add to `.env`:

        ```bash title=".env" theme={null}
        API_KEY=<your-helius-api-key>
        ```

        <Note>
          In the code examples, use `createRpc(RPC_URL)` with the devnet URL.
        </Note>
      </Tab>
    </Tabs>

    ```typescript theme={null}
    import "dotenv/config";
    import { Keypair } from "@solana/web3.js";
    import { createRpc, bn } from "@lightprotocol/stateless.js";
    import { createMint, compressSplTokenAccount } from "@lightprotocol/compressed-token";
    import { createAssociatedTokenAccount, mintTo, TOKEN_PROGRAM_ID } from "@solana/spl-token";
    import { homedir } from "os";
    import { readFileSync } from "fs";

    // devnet:
    const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`;
    // localnet:
    // const RPC_URL = undefined;
    const payer = Keypair.fromSecretKey(
        new Uint8Array(
            JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8"))
        )
    );

    (async function () {
        // devnet:
        const rpc = createRpc(RPC_URL);
        // localnet:
        // const rpc = createRpc();

        // Setup: Create mint and SPL token account with tokens
        const { mint } = await createMint(rpc, payer, payer.publicKey, 9);
        const owner = Keypair.generate();
        const tokenAccount = await createAssociatedTokenAccount(
            rpc,
            payer,
            mint,
            owner.publicKey,
            undefined,
            TOKEN_PROGRAM_ID
        );
        await mintTo(rpc, payer, mint, tokenAccount, payer, bn(1_000_000_000).toNumber());

        // Compress entire SPL token account balance
        const tx = await compressSplTokenAccount(
            rpc,
            payer,
            mint,
            owner,
            tokenAccount
        );

        console.log("Mint:", mint.toBase58());
        console.log("Tx:", tx);
    })();
    ```

    <Info>
      The SPL mint must have an SPL Interface PDA for compression.<br /> The script creates it for you.

      For development, create a new mint with SPL interface via [`createMint()`](https://github.com/Lightprotocol/examples-zk-compression/tree/main/compressed-token-cookbook) or add an SPL interface to an existing mint via [`createSplInterface()`](https://github.com/Lightprotocol/examples-zk-compression/tree/main/compressed-token-cookbook).
    </Info>
  </Step>
</Steps>

# Troubleshooting

<AccordionGroup>
  <Accordion title="Insufficient balance in token account">
    The token account doesn't have enough tokens for the operation.

    ```typescript theme={null}
    // Check token account balance before compression
    const balance = await rpc.getTokenAccountBalance(tokenAccount);

    if (Number(balance.value.amount) === 0) {
        console.log("Token account is empty");
        return;
    }

    console.log("Available balance:", Number(balance.value.amount));

    // Proceed with compression
    const compressTx = await compressSplTokenAccount(
        rpc,
        payer,
        mint,
        owner,
        tokenAccount,
    );
    ```
  </Accordion>

  <Accordion title="Remaining amount exceeds balance">
    The `remainingAmount` parameter exceeds the current account balance.

    ```typescript theme={null}
    const balance = await rpc.getTokenAccountBalance(tokenAccount);
    const availableAmount = Number(balance.value.amount);
    const remainingAmount = bn(500_000_000); // 0.5 tokens

    if (remainingAmount.gt(bn(availableAmount))) {
        console.log(`Cannot leave ${remainingAmount.toString()} tokens`);
        console.log(`Available balance: ${availableAmount}`);
        throw new Error("Remaining amount exceeds balance");
    }

    // Use valid remaining amount
    const compressTx = await compressSplTokenAccount(
        rpc,
        payer,
        mint,
        owner,
        tokenAccount,
        remainingAmount, // must be <= balance
    );
    ```
  </Accordion>
</AccordionGroup>

# Advanced Configuration

<AccordionGroup>
  <Accordion title="Partial Account Compression">
    Compress most tokens while leaving some in SPL format:

    ```typescript theme={null}
    import { bn } from '@lightprotocol/stateless.js';

    // Leave 100 tokens (0.1 with 9 decimals) in SPL account
    const remainingAmount = bn(100_000_000);

    const compressTx = await compressSplTokenAccount(
        rpc,
        payer,
        mint,
        owner,
        tokenAccount,
        remainingAmount, // amount to keep in SPL format
    );

    // Account will retain remainingAmount tokens
    ```
  </Accordion>

  <Accordion title="Compress Multiple Accounts">
    Compress several token accounts for the same mint:

    ```typescript theme={null}
    const tokenAccounts = [
        { account: new PublicKey("ACCOUNT_1"), owner: owner1 },
        { account: new PublicKey("ACCOUNT_2"), owner: owner2 },
        { account: new PublicKey("ACCOUNT_3"), owner: owner3 },
    ];

    // Compress each account
    for (const { account, owner } of tokenAccounts) {
        console.log(`Compressing account: ${account.toBase58()}`);

        try {
            const compressTx = await compressSplTokenAccount(
                rpc,
                payer,
                mint,
                owner,
                account,
            );
            console.log(`Compressed: ${compressTx}`);
        } catch (error) {
            console.log(`Failed: ${error.message}`);
        }
    }
    ```
  </Accordion>
</AccordionGroup>

# Next Steps

<Card title="How to Create a Mint Account with Interface PDA" icon="chevron-right" color="#0066ff" href="/compressed-tokens/guides/create-mint-with-token-pool" horizontal />
