How to Send Transactions with Solana Kit

·

Sending transactions on the Solana blockchain has become more intuitive, modular, and developer-friendly with the release of Solana Kit—the modernized successor to Solana Web3.js 2.0. Built with composability, type safety, and clean functional patterns in mind, Solana Kit empowers developers to build robust blockchain applications with ease.

This comprehensive guide walks you through creating and executing basic Solana transactions using Solana Kit. Whether you're new to Solana development or upgrading from the legacy SDK, you'll gain hands-on experience with key workflows like airdropping SOL, constructing transfer transactions, and leveraging functional programming patterns for cleaner code.

By the end, you’ll understand how to use core features such as factory functions, pipe-based transaction assembly, and granular instruction handling—all essential tools in today’s Solana development toolkit.

What Is Solana Kit?

Solana Kit is a reimagined JavaScript/TypeScript library designed to streamline interactions with the Solana blockchain. It introduces a modern API architecture focused on composability, modularity, and enhanced developer experience.

Key improvements over previous versions include:

These enhancements make Solana Kit ideal for building scalable dApps with maintainable codebases.

👉 Discover powerful blockchain tools that integrate seamlessly with modern Solana development workflows.

Setting Up Your Development Environment

Before writing any code, ensure your environment meets the following requirements:

Start by creating a new project directory:

mkdir solana-transfer-demo && cd solana-transfer-demo

Initialize it as a Node.js project and install required dependencies:

npm init -y
npm install @solana/kit @solana-program/system
npm install --save-dev typescript ts-node @types/node

Generate a tsconfig.json file with JSON module resolution enabled:

tsc --init --resolveJsonModule true

Create a transfer.ts file where we’ll write our transaction logic.

Importing Required Dependencies

In transfer.ts, import essential functions from Solana Kit and related packages:

import {
  airdropFactory,
  createKeyPairSignerFromBytes,
  createSolanaRpc,
  createSolanaRpcSubscriptions,
  generateKeyPairSigner,
  lamports,
  sendAndConfirmTransactionFactory,
  pipe,
  createTransactionMessage,
  setTransactionMessageFeePayer,
  setTransactionMessageLifetimeUsingBlockhash,
  appendTransactionMessageInstruction,
  signTransactionMessageWithSigners,
  getSignatureFromTransaction,
  address,
} from "@solana/kit";
import { getTransferSolInstruction } from "@solana-program/system";

const LAMPORTS_PER_SOL = BigInt(1_000_000_000);

Notice how each function serves a single purpose—this modularity enhances readability and testability. Also, note that amounts are now handled using BigInt, aligning with Rust-based program expectations on Solana.

Establishing Connection to the Solana Cluster

Connect to a local or remote Solana cluster using HTTP and WebSocket providers:

const httpProvider = 'http://127.0.0.1:8899';
const wssProvider = 'ws://127.0.0.1:8900';
const rpc = createSolanaRpc(httpProvider);
const rpcSubscriptions = createSolanaRpcSubscriptions(wssProvider);
console.log(`✅ - Established connection to ${httpProvider}`);

For production environments, replace these URLs with your secure endpoints from a reliable provider.

👉 Access high-performance RPC endpoints optimized for Solana dApp development.

Generating Wallet Signers

You’ll need at least two signers—one to send funds and another to receive them.

const user1 = await generateKeyPairSigner();
console.log(`✅ - New user1 address created: ${user1.address}`);

// Load user2 from an existing keypair file
import secret from './my-keypair.json';
const user2 = await createKeyPairSignerFromBytes(new Uint8Array(secret));
console.log(`✅ - user2 address loaded: ${user2.address}`);

To generate a new keypair via CLI:

solana-keygen new --no-bip39-passphrase --outfile ./my-keypair.json

Airdropping SOL for Testing

Fund your test wallets using either native RPC calls or factory functions:

// Method 1: Using direct RPC call
const tx1 = await rpc.requestAirdrop(
  user1.address,
  lamports(LAMPORTS_PER_SOL),
  { commitment: 'processed' }
).send();
console.log(`✅ - Airdropped 1 SOL to user1`);

// Method 2: Using airdrop factory
const airdrop = airdropFactory({ rpc, rpcSubscriptions });
const tx2 = await airdrop({
  commitment: 'processed',
  lamports: lamports(LAMPORTS_PER_SOL),
  recipientAddress: user2.address
});
console.log(`✅ - Airdropped 1 SOL to user2 using factory`);

Both approaches work reliably in devnet or local environments.

Constructing a Transfer Transaction

Use the pipe function to build transactions step-by-step in a readable, functional style:

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

const transactionMessage = pipe(
  createTransactionMessage({ version: 0 }),
  tx => setTransactionMessageFeePayer(user1.address, tx),
  tx => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
  tx => appendTransactionMessageInstruction(
    getTransferSolInstruction({
      amount: lamports(LAMPORTS_PER_SOL / BigInt(2)),
      destination: user2.address,
      source: user1,
    }),
    tx
  )
);

This pattern ensures immutability and type safety while allowing flexible extension with additional instructions.

Signing and Confirming the Transaction

Finalize and broadcast the transaction:

const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);
const sendAndConfirmTransaction = sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions });

try {
  await sendAndConfirmTransaction(signedTransaction, {
    commitment: 'confirmed',
    skipPreflight: true,
  });
  const signature = getSignatureFromTransaction(signedTransaction);
  console.log('✅ - Transfer successful:', signature);
} catch (e) {
  console.error('❌ Transaction failed:', e);
}

The factory-based approach lets you reuse confirmation logic across multiple transactions.

Frequently Asked Questions

Q: What is the difference between Solana Kit and Web3.js?
A: Solana Kit is the next-generation rewrite of Web3.js, featuring a functional API, better TypeScript support, modular architecture, and improved developer ergonomics.

Q: Can I use Solana Kit in production?
A: Yes. While still evolving, Solana Kit follows strict typing and immutability principles that make it suitable for production-grade applications.

Q: Why does Solana Kit use pipe for transaction building?
A: The pipe function enables clean composition of operations, making complex transaction logic easier to read, debug, and maintain.

Q: Do I need to define LAMPORTS_PER_SOL manually?
A: Yes—the constant is no longer exported by default. You must define it yourself using BigInt(1_000_000_000) for accuracy.

Q: How do I handle multiple instructions in one transaction?
A: Simply add more appendTransactionMessageInstruction steps inside the pipe chain. Each instruction executes atomically within the same transaction.

Q: Is there backward compatibility with older Web3.js code?
A: Not directly. Solana Kit represents a breaking redesign. However, migration guides and examples are available in official repositories.

Final Thoughts

Solana Kit marks a significant leap forward in blockchain development tooling. Its focus on functional composition, type safety, and modular design makes it easier than ever to write clean, reliable code for Solana applications.

By mastering concepts like factory functions, pipe-based construction, and granular instruction handling, you position yourself at the forefront of modern Solana development.

Whether you're building DeFi protocols, NFT marketplaces, or wallet integrations, Solana Kit provides the foundation for scalable, maintainable dApps.

👉 Elevate your blockchain development journey with tools built for speed and reliability.

Core Keywords: