Browser Setup
The CCIP SDK works in browser environments with proper bundler configuration. What you need depends on which chains you use and which bundler you have.
What You Need
The SDK itself requires only the buffer polyfill — and only when using Solana, TON, or Sui chains. Wallet libraries (MetaMask SDK, WalletConnect, RainbowKit) may require additional polyfills.
| Polyfill | When required |
|---|---|
buffer | Solana, TON, or Sui chains (not needed for EVM-only or Aptos-only) |
crypto | MetaMask SDK, some wallet libraries |
stream | MetaMask SDK |
process | MetaMask SDK, WalletConnect |
util | Solana Wallet Adapter |
Additionally, Webpack and Next.js need a resolve.alias for @noble/hashes to fix a version conflict between SDK dependencies. The ethers dependency tree includes an older @noble/hashes version that lacks sub-paths (./blake2.js, ./sha2.js) required by @mysten/sui. Without the alias, you'll get ERR_PACKAGE_PATH_NOT_EXPORTED. Add version overrides to your package.json:
- npm
- yarn
- pnpm
{
"overrides": {
"@noble/hashes": "^1.8.0"
}
}
{
"resolutions": {
"**/@noble/hashes": "^1.8.0"
}
}
{
"pnpm": {
"overrides": {
"@noble/hashes": "^1.8.0"
}
}
}
This is safe — @noble/[email protected] is backward-compatible with ethers' needs. Vite does not need this fix.
Vite
Install the polyfill plugin:
npm install vite-plugin-node-polyfills
Vite always needs 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. Production builds tree-shake correctly.
- SDK Only
- With Wallet Libraries
// 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'],
globals: { Buffer: true },
}),
],
})
// 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'],
// Don't include @chainlink/ccip-sdk — let it tree-shake
},
},
},
},
optimizeDeps: {
include: ['buffer'],
},
})
Webpack
EVM-only consumers do not need the buffer polyfill on Webpack — non-EVM code is tree-shaken in production and never executed in development.
All Webpack configs need the @noble/hashes alias (see above).
- EVM Only
- Multi-Chain
- With Wallet Libraries
// webpack.config.js
const path = require('path')
module.exports = {
resolve: {
alias: {
'@noble/hashes': path.dirname(require.resolve('@noble/hashes')),
},
},
}
npm install buffer
// webpack.config.js
const path = require('path')
const webpack = require('webpack')
module.exports = {
resolve: {
alias: {
'@noble/hashes': path.dirname(require.resolve('@noble/hashes')),
},
fallback: {
buffer: require.resolve('buffer/'),
},
},
plugins: [
new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer'],
}),
],
}
npm install buffer crypto-browserify stream-browserify util process
// webpack.config.js
const path = require('path')
const webpack = require('webpack')
module.exports = {
resolve: {
alias: {
'@noble/hashes': path.dirname(require.resolve('@noble/hashes')),
},
fallback: {
buffer: require.resolve('buffer/'),
crypto: require.resolve('crypto-browserify'),
stream: require.resolve('stream-browserify'),
util: require.resolve('util/'),
process: require.resolve('process/browser'),
},
},
plugins: [
new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer'],
process: 'process/browser',
}),
],
}
Next.js
Requires Next.js >= 13.4.5 (supports moduleResolution: "bundler"). For older versions, see the legacy workaround below.
Like Webpack, EVM-only consumers do not need the buffer polyfill. All configs need the @noble/hashes alias.
- EVM Only
- Multi-Chain
// next.config.js
const path = require('path')
/** @type {import('next').NextConfig} */
const nextConfig = {
webpack: (config, { isServer }) => {
if (!isServer) {
config.resolve.alias = {
...config.resolve.alias,
'@noble/hashes': path.dirname(require.resolve('@noble/hashes')),
}
}
return config
},
}
module.exports = nextConfig
npm install buffer
// next.config.js
const path = require('path')
/** @type {import('next').NextConfig} */
const nextConfig = {
webpack: (config, { isServer }) => {
if (!isServer) {
config.resolve.alias = {
...config.resolve.alias,
'@noble/hashes': path.dirname(require.resolve('@noble/hashes')),
}
config.resolve.fallback = {
...config.resolve.fallback,
buffer: require.resolve('buffer/'),
}
}
return config
},
}
module.exports = nextConfig
For client components using Solana/TON/Sui, add at the top of the component:
'use client'
import { Buffer } from 'buffer'
if (typeof window !== 'undefined') {
window.Buffer = Buffer
}
Next.js 12 – 13.4.4
These versions force moduleResolution: "node", which cannot resolve the SDK's type declarations. Add paths to your tsconfig.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. Add the buffer shim to your client entry:
npm install buffer
// app/entry.client.tsx
import { Buffer } from 'buffer'
globalThis.Buffer = Buffer
// ... rest of entry.client.tsx
Tree-Shaking
The SDK supports tree-shaking — only the chains you import are bundled:
// Only EVMChain code is bundled
import { EVMChain } from '@chainlink/ccip-sdk'
// All chains — largest bundle, use only if needed
import { allSupportedChains } from '@chainlink/ccip-sdk/all'
| Import | Minified | Gzipped |
|---|---|---|
| EVM only | 740 KB | ~180 KB |
| Solana only | 1.2 MB | ~290 KB |
| Aptos only | 700 KB | ~170 KB |
| Sui only | 756 KB | ~185 KB |
| TON only | 760 KB | ~185 KB |
| EVM + Solana | 1.4 MB | ~340 KB |
| All chains | 2.0 MB | ~480 KB |
Don't place @chainlink/ccip-sdk in manualChunks — this disables tree-shaking:
// vite.config.ts
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: {
'vendor-react': ['react', 'react-dom'],
// DON'T add @chainlink/ccip-sdk here
},
},
},
},
})
To verify tree-shaking is working, check your bundle size:
# Vite
npx vite-bundle-visualizer
# Webpack
npx webpack-bundle-analyzer dist/stats.json
EVM-only bundles should be ~740 KB minified. If you see >1 MB, tree-shaking may not be working — verify you're using ES module imports (not require()) and not importing allSupportedChains.
Troubleshooting
"ERR_PACKAGE_PATH_NOT_EXPORTED"
The ethers dependency tree includes an older @noble/hashes that conflicts with other SDK dependencies requiring v1.8.0+. Add the package.json overrides and resolve.alias shown in What You Need and your bundler section above.
"Buffer is not defined"
Using Solana, TON, or Sui chains without the Buffer polyfill, or the polyfill isn't loading before SDK code. Follow the configuration for your bundler above.
"process is not defined"
Wallet libraries (MetaMask SDK, WalletConnect) require process. Use the "With Wallet Libraries" tab in your bundler section above.
Bundle size larger than expected
Verify you're importing specific chains (EVMChain), not allSupportedChains. Run a bundle analyzer (see Tree-Shaking). On Webpack/Next.js, the @noble/hashes alias fix must be applied before tree-shaking can work.
Vite dev server errors with EVM-only code
Vite pre-bundles all SDK dependencies in dev mode, including Solana/TON libraries that need Buffer. Add the Buffer polyfill even for EVM-only development — production builds tree-shake correctly.
"Cannot find module 'buffer'"
Install it: npm install buffer
Related
- Viem Integration — Use viem/wagmi clients with the SDK
- Multi-Chain — Chain-specific setup and cross-family messaging