Kit-squared: @solana/kit in SvelteKit, no React needed
@solana/kit is framework-agnostic. Here's how to wire it into a SvelteKit app — RPC store, wallet store, reactive subscriptions, no React-only assumptions.
devrels.xyz/a/75short linkMost Solana JS tutorials assume React. @solana/kit deliberately doesn't — it's framework-agnostic functional code, no React adapters, no hooks. That makes it a clean fit for SvelteKit, where the reactivity model is the framework's job, not the SDK's.
This article is the integration pattern.
Why kit is the right base for SvelteKit
- No React. Classic web3.js was OK in Svelte but you always felt the React shape in its class-based API. Kit is just functions.
- SSR-safe. No hidden globals, no
windowassumptions. The RPC client works in server load functions and inonMount. - Tree-shakeable. SvelteKit's build dead-code-eliminates aggressively; kit's per-program packages let you ship a ~25KB Solana bundle.
- Bigint-everywhere. Svelte stores hold bigints without complaint; no
BN.jsoverhead.
RPC as a Svelte store
// src/lib/solana/rpc.ts
import { writable, readable, type Readable } from "svelte/store"
import {
createSolanaRpc,
createSolanaRpcSubscriptions,
type Address,
type Slot,
} from "@solana/kit"
const HTTP = import.meta.env.PUBLIC_SOLANA_RPC ?? "https://api.mainnet-beta.solana.com"
const WS = HTTP.replace(/^http/, "ws")
export const rpc = createSolanaRpc(HTTP)
export const subs = createSolanaRpcSubscriptions(WS)
// A reactive store backed by an RPC subscription
export function slotStore(): Readable<Slot | null> {
return readable<Slot | null>(null, (set) => {
const ac = new AbortController()
;(async () => {
const notifications = await subs.slotNotifications().subscribe({ abortSignal: ac.signal })
for await (const n of notifications) set(n.slot)
})()
return () => ac.abort()
})
}
export function accountStore(address: Address) {
return readable<{ lamports: bigint; data: Uint8Array } | null>(null, (set) => {
const ac = new AbortController()
;(async () => {
// initial fetch
const { value } = await rpc.getAccountInfo(address).send()
set(value as any)
// subscribe to changes
const notifications = await subs.accountNotifications(address).subscribe({
abortSignal: ac.signal,
})
for await (const n of notifications) set(n.value as any)
})()
return () => ac.abort()
})
}Each store wraps a kit subscription in Svelte's store contract. The cleanup function fires when the last subscriber unsubscribes, which aborts the RPC subscription. No leaks.
Wallet adapter for Svelte
For Phantom / Solflare / Backpack connections in a SvelteKit app, use @wallet-standard/appdirectly — wallet standard is framework-agnostic, no React adapter required:
// src/lib/solana/wallet.ts
import { writable } from "svelte/store"
import { getWallets, type Wallet } from "@wallet-standard/app"
export const wallets = writable<Wallet[]>([])
export const selected = writable<Wallet | null>(null)
export const account = writable<{ address: string; publicKey: Uint8Array } | null>(null)
if (typeof window !== "undefined") {
const { get, on } = getWallets()
// Snapshot
wallets.set(get().filter((w) => w.chains.includes("solana:mainnet")))
// Stay in sync with wallet installs/removals
on("register", () => wallets.set(get()))
on("unregister", () => wallets.set(get()))
}
export async function connect(wallet: Wallet) {
const standardFeature = wallet.features["standard:connect" as const]
if (!standardFeature) throw new Error("wallet doesn't implement standard:connect")
const result = await (standardFeature as any).connect()
selected.set(wallet)
account.set(result.accounts[0])
}SSR-safe load functions
// src/routes/+page.server.ts
import { rpc } from "$lib/solana/rpc"
import { address } from "@solana/kit"
export async function load({ params }) {
// Runs on the server — no window, no wallet, just RPC
const balance = await rpc.getBalance(address(params.addr)).send()
return { addressBalance: balance.value }
}<!-- src/routes/+page.svelte -->
<script lang="ts">
import { slotStore } from "$lib/solana/rpc"
export let data
const slot = slotStore() // reactive store of current slot
</script>
<h1>Balance: {data.addressBalance} lamports</h1>
<p>Current slot: {$slot ?? "loading"}</p>Sending a tx from Svelte
<script lang="ts">
import { account, selected } from "$lib/solana/wallet"
import { rpc } from "$lib/solana/rpc"
import {
pipe, createTransactionMessage, setTransactionMessageFeePayer,
setTransactionMessageLifetimeUsingBlockhash, appendTransactionMessageInstruction,
address, lamports,
} from "@solana/kit"
import { getTransferSolInstruction } from "@solana-program/system"
async function send() {
if (!$account || !$selected) return
const ix = getTransferSolInstruction({
source: $account.address as any,
destination: address("RecipientPubkey…"),
amount: lamports(10_000_000n),
})
const { value: bh } = await rpc.getLatestBlockhash().send()
const message = pipe(
createTransactionMessage({ version: 0 }),
(m) => setTransactionMessageFeePayer($account!.address as any, m),
(m) => setTransactionMessageLifetimeUsingBlockhash(bh, m),
(m) => appendTransactionMessageInstruction(ix, m),
)
// Hand the encoded message to the wallet to sign + send
const signFeature = $selected.features["solana:signAndSendTransaction"]
const result = await (signFeature as any).signAndSendTransaction({
account: $account,
transaction: /* encode message to wire format */ ,
chain: "solana:mainnet",
})
console.log("sig:", result[0].signature)
}
</script>
<button on:click={send}>Send 0.01 SOL</button>The case for SvelteKit + Solana
SvelteKit has aggressive bundle optimisation, real SSR (load functions, +page.server.ts), and a smaller runtime than Next.js. Combined with kit's tree shaking, the result is a Solana dapp that ships dramatically less JavaScript than the Next.js/React equivalent. For consumer apps where time-to- interactive matters — gaming, social, retail trading — that gap is real.
References
Kit + SvelteKit is the lightest Solana stack you can ship in 2026. The framework does reactivity, kit does Solana, neither carries assumptions about the other.
Keep reading
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.
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.
The fastest Solana vanity grinder just made its slow path fast. v0.8.0 batches ed25519 keygen 8 lanes wide with AVX-512 IFMA on CPU and rebuilds the OpenCL keypair kernels — Montgomery batch inversion, a radix-32 comb for fixed-base scalarmult, fused base58 early-reject. Real signable vanity keypairs at 65M/s per 4090.
Get new articles in your inbox
Technical deep-dives on Solana tooling, infrastructure, and ecosystem. No noise.
