Skip to main content
For the complete documentation index, see llms.txt

Set up your Midnight development environment

Every Midnight project relies on the same small toolkit: Docker to run infrastructure such as the proof server, the Compact compiler to build smart contracts, and an editor that understands the Compact language. This guide installs all of them once, so the rest of the guides in this section can focus on building and deploying.

The toolchain runs natively on macOS and Linux. On Windows, you develop inside the Windows Subsystem for Linux (WSL), and this guide covers that path too.

Prerequisites

  • Basic knowledge of JavaScript/TypeScript
  • Familiarity with command-line interfaces

Set up your platform

Download and install Docker Desktop for your operating system. New users might need to set up an account.

Docker hosts completed code in images. Midnight components such as the proof server are distributed as Docker images, so Docker must be running before you start them.

Install the Compact compiler

Compact is Midnight's smart contract language. The Compact developer tools manage the compiler toolchain for you and keep it up to date.

  1. Run the installer script (on Windows, inside your Ubuntu terminal):
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/midnightntwrk/compact/releases/latest/download/compact-installer.sh | sh

The installer places the compact CLI in $HOME/.local/bin and automatically updates your shell's PATH. The compiler toolchain versions that compact update downloads later live under $HOME/.compact/.

  1. To apply the PATH changes to your current session, reload your shell configuration:
source ~/.bashrc
  1. Verify the installation by checking the version:
compact --version
  1. Download the latest compiler toolchain:
compact update
  1. Confirm the installation and check that the toolchain is current:
compact check

If the installation succeeded, you should see output similar to the following:

compact: aarch64-darwin -- Up to date -- 0.31.1

See the Compact developer tools reference for the full set of subcommands, and the compatibility matrix for the compiler version that matches the rest of the toolchain.

Install the Compact VS Code extension

The Compact VS Code extension provides syntax highlighting and real-time error checking, which is essential for writing smart contracts.

  1. Download the Compact VS Code extension VSIX package from the releases page.
  2. Open VS Code.
  3. Go to the Extensions view (press Ctrl+Shift+X), click the ... (More Actions) menu at the top-right of the extensions pane, and select Install from VSIX....
  4. Select the .vsix file you just downloaded to complete the installation.

Run the proof server

Midnight uses zero-knowledge (ZK) cryptography to enable shielded transactions and data protection. An essential element of this architecture is ZK functionality provided by a Midnight proof server, which generates proofs locally for the network to verify on-chain.

The information that a DApp sends to the proof server includes private data, such as details of token ownership or a DApp's private state. To protect your data, you should access only a local proof server, or perhaps one on a remote machine that you control, over an encrypted channel.

Your wallet communicates with the proof server to invoke ZK functionality and generate ZK proofs for your transactions, so the proof server must be running whenever you process transactions on the Midnight network.

Start the proof server with Docker:

docker run -p 6300:6300 midnightntwrk/proof-server:latest midnight-proof-server -v

You should see output similar to:

actix_server::server: starting service: "actix-web-service-0.0.0.0:6300", workers: 14, listening on: 0.0.0.0:6300
tip

Keep this terminal window open. The proof server must stay active to compile and deploy contracts. To stop it, press Ctrl+C or stop the container.

If you need a specific proof server version instead of latest, check the compatibility matrix for the version that matches your node and SDK.

The proof server listens on port 6300; do not change this port.

Your privacy

The proof server exists to protect your privacy. It does not open any network connections; it listens on its assigned port for requests from your wallet.

Optional: use Bun as your runtime

The guides and tutorials in this documentation use Node.js with npm or Yarn. Bun is a modern JavaScript runtime and toolkit that can offer significantly faster performance, and it works with Midnight development too. This section covers installing Bun, setting up a Midnight project with it, and the compatibility considerations to keep in mind. If you are happy with Node.js, skip ahead to the next steps.

Install Bun on macOS

  1. Run the command below:
curl -fsSL https://bun.sh/install | bash

This script downloads the appropriate Bun binary for your system and installs it to ~/.bun/bin.

  1. Verify the installation. Close and reopen your terminal, then run:
bun --version

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

  1. Install required dependencies. Bun's installer requires unzip to extract the binary:
sudo apt update
sudo apt install unzip -y
  1. Run the official Bun installation script:
curl -fsSL https://bun.sh/install | bash
  1. Reload your shell configuration so the bun command is available:
source ~/.bashrc
  1. Verify the installation:
bun --version

You should see the installed Bun version printed to the terminal.

  1. If bun is not found, add Bun's install directory to your PATH:
export PATH="$HOME/.bun/bin:$PATH"

Set up a Midnight project with Bun

With both Bun and the Compact compiler installed, you can create a Midnight application project.

  1. Initialize a new project:
mkdir my-midnight-app
cd my-midnight-app
bun init -y

This creates a basic package.json.

  1. Create the required directories. The project requires separate folders for smart contracts and application source code:
mkdir src contracts
  1. Install the Midnight runtime package. Install a specific version to avoid compatibility issues:
bun add @midnight-ntwrk/compact-runtime@0.16.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
info

Always refer to the compatibility matrix for the correct version of the runtime package to install.

  1. Update the tsconfig.json file:
tsconfig.json
{
"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 scripts

Update your package.json with the Bun-specific scripts below:

package.json
"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.compact into 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 a smart contract with Compact

In this section, you create a Compact smart contract that stores and reads a message on the Midnight blockchain. Then, you compile it for use in your TypeScript/Bun application.

  1. Create a file named message.compact in the contracts directory:
touch contracts/message.compact
  1. Add the code below to the file:
message.compact
pragma language_version 0.23;

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.23; Specifies the exact Compact language version required for this smart contract. Using version 0.23 ensures compatibility with the runtime version 0.16.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 called message on 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.
  1. Compile with compact:
compact compile contracts/message.compact contracts/managed

What this does:

  • Converts the human-readable .compact contract 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 the compiled contract with Bun

Now that you have compiled your Compact contract, the next step is to interact with it from a Bun-powered TypeScript application. Here you create a client that simulates storing and reading a message from your Midnight contract.

  1. Create src/message-client.ts:
touch src/message-client.ts

Add the following code:

message-client.ts
import { Contract, ledger } from "../contracts/managed/contract/index.js";

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 MessageClient class.
  • Loads your compiled Compact contract.
  • Provides two methods:
    • storeMessage(): simulates writing data.
    • getMessage(): simulates reading data.
  • Keeps the example minimal while preserving the project structure that real Midnight apps require.
  1. Create src/index.ts to serve as your application entry point:
touch src/index.ts

Add the following code:

index.ts
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);

This file boots your Midnight app, creates an instance of MessageClient, calls the store and retrieve functions, and prints the results in your terminal.

  1. 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.

Native module compatibility. 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. 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
tip

Choose one package manager for your project and have your team use only that one.

Environment variables. 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

Migrate an existing project from npm to Bun

If your Midnight project was originally set up using Node.js and npm, you can migrate to Bun with a few steps.

  1. Confirm that you have Bun on your system:
bun --version

If not found, install Bun.

  1. Remove npm artifacts:
cd your-midnight-project
rm -rf node_modules package-lock.json
warning

Back up your package-lock.json first if you need to revert.

  1. Install dependencies with Bun:
bun install
  1. Verify the migration by testing that your application works correctly with Bun:
bun run dev

Troubleshoot

  1. 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.16.0
  1. Version mismatch errors

Problem:

CompactError: Version mismatch: compiled code expects 0.16.0, runtime is 0.9.0
note

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.16.0

Then recompile your smart contracts:

compact compile contracts/message.compact contracts/managed
  1. Compact compiler language version errors

Problem:

Exception: message.compact line 1 char 1:
language version 0.22.0 mismatch

Solution:

Update your smart contract to use the exact language version:

pragma language_version 0.23;
note

Using an exact version number (such as 0.23) instead of a range prevents compatibility issues with different compiler versions.

  1. 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/.local/bin:$PATH"
  • Try reinstalling:
curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/midnightntwrk/compact/releases/latest/download/compact-installer.sh | sh

Next steps

Your environment is ready. Before you can deploy anything, your wallet needs test tokens to pay for transactions:

  • Fund your wallet with tNIGHT and tDUST.
  • Prefer to start with the language instead? Write your first contract with the hello world tutorial.