All articles
solanatypescriptweb3jskitgill

@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:

typescript
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:

typescript
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.

typescript
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

@solana/kit vs @solana/web3.js vs gill: the JS client situation in 2026 | devrels.xyz