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

Bun + React

This guide will help you integrate SwapKit into your Bun-powered React application. Bun is a fast JavaScript runtime that includes a bundler, test runner, and package manager.

Install SwapKit:

bun add @swapkit/sdk

Create a new Bun + React project:

bun create react my-swapkit-app
cd my-swapkit-app

Create a bunfig.toml file for Bun configuration:

[serve.static]
plugins = ["bun-plugin-tailwind"]
env = "BUN_PUBLIC_*"

Create a server file to serve your React application:

// src/server.tsx
import { 
function serve<T, R extends { [K in keyof R]: Bun.RouterTypes.RouteValue<K & string>; }>(options: Bun.ServeFunctionOptions<T, R> & {
    static?: R;
}): Bun.Server
Bun.serve provides a high-performance HTTP server with built-in routing support. It enables both function-based and object-based route handlers with type-safe parameters and method-specific handling.
@paramoptions - Server configuration options@categoryHTTP & Networking@exampleBasic Usage ```ts Bun.serve({ port: 3000, fetch(req) { return new Response("Hello World"); } }); ```@exampleRoute-based Handlers ```ts Bun.serve({ routes: { // Static responses "/": new Response("Home page"), // Function handlers with type-safe parameters "/users/:id": (req) => { // req.params.id is typed as string return new Response(`User ${req.params.id}`); }, // Method-specific handlers "/api/posts": { GET: () => new Response("Get posts"), POST: async (req) => { const body = await req.json(); return new Response("Created post"); }, DELETE: (req) => new Response("Deleted post") }, // Wildcard routes "/static/*": (req) => { // Handle any path under /static/ return new Response("Static file"); }, // Disable route (fall through to fetch handler) "/api/legacy": false }, // Fallback handler for unmatched routes fetch(req) { return new Response("Not Found", { status: 404 }); } }); ```@examplePath Parameters ```ts Bun.serve({ routes: { // Single parameter "/users/:id": (req: BunRequest<"/users/:id">) => { return new Response(`User ID: ${req.params.id}`); }, // Multiple parameters "/posts/:postId/comments/:commentId": ( req: BunRequest<"/posts/:postId/comments/:commentId"> ) => { return new Response(JSON.stringify(req.params)); // Output: {"postId": "123", "commentId": "456"} } } }); ```@exampleRoute Precedence ```ts // Routes are matched in the following order: // 1. Exact static routes ("/about") // 2. Parameter routes ("/users/:id") // 3. Wildcard routes ("/api/*") Bun.serve({ routes: { "/api/users": () => new Response("Users list"), "/api/users/:id": (req) => new Response(`User ${req.params.id}`), "/api/*": () => new Response("API catchall"), "/*": () => new Response("Root catchall") } }); ```@exampleError Handling ```ts Bun.serve({ routes: { "/error": () => { throw new Error("Something went wrong"); } }, error(error) { // Custom error handler console.error(error); return new Response(`Error: ${error.message}`, { status: 500 }); } }); ```@exampleServer Lifecycle ```ts const server = Bun.serve({ // Server config... }); // Update routes at runtime server.reload({ routes: { "/": () => new Response("Updated route") } }); // Stop the server server.stop(); ```@exampleDevelopment Mode ```ts Bun.serve({ development: true, // Enable hot reloading routes: { // Routes will auto-reload on changes } }); ```@exampleType-Safe Request Handling ```ts type Post = { id: string; title: string; }; Bun.serve({ routes: { "/api/posts/:id": async ( req: BunRequest<"/api/posts/:id"> ) => { if (req.method === "POST") { const body: Post = await req.json(); return Response.json(body); } return new Response("Method not allowed", { status: 405 }); } } }); ```
serve
} from "bun";
const const PORT: string | 3000PORT = var process: NodeJS.Processprocess.NodeJS.Process.env: NodeJS.ProcessEnv
The `process.env` property returns an object containing the user environment. See [`environ(7)`](http://man7.org/linux/man-pages/man7/environ.7.html). An example of this object looks like: ```js { TERM: 'xterm-256color', SHELL: '/usr/local/bin/bash', USER: 'maciej', PATH: '~/.bin/:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin', PWD: '/Users/maciej', EDITOR: 'vim', SHLVL: '1', HOME: '/Users/maciej', LOGNAME: 'maciej', _: '/usr/local/bin/node' } ``` It is possible to modify this object, but such modifications will not be reflected outside the Node.js process, or (unless explicitly requested) to other `Worker` threads. In other words, the following example would not work: ```bash node -e 'process.env.foo = "bar"' &#x26;&#x26; echo $foo ``` While the following will: ```js import { env } from 'node:process'; env.foo = 'bar'; console.log(env.foo); ``` Assigning a property on `process.env` will implicitly convert the value to a string. **This behavior is deprecated.** Future versions of Node.js may throw an error when the value is not a string, number, or boolean. ```js import { env } from 'node:process'; env.test = null; console.log(env.test); // => 'null' env.test = undefined; console.log(env.test); // => 'undefined' ``` Use `delete` to delete a property from `process.env`. ```js import { env } from 'node:process'; env.TEST = 1; delete env.TEST; console.log(env.TEST); // => undefined ``` On Windows operating systems, environment variables are case-insensitive. ```js import { env } from 'node:process'; env.TEST = 1; console.log(env.test); // => 1 ``` Unless explicitly specified when creating a `Worker` instance, each `Worker` thread has its own copy of `process.env`, based on its parent thread's `process.env`, or whatever was specified as the `env` option to the `Worker` constructor. Changes to `process.env` will not be visible across `Worker` threads, and only the main thread can make changes that are visible to the operating system or to native add-ons. On Windows, a copy of `process.env` on a `Worker` instance operates in a case-sensitive manner unlike the main thread.
@sincev0.1.27
env
.string | undefinedPORT || 3000;
serve<unknown, {}>(options: Bun.ServeFunctionOptions<unknown, {}> & {
    static?: {} | undefined;
}): Bun.Server
Bun.serve provides a high-performance HTTP server with built-in routing support. It enables both function-based and object-based route handlers with type-safe parameters and method-specific handling.
@paramoptions - Server configuration options@categoryHTTP & Networking@exampleBasic Usage ```ts Bun.serve({ port: 3000, fetch(req) { return new Response("Hello World"); } }); ```@exampleRoute-based Handlers ```ts Bun.serve({ routes: { // Static responses "/": new Response("Home page"), // Function handlers with type-safe parameters "/users/:id": (req) => { // req.params.id is typed as string return new Response(`User ${req.params.id}`); }, // Method-specific handlers "/api/posts": { GET: () => new Response("Get posts"), POST: async (req) => { const body = await req.json(); return new Response("Created post"); }, DELETE: (req) => new Response("Deleted post") }, // Wildcard routes "/static/*": (req) => { // Handle any path under /static/ return new Response("Static file"); }, // Disable route (fall through to fetch handler) "/api/legacy": false }, // Fallback handler for unmatched routes fetch(req) { return new Response("Not Found", { status: 404 }); } }); ```@examplePath Parameters ```ts Bun.serve({ routes: { // Single parameter "/users/:id": (req: BunRequest<"/users/:id">) => { return new Response(`User ID: ${req.params.id}`); }, // Multiple parameters "/posts/:postId/comments/:commentId": ( req: BunRequest<"/posts/:postId/comments/:commentId"> ) => { return new Response(JSON.stringify(req.params)); // Output: {"postId": "123", "commentId": "456"} } } }); ```@exampleRoute Precedence ```ts // Routes are matched in the following order: // 1. Exact static routes ("/about") // 2. Parameter routes ("/users/:id") // 3. Wildcard routes ("/api/*") Bun.serve({ routes: { "/api/users": () => new Response("Users list"), "/api/users/:id": (req) => new Response(`User ${req.params.id}`), "/api/*": () => new Response("API catchall"), "/*": () => new Response("Root catchall") } }); ```@exampleError Handling ```ts Bun.serve({ routes: { "/error": () => { throw new Error("Something went wrong"); } }, error(error) { // Custom error handler console.error(error); return new Response(`Error: ${error.message}`, { status: 500 }); } }); ```@exampleServer Lifecycle ```ts const server = Bun.serve({ // Server config... }); // Update routes at runtime server.reload({ routes: { "/": () => new Response("Updated route") } }); // Stop the server server.stop(); ```@exampleDevelopment Mode ```ts Bun.serve({ development: true, // Enable hot reloading routes: { // Routes will auto-reload on changes } }); ```@exampleType-Safe Request Handling ```ts type Post = { id: string; title: string; }; Bun.serve({ routes: { "/api/posts/:id": async ( req: BunRequest<"/api/posts/:id"> ) => { if (req.method === "POST") { const body: Post = await req.json(); return Response.json(body); } return new Response("Method not allowed", { status: 405 }); } } }); ```
serve
({
port: string | numberport: const PORT: string | 3000PORT, async function fetch(this: Bun.Server, req: Request): Promise<Response>fetch(req: Requestreq) { const const url: URLurl = new var URL: new (url: string | URL, base?: string | URL) => URL
The URL interface represents an object providing static methods used for creating object URLs. [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL)
URL
(req: Requestreq.Request.url: string
Returns the URL of request as a string. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/url)
url
);
// Serve static files if (const url: URLurl.URL.pathname: string
[MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/pathname)
pathname
=== "/") {
return new var Response: new (body?: BodyInit | null, init?: ResponseInit) => Response
This Fetch API interface represents the response to a request. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response)
Response
(module "bun"
Bun.js runtime APIs
@example```js import {file} from 'bun'; // Log the file to the console const input = await file('/path/to/file.txt').text(); console.log(input); ``` This module aliases `globalThis.Bun`.
Bun
.function file(path: string | URL, options?: BlobPropertyBag): Bun.BunFile (+2 overloads)
[`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) powered by the fastest system calls available for operating on files. This Blob is lazy. That means it won't do any work until you read from it. - `size` will not be valid until the contents of the file are read at least once. - `type` is auto-set based on the file extension when possible
@example```js const file = Bun.file("./hello.json"); console.log(file.type); // "application/json" console.log(await file.json()); // { hello: "world" } ```@example```js await Bun.write( Bun.file("./hello.txt"), "Hello, world!" ); ```@parampath The path to the file (lazily loaded) if the path starts with `s3://` it will behave like {@link S3File}
file
("pages/index.html"));
} // Handle API routes if needed if (const url: URLurl.URL.pathname: string
[MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/pathname)
pathname
.String.startsWith(searchString: string, position?: number): boolean
Returns true if the sequence of elements of searchString converted to a String is the same as the corresponding elements of this object (converted to a String) starting at position. Otherwise returns false.
startsWith
("/api/")) {
// Add your API logic here } // Default 404 return new var Response: new (body?: BodyInit | null, init?: ResponseInit) => Response
This Fetch API interface represents the response to a request. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response)
Response
("Not Found", { ResponseInit.status?: number | undefinedstatus: 404 });
}, }); console.Console.log(message?: any, ...optionalParams: any[]): void (+3 overloads)
Prints to `stdout` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v24.x/api/util.html#utilformatformat-args)). ```js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout ``` See [`util.format()`](https://nodejs.org/docs/latest-v24.x/api/util.html#utilformatformat-args) for more information.
@sincev0.1.100
log
(`Server running at http://localhost:${const PORT: string | 3000PORT}`);

Create your main React application with SwapKit:

// src/App.tsx
import { function useState<S>(initialState: S | (() => S)): [S, React.Dispatch<React.SetStateAction<S>>] (+1 overload)
Returns a stateful value, and a function to update it.
@version16.8.0@see{@link https://react.dev/reference/react/useState}
useState
} from 'react';
import {
function createSwapKit(config?: Parameters<typeof SwapKit>[0]): {
    chainflip: {
        supportedSwapkitProviders: ProviderName[];
    } & {
        swap: (swapParams: RequestSwapDepositAddressParams) => Promise<...>;
    };
    ... 5 more ...;
    near: {
        ...;
    } & {
        ...;
    };
} & {
    ...;
} & {
    ...;
}
createSwapKit
, enum ChainChain, enum WalletOptionWalletOption } from '@swapkit/sdk';
const
const swapKit: {
    chainflip: {
        supportedSwapkitProviders: ProviderName[];
    } & {
        swap: (swapParams: RequestSwapDepositAddressParams) => Promise<...>;
    };
    ... 5 more ...;
    near: {
        ...;
    } & {
        ...;
    };
} & {
    ...;
} & {
    ...;
}
swapKit
=
function createSwapKit(config?: Parameters<typeof SwapKit>[0]): {
    chainflip: {
        supportedSwapkitProviders: ProviderName[];
    } & {
        swap: (swapParams: RequestSwapDepositAddressParams) => Promise<...>;
    };
    ... 5 more ...;
    near: {
        ...;
    } & {
        ...;
    };
} & {
    ...;
} & {
    ...;
}
createSwapKit
();
export function function App(): React.JSX.ElementApp() { const [const isConnected: booleanisConnected, const setIsConnected: React.Dispatch<React.SetStateAction<boolean>>setIsConnected] = useState<boolean>(initialState: boolean | (() => boolean)): [boolean, React.Dispatch<React.SetStateAction<boolean>>] (+1 overload)
Returns a stateful value, and a function to update it.
@version16.8.0@see{@link https://react.dev/reference/react/useState}
useState
(false);
const [const address: stringaddress, const setAddress: React.Dispatch<React.SetStateAction<string>>setAddress] = useState<string>(initialState: string | (() => string)): [string, React.Dispatch<React.SetStateAction<string>>] (+1 overload)
Returns a stateful value, and a function to update it.
@version16.8.0@see{@link https://react.dev/reference/react/useState}
useState
<string>('');
const const connectWallet: () => Promise<void>connectWallet = async () => { try { await
const swapKit: {
    chainflip: {
        supportedSwapkitProviders: ProviderName[];
    } & {
        swap: (swapParams: RequestSwapDepositAddressParams) => Promise<...>;
    };
    ... 5 more ...;
    near: {
        ...;
    } & {
        ...;
    };
} & {
    ...;
} & {
    ...;
}
swapKit
.connectEVMWallet: (chains: Chain[], walletType?: EVMWalletOptions | undefined, eip1193Provider?: Eip1193Provider | undefined) => Promise<boolean>connectEVMWallet([enum ChainChain.function (enum member) Chain.Ethereum = "ETH"Ethereum], enum WalletOptionWalletOption.function (enum member) WalletOption.METAMASK = "METAMASK"METAMASK);
const setIsConnected: (value: React.SetStateAction<boolean>) => voidsetIsConnected(true); const const ethAddress: stringethAddress = await
const swapKit: {
    chainflip: {
        supportedSwapkitProviders: ProviderName[];
    } & {
        swap: (swapParams: RequestSwapDepositAddressParams) => Promise<...>;
    };
    ... 5 more ...;
    near: {
        ...;
    } & {
        ...;
    };
} & {
    ...;
} & {
    ...;
}
swapKit
.getAddress: <Chain.Ethereum>(chain: Chain.Ethereum) => stringgetAddress(enum ChainChain.function (enum member) Chain.Ethereum = "ETH"Ethereum);
const setAddress: (value: React.SetStateAction<string>) => voidsetAddress(const ethAddress: stringethAddress); } catch (error) { console.Console.error(message?: any, ...optionalParams: any[]): void (+3 overloads)
Prints to `stderr` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v24.x/api/util.html#utilformatformat-args)). ```js const code = 5; console.error('error #%d', code); // Prints: error #5, to stderr console.error('error', code); // Prints: error 5, to stderr ``` If formatting elements (e.g. `%d`) are not found in the first string then [`util.inspect()`](https://nodejs.org/docs/latest-v24.x/api/util.html#utilinspectobject-options) is called on each argument and the resulting string values are concatenated. See [`util.format()`](https://nodejs.org/docs/latest-v24.x/api/util.html#utilformatformat-args) for more information.
@sincev0.1.100
error
('Failed to connect wallet:', error);
} }; const const disconnectWallet: () => voiddisconnectWallet = () => {
const swapKit: {
    chainflip: {
        supportedSwapkitProviders: ProviderName[];
    } & {
        swap: (swapParams: RequestSwapDepositAddressParams) => Promise<...>;
    };
    ... 5 more ...;
    near: {
        ...;
    } & {
        ...;
    };
} & {
    ...;
} & {
    ...;
}
swapKit
.
Property 'disconnectWallet' does not exist on type '{ chainflip: { supportedSwapkitProviders: ProviderName[]; } & { swap: (swapParams: RequestSwapDepositAddressParams) => Promise<string>; }; ... 5 more ...; near: { ...; } & { ...; }; } & { ...; } & { ...; }'. Did you mean 'disconnectAll'?
disconnectWallet
(enum ChainChain.function (enum member) Chain.Ethereum = "ETH"Ethereum);
const setIsConnected: (value: React.SetStateAction<boolean>) => voidsetIsConnected(false); const setAddress: (value: React.SetStateAction<string>) => voidsetAddress(''); }; return ( <
'React' refers to a UMD global, but the current file is a module. Consider adding an import instead.
div
className="p-8">
<
'React' refers to a UMD global, but the current file is a module. Consider adding an import instead.
h1
className="text-3xl font-bold mb-4">SwapKit + Bun</h1>
{!const isConnected: booleanisConnected ? ( <
'React' refers to a UMD global, but the current file is a module. Consider adding an import instead.
button
onClick={const connectWallet: () => Promise<void>connectWallet} className="px-4 py-2 bg-blue-500 text-white rounded" > Connect Wallet </button> ) : ( <
'React' refers to a UMD global, but the current file is a module. Consider adding an import instead.
div
>
<
'React' refers to a UMD global, but the current file is a module. Consider adding an import instead.
p
className="mb-4">Connected: {const address: stringaddress}</p>
<
'React' refers to a UMD global, but the current file is a module. Consider adding an import instead.
button
onClick={const disconnectWallet: () => voiddisconnectWallet} className="px-4 py-2 bg-red-500 text-white rounded" > Disconnect </button> </div> )} </div> ); }

Create the entry point for your React application:

// pages/index.tsx
import { function createRoot(container: Container, options?: RootOptions): Root
createRoot lets you create a root to display React components inside a browser DOM node.
@see{@link https://react.dev/reference/react-dom/client/createRoot API Reference for `createRoot`}
createRoot
} from 'react-dom/client';
import { import AppApp } from
Cannot find module '../src/App' or its corresponding type declarations.
'../src/App'
;
import '../styles/index.css'; const container = var document: Document
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.getElementById('root');
if (container) { const const root: Rootroot = function createRoot(container: Container, options?: RootOptions): Root
createRoot lets you create a root to display React components inside a browser DOM node.
@see{@link https://react.dev/reference/react-dom/client/createRoot API Reference for `createRoot`}
createRoot
(container);
const root: Rootroot.Root.render(children: React.ReactNode): voidrender(<
'React' refers to a UMD global, but the current file is a module. Consider adding an import instead.
App
/>);
}

Create an HTML template:

<!-- pages/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>SwapKit + Bun</title>
</head>
<body>
  <div id="root"></div>
  <script type="module" src="/pages/index.tsx"></script>
</body>
</html>

Create a build script for production:

// build.ts
import { function build(config: Bun.BuildConfig): Promise<Bun.BuildOutput>
Bundles JavaScript, TypeScript, CSS, HTML and other supported files into optimized outputs.
@paramconfig - Build configuration options@returnsPromise that resolves to build output containing generated artifacts and build status@throws{AggregateError} When build fails and config.throw is true (default in Bun 1.2+)@categoryBundler@exampleBasic usage - Bundle a single entrypoint and check results ```ts const result = await Bun.build({ entrypoints: ['./src/index.tsx'], outdir: './dist' }); if (!result.success) { console.error('Build failed:', result.logs); process.exit(1); } ```@exampleSet up multiple entrypoints with code splitting enabled ```ts await Bun.build({ entrypoints: ['./src/app.tsx', './src/admin.tsx'], outdir: './dist', splitting: true, sourcemap: "external" }); ```@exampleConfigure minification and optimization settings ```ts await Bun.build({ entrypoints: ['./src/index.tsx'], outdir: './dist', minify: { whitespace: true, identifiers: true, syntax: true }, drop: ['console', 'debugger'] }); ```@exampleSet up custom loaders and mark packages as external ```ts await Bun.build({ entrypoints: ['./src/index.tsx'], outdir: './dist', loader: { '.png': 'dataurl', '.svg': 'file', '.txt': 'text', '.json': 'json' }, external: ['react', 'react-dom'] }); ```@exampleConfigure environment variable handling with different modes ```ts // Inline all environment variables await Bun.build({ entrypoints: ['./src/index.tsx'], outdir: './dist', env: 'inline' }); // Only include specific env vars await Bun.build({ entrypoints: ['./src/index.tsx'], outdir: './dist', env: 'PUBLIC_*' }); ```@exampleSet up custom naming patterns for all output types ```ts await Bun.build({ entrypoints: ['./src/index.tsx'], outdir: './dist', naming: { entry: '[dir]/[name]-[hash].[ext]', chunk: 'chunks/[name]-[hash].[ext]', asset: 'assets/[name]-[hash].[ext]' } }); ```@exampleWork with build artifacts in different formats ```ts const result = await Bun.build({ entrypoints: ['./src/index.tsx'] }); for (const artifact of result.outputs) { const text = await artifact.text(); const buffer = await artifact.arrayBuffer(); const bytes = await artifact.bytes(); new Response(artifact); await Bun.write(artifact.path, artifact); } ```@exampleImplement comprehensive error handling with position info ```ts try { const result = await Bun.build({ entrypoints: ['./src/index.tsx'], }); } catch (e) { const error = e as AggregateError; console.error('Build failed:'); for (const msg of error.errors) { if ('position' in msg) { console.error( `${msg.message} at ${msg.position?.file}:${msg.position?.line}:${msg.position?.column}` ); } else { console.error(msg.message); } } } ```@exampleSet up Node.js target with specific configurations ```ts await Bun.build({ entrypoints: ['./src/server.ts'], outdir: './dist', target: 'node', format: 'cjs', sourcemap: 'external', minify: false, packages: 'external' }); ```@exampleConfigure experimental CSS bundling with multiple themes ```ts await Bun.build({ entrypoints: [ './src/styles.css', './src/themes/dark.css', './src/themes/light.css' ], outdir: './dist/css', }); ```@exampleDefine compile-time constants and version information ```ts await Bun.build({ entrypoints: ['./src/index.tsx'], outdir: './dist', define: { 'process.env.NODE_ENV': JSON.stringify('production'), 'CONSTANTS.VERSION': JSON.stringify('1.0.0'), 'CONSTANTS.BUILD_TIME': JSON.stringify(new Date().toISOString()) } }); ```@exampleCreate a custom plugin for handling special file types ```ts await Bun.build({ entrypoints: ['./src/index.tsx'], outdir: './dist', plugins: [ { name: 'my-plugin', setup(build) { build.onLoad({ filter: /\.custom$/ }, async (args) => { const content = await Bun.file(args.path).text(); return { contents: `export default ${JSON.stringify(content)}`, loader: 'js' }; }); } } ] }); ```@exampleEnable bytecode generation for faster startup ```ts await Bun.build({ entrypoints: ['./src/server.ts'], outdir: './dist', target: 'bun', format: 'cjs', bytecode: true }); ```@exampleAdd custom banner and footer to output files ```ts await Bun.build({ entrypoints: ['./src/index.tsx'], outdir: './dist', banner: '"use client";\n// Built with Bun', footer: '// Generated on ' + new Date().toISOString() }); ```@exampleConfigure CDN public path for asset loading ```ts await Bun.build({ entrypoints: ['./src/index.tsx'], outdir: './dist', publicPath: 'https://cdn.example.com/assets/', loader: { '.png': 'file', '.svg': 'file' } }); ```@exampleSet up package export conditions for different environments ```ts await Bun.build({ entrypoints: ['./src/index.tsx'], outdir: './dist', conditions: ['production', 'browser', 'module'], packages: 'external' }); ```
build
} from "bun";
await function build(config: Bun.BuildConfig): Promise<Bun.BuildOutput>
Bundles JavaScript, TypeScript, CSS, HTML and other supported files into optimized outputs.
@paramconfig - Build configuration options@returnsPromise that resolves to build output containing generated artifacts and build status@throws{AggregateError} When build fails and config.throw is true (default in Bun 1.2+)@categoryBundler@exampleBasic usage - Bundle a single entrypoint and check results ```ts const result = await Bun.build({ entrypoints: ['./src/index.tsx'], outdir: './dist' }); if (!result.success) { console.error('Build failed:', result.logs); process.exit(1); } ```@exampleSet up multiple entrypoints with code splitting enabled ```ts await Bun.build({ entrypoints: ['./src/app.tsx', './src/admin.tsx'], outdir: './dist', splitting: true, sourcemap: "external" }); ```@exampleConfigure minification and optimization settings ```ts await Bun.build({ entrypoints: ['./src/index.tsx'], outdir: './dist', minify: { whitespace: true, identifiers: true, syntax: true }, drop: ['console', 'debugger'] }); ```@exampleSet up custom loaders and mark packages as external ```ts await Bun.build({ entrypoints: ['./src/index.tsx'], outdir: './dist', loader: { '.png': 'dataurl', '.svg': 'file', '.txt': 'text', '.json': 'json' }, external: ['react', 'react-dom'] }); ```@exampleConfigure environment variable handling with different modes ```ts // Inline all environment variables await Bun.build({ entrypoints: ['./src/index.tsx'], outdir: './dist', env: 'inline' }); // Only include specific env vars await Bun.build({ entrypoints: ['./src/index.tsx'], outdir: './dist', env: 'PUBLIC_*' }); ```@exampleSet up custom naming patterns for all output types ```ts await Bun.build({ entrypoints: ['./src/index.tsx'], outdir: './dist', naming: { entry: '[dir]/[name]-[hash].[ext]', chunk: 'chunks/[name]-[hash].[ext]', asset: 'assets/[name]-[hash].[ext]' } }); ```@exampleWork with build artifacts in different formats ```ts const result = await Bun.build({ entrypoints: ['./src/index.tsx'] }); for (const artifact of result.outputs) { const text = await artifact.text(); const buffer = await artifact.arrayBuffer(); const bytes = await artifact.bytes(); new Response(artifact); await Bun.write(artifact.path, artifact); } ```@exampleImplement comprehensive error handling with position info ```ts try { const result = await Bun.build({ entrypoints: ['./src/index.tsx'], }); } catch (e) { const error = e as AggregateError; console.error('Build failed:'); for (const msg of error.errors) { if ('position' in msg) { console.error( `${msg.message} at ${msg.position?.file}:${msg.position?.line}:${msg.position?.column}` ); } else { console.error(msg.message); } } } ```@exampleSet up Node.js target with specific configurations ```ts await Bun.build({ entrypoints: ['./src/server.ts'], outdir: './dist', target: 'node', format: 'cjs', sourcemap: 'external', minify: false, packages: 'external' }); ```@exampleConfigure experimental CSS bundling with multiple themes ```ts await Bun.build({ entrypoints: [ './src/styles.css', './src/themes/dark.css', './src/themes/light.css' ], outdir: './dist/css', }); ```@exampleDefine compile-time constants and version information ```ts await Bun.build({ entrypoints: ['./src/index.tsx'], outdir: './dist', define: { 'process.env.NODE_ENV': JSON.stringify('production'), 'CONSTANTS.VERSION': JSON.stringify('1.0.0'), 'CONSTANTS.BUILD_TIME': JSON.stringify(new Date().toISOString()) } }); ```@exampleCreate a custom plugin for handling special file types ```ts await Bun.build({ entrypoints: ['./src/index.tsx'], outdir: './dist', plugins: [ { name: 'my-plugin', setup(build) { build.onLoad({ filter: /\.custom$/ }, async (args) => { const content = await Bun.file(args.path).text(); return { contents: `export default ${JSON.stringify(content)}`, loader: 'js' }; }); } } ] }); ```@exampleEnable bytecode generation for faster startup ```ts await Bun.build({ entrypoints: ['./src/server.ts'], outdir: './dist', target: 'bun', format: 'cjs', bytecode: true }); ```@exampleAdd custom banner and footer to output files ```ts await Bun.build({ entrypoints: ['./src/index.tsx'], outdir: './dist', banner: '"use client";\n// Built with Bun', footer: '// Generated on ' + new Date().toISOString() }); ```@exampleConfigure CDN public path for asset loading ```ts await Bun.build({ entrypoints: ['./src/index.tsx'], outdir: './dist', publicPath: 'https://cdn.example.com/assets/', loader: { '.png': 'file', '.svg': 'file' } }); ```@exampleSet up package export conditions for different environments ```ts await Bun.build({ entrypoints: ['./src/index.tsx'], outdir: './dist', conditions: ['production', 'browser', 'module'], packages: 'external' }); ```
build
({
BuildConfig.entrypoints: string[]entrypoints: ["./pages/index.tsx"], BuildConfig.outdir?: string | undefinedoutdir: "./dist", BuildConfig.target?: Bun.Target | undefined
@default"browser"
target
: "browser",
BuildConfig.minify?: boolean | {
    whitespace?: boolean;
    syntax?: boolean;
    identifiers?: boolean;
} | undefined
Whether to enable minification. Use `true`/`false` to enable/disable all minification options. Alternatively, you can pass an object for granular control over certain minifications.
@defaultfalse
minify
: true,
BuildConfig.splitting?: boolean | undefinedsplitting: true, BuildConfig.sourcemap?: boolean | "external" | "none" | "linked" | "inline" | undefined
Specifies if and how to generate source maps. - `"none"` - No source maps are generated - `"linked"` - A separate `*.ext.map` file is generated alongside each `*.ext` file. A `//# sourceMappingURL` comment is added to the output file to link the two. Requires `outdir` to be set. - `"inline"` - an inline source map is appended to the output file. - `"external"` - Generate a separate source map file for each input file. No `//# sourceMappingURL` comment is added to the output file. `true` and `false` are aliases for `"inline"` and `"none"`, respectively.
@default"none"@see{@link outdir} required for `"linked"` maps@see{@link publicPath} to customize the base url of linked source maps
sourcemap
: "external",
});

Bun uses BUN_PUBLIC_ prefix for client-side environment variables:

# .env
BUN_PUBLIC_SWAPKIT_API_KEY=your_api_key_here
BUN_PUBLIC_WALLETCONNECT_PROJECT_ID=your_project_id_here

Access them in your code:

import { 
const SKConfig: {
    getState: () => SwapKitConfigStore;
    get: <T extends "apiKeys" | "apis" | "chains" | "wallets" | "explorerUrls" | "nodeUrls" | "rpcUrls" | "envs" | "integrations">(key: T) => SwapKitConfigStore[T];
    ... 6 more ...;
    setIntegrationConfig: <T extends keyof SKConfigIntegrations>(integration: T, config: SKConfigIntegrations[T]) => void;
}
SKConfig
} from '@swapkit/sdk';
if (var process: NodeJS.Processprocess.NodeJS.Process.env: NodeJS.ProcessEnv
The `process.env` property returns an object containing the user environment. See [`environ(7)`](http://man7.org/linux/man-pages/man7/environ.7.html). An example of this object looks like: ```js { TERM: 'xterm-256color', SHELL: '/usr/local/bin/bash', USER: 'maciej', PATH: '~/.bin/:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin', PWD: '/Users/maciej', EDITOR: 'vim', SHLVL: '1', HOME: '/Users/maciej', LOGNAME: 'maciej', _: '/usr/local/bin/node' } ``` It is possible to modify this object, but such modifications will not be reflected outside the Node.js process, or (unless explicitly requested) to other `Worker` threads. In other words, the following example would not work: ```bash node -e 'process.env.foo = "bar"' &#x26;&#x26; echo $foo ``` While the following will: ```js import { env } from 'node:process'; env.foo = 'bar'; console.log(env.foo); ``` Assigning a property on `process.env` will implicitly convert the value to a string. **This behavior is deprecated.** Future versions of Node.js may throw an error when the value is not a string, number, or boolean. ```js import { env } from 'node:process'; env.test = null; console.log(env.test); // => 'null' env.test = undefined; console.log(env.test); // => 'undefined' ``` Use `delete` to delete a property from `process.env`. ```js import { env } from 'node:process'; env.TEST = 1; delete env.TEST; console.log(env.TEST); // => undefined ``` On Windows operating systems, environment variables are case-insensitive. ```js import { env } from 'node:process'; env.TEST = 1; console.log(env.test); // => 1 ``` Unless explicitly specified when creating a `Worker` instance, each `Worker` thread has its own copy of `process.env`, based on its parent thread's `process.env`, or whatever was specified as the `env` option to the `Worker` constructor. Changes to `process.env` will not be visible across `Worker` threads, and only the main thread can make changes that are visible to the operating system or to native add-ons. On Windows, a copy of `process.env` on a `Worker` instance operates in a case-sensitive manner unlike the main thread.
@sincev0.1.27
env
.string | undefinedBUN_PUBLIC_SWAPKIT_API_KEY) {
const SKConfig: {
    getState: () => SwapKitConfigStore;
    get: <T extends "apiKeys" | "apis" | "chains" | "wallets" | "explorerUrls" | "nodeUrls" | "rpcUrls" | "envs" | "integrations">(key: T) => SwapKitConfigStore[T];
    ... 6 more ...;
    setIntegrationConfig: <T extends keyof SKConfigIntegrations>(integration: T, config: SKConfigIntegrations[T]) => void;
}
SKConfig
.setApiKey: <"swapKit">(key: "swapKit", apiKey: string) => voidsetApiKey('swapKit', var process: NodeJS.Processprocess.NodeJS.Process.env: NodeJS.ProcessEnv
The `process.env` property returns an object containing the user environment. See [`environ(7)`](http://man7.org/linux/man-pages/man7/environ.7.html). An example of this object looks like: ```js { TERM: 'xterm-256color', SHELL: '/usr/local/bin/bash', USER: 'maciej', PATH: '~/.bin/:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin', PWD: '/Users/maciej', EDITOR: 'vim', SHLVL: '1', HOME: '/Users/maciej', LOGNAME: 'maciej', _: '/usr/local/bin/node' } ``` It is possible to modify this object, but such modifications will not be reflected outside the Node.js process, or (unless explicitly requested) to other `Worker` threads. In other words, the following example would not work: ```bash node -e 'process.env.foo = "bar"' &#x26;&#x26; echo $foo ``` While the following will: ```js import { env } from 'node:process'; env.foo = 'bar'; console.log(env.foo); ``` Assigning a property on `process.env` will implicitly convert the value to a string. **This behavior is deprecated.** Future versions of Node.js may throw an error when the value is not a string, number, or boolean. ```js import { env } from 'node:process'; env.test = null; console.log(env.test); // => 'null' env.test = undefined; console.log(env.test); // => 'undefined' ``` Use `delete` to delete a property from `process.env`. ```js import { env } from 'node:process'; env.TEST = 1; delete env.TEST; console.log(env.TEST); // => undefined ``` On Windows operating systems, environment variables are case-insensitive. ```js import { env } from 'node:process'; env.TEST = 1; console.log(env.test); // => 1 ``` Unless explicitly specified when creating a `Worker` instance, each `Worker` thread has its own copy of `process.env`, based on its parent thread's `process.env`, or whatever was specified as the `env` option to the `Worker` constructor. Changes to `process.env` will not be visible across `Worker` threads, and only the main thread can make changes that are visible to the operating system or to native add-ons. On Windows, a copy of `process.env` on a `Worker` instance operates in a case-sensitive manner unlike the main thread.
@sincev0.1.27
env
.stringBUN_PUBLIC_SWAPKIT_API_KEY);
}

Bun handles module resolution differently than Node.js. If you encounter issues:

  1. Clear the cache: bun clean
  2. Reinstall dependencies: bun install

Bun supports TypeScript out of the box. Create a tsconfig.json:

{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "jsx": "react-jsx",
    "moduleResolution": "bundler",
    "types": ["bun-types"]
  }
}

For a complete working example, check out the Bun + React playground in the SwapKit repository.