@solana/kit vs @solana/web3.js vs gill: the JS client situation in 2026 logo@solana/kit vs @solana/web3.js vs gill: the JS client situation in 2026
Legacy web3.js is on borrowed time. @solana/kit is the official successor. gill is the ergonomic wrapper. Here's the actual difference and what to use when.
devrels.xyz/a/11Every 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
Keep reading
Branded types, pipe-based composition, codecs for serialization, no classes, no defaults. Kit's a fundamental redesign — not a coat of paint on web3.js. The concrete shape.
Solana's TypeScript ecosystem fractured: web3.js v1, then the Kit rewrite, then Gill and Kite wrappers — and choice paralysis. web3.js 3.0 is the convergence move: the API everyone already knows, rebuilt on Kit's modern internals. What it actually is, with the package facts the announcement leaves out.
Create or authorize stake accounts so Marinade can rebalance them. Keep withdraw authority. Prepare an unstake, wait one epoch, then withdraw.
Get new articles in your inbox
Technical deep-dives on Solana tooling, infrastructure, and ecosystem. No noise.
