Airdropping tokens

Airdrop tokens to many wallets using parallel transaction plans

This recipe airdrops a freshly minted SPL token to many recipient wallets at once. It demonstrates how to compose an instruction plan that creates the mint sequentially first and then mints to every recipient in parallel — letting Kit pack the work into as few transactions as possible and send the parallel batches concurrently.

Set up a client

Install Kit and the plugins you need.

npm install @solana/kit @solana/kit-plugin-rpc @solana/kit-plugin-signer @solana-program/token

Compose a client with a generated signer, a local RPC connection, an airdrop to fund the signer, and the Token program plugin. Make sure a local validator is running (solana-test-validator) before this code executes.

import { ,  } from '@solana/kit';
import {  } from '@solana/kit-plugin-rpc';
import { ,  } from '@solana/kit-plugin-signer';
import {  } from '@solana-program/token';
 
const  = await ()
    .(())
    .(())
    .(((100_000_000_000n)))
    .(());

The signer is funded with 100 SOL because creating ATAs costs a small amount of rent for each recipient.

Generate the recipients

For the demo, generate 100 random destination addresses up front. In a real airdrop, this list would come from a database, a CSV, or some other source.

import {  } from '@solana/kit';
 
const  = await .(
    .({ : 100 }, async () => (await ()).),
);

Build the airdrop plan

Compose the work as a sequentialInstructionPlan whose first child creates the mint and whose second child is a parallelInstructionPlan containing one mint-to-ATA plan per recipient.

import {
    ,
    ,
    ,
    ,
} from '@solana/kit';
const  = null as unknown as [];
const  = await ();
 
const  = ([
    ...({
        : ,
        : 6,
        : ..,
    }),
    (
        await .(
            .(() =>
                ...({
                    : .,
                    ,
                    : .,
                    : 1_000n * 10n ** 6n, // 1,000 tokens
                    : 6,
                }),
            ),
        ),
    ),
]);

The mint must exist before any recipient can receive tokens, which is why the outer plan is sequential. Each mintToATA is independent of the others, so wrapping them in a parallelInstructionPlan lets Kit run them concurrently. The Token plugin's mintToATA is asynchronous because it derives each recipient's ATA address up front, so wrap the whole list in a single Promise.all.

Send and inspect the results

client.sendTransactions(plan) plans, signs, sends, and confirms every transaction in the tree. Wrap the call in passthroughFailedTransactionPlanExecution so a failure on one transaction does not throw — you keep the full result tree and can decide what to do per recipient.

import {
    ,
    ,
    ,
} from '@solana/kit';
const  = null as unknown as ;
const  = await (
    .(),
);
 
for (const [, ] of ().()) {
    if (. === 'successful') {
        .(`#${} ✅ ${..}`);
    } else if (. === 'failed') {
        .(`#${} ❌ ${..}`);
    } else {
        .(`#${} ⏭️  canceled`);
    }
}

flattenTransactionPlanResult collapses the tree into one entry per transaction in the order they were planned, so iterating the array is enough to log each outcome individually. For a single bottom-line view across the whole airdrop, summarizeTransactionPlanResult returns success/failure/cancellation counts and a top-level successful boolean.

Next steps

On this page