Sending transactions

Send single transactions with a Kit client

A Kit client can take a list of instructions and turn it into a fully signed, sent, and confirmed transaction in a single call. This guide covers the basics of sending one transaction at a time. When an operation needs to span multiple transactions, see Sending multiple transactions.

Create a transaction-ready client

Sending transactions requires a client that exposes a sendTransaction method. At the lowest level, this means installing the planAndSendTransactions plugin from @solana/kit-plugin-instruction-plan on top of a custom transactionPlanner and transactionPlanExecutor. In practice, you almost always pick a higher-level bundle that does this for you.

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

The bundle plugins from @solana/kit-plugin-rpc (solanaRpc, solanaMainnetRpc, solanaDevnetRpc, solanaLocalRpc) and the litesvm plugin from @solana/kit-plugin-litesvm all install a working planner and executor out of the box. Community plugins that target other backends should follow the same pattern, so the rest of this guide works the same way regardless of where transactions are actually sent.

The signer plugin must be installed before the bundle, because the bundle's transaction planner needs a payer on the client to plan transactions. See Setting up signers for the full set of signer options.

Send instructions

Once your client is ready, client.sendTransaction([...]) accepts an array of instructions and turns them into a single transaction. The client takes care of fetching a recent blockhash, estimating compute units when applicable, setting the fee payer, signing with all attached signers, sending the transaction, and waiting for confirmation.

import { ,  } from '@solana/kit';
import {  } from '@solana-program/system';
const  = ('GdnSyH3YtwcxFvQrVVJMm1JhTS4QVX7MFsX56uJLUfiZ');
 
const  = await .([
    ({
        : .,
        : ,
        : (500_000n),
    }),
    ({
        : .,
        : ,
        : (500_000n),
    }),
]);

A single client.sendTransaction([...]) call always produces exactly one transaction onchain, which means every instruction succeeds together or fails together. If you have so many instructions that they cannot fit in one transaction, use client.sendTransactions(...) instead.

Plan before sending

Sometimes you do not want to send the transaction immediately. You may want to inspect the planned message before signing, log it for debugging, or take over the rest of the lifecycle yourself. The client.planTransaction([...]) method returns the planned transaction message and stops there, leaving signing and sending to you.

import { ,  } from '@solana/kit';
import {  } from '@solana-program/system';
const  = ('GdnSyH3YtwcxFvQrVVJMm1JhTS4QVX7MFsX56uJLUfiZ');
 
const  = await .([
    ({
        : .,
        : ,
        : (500_000n),
    }),
]);

This gives you full control over what happens next: you can sign the message with signTransactionMessageWithSigners, encode it for transmission to another service, or pass it to a custom executor. Note that the executor used by client.sendTransaction([...]) may further mutate the planned message before sending — for example by attaching a fresh blockhash or refreshing the compute unit limit — so the message you inspect here is not guaranteed to be byte-identical to what would land onchain. The Kit without a client guide goes deeper into building and sending transactions step by step.

Handle transaction errors

When a transaction fails, client.sendTransaction(...) throws a SolanaError with the SOLANA_ERROR__FAILED_TO_SEND_TRANSACTION code. The error message identifies whether the failure happened in preflight or onchain, and the cause carries the underlying error you can branch on.

import {
    ,
    ,
    ,
    ,
} from '@solana/kit';
import {  } from '@solana-program/system';
try {
    await .([
        ({
            : .,
            : ,
            : (500_000n),
        }),
    ]);
} catch () {
    if ((, )) {
        .(.);
        .('Logs:', ..);
    } else {
        throw ;
    }
}

The same error.context object also exposes the underlying transactionPlanResult, which is particularly useful when you want to inspect the failed transaction message or its signature. Program-specific errors (such as System program or SPL Token program errors) live deeper inside error.cause. The Errors guide covers how to identify and handle them.

Inspect transaction signatures

A successful client.sendTransaction(...) resolves with a result object whose context carries the transaction signature and the original transaction message. You can use the signature to log a link to a block explorer or store it for later reference.

import { ,  } from '@solana/kit';
import {  } from '@solana-program/system';
const  = await .([
    ({
        : .,
        : ,
        : (500_000n),
    }),
]);
 
.(`✅ ${..}`);

Transaction signatures are deterministic, so the signature is known as soon as the fee payer signs the transaction — you do not need to wait for confirmation to learn what it will be. If you build and sign your own transactions, the getSignatureFromTransaction helper exposes the same value.

Next steps

On this page