Skip to content
SwapKit is a powerful suite of tools for building blockchain applications.

Next.js

This guide will help you integrate SwapKit into your Next.js application with proper Node.js polyfills and WebAssembly support.

Install SwapKit and required dependencies:

Terminal window
bun add @swapkit/sdk node-polyfill-webpack-plugin

Additional polyfill dependencies:

Terminal window
bun add buffer crypto-browserify stream-browserify stream-http https-browserify os-browserify path-browserify

Update your next.config.mjs to include necessary polyfills and WebAssembly support:

// @noErrorValidation
import { createRequire } from "module";
import NodePolyfillPlugin from "node-polyfill-webpack-plugin";
const require = createRequire(import.meta.url);
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
webpack: (config, { isServer, webpack }) => {
if (!isServer) {
// Add polyfills for browser
config.plugins.push(new NodePolyfillPlugin());
config.plugins.push(
new webpack.ProvidePlugin({
global: require.resolve("global"),
process: "process/browser",
Buffer: ["buffer", "Buffer"],
})
);
config.plugins.push(
new webpack.DefinePlugin({
"global.crypto": "crypto",
"global.msCrypto": "crypto",
"global.process": "process",
"global.Buffer": "Buffer",
})
);
// Configure fallbacks
config.resolve.fallback = {
...config.resolve.fallback,
buffer: require.resolve("buffer"),
crypto: require.resolve("crypto-browserify"),
fs: false,
stream: require.resolve("stream-browserify"),
path: require.resolve("path-browserify"),
process: require.resolve("process/browser"),
};
// Configure aliases
config.resolve.alias = {
...config.resolve.alias,
crypto: require.resolve("crypto-browserify"),
path: require.resolve("path-browserify"),
process: require.resolve("process/browser"),
stream: require.resolve("stream-browserify"),
http: require.resolve("stream-http"),
https: require.resolve("https-browserify"),
os: require.resolve("os-browserify/browser"),
};
}
// Enable WebAssembly
config.experiments = {
...config.experiments,
asyncWebAssembly: true,
syncWebAssembly: true,
topLevelAwait: true,
};
return config;
},
};
export default nextConfig;

Add browser field to your package.json to handle Node.js modules:

{
"browser": {
"dns": false,
"fs": false,
"net": false,
"perf_hooks": false,
"stream": false,
"timers": false,
"tls": false,
"zlib": false
}
}

Create a SwapKit instance configuration:

src/lib/swapKit.ts
// @noErrorValidation
import { createSwapKit } from '@swapkit/sdk';
import { SKConfig } from '@swapkit/sdk';
// Configure API keys from environment variables
if (process.env.NEXT_PUBLIC_SWAPKIT_API_KEY) {
SKConfig.setApiKey('swapKit', process.env.NEXT_PUBLIC_SWAPKIT_API_KEY);
}
if (process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID) {
SKConfig.setApiKey('walletConnectProjectId', process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID);
}
export const swapKitClient = createSwapKit();

Create a client component for wallet interactions:

src/components/WalletButton.tsx
// @noErrorValidation
'use client';
import { useState } from 'react';
import { swapKitClient } from '@/lib/swapKit';
import { Chain, WalletOption } from '@swapkit/sdk';
export function WalletButton() {
const [isConnected, setIsConnected] = useState(false);
const [address, setAddress] = useState<string>('');
const [isLoading, setIsLoading] = useState(false);
const connectWallet = async () => {
setIsLoading(true);
try {
await swapKitClient.connectEVMWallet([Chain.Ethereum], WalletOption.METAMASK);
setIsConnected(true);
const ethAddress = await swapKitClient.getAddress(Chain.Ethereum);
setAddress(ethAddress);
} catch (error) {
console.error('Failed to connect wallet:', error);
} finally {
setIsLoading(false);
}
};
const disconnectWallet = () => {
swapKitClient.disconnectWallet(Chain.Ethereum);
setIsConnected(false);
setAddress('');
};
if (isConnected) {
return (
<div>
<p>Connected: {address.slice(0, 6)}...{address.slice(-4)}</p>
<button onClick={disconnectWallet}>Disconnect</button>
</div>
);
}
return (
<button onClick={connectWallet} disabled={isLoading}>
{isLoading ? 'Connecting...' : 'Connect Wallet'}
</button>
);
}

For more complex applications, use a context provider:

src/providers/SwapKitProvider.tsx
// @noErrorValidation
'use client';
import { createContext, useContext, ReactNode } from 'react';
import { SwapKit } from '@swapkit/sdk';
import { swapKitClient } from '@/lib/swapKit';
const SwapKitContext = createContext<SwapKit | null>(null);
export function SwapKitProvider({ children }: { children: ReactNode }) {
return (
<SwapKitContext.Provider value={swapKitClient}>
{children}
</SwapKitContext.Provider>
);
}
export function useSwapKit() {
const context = useContext(SwapKitContext);
if (!context) {
throw new Error('useSwapKit must be used within SwapKitProvider');
}
return context;
}

Use in your root layout:

src/app/layout.tsx
// @noErrorValidation
import { SwapKitProvider } from '@/providers/SwapKitProvider';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<SwapKitProvider>
{children}
</SwapKitProvider>
</body>
</html>
);
}

Create a .env.local file:

Terminal window
NEXT_PUBLIC_SWAPKIT_API_KEY=your_api_key_here
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=your_project_id_here

SwapKit operations that require wallet connections must be performed in client components. For server components, you can only use read-only operations:

// @noErrorValidation
// Server component - read-only operations
import { AssetValue, SwapKitApi } from '@swapkit/sdk';
export async function TokenPrice({ symbol }: { symbol: string }) {
const price = await SwapKitApi.getPrice({
identifier: symbol,
currency: 'USD'
});
return <div>Price: ${price.price_usd}</div>;
}

For Cosmos ecosystem wallets like Keplr and Cosmostation, create a specialized component:

src/components/CosmosWalletButton.tsx
// @noErrorValidation
'use client';
import { useState } from 'react';
import { swapKitClient } from '@/lib/swapKit';
import { Chain, WalletOption } from '@swapkit/sdk';
export function CosmosWalletButton() {
const [isConnected, setIsConnected] = useState(false);
const [addresses, setAddresses] = useState<Record<string, string>>({});
const [isLoading, setIsLoading] = useState(false);
const connectCosmostation = async () => {
setIsLoading(true);
try {
await swapKitClient.connectCosmostation([Chain.Cosmos, Chain.THORChain, Chain.Kujira]);
setIsConnected(true);
const chains = [Chain.Cosmos, Chain.THORChain, Chain.Kujira];
const newAddresses: Record<string, string> = {};
for (const chain of chains) {
try {
const address = await swapKitClient.getAddress(chain);
if (address) {
newAddresses[chain] = address;
}
} catch {
// Chain might not be connected, skip it
}
}
setAddresses(newAddresses);
} catch (error) {
console.error('Failed to connect Cosmostation:', error);
} finally {
setIsLoading(false);
}
};
const disconnectWallet = () => {
Object.keys(addresses).forEach(chain => {
swapKitClient.disconnectWallet(chain as Chain);
});
setIsConnected(false);
setAddresses({});
};
if (isConnected) {
return (
<div className="space-y-2">
<h3>Connected Cosmos Chains:</h3>
{Object.entries(addresses).map(([chain, address]) => (
<p key={chain}>
{chain}: {address.slice(0, 8)}...{address.slice(-6)}
</p>
))}
<button onClick={disconnectWallet}>Disconnect</button>
</div>
);
}
return (
<button onClick={connectCosmostation} disabled={isLoading}>
{isLoading ? 'Connecting...' : 'Connect Cosmostation'}
</button>
);
}

The webpack configuration should handle WebAssembly modules. If issues persist, check that experiments.asyncWebAssembly is enabled in your next.config.js.

For a complete working example, check out the Next.js playground in the SwapKit repository.