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.

🚀 Next.js Playground Ready!

Skip the setup and start building immediately with our configured Next.js environment

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:

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) {
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",
})
);
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"),
};
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"),
};
}
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:

// @noErrorValidation
import { createSwapKit } from "@swapkit/sdk";
import { SKConfig } from "@swapkit/sdk";
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:

"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:

"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:

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:

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:

"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 {}
}
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](https: