Skip to main content
Version: 1.0.0

Browser Setup

The CCIP SDK works in browser environments with proper bundler configuration. This guide covers polyfill requirements and common bundler setups.

Polyfill Requirements

SDK-Only Projects

The buffer polyfill is required by the SDK's Solana, TON, and Sui chain implementations. EVM-only and Aptos-only consumers do not need buffer at runtime.

PolyfillRequired ByNOT Required By
bufferSolana, TON, Sui chainsEVM, Aptos

Bundler behavior differs:

  • Vite: Always include the buffer polyfill, even for EVM-only projects. Vite's dev server pre-bundles all SDK dependencies eagerly (including Solana/TON code), so the polyfill must be resolvable.
  • Webpack/Next.js: EVM-only consumers do not need the buffer polyfill. Non-EVM code is tree-shaken in production and never executed at runtime in development.

With Wallet Libraries

If you're using wallet connection libraries (RainbowKit, MetaMask SDK, Solana Wallet Adapter), additional polyfills are needed:

PolyfillRequired ByNOT Required By
bufferSolana, TON, Sui chainsEVM, Aptos
crypto@metamask/sdk, wallet libraries@chainlink/ccip-sdk
stream@metamask/sdk@chainlink/ccip-sdk
process@metamask/sdk, @walletconnect@chainlink/ccip-sdk
util@solana/wallet-adapter@chainlink/ccip-sdk

Dependency Version Conflict (@noble/hashes)

The SDK depends on ethers (which pins @noble/hashes@1.3.2) and @mysten/sui (which requires @noble/hashes@^1.8.0). Node.js handles this automatically via nested node_modules, but Webpack and Next.js may resolve to the wrong version, causing ERR_PACKAGE_PATH_NOT_EXPORTED.

Add version overrides to your project's package.json to force a single compatible version:

JSON
{
"overrides": {
"@noble/hashes": "^1.8.0"
}
}

This is safe — @noble/hashes@1.8.0 is backward-compatible with ethers' needs.

In addition, add a resolve.alias in your bundler config to ensure the correct version is used (see the Webpack and Next.js sections below).

Vite Configuration

TypeScript
// vite.config.ts - Minimal config for CCIP SDK only
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { nodePolyfills } from 'vite-plugin-node-polyfills'

export default defineConfig({
plugins: [
react(),
nodePolyfills({
include: ['buffer'],
globals: { Buffer: true },
}),
],
})

Install the polyfill plugin:

Bash
npm install vite-plugin-node-polyfills

Webpack Configuration

JavaScript
// webpack.config.js - EVM-only (no polyfills needed)
const path = require('path')

module.exports = {
resolve: {
alias: {
'@noble/hashes': path.dirname(require.resolve('@noble/hashes')),
},
},
}

EVM-only consumers do not need the buffer polyfill on Webpack. Non-EVM code is tree-shaken in production and never executed in development.

Install polyfill packages:

Bash
# If using Solana, TON, or Sui chains:
npm install buffer
# If using wallet libraries:
npm install crypto-browserify stream-browserify util process

Next.js Configuration

Recommended: Next.js >= 13.4.5 (supports moduleResolution: "bundler"). For older versions, see the legacy workaround below.

JavaScript
// next.config.js
const path = require('path')

/** @type {import('next').NextConfig} */
const nextConfig = {
webpack: (config, { isServer }) => {
if (!isServer) {
// Fix @noble/hashes version conflict
config.resolve.alias = {
...config.resolve.alias,
'@noble/hashes': path.dirname(require.resolve('@noble/hashes')),
}
}
return config
},
}

module.exports = nextConfig

EVM-only consumers do not need the buffer polyfill on Next.js.

Tree-Shaking

The SDK supports tree-shaking — only the chains you import are bundled:

TypeScript
// Only EVMChain is bundled
import { EVMChain } from '@chainlink/ccip-sdk'

// Only SolanaChain is bundled
import { SolanaChain } from '@chainlink/ccip-sdk'

// All chains - largest bundle, use only if needed
import { allSupportedChains } from '@chainlink/ccip-sdk/all'

Webpack/Next.js: Tree-shaking requires the @noble/hashes version fix first. Without it, Webpack fails at module resolution before tree-shaking can run.

Bundle Sizes

ImportMinifiedGzipped
EVM only740 KB~180 KB
Solana only1.2 MB~290 KB
Aptos only700 KB~170 KB
Sui only756 KB~185 KB
TON only760 KB~185 KB
EVM + Solana1.4 MB~340 KB
All chains2.0 MB~480 KB

Important: Don't place @chainlink/ccip-sdk in manualChunks configuration, as this disables tree-shaking:

TypeScript
// vite.config.ts
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: {
'vendor-react': ['react', 'react-dom'],
'vendor-solana': ['@solana/web3.js'],
// DON'T add @chainlink/ccip-sdk here
},
},
},
},
})

Using with Wagmi/Viem

When using the SDK with wagmi, you may encounter type mismatches with fromViemClient():

TypeScript
import { getPublicClient } from '@wagmi/core'
import { fromViemClient } from '@chainlink/ccip-sdk/viem'
import type { PublicClient, Transport, Chain } from 'viem'

// Type bridge for wagmi compatibility
function toGenericPublicClient(
client: ReturnType<typeof getPublicClient>
): PublicClient<Transport, Chain> {
return client as PublicClient<Transport, Chain>
}

// Usage
const wagmiClient = getPublicClient(wagmiConfig, { chainId: 11155111 })
const publicClient = toGenericPublicClient(wagmiClient)
const chain = await fromViemClient(publicClient)

This cast is safe when both packages use the same viem version.

Complete Vite Example

Full configuration for a React app with EVM and Solana support:

TypeScript
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { nodePolyfills } from 'vite-plugin-node-polyfills'

export default defineConfig({
plugins: [
react(),
nodePolyfills({
include: ['buffer', 'crypto', 'stream', 'util', 'process'],
globals: {
Buffer: true,
global: true,
process: true,
},
}),
],
define: {
'process.env': {},
},
build: {
rollupOptions: {
output: {
manualChunks: {
'vendor-react': ['react', 'react-dom'],
'vendor-solana': ['@solana/web3.js', '@solana/wallet-adapter-base'],
'vendor-evm': ['wagmi', 'viem', '@rainbow-me/rainbowkit'],
// Don't include @chainlink/ccip-sdk - let it tree-shake
},
},
},
},
optimizeDeps: {
include: ['buffer'],
},
})

Framework Integration

Next.js

See the Next.js Configuration section above for webpack config (including the required @noble/hashes resolve.alias fix).

For client components using Solana/TON/Sui, install the buffer polyfill and add at the top:

Bash
npm install buffer
TSX
'use client'
import { Buffer } from 'buffer'
if (typeof window !== 'undefined') {
window.Buffer = Buffer
}

Next.js 12 – 13.4.4 (Legacy)

These versions force moduleResolution: "node", which cannot resolve the SDK's type declarations. Add the following paths mapping to your tsconfig.json:

JSON
{
"compilerOptions": {
"paths": {
"@chainlink/ccip-sdk": [
"./node_modules/@chainlink/ccip-sdk/src/index.ts"
],
"@chainlink/ccip-sdk/viem": [
"./node_modules/@chainlink/ccip-sdk/src/viem.ts"
]
}
}
}

Remix

Remix uses esbuild under the hood. Add the buffer shim to your client entry:

Bash
npm install buffer
TypeScript
// app/entry.client.tsx
import { Buffer } from 'buffer'
globalThis.Buffer = Buffer

// ... rest of entry.client.tsx

Verify Your Setup

After configuring your bundler, verify the polyfill is working:

TypeScript
// Add to your app's entry point or browser console
console.log('Buffer available:', typeof Buffer !== 'undefined')
console.log('Buffer works:', Buffer.from('test').toString('hex') === '74657374')

Check bundle size to verify tree-shaking:

Bash
# Check output file size
ls -lh dist/*.js

# For detailed analysis
npx source-map-explorer dist/bundle.js

Expected sizes for EVM-only: ~740 KB minified, ~180 KB gzipped.

Troubleshooting

"ERR_PACKAGE_PATH_NOT_EXPORTED"

Cause: ethers pins @noble/hashes@1.3.2 while other SDK dependencies require @noble/hashes@1.8.0+. Webpack may resolve to the v1.3.2 copy, which lacks sub-paths like ./blake2.js and ./sha2.js that were added in v1.8.0.

Solution: Add version overrides to your package.json and resolve.alias to your bundler config. See the Dependency Version Conflict section above.

"Buffer is not defined"

Cause: Using Solana or TON chains without the Buffer polyfill, or the polyfill isn't loading before SDK code.

Solution:

  1. Verify the polyfill configuration for your bundler
  2. Ensure buffer package is installed: npm ls buffer
  3. For Bun, use a custom build script to ensure correct load order

"process is not defined"

Cause: Wallet libraries (MetaMask SDK, WalletConnect) require process.

Solution: Add the process polyfill if using wallet libraries that require it.

Bundle size larger than expected

Cause: Tree-shaking may not be working, or you're importing more chains than needed.

Symptoms: EVM-only bundle exceeds 1 MB.

Solution:

  1. Verify you're using ES module imports (not require())
  2. Check you're importing specific chains, not allSupportedChains
  3. Run a bundle analyzer:
    Bash
    # Webpack
    npx webpack-bundle-analyzer dist/stats.json

    # Vite
    npx vite-bundle-visualizer

Vite dev server errors with EVM-only code

Cause: Vite pre-bundles all SDK dependencies in development mode, including Solana/TON libraries that need Buffer.

Solution: Add the Buffer polyfill even for EVM-only development. This is only needed for vite dev; production builds will tree-shake correctly.

Type errors with wagmi

Cause: Wagmi's getPublicClient() returns a chain-specific typed client that doesn't match the SDK's expected type.

Solution: Use the type bridge function shown in "Using with Wagmi/Viem" section, or see the Viem Integration guide.

"Cannot find module 'buffer'"

Cause: The buffer package is not installed.

Solution:

Bash
npm install buffer