@solana/kit 7.0.0 is the modern TypeScript client stack for Solana: functional composition, branded types, tree-shakable modules, and explicit network I/O. It is the default for new clients in 2026. Legacy @solana/web3.js v1 is a migration source, not a greenfield default.
This page maps RPC, subscriptions, keypairs and signers, transaction messages, codecs, address lookup tables (ALTs), and the web3.js v1 migration path before the focused recipe pages.
Kit splits what web3.js v1 packed into Connection, Transaction, and PublicKey into smaller, typed surfaces. You create an RPC client for HTTP JSON-RPC, a subscriptions client for WebSockets, and you build transaction messages with pure transforms (pipe, fee payer, blockhash lifetime, instructions) before signing and sending.
Signers are the unit of authorization: local KeyPairSigners for scripts and tests, wallet-backed signers for browsers, all sharing one interface so fee payer and instruction authorities are not ad hoc public-key strings. Addresses are branded base58 strings validated at construction. Amounts that touch the chain are bigint lamports, not floating SOL and not BN by default.
Codecs encode and decode instruction and account layouts without assuming Anchor codegen. Version 0 messages plus ALTs shrink account lists when multi-hop DeFi or large remaining-account sets would blow size limits. Migration is intentional: port reads first, then message build and wallet sign, then delete web3.js so you do not run two client mental models forever.
@solana/kit is a client SDK, not an on-chain framework. It talks to RPC nodes, builds wire-format transactions, signs (or hands signing to a wallet), and decodes account bytes. On-chain logic still lives in programs (native, Anchor 0.32.1, Pinocchio, and so on).
Mutable class APIs encouraged editing a tx object until it worked. Kit prefers a pipeline: create message, set fee payer and lifetime, append instructions, optionally compress with ALTs, sign, then send and confirm.
createSolanaRpc(url) returns a typed JSON-RPC proxy. Methods do not hit the network until you call .send(). That makes request construction, batching strategies, and testing less magical than fire-on-call methods.
Subscriptions use a separate client (createSolanaRpcSubscriptions) over WebSocket. Notification APIs return streams you consume with for await and cancel with AbortSignal. HTTP and WS URLs must target the same cluster; a common production bug is HTTPS mainnet with WSS still on devnet.
Commitment (processed, confirmed, finalized) is a first-class option on reads and confirmations. Product UX usually waits on confirmed; irreversible off-chain effects should wait on finalized.
generateKeyPairSigner() for ephemeral Ed25519 identities.
createKeyPairSignerFromBytes (or related import helpers) for solana-keygen JSON arrays.
Browser apps should not embed secret keys. Wallet adapters and Wallet Standard integrations expose signers that implement the same roles without revealing private keys. Fee payers use helpers like setTransactionMessageFeePayerSigner so the message carries both address and signing capability.
Off-chain message signing for auth is a sibling concern: same identity, different payload. Keep domain separation so login signatures cannot be confused with transaction approvals.
Prefer version 0 messages for new work. Build immutably:
createTransactionMessage({ version: 0 })
Set fee payer (signer-aware).
Set lifetime from a fresh getLatestBlockhash result.
Append instructions (compute budget first when you set CU limit/price).
Sign once the message is complete.
pipe keeps multi-step transforms readable. Instructions often come from scoped packages such as @solana-program/system (getTransferSolInstruction) rather than a single monolithic SystemProgram object. Multi-instruction transactions remain atomic on-chain: all succeed or none commit.
Stale blockhashes expire. Fetch lifetime close to submit, and design retries to rebuild messages rather than reusing a dead lifetime.
Programs speak bytes. Kit codecs compose small primitives into structs:
Fixed widths: u8, u32, u64, and friends as encoders/decoders.
getAddressEncoder / getAddressDecoder for 32-byte pubkeys in layouts.
getStructEncoder / getStructDecoder for ordered field layouts.
Discriminators (often 8-byte Anchor hashes or custom tags) as leading fields.
Use codecs when you lack a generated client, when indexing raw accounts, or when validating instruction data before send. Prefer Codama or Anchor-generated clients for known program APIs; keep hand-rolled codecs for edges generators do not cover.
Endianness, padding, and option tags must match the on-chain layout. A clean TypeScript type that diverges from the program's borsh/bytemuck layout is still wrong on the wire.
Legacy and oversized account lists fail with size or account-count limits. Version 0 messages can reference accounts through address lookup tables: on-chain tables of addresses that the runtime expands during processing so the wire transaction carries compact indexes instead of full keys for every account.
Client-side, fetch table account data, build a full logical message, then compress with helpers such as compressTransactionMessageUsingAddressLookupTables. Tables must exist and be activated before production use; create/extend/freeze is operational work, not free at submit time.
Use ALTs for large DeFi routes, bulk NFT ops, and repeated large account sets. Skip ALT complexity for simple two-account transfers.
After the message is complete, signTransactionMessageWithSigners resolves embedded signers. Factories such as sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions }) wait for the chosen commitment. A signature means submission was accepted; product correctness still depends on confirmation policy and errors (expired blockhash, funds, simulation).
Do not rewrite the entire app in one PR if the surface is large. A durable sequence:
Phase
Scope
Exit criteria
1
RPC reads only
Balances, accounts, and slots use kit RPC
2
Message build + wallet sign
User flows sign kit messages
3
Remove web3.js
Single dependency tree in CI
4
Generated program clients
Codama/IDL clients for your programs
Convert PublicKey to Address at module boundaries once. Standardize on bigint for lamports. Replace implicit confirm habits with explicit factories and commitment. Kill dual stacks on a deadline; endless partial migration doubles bug surface.
Import only the helpers you need. Prefer @solana-program/* instruction builders over copy-pasted account metas. Keep wallet code out of server/edge bundles; load file keypairs only in dedicated Node scripts.
Public RPCs rate-limit aggressively. Production needs a provider URL, separate HTTP and WS endpoints, and backoff on 429/5xx. Subscriptions drop; reconnect with backoff and resync from HTTP rather than assuming a gap-free stream.
Share layout modules (or generate once) across frontend, workers, and indexers. Divergent hand-rolled parsers are a silent incident class. Version account data on-chain when layouts evolve; decode via discriminator or version fields.
Treat lookup tables as infrastructure: ownership, authority, extension cadence, and freeze policy belong in runbooks. Avoid stale cached table views; measure wire size before and after compression in CI for critical routes.
Unit-test pure message transforms and codecs offline. Integration-test send/confirm on local validators (Solana CLI 3.0.10 / Agave-class) or Surfpool-style envs. Simulate before send to catch meta errors cheaper than mainnet retries.
Misconception: Kit is "web3.js with different import paths."
The programming model changed: immutable messages, branded types, explicit .send(), and signer interfaces. Treating it as a rename guarantees awkward hybrid code.
Misconception: PublicKey and Address are interchangeable everywhere.
They are not the same type. Convert at boundaries; do not pass class instances into kit APIs expecting branded strings.
Misconception: If .send() is annoying, skip it or wrap it away forever. .send() makes I/O explicit. You can thin-wrap for app ergonomics, but hiding all network boundaries tends to recreate the old implicit Connection mess.
Misconception: Browser dapps should ship KeyPairSigners in the bundle.
User authority belongs in wallets. Local keypair signers are for servers, CI, and tests (with secret hygiene).
Misconception: Codecs are only for people without Anchor.
Generated clients cover known programs. Codecs still matter for unknown accounts, custom layouts, migrations, and indexers.
Misconception: ALTs replace careful account design.
They compress references; they do not remove lock contention, CU cost, or the need for correct writable/signer metas.
Misconception: A signature string means the transfer is final.
Confirmation commitment decides durability. Design UX and backend effects around that ladder.
Misconception: Running kit and web3.js side by side indefinitely is fine.
It works briefly. Long term you pay double dependency weight and double cognitive load. Plan removal.
A modular TypeScript client stack for Solana RPC, signing, transaction messages, codecs, and related helpers, designed for tree-shaking and explicit composition in the 7.x line.
Should new projects still start on web3.js v1?
No. Prefer @solana/kit 7.0.0 for new TypeScript clients. Use web3.js v1 only while migrating legacy code.
Why does every RPC method need .send()?
So building a request is pure and network I/O is intentional. That improves typing, testing, and control over retries and batching.
What is a Signer versus an Address?
An Address identifies an account. A Signer can prove authority for that address (or a role) when a transaction requires signatures.
When do I use createTransactionMessage versus older Transaction classes?
Use kit transaction messages for all new kit code. Avoid constructing web3.js Transaction objects if you have already adopted kit signing and send helpers.
Where do System Program transfers come from now?
From scoped packages such as @solana-program/system (for example getTransferSolInstruction), composed into a message with fee payer and lifetime set.
Do I need codecs if I use Codama or Anchor clients?
Not for every instruction. You still want codec literacy for raw account inspection, custom programs, and services that cannot take a full generated client.
When are address lookup tables worth it?
When version-0 transactions would otherwise exceed size or account limits, especially multi-account DeFi routes and bulk operations that reuse large address sets.
How do subscriptions relate to getAccountInfo?
HTTP reads give point-in-time state. Subscriptions push updates; after reconnects, rebaseline with HTTP so you do not miss gaps.
What commitment should I confirm with?
Many app actions use confirmed. Use finalized before irreversible external side effects. Treat processed as optimistic UI only.
How should I migrate a large React dapp?
Phase it: kit RPC reads, then message build and wallet signing, then remove web3.js, then generated program clients. See Migrating from web3.js v1.
Does kit replace Anchor?
No. Anchor targets on-chain programs (and its own client tooling). Kit is the general TypeScript client stack for talking to the cluster and composing transactions.