Upgrade guide
Upgrade your Web3.js project to Kit
Why upgrade?
Kit is a complete rewrite of the Web3.js library. It is designed to be more composable, customizable, and efficient than its predecessor. Its functional design enables the entire library to be tree-shaken, drastically reducing your bundle size. It also takes advantage of modern JavaScript features — such as native Ed25519 key support and bigint for large values — resulting in an even smaller bundle, better performance and most importantly, a reduced attack surface for your application.
Unlike Web3.js, Kit doesn't rely on JavaScript classes or other non-tree-shakeable features. This brings us to our first key difference.
Where's my Connection class?
In Web3.js, the Connection class serves as a central entry point, making the library's API easier to discover via a single object. However, this comes at a cost: using the Connection class forces you to bundle every method it provides, even if you only use a few. As a result, your users must download the entire library, even when most of it goes unused.
To avoid this, Kit does not include a single entry-point class like Connection. Instead, it offers a set of functions that you can import and use as needed. Two key functions replace most of the Connection class's functionality: createSolanaRpc and createSolanaRpcSubscriptions.
The former, createSolanaRpc, returns an Rpc object for making RPC requests to a specified endpoint. Read more about RPCs here.
The latter, createSolanaRpcSubscriptions, returns an RpcSubscriptions object, which lets you to subscribe to events on the Solana network. Read more about RPC Subscriptions here.
Note that, although Rpc and RpcSubscriptions look like classes, they are actually Proxy objects. This means they dynamically construct RPC requests or subscriptions based on method names and parameters. TypeScript is then used to provide type safety for the RPC API, making it easy to discover available RPC methods while keeping the library lightweight. Regardless of whether your RPC supports 1 method or 100, the bundle size remains unchanged.
Introducing Kit clients
The functional approach above gives you maximum treeshakability, but it can feel verbose compared to Web3.js's Connection. Kit addresses this with plugin-based clients — a single object that bundles the functionality you need while still letting you choose what goes in. You cherry-pick plugins, so you typically only bundle what you actually use.
A Kit client is an immutable JavaScript object built by chaining .use() calls. Each plugin adds capabilities to the client — like signer roles, RPC access, transaction sending, or typed program instructions. Start with createClient() from @solana/kit, add signer plugins such as signer(payer), then apply RPC bundles like solanaDevnetRpc() to install RPC, subscriptions, transaction planning, sending, and devnet airdrops. You may then extend it with program plugins like systemProgram() and tokenProgram() to add typed access to the accounts and instructions of those programs.
The rest of this guide uses a client for the Kit examples. To learn more about the plugin system, see Plugins.
Fetching and decoding accounts
Fetching onchain accounts is as simple as calling the appropriate RPC method on the client. Kit also provides helper functions like fetchEncodedAccount, which returns a MaybeAccount object with an exists boolean to indicate whether the account is present onchain:
To decode raw account data, Kit provides a composable serialization library called codecs. You can define a codec for any account type by combining primitives:
You can read more about codecs here.
Once you have a codec, you can use decodeAccount to transform an encoded account into a decoded one:
Using program libraries
Fortunately, you don't need to create a custom codec for every account. Kit provides client libraries for many popular Solana programs, generated via Codama, ensuring a consistent structure across them. These libraries can be used as standalone imports or as client plugins.
As client plugins, they add typed .accounts and .instructions namespaces to your client. For example, here's how to fetch and decode a Nonce account using the System program:
They can also be used as standalone functions without a client:
Check out the "Available plugins" page for a list of available program libraries compatible with Kit.
Creating instructions
Program libraries also provide functions for creating instructions. With a client, you can create instructions through the program's typed namespace:
Without a client, you can use the standalone instruction helpers directly. In this case, Kit uses TransactionSigner objects for accounts that need to sign. This allows signers to be extracted from built transactions later, enabling automatic transaction signing without manually tracking which keys need to sign.
Sending transactions
In Web3.js, sending a transaction involves creating a Transaction object, adding instructions, signing it, and sending it. Kit clients reduce this to a single call:
With a client, building the transaction message, setting the fee payer, fetching a recent blockhash, signing, sending, and confirming are all handled for you.
You can also send multiple instructions as a single atomic transaction using client.sendTransaction([...]):
For full control over each of these steps, you can build transactions manually. Kit uses an immutable transaction model where each helper returns a new transaction object with an updated type. The pipe function lets you chain these helpers together:
A few things to note about the manual approach:
- Signers: Kit uses
TransactionSignerobjects (highlighted above) instead of raw keypairs. Since signers are attached to instructions and the fee payer,signTransactionMessageWithSignerscan sign the transaction automatically without needing to pass signers separately. Read more about signers here. - Immutability: Each transaction helper returns a new object with a narrower type, ensuring that required fields (fee payer, lifetime, etc.) are set before the transaction can be signed or sent. The
pipefunction chains these transformations together. - Signatures: Transaction signatures are deterministically known before sending. The
getSignatureFromTransactionhelper extracts the signature from the signed transaction, andsendAndConfirmdoes not return it.
Closing words
We've now explored the key differences between Web3.js and Kit, giving you a solid foundation for upgrading your project. Since Kit is a complete rewrite, there's no simple step-by-step migration guide, and the process may take some time.
To ease the transition, Kit provides a @solana/compat package, which allows for incremental migration. This package includes functions that convert core types — such as public keys and transactions — between Web3.js and Kit. This means you can start integrating Kit without having to refactor your entire project at once.
If you're using a Kit client, the upgrade is even more straightforward — the client-based API is conceptually closer to Web3.js's Connection model while still giving you the benefits of Kit's modular architecture. Check out the Getting Started tutorial to see the client-based approach in action or explore Plugins to learn more about the plugin system.