Set up Bun for Midnight development
Bun is a modern JavaScript runtime and toolkit that can offer significantly faster performance compared to Node.js and npm. This guide walks you through using Bun with Midnight Network development, covering installation, configuration, compatibility considerations, best practices, and much more.
By the end of this guide, you will:
- Install and configure Bun for Midnight development.
- Understand compatibility between Bun and Midnight's toolchain.
- Work with the Compact compiler using Bun.
- Troubleshoot common issues using Bun.
Prerequisites
Before starting this guide, ensure you have:
- Basic knowledge of JavaScript/TypeScript
- Familiarity with command-line interfaces
- Understanding of package managers (npm, yarn)
Docker is not required for this tutorial. It's only needed when running actual Midnight proof servers.
Here's what your complete project will look like by the end of this guide:
Install Bun
In this section, you'll install Bun on your development machine.
Install Bun on Mac
- Run the command below:
curl -fsSL https://bun.sh/install | bash
This script:
- Downloads the appropriate Bun binary for your system.
- Installs it to
~/.bun/bin.
- Verify the installation:
Close and reopen your terminal, then run:
bun --version
Example of expected output:
If bun --version returns "command not found." manually add Bun to your PATH.
export PATH="$HOME/.bun/bin:$PATH”
Install Bun on linux or WSL
Follow the steps below to install Bun on Linux or Windows Subsystem for Linux (WSL).
- Install required dependencies
Bun’s installer requires unzip to extract the binary.
sudo apt update
sudo apt install unzip -y
- Install Bun
Run the official Bun installation script:
curl -fsSL https://bun.sh/install | bash
- Reload your shell configuration
Update your environment so the bun command is available:
source ~/.bashrc
- Verify the installation
bun --version
You should see the installed Bun version printed to the terminal.
- Fix “command not found” (if needed)
If bun is not found, add Bun’s install directory to your PATH:
export PATH="$HOME/.local/bin:$PATH"
Install using the installer script
Here, you will install the Compact compiler. This is a standalone tool (separate from Bun) used to turn Compact smart contracts (written in the Compact language) into code that can run on the Midnight blockchain.
- Install using the Compact installer:
curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/midnightntwrk/compact/releases/latest/download/compact-installer.sh | sh
By default, the installer places the compact binary in $HOME/.local/bin
- Update the compiler
After installation, update the Compact compiler to the version used in this tutorial:
compact update 0.26.0
- Verify the installation
Confirm that Compact is installed and correctly configured:
compact check
If the installation is successful, you should see output similar to the following:
- Fix “command not found” (PATH issue)
If you see an error such as:
compact: command not found
it means the directory where Compact was installed ($HOME/.local/bin) is not included in your PATH.
Add it to your current terminal session:
export PATH="$HOME/.local/bin:$PATH"
Install Midnight Packages with Bun
With both Bun and the Compact compiler installed, you can now create a Midnight application project.
- Initialize a new project:
mkdir my-midnight-app
cd my-midnight-app
bun init -y
This creates a basic package.json.
- Create the required directories:
The project requires separate folders for smart contracts and application source code.
mkdir src contracts
- Install the Midnight runtime package
Install a specific version to avoid compatibility issues:
bun add @midnight-ntwrk/compact-runtime@0.9.0
This gives you everything you need to:
- Run your smart contracts
- Manage your app's data
- Work with zero-knowledge proofs
- Get type definitions for TypeScript
- Update the
tsconfig.jsonfile:
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "node",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"resolveJsonModule": true
},
"include": ["src/**/*"]
}
This configuration ensures:
- Bun can resolve imports correctly.
- TypeScript compiles cleanly.
- Midnight’s runtime packages work without extra setup.
Configure the project
Update your package.json with the Bun-specific scripts below:
"scripts": {
"dev": "bun run --hot src/index.ts",
"start": "bun run dist/index.js",
"test": "bun test",
"install:midnight": "bun install",
"compile:contract": "compact compile contracts/message.compact contracts/managed",
"build:contract": "bun run compile:contract && bun build src/index.ts --outdir dist"
},
Script explanations:
-
dev: Runs the app in development mode with hot reload on src/index.ts.
-
start: Runs the compiled production app from dist/index.js.
-
test: Runs all tests using Bun’s test runner.
-
install:midnight: Installs project dependencies with Bun.
-
compile:contract: Compiles the Compact smart contract
message.compactinto the contracts/managed output directory. -
build:contract: First compiles the smart contract, then bundles the app entry file into the dist folder for production.
Create smart contract with Compact
In this section, you will create a simple Compact smart contract that allows you to store and read a message on the Midnight blockchain. Then, you will compile it so it can be used in your TypeScript/Bun application.
- Create the smart contract file.
Create a file named message.compact in the contracts directory:
touch contracts/message.compact
- Add the code below to the file:
pragma language_version 0.18;
import CompactStandardLibrary;
// Public ledger state - visible on blockchain
export ledger message: Opaque<"string">;
// Circuit to store a message on the blockchain
// The message will be publicly visible
export circuit storeMessage(customMessage: Opaque<"string">): [] {
message = disclose(customMessage);
}
Explanation:
pragma language_version 0.18;Specifies the exact Compact compiler version required for this smart contract. Using version 0.18 ensures compatibility with the runtime version 0.9.0 you installed earlier.import CompactStandardLibrary;Loads standard functions and types provided by Midnight for contracts.export ledger message: Opaque<"string">;Declares a public state variable calledmessageon the blockchain. Its value will be visible to everyone.export circuit storeMessage(customMessage: Opaque<"string">): [] { ... }Defines a function (circuit) to store a message on the blockchain.disclose()makes the message publicly readable.
- Compile with compact
compact compile contracts/message.compact contracts/managed
What this does:
- Converts the human-readable
.compactcontract into a compiled module that your application can interact with. - Saves the compiled contract in
contracts/managed, making it ready for integration with your Bun/TypeScript app.
Integrate compiled smart contracts with Bun
Now that your Compact contracts are compiled, the next step is to interact with them from a Bun-powered TypeScript application.
Here you’ll create a client that simulates storing and reading a message from your Midnight contract.
- Create
src/message-client.ts
touch src/message-client.ts
Add the following code:
import { Contract, ledger } from "../contracts/managed/contract/index.cjs";
export class MessageClient {
private contract: Contract<any>;
constructor() {
this.contract = new Contract({});
}
async storeMessage(customMessage: string) {
console.log(`📦 (Simulated) Storing message: "${customMessage}"`);
// Real implementation needs proper Midnight context
return { success: true, message: customMessage };
}
async getMessage() {
console.log("📥 (Simulated) Fetching message from ledger...");
return "Hello Midnight!";
}
}
What this does:
- Creates a
MessageClientclass. - Loads your compiled Compact contract.
- Provides two methods:
storeMessage(): simulates writing data.getMessage(): simulates reading data.
- Keeps things simple while preserving the project structure required by real Midnight apps.
- Create
src/index.ts
This file will serve as your application entry point.
touch src/index.ts
Add the following code:
import { MessageClient } from "./message-client";
async function main() {
console.log("🚀 Starting Midnight Message App...");
const client = new MessageClient();
console.log("📝 Storing message...");
await client.storeMessage("Hello Midnight!");
console.log("📖 Reading message...");
const message = await client.getMessage();
console.log("✅ Message:", message);
}
main().catch(console.error);
What this file does:
- Boot your Midnight app
- Creates an instance of
MessageClient - Calls the store and retrieves functions
- Prints the results nicely in your terminal
- Run the app with Bun:
bun run --hot src/index.ts
Known limitations and workarounds
While Bun offers significant performance improvements, there are some limitations you should be aware of when building Midnight applications. Here are the common issues and how to work around them.
Native module compatibility
Issue: some npm packages with native Node.js addons may not work correctly with Bun.
Workaround:
# If a package fails, try running it with Node.js compatibility mode
bun --bun run your-script.ts
# Or fall back to Node.js for specific scripts
node your-script.js
Package manager lock files
Issue: mixing Bun and npm in the same project can cause conflicts with lock files.
Workaround:
# Pick one and stick with it. If using Bun, remove npm files
rm package-lock.json
# If using npm, remove Bun files
rm bun.lock
Choose one package manager for your project and have your team use only that one.
Environment variables
Issue:
bun automatically handles .env files, which might cause unexpected behavior if you're using other environment variable tools.
Workaround:
# Bun loads .env automatically, no library needed# If you need to disable this:
bun --env-file= run your-script.ts
# Or specify a different env file:
bun --env-file=.env.production run your-script.ts
Migration guide (npm → Bun)
If your Midnight project was originally set up using Node.js + npm, you can migrate to Bun with just a few steps. This guide walks you through the process safely and cleanly.
- Install Bun
Make sure Bun is installed on your system.
To check
bun --version
If not found, go to this step and install Bun.
- Remove npm Artifacts:
cd your-midnight-project
rm -rf node_modules package-lock.json
Back up your package-lock.json first if you need to revert.
- Install dependencies with Bun:
bun install
- Verify the Migration
Test that your application works correctly with Bun:
bun run dev
Troubleshoot common issues
- Module Not Found Errors
Problem:
bun run --hot src/index.ts
Cannot find module '@midnight-ntwrk/compact-runtime’
Solution:
bun add @midnight-ntwrk/compact-runtime@0.9.0
- Version mismatch errors
Problem:
CompactError: Version mismatch: compiled code expects 0.9.0, runtime is 0.8.1
The Compact compiler and runtime versions must match exactly. Always check version compatibility before compiling.
Solution:
Install the matching runtime version:
bun add @midnight-ntwrk/compact-runtime@0.9.0
Then recompile your smart contracts:
compact compile contracts/message.compact contracts/managed
- Compact compiler language version errors
Problem:
Exception: message.compact line 1 char 1:
language version 0.18.0 mismatch
Solution:
Update your smart contract to use the exact language version:
pragma language_version 0.18;
Using an exact version number (such as 0.18) instead of a range prevents compatibility issues with different compiler versions.
- Compact compiler installation issues
Problem:
The Compact compiler fails to install or doesn't work after installation.
Solutions:
- Verify the installer script ran successfully:
compact --version
- If the command isn't found, manually add it to your PATH:
export PATH="$HOME/.compact/bin:$PATH"
- Try reinstalling:
curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/midnightntwrk/compact/releases/latest/download/compact-installer.sh | sh
Conclusion
In this guide, you learned how to:
- Install and configure Bun as a drop-in replacement for Node.js.
- Use Bun to manage Midnight runtime packages.
- Compile Compact smart contracts using the Compact compiler.
- Set up a client app structure that integrates with compiled smart contracts.
- Migrate existing Midnight projects from npm to Bun safely.
For the next step, you can try interacting with real Midnight contracts, add wallet and proof-server support, and extend your Bun setup for bundling, testing, and production.
Related resources: