@solana/kit vs @solana/web3.js vs gill: the JS client situation in 2026
Three JavaScript clients, three philosophies. What to pick for a new Solana project in 2026, and how to migrate if you're stuck on the old web3.js.
Every Solana frontend in the world used to import the same package: @solana/web3.js. It worked, but it was old — class-based, non-tree-shakeable, default-export-everything. Bundle size hurt. Type inference hurt. The maintainers knew, and in 2024 they shipped a ground-up rewrite under a new name: @solana/kit.
Two years later, kit is the official client and gill is the popular ergonomic wrapper around it. Here's the actual difference between the three.
@solana/web3.js (the legacy one)
Class-based, monolithic. Importing one symbol pulls in the whole library:
import { Connection, Keypair, Transaction, SystemProgram, LAMPORTS_PER_SOL } from "@solana/web3.js"
const conn = new Connection("https://api.mainnet-beta.solana.com")
const payer = Keypair.generate()
const tx = new Transaction().add(
SystemProgram.transfer({
fromPubkey: payer.publicKey,
toPubkey: new PublicKey("..."),
lamports: 0.01 * LAMPORTS_PER_SOL,
})
)
const sig = await conn.sendTransaction(tx, [payer])Status in 2026: maintenance mode. New features land in kit, not here. Compatibility is preserved but nobody's optimising. If you start a new project on web3.js today, you'll be migrating within a year.
@solana/kit (the official successor)
Functional, tree-shakeable, strict TypeScript. Every primitive is a plain function or branded type. No classes, no new, everything pipes:
import {
createSolanaRpc,
createKeyPairSignerFromBytes,
pipe,
createTransactionMessage,
setTransactionMessageFeePayer,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstruction,
signAndSendTransactionMessageWithSigners,
lamports,
} from "@solana/kit"
import { getTransferSolInstruction } from "@solana-program/system"
const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com")
const payer = await createKeyPairSignerFromBytes(secretKeyBytes)
const ix = getTransferSolInstruction({
source: payer,
destination: recipient,
amount: lamports(10_000_000n),
})
const { value: blockhash } = await rpc.getLatestBlockhash().send()
const tx = pipe(
createTransactionMessage({ version: 0 }),
(m) => setTransactionMessageFeePayer(payer.address, m),
(m) => setTransactionMessageLifetimeUsingBlockhash(blockhash, m),
(m) => appendTransactionMessageInstruction(ix, m),
)
const sig = await signAndSendTransactionMessageWithSigners(tx)Verbose. Very typed. Tree-shaking actually works — a transfer-only bundle is ~25KB instead of web3.js's ~250KB.
Status in 2026: the official, current client. Most new tooling (codama, recent SDKs from Crossmint, Privy, Anchor 0.31+) targets kit. Maintained by Anza.
gill (the ergonomic wrapper)
gill is Decal Labs' opinionated wrapper around @solana/kit. It restores web3.js-style ergonomics on top of the modern foundations — chainable builders, sensible defaults, less ceremony — without giving up tree shaking.
import { createSolanaClient, generateKeyPairSigner, getExplorerLink } from "gill"
import { getTransferSolInstruction } from "@solana-program/system"
const { rpc, sendAndConfirmTransaction } = createSolanaClient({ urlOrMoniker: "mainnet" })
const payer = await generateKeyPairSigner()
const transferIx = getTransferSolInstruction({
source: payer,
destination: recipient,
amount: 10_000_000n,
})
const sig = await sendAndConfirmTransaction({
feePayer: payer,
instructions: [transferIx],
})
console.log(getExplorerLink({ transaction: sig }))Roughly the same lines of code as the old web3.js, all the tree shaking of kit, all the typing of kit, plus opinionated helpers like getExplorerLink and urlOrMoniker: "mainnet" that web3.js never had.
The decision
New project in 2026:
- Building a frontend → gill. You get kit's benefits without writing kit's ceremony. Bundle is small, types are strong, code reads cleanly.
- Building a library / SDK that other people will depend on → kit directly. Don't inflict gill on your consumers — let them choose.
- Server-side script / one-shot tooling → either works. gill if you want it quick, kit if you want explicit.
Existing project on web3.js:
- Greenfield rewrite already on the roadmap → migrate to gill (or kit) on the next major version. Don't do it mid-feature.
- Production app, no scheduled rewrite → stay on web3.js for now. It still works. Migrate when you next touch the file.
Migration tip
Kit and gill both publish program-specific instruction packages (@solana-program/system, @solana-program/token, etc.) that mirror what web3.js bundled. The migration is largely mechanical: replace new Transaction().add(SystemProgram.transfer(...)) with getTransferSolInstruction(...) inside the new pipe-builder pattern. Type errors will guide you the rest of the way.
References
- anza-xyz/kit — @solana/kit source
- DecalLabs/gill — gill source
- @solana/kit docs