--- name: solana-kit-migration description: Helps developers understand when to use @solana/kit vs @solana/web3.js (v1), provides migration guidance, API mappings, and handles edge cases for Solana JavaScript SDK transitions --- # Solana Kit Migration Assistant This skill helps you navigate the transition between `@solana/web3.js` (v1.x) and `@solana/kit` (formerly web3.js 2.0), providing guidance on when to use each library and how to migrate between them. ## Overview The Solana JavaScript ecosystem has two major SDK options: | Library | Status | Use Case | |---------|--------|----------| | `@solana/web3.js` (1.x) | Maintenance mode | Legacy projects, Anchor-dependent apps | | `@solana/kit` | Active development | New projects, performance-critical apps | **Key Decision**: `@solana/kit` is the future, but migration isn't always straightforward. ## When to Use Each Library ### Use @solana/kit When: 1. **Starting a new project** without Anchor dependencies 2. **Bundle size matters** - Kit is tree-shakeable (26% smaller bundles) 3. **Performance is critical** - ~200ms faster confirmation latency, 10x faster crypto ops 4. **Using standard programs** (System, Token, Associated Token) 5. **Building browser applications** where bundle size impacts load time 6. **Type safety is important** - Better TypeScript support catches errors at compile time 7. **Using modern JavaScript** - Native BigInt, WebCrypto, AsyncIterators ### Use @solana/web3.js (v1.x) When: 1. **Using Anchor** - Anchor doesn't support Kit out of the box yet 2. **Existing large codebase** - Migration cost outweighs benefits 3. **Dependencies require v1** - Check if your SDKs support Kit 4. **Rapid prototyping** - v1's OOP style may be more familiar 5. **Documentation/examples** - More community resources for v1 ### Use Both (Hybrid Approach) When: 1. **Gradual migration** - Use `@solana/compat` for interoperability 2. **Mixed dependencies** - Some libs require v1, some support Kit 3. **Feature-by-feature migration** - Convert hot paths first ## Quick Decision Flowchart ``` START │ ├─ New project? ─────────────────────────────────────────┐ │ │ │ │ ├─ Using Anchor? ──► YES ──► Use @solana/web3.js │ │ │ │ │ └─ No Anchor? ──► Use @solana/kit │ │ │ └─ Existing project? ────────────────────────────────────┤ │ │ ├─ Performance issues? ──► Consider migration │ │ │ ├─ Bundle size issues? ──► Consider migration │ │ │ └─ Working fine? ──► Stay with current SDK │ ``` ## Instructions for Migration Analysis When a user asks about migration, follow these steps: ### Step 1: Analyze Current Codebase Run the migration analysis script to detect: - Which SDK version is currently used - Anchor dependencies - Third-party SDK dependencies - Usage patterns that need migration ```bash # Use the analyze-migration.sh script in scripts/ ./scripts/analyze-migration.sh /path/to/project ``` ### Step 2: Check Dependencies Look for these blocking dependencies: - `@coral-xyz/anchor` or `@project-serum/anchor` - Wait for Anchor Kit support - SDKs that haven't migrated (check their package.json) ### Step 3: Assess Migration Complexity Count occurrences of these patterns that need changes: - `new Connection(...)` → `createSolanaRpc(...)` - `Keypair.fromSecretKey(...)` → `createKeyPairSignerFromBytes(...)` - `new PublicKey(...)` → `address(...)` - `new Transaction()` → `createTransactionMessage(...)` - Class-based patterns → Functional composition with `pipe()` ### Step 4: Recommend Strategy Based on findings, recommend: - **Full Migration**: If no blockers and < 50 migration points - **Gradual Migration**: If 50-200 migration points, use `@solana/compat` - **Wait**: If Anchor-dependent or critical SDKs don't support Kit - **Hybrid**: If only specific modules need Kit performance ## API Migration Reference See `resources/api-mappings.md` for complete mappings. Key conversions: ### Connection → RPC ```typescript // v1 const connection = new Connection(url, 'confirmed'); const balance = await connection.getBalance(pubkey); // Kit const rpc = createSolanaRpc(url); const { value: balance } = await rpc.getBalance(address).send(); ``` ### Keypair → KeyPairSigner ```typescript // v1 const keypair = Keypair.fromSecretKey(secretKey); console.log(keypair.publicKey.toBase58()); // Kit const signer = await createKeyPairSignerFromBytes(secretKey); console.log(signer.address); ``` ### Transaction Building ```typescript // v1 const tx = new Transaction().add( SystemProgram.transfer({ fromPubkey: sender.publicKey, toPubkey: recipient, lamports: amount, }) ); tx.recentBlockhash = blockhash; tx.feePayer = sender.publicKey; // Kit const tx = pipe( createTransactionMessage({ version: 0 }), tx => setTransactionMessageFeePayer(sender.address, tx), tx => setTransactionMessageLifetimeUsingBlockhash(blockhash, tx), tx => appendTransactionMessageInstruction( getTransferSolInstruction({ source: sender, destination: address(recipient), amount: lamports(BigInt(amount)), }), tx ), ); ``` ## Edge Cases & Gotchas ### 1. BigInt Conversion Kit uses native BigInt everywhere. Watch for: ```typescript // WRONG - will fail const amount = 1000000000; // CORRECT const amount = 1_000_000_000n; // or const amount = BigInt(1000000000); // or use helper const amount = lamports(1_000_000_000n); ``` ### 2. Base58 Encoding Errors Kit may require explicit encoding: ```typescript // If you see: "Encoded binary (base 58) data should be less than 128 bytes" // Add encoding parameter: await rpc.getAccountInfo(address, { encoding: 'base64' }).send(); ``` ### 3. Async Keypair Generation Kit keypair creation is async (uses WebCrypto): ```typescript // v1 - synchronous const keypair = Keypair.generate(); // Kit - MUST await const keypair = await generateKeyPairSigner(); ``` ### 4. RPC Method Chaining Kit RPC calls require `.send()`: ```typescript // v1 const balance = await connection.getBalance(pubkey); // Kit - don't forget .send()! const { value: balance } = await rpc.getBalance(address).send(); ``` ### 5. PublicKey vs Address These are different types and not interchangeable: ```typescript // Use @solana/compat for conversion import { fromLegacyPublicKey, toLegacyPublicKey } from '@solana/compat'; const kitAddress = fromLegacyPublicKey(legacyPublicKey); const legacyPubkey = toLegacyPublicKey(kitAddress); ``` ### 6. Transaction Signing Signing flow is different: ```typescript // v1 transaction.sign(keypair); // or const signed = await connection.sendTransaction(tx, [keypair]); // Kit - use signer pattern const signedTx = await signTransactionMessageWithSigners(txMessage); const signature = await sendAndConfirmTransaction(signedTx); ``` ### 7. Anchor Incompatibility Anchor generates v1 types. If using Anchor: ```typescript // Keep @solana/web3.js for Anchor interactions import { Connection, PublicKey } from '@solana/web3.js'; import { Program } from '@coral-xyz/anchor'; // Use Kit for non-Anchor parts if needed // Bridge with @solana/compat ``` ### 8. Subscription Handling Kit uses AsyncIterators: ```typescript // v1 const subscriptionId = connection.onAccountChange(pubkey, callback); connection.removeAccountChangeListener(subscriptionId); // Kit - use AbortController const abortController = new AbortController(); const notifications = await rpcSubscriptions .accountNotifications(address) .subscribe({ abortSignal: abortController.signal }); for await (const notification of notifications) { // handle notification } // To unsubscribe: abortController.abort(); ``` ### 9. VersionedTransaction Migration ```typescript // v1 const versionedTx = new VersionedTransaction(messageV0); // Kit - transactions are versioned by default const tx = createTransactionMessage({ version: 0 }); ``` ### 10. Lookup Tables Address Lookup Tables work differently: ```typescript // v1 const lookupTable = await connection.getAddressLookupTable(tableAddress); const messageV0 = new TransactionMessage({...}).compileToV0Message([lookupTable.value]); // Kit // Lookup tables are handled in transaction compilation // See resources/lookup-tables-example.md ``` ## Alternative: Consider Gill If Kit feels too low-level, consider [Gill](https://github.com/solana-foundation/gill): - Built on Kit primitives - Higher-level abstractions - Simpler API for common tasks - Full Kit compatibility ```typescript import { createSolanaClient, sendSol } from 'gill'; const client = createSolanaClient({ rpcUrl }); await sendSol(client, { from: signer, to: recipient, amount: lamports(1n) }); ``` ## Guidelines - Always check Anchor compatibility before recommending Kit migration - Recommend `@solana/compat` for gradual migrations - Bundle size benefits matter most for browser applications - Performance benefits matter most for high-throughput backends - Don't migrate stable, working code without clear benefits - Test thoroughly - Kit has different error types and behaviors ## Files in This Skill ``` solana-kit-migration/ ├── SKILL.md # This file ├── scripts/ │ ├── analyze-migration.sh # Codebase analysis script │ └── detect-patterns.js # Pattern detection utility ├── resources/ │ ├── api-mappings.md # Complete API reference │ ├── compatibility-matrix.md # SDK compatibility info │ └── package-comparison.md # Feature comparison ├── examples/ │ ├── v1-to-kit/ # Migration examples │ │ ├── basic-transfer.md │ │ ├── token-operations.md │ │ └── subscription-handling.md │ └── mixed-codebase/ # Hybrid approach examples │ └── anchor-with-kit.md └── docs/ └── edge-cases.md # Detailed edge cases ``` ## Notes - Kit was released as @solana/web3.js@2.0.0 on December 16, 2024 - It was later renamed to @solana/kit to avoid confusion - The 1.x line is in maintenance mode but still widely used - Migration tooling is evolving - check for updates regularly