---
title: SPL Token Program
description: Kit-compatible @solana-program/token client for mint creation, transfers, ATAs, delegation, burning, and instruction plans.
---

# SPL Token Program

Solana's standard token program. Defines Mints (token config + supply) and Token Accounts (per-owner balances). For tokens that need extensions, use [Token-2022](token-2022.md) instead.

If using plugin clients, prefer `client.use(tokenProgram())` for a fluent API that auto-derives ATAs and defaults the payer. The low-level instructions below are for manual `pipe()` transaction building. See [overview.md](../overview.md) and [plugins.md](../plugins.md).

Program address: `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`

```ts
import { TOKEN_PROGRAM_ADDRESS } from '@solana-program/token';
```

## Account Types

### Mint (82 bytes)

```ts
import { fetchMint, fetchMaybeMint, getMintSize } from '@solana-program/token';

const mint = await fetchMint(rpc, mintAddress);
// mint.data.decimals, mint.data.supply, mint.data.mintAuthority, mint.data.freezeAuthority
```

### Token Account (165 bytes)

```ts
import { fetchToken, fetchMaybeToken, getTokenSize } from '@solana-program/token';

const token = await fetchToken(rpc, tokenAddress);
// token.data.mint, token.data.owner, token.data.amount
```

### Multisig

```ts
import { fetchMultisig } from '@solana-program/token';

const multisig = await fetchMultisig(rpc, multisigAddress);
// multisig.data.m, multisig.data.n, multisig.data.signers
```

## PDA: Associated Token Account

One deterministic token account per owner per mint. Derived from owner + mint + token program — no on-chain lookup needed. Always prefer ATAs for user-facing flows.

```ts
import { findAssociatedTokenPda, TOKEN_PROGRAM_ADDRESS } from '@solana-program/token';

const [ata] = await findAssociatedTokenPda({
  owner: walletAddress,
  mint: mintAddress,
  tokenProgram: TOKEN_PROGRAM_ADDRESS,
});
```

## Key Instructions

### Initialize Mint

```ts
import { getInitializeMintInstruction } from '@solana-program/token';

const ix = getInitializeMintInstruction({
  mint: mintKeypair.address,
  decimals: 9,
  mintAuthority: authority.address,
  freezeAuthority: authority.address, // optional
});
```

### Transfer

Prefer `getTransferCheckedInstruction` — validates mint and decimals on-chain, preventing wrong-token transfers.

```ts
import { getTransferInstruction, getTransferCheckedInstruction } from '@solana-program/token';

// Simple transfer
const ix = getTransferInstruction({
  source: sourceTokenAccount,
  destination: destTokenAccount,
  authority: owner,
  amount: 1_000_000n,
});

// Checked transfer (validates decimals)
const ix = getTransferCheckedInstruction({
  source: sourceTokenAccount,
  mint: mintAddress,
  destination: destTokenAccount,
  authority: owner,
  amount: 1_000_000n,
  decimals: 9,
});
```

### Mint To

```ts
import { getMintToInstruction, getMintToCheckedInstruction } from '@solana-program/token';

const ix = getMintToInstruction({
  mint: mintAddress,
  token: destinationTokenAccount,
  mintAuthority: authority,
  amount: 1_000_000_000n,
});
```

### Approve Delegate

```ts
import { getApproveInstruction } from '@solana-program/token';

const ix = getApproveInstruction({
  source: tokenAccount,
  delegate: delegateAddress,
  owner: owner,
  amount: 500_000n,
});
```

### Burn

```ts
import { getBurnInstruction } from '@solana-program/token';

const ix = getBurnInstruction({
  account: tokenAccount,
  mint: mintAddress,
  authority: owner,
  amount: 100_000n,
});
```

## Instruction Plans

Handle multi-step operations (e.g., create ATA if needed). Auto-check preconditions and only include necessary instructions — use for user-facing flows. Build a plan with the `get*InstructionPlan` builders, then execute it through a plugin client that has planning + sending capability via `client.sendTransaction(plan)` (see [plugins.md](../plugins.md)). For a shorter form, `client.use(tokenProgram())` exposes `client.token.instructions.createMint(...)` / `client.token.instructions.mintToATA(...)`; call `.sendTransaction()` on the returned plan to submit (e.g. `await client.token.instructions.createMint({ newMint, decimals, mintAuthority }).sendTransaction()`).

### Create Mint

```ts
import { getCreateMintInstructionPlan } from '@solana-program/token';

const plan = getCreateMintInstructionPlan({
  payer,
  newMint: mintKeypair,
  decimals: 9,
  mintAuthority: authority.address,
});

await client.sendTransaction(plan);
```

### Mint to ATA (Creates ATA if needed)

Use the async builder — it derives the ATA automatically.

```ts
import { getMintToATAInstructionPlanAsync } from '@solana-program/token';

const plan = await getMintToATAInstructionPlanAsync({
  payer,
  owner: recipientAddress,
  mint: mintAddress,
  mintAuthority: authority,
  amount: 1_000_000_000n,
  decimals: 9,
});

await client.sendTransaction(plan);
```

## Complete Pattern: Create Token + Mint

```ts
import {
  pipe, createTransactionMessage, setTransactionMessageFeePayerSigner,
  setTransactionMessageLifetimeUsingBlockhash, appendTransactionMessageInstructions,
  signTransactionMessageWithSigners, sendAndConfirmTransactionFactory,
  assertIsTransactionWithBlockhashLifetime, generateKeyPairSigner, lamports,
} from '@solana/kit';
import {
  getInitializeMintInstruction, getMintToInstruction,
  getMintSize, TOKEN_PROGRAM_ADDRESS, findAssociatedTokenPda,
  getCreateAssociatedTokenInstruction,
} from '@solana-program/token';
import { getCreateAccountInstruction } from '@solana-program/system';

// 1. Generate mint keypair
const mintKeypair = await generateKeyPairSigner();

// 2. Get rent
const mintRent = await rpc.getMinimumBalanceForRentExemption(BigInt(getMintSize())).send();

// 3. Derive ATA
const [ata] = await findAssociatedTokenPda({
  owner: recipient.address,
  mint: mintKeypair.address,
  tokenProgram: TOKEN_PROGRAM_ADDRESS,
});

const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();

const message = pipe(
  createTransactionMessage({ version: 0 }),
  m => setTransactionMessageFeePayerSigner(payer, m),
  m => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, m),
  m => appendTransactionMessageInstructions([
    // Create mint account
    getCreateAccountInstruction({
      payer,
      newAccount: mintKeypair,
      lamports: lamports(mintRent),
      space: getMintSize(),
      programAddress: TOKEN_PROGRAM_ADDRESS,
    }),
    // Initialize mint
    getInitializeMintInstruction({
      mint: mintKeypair.address,
      decimals: 9,
      mintAuthority: payer.address,
    }),
    // Create ATA
    getCreateAssociatedTokenInstruction({
      payer,
      ata,
      owner: recipient.address,
      mint: mintKeypair.address,
    }),
    // Mint tokens
    getMintToInstruction({
      mint: mintKeypair.address,
      token: ata,
      mintAuthority: payer,
      amount: 1_000_000_000n,
    }),
  ], m),
);

const sendAndConfirm = sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions });
const signed = await signTransactionMessageWithSigners(message);
assertIsTransactionWithBlockhashLifetime(signed);
await sendAndConfirm(signed, { commitment: 'confirmed' });
```
