DEV Community

Cover image for Setting up Midnight on Windows via WSL2: The Complete Guide
Uroy Nwankwo
Uroy Nwankwo

Posted on

Setting up Midnight on Windows via WSL2: The Complete Guide

Midnight's toolchain runs natively on UNIX systems, Linux and macOS. If you're on Windows, you will need the Windows Subsystem for Linux 2 (WSL2).
This tutorial takes you from a fresh Windows machine to a working Midnight dev environment.

Target audience: Windows developers who want to build on the Midnight network.

Prerequisites:

  • Windows 10 (version 2004+) or Windows 11
  • Administrator access
  • stable internet connection.

What you'll have by the end: A winodws machine setup with a complete development environment for building on the midnight network.

You will set up WSL2, configure Docker Desktop, allocate enough memory for the proof server, install the Compact compiler, and verify everything by deploying the Hello World contract. It also shows which Windows approaches fail, so you can skip the dead ends.

What does not work on Windows

You cannot run the Midnight toolchain natively on Windows. The following approaches all fail:

  • PowerShell / Command Prompt: the Compact installer script is a POSIX shell script. It will not run.
  • Windows-native Node.js: even if you install Node.js for Windows, the Compact compiler and proof server depend on Linux binaries. They will not resolve correctly.
  • Git Bash / Cygwin: these are POSIX compatibility layers, not real Linux environments. The installer may appear to work, but it will produce broken PATH entries and missing binaries at runtime.

The supported Windows setup is WSL2 with a real Linux distribution. Everything after this point assumes you are inside a WSL2 terminal unless explicitly marked [Windows terminal].

Step 1: Install and configure WSL2

[Windows terminal: run PowerShell as Administrator]

wsl --install
Enter fullscreen mode Exit fullscreen mode

 PowerShell showing wsl --install progress plus the success or reboot prompt message.

This command installs WSL2 and downloads Ubuntu, which is the recommended distribution. Restart your machine when prompted.

After restart, open Ubuntu from the Start menu. The first launch completes the Ubuntu setup and asks you to create a Linux username and password. These credentials are for your WSL2 environment only. They do not need to match your Windows credentials.

Verify WSL2 is active:

wsl --list --verbose
Enter fullscreen mode Exit fullscreen mode

PowerShell showing Ubuntu with STATE set and VERSION 2 in the  raw `wsl --list --verbose` endraw  output

You should see Ubuntu listed with Version 2. If it shows Version 1, upgrade it:

wsl --set-version Ubuntu 2
Enter fullscreen mode Exit fullscreen mode

Step 2: Configure WSL2 memory with .wslconfig

This is the step the official docs miss. The Midnight proof server generates zero-knowledge proofs locally, which takes real memory. By default, WSL2 caps memory at 1 GB, so the proof server can run out of memory and crash without much explanation.

You need to create a .wslconfig file in your Windows user profile directory to raise this limit.

[Windows terminal]

Open Notepad (or any text editor) and create the file at C:\Users\<YourUsername>\.wslconfig:

# .wslconfig: WSL2 resource configuration
[wsl2]
memory=8GB          # Allocate 8 GB RAM to WSL2 (minimum 4 GB for proof server)
processors=4        # Number of CPU cores available to WSL2
swap=2GB            # Optional: virtual swap space
localhostForwarding=true
Enter fullscreen mode Exit fullscreen mode

C:\Users\<YourUsername>\.wslconfig open in Notepad with both the file path and config contents visible.

Save the file, then restart WSL2 from a Windows terminal:

wsl --shutdown
Enter fullscreen mode Exit fullscreen mode

Wait 10 seconds, then reopen your Ubuntu terminal. The new memory limit takes effect immediately.

Warning: The proof server can crash with less than 4 GB allocated. 8GB is the safer setting. If your machine has 16 GB of RAM or more, giving WSL2 8GB still leaves enough memory for Windows and a browser.

Step 3: Set up Docker Desktop with the WSL2 backend

The Midnight proof server runs as a Docker container. Docker Desktop must use the WSL2 backend. The Hyper-V backend does not give your WSL2 terminal access to Docker.

  1. Download and install Docker Desktop.
  2. During installation, select Use WSL2 instead of Hyper-V when prompted.
  3. After installation, open Docker Desktop and go to Settings → General. Confirm that Use the WSL2 based engine is checked.
  4. Go to Settings → Resources → WSL Integration. Enable integration for your Ubuntu distribution.
  5. Click Apply & Restart.

Docker Desktop Settings → General with  raw `Use the WSL2 based engine` endraw  checked.

 Docker Desktop Settings → Resources → WSL Integration with the Ubuntu distro toggle enabled.

Verify Docker is accessible from inside WSL2:

[WSL terminal]

docker --version
Enter fullscreen mode Exit fullscreen mode

You should see output like Docker version 26.x.x, build .... If you see command not found, Docker is not exposed inside WSL yet. Go back to item 4 in this section and make sure WSL integration is enabled for your Ubuntu distro.

Step 4: Install Node.js inside WSL2

The Midnight DApp tooling requires Node.js v22 or later. Install it inside WSL2 with nvm (Node Version Manager). That keeps the version under your user account and avoids sudo headaches.

[WSL terminal]

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
Enter fullscreen mode Exit fullscreen mode

Reload your shell:

source ~/.bashrc
Enter fullscreen mode Exit fullscreen mode

Install and activate Node.js v22:

nvm install 22
nvm use 22
node --version   # should output v22.x.x
Enter fullscreen mode Exit fullscreen mode

WSL terminal showing nvm use 22 and node --version returning a v22.x.x version.

Note: Do not install Node.js with apt for this workflow. Ubuntu's apt packages are usually older and do not meet the v22 requirement.

Step 5: Install the Compact compiler

[WSL terminal]

Run the official Compact installer:

curl --proto '=https' --tlsv1.2 -LsSf \
  https://github.com/midnightntwrk/compact/releases/latest/download/compact-installer.sh | sh
Enter fullscreen mode Exit fullscreen mode

The installer downloads the Compact binary and adds it to your PATH. Reload your shell config so the PATH change takes effect:

source ~/.bashrc
# or, if you use zsh:
source ~/.zshrc
Enter fullscreen mode Exit fullscreen mode

Verify the installation:

compact --version
compact compile --version
which compact
Enter fullscreen mode Exit fullscreen mode

WSL terminal showing successful output for compact --version, compact compile --version, and which compact

All three commands should return valid output. If compact: command not found appears, the PATH was not updated. Add it manually:

export PATH="$HOME/.compact/bin:$PATH"
echo 'export PATH="$HOME/.compact/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
Enter fullscreen mode Exit fullscreen mode

Update to the latest compiler version:

compact update
Enter fullscreen mode Exit fullscreen mode

Warning: If compact update fails with:

Failed to spawn artifact extraction command
No such file or directory (os error 2)

your WSL environment is missing required system tools (for example unzip or tar). Install them before retrying:

sudo apt update
sudo apt install -y unzip tar gzip curl

Install a package manager

The Hello World example later in this tutorial uses yarn. Install it with npm:

npm install -g yarn
Enter fullscreen mode Exit fullscreen mode

Verify it installed:

yarn --version
Enter fullscreen mode Exit fullscreen mode

Note: yarn is optional. You can use npm or pnpm instead.
If you prefer a different package manager, substitute yarn commands
with your preferred equivalent throughout this tutorial
(e.g. npm install instead of yarn install, npm run env:up
instead of yarn env:up).

Step 6: Start the proof server

The proof server generates ZK proofs for your transactions. It runs as a Docker container on port 6300.

[WSL terminal]

Make sure Docker Desktop is running (check your Windows system tray for the Docker icon). Then start the proof server:

docker run -p 6300:6300 midnightntwrk/proof-server:8.0.3 midnight-proof-server -v
Enter fullscreen mode Exit fullscreen mode

This command occupies the terminal while the server runs. Open a second WSL2 terminal window for the next steps. You should see log output ending with something like:

 INFO actix_server::server: starting service: "actix-web-service-0.0.0.0:6300", 
 workers: 4, listening on: 0.0.0.0:6300
Enter fullscreen mode Exit fullscreen mode

WSL terminal with the proof server container running and the listening on: 0.0.0.0:6300 log visible.

That confirms the proof server is running and ready.

Tip: Keep the proof server terminal open while you work. If you close it, any compile or deploy step that needs ZK proofs will hang or fail.

Step 7: Install the Compact VS Code extension

Before opening any contract files, install the Compact VS Code
extension. It provides syntax highlighting and code snippet
completion for .compact files. Without it, VS Code treats
your contract as plain text.

[WSL terminal]

Download the VSIX package:

curl -L -o compact.vsix https://raw.githubusercontent.com/midnight-ntwrk/releases/gh-pages/artifacts/vscode-extension/compact-0.2.13/compact-0.2.13.vsix
Enter fullscreen mode Exit fullscreen mode

Install it in VS Code:

code --install-extension compact.vsix
Enter fullscreen mode Exit fullscreen mode

Alternatively, install it manually through the VS Code UI:

  1. Open VS Code
  2. Go to Extensions (Ctrl+Shift+X)
  3. Click the ... menu at the top right of the Extensions panel
  4. Select Install from VSIX...
  5. Navigate to and select the downloaded compact.vsix file

Verification: Open the Extensions panel and confirm
Compact Language Support appears in your installed extensions list.

VS Code Extensions panel showing the Compact Language Support extension installed

Step 8: Deploy the Hello World contract

With the proof server running, verify the full setup by cloning the Hello World example, compiling a Compact smart contract, and deploying it to a local Devnet.

Before cloning the example project, set up a working directory inside your WSL environment. A fresh Ubuntu install starts in your home directory, which is typically empty.

Check your current location:

ls
Enter fullscreen mode Exit fullscreen mode

If nothing meaningful appears, create a directory for your development work:

mkdir -p ~/dev
cd ~/dev
Enter fullscreen mode Exit fullscreen mode

The -p flag makes this safe to run:

  • It creates parent directories if they do not exist.
  • It does not fail if the directory already exists.

That means the command works on both fresh and existing setups.

Note: Keep your project inside WSL (for example ~/dev), not in the Windows filesystem (/mnt/c/...). Working in /mnt/c often causes slower file access, permission issues, and strange behavior with Node.js and Docker.

Confirm your location:

pwd
Enter fullscreen mode Exit fullscreen mode

You should see a path like:

/home/<your-username>/dev
Enter fullscreen mode Exit fullscreen mode

Now clone the Hello World example:

[WSL terminal: new window]

git clone https://github.com/midnightntwrk/example-hello-world.git
cd example-hello-world
Enter fullscreen mode Exit fullscreen mode

Fix the docker-compose.yml before running

The default docker-compose.yml in the Hello World repo has two
issues that can make yarn env:up fail on a fresh setup.
Open docker-compose.yml and find the proof-server service block.

It currently looks like this:

proof-server:
  image: 'midnightntwrk/proof-server:8.0.3'
  command: ['midnight-proof-server -v']
  ports:
    - '127.0.0.1:6300:6300'
  environment:
    RUST_BACKTRACE: 'full'
  healthcheck:
    test: ['CMD', 'curl', '-f', 'http://localhost:6300/version']
    interval: 10s
    timeout: 5s
    retries: 20
    start_period: 10s
Enter fullscreen mode Exit fullscreen mode

Replace it with:

proof-server:
  image: 'midnightntwrk/proof-server:8.0.3'
  command: ['midnight-proof-server', '-v']
  ports:
    - '127.0.0.1:6300:6300'
  environment:
    RUST_BACKTRACE: 'full'
  healthcheck:
    test: ['CMD-SHELL', 'echo > /dev/tcp/127.0.0.1/6300']
    interval: 10s
    timeout: 5s
    retries: 20
    start_period: 10s
Enter fullscreen mode Exit fullscreen mode

Two things changed:

  • command: the original passes the entire string as a single executable, which fails silently. The corrected version passes the flag as a separate argument as Docker expects.
  • healthcheck: the original uses curl to check if the server is ready, but the proof server image is a minimal production image and does not include curl. The replacement uses a TCP socket check via bash's built-in /dev/tcp, which works without any additional tools.

Note: These issues have been reported upstream. See
issue #16 and PR #17.
If the PR has merged by the time you read this, your file may
already have the corrected command. Only apply the changes that
differ from what you see.

Install dependencies:

yarn install
Enter fullscreen mode Exit fullscreen mode

Create the contract file:

touch contracts/hello-world.compact
code . # opens VS Code for the current working directory
Enter fullscreen mode Exit fullscreen mode

VS Code opened from WSL with  raw `contracts/hello-world.compact` endraw  visible and Compact syntax highlighting active

Open contracts/hello-world.compact in VS Code and paste the following:

pragma language_version >= 0.22;

export ledger message: Opaque<"string">;

export circuit storeMessage(newMessage: Opaque<"string">): [] {
  message = disclose(newMessage);
}
Enter fullscreen mode Exit fullscreen mode

A quick breakdown of what this contract does:

  • ledger message declares a public, persistent on-chain state variable that stores a string.
  • circuit storeMessage defines the logic to update that variable.
  • newMessage is a private input by default. The disclose() call marks it safe to write to public ledger state. Without it, the compiler rejects the assignment.

Compile the contract. The compact compile command expects paths
relative to the contracts/ directory, so navigate into it first:

cd contracts
compact compile hello-world.compact managed/hello-world.compact
Enter fullscreen mode Exit fullscreen mode

After compilation completes, navigate back to the project root
before running the next commands:

cd ..
Enter fullscreen mode Exit fullscreen mode

Expected output:

Compiling 1 circuits:
  circuit "storeMessage" (k=6, rows=26)
Enter fullscreen mode Exit fullscreen mode

WSL terminal showing the successful compact compile output with Compiling 1 circuits

This generates ZK circuits, proving and verifying keys, and TypeScript API bindings in the contracts/managed/ directory.

Start the local Devnet environment. The first run pulls the required Docker images. Run this in the project terminal while the proof server stays open in the other terminal:

yarn env:up
Enter fullscreen mode Exit fullscreen mode

In your second terminal, deploy and run the test:

yarn test:local
Enter fullscreen mode Exit fullscreen mode

A successful run looks like this:

[12:46:12.694] INFO: Wallet sync complete after 23 emissions
[12:46:12.703] INFO: Providers initialized. Ready to test
[12:46:32.347] INFO: Contract deployed at: bba6579743ae23b44301d4a9f8df30dbd5244d63a59d8fbc2c9fc7ea521a04f8

 ✓ Hello World Contract > Deploys the contract   19649ms
 ✓ Hello World Contract > Stores a message        18184ms
Enter fullscreen mode Exit fullscreen mode

Final success screenshot showing yarn test:local passing, including the deployed contract address and both passing checks.

Your Midnight dev environment is now working on Windows.

Troubleshooting

Proof server crashes or goes silent

Cause: WSL2 ran out of memory.

Fix: Open .wslconfig and increase the memory value (minimum 4GB, recommended 8GB). Shut down WSL2 with wsl --shutdown from a Windows terminal, then restart Ubuntu and rerun the proof server.

docker: command not found inside WSL

Cause: Docker Desktop's WSL2 integration is not enabled for your distro.

Fix: Open Docker Desktop → Settings → Resources → WSL Integration → enable your Ubuntu distro → Apply & Restart.

compact: command not found after installation

Cause: The PATH update was not applied to the current shell session.

Fix:

export PATH="$HOME/.compact/bin:$PATH"
echo 'export PATH="$HOME/.compact/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
Enter fullscreen mode Exit fullscreen mode

compact update fails with “Failed to spawn artifact extraction command”

Cause: Missing system utilities (unzip, tar, etc.) in WSL.

Fix:

sudo apt update
sudo apt install -y unzip tar gzip curl
Enter fullscreen mode Exit fullscreen mode

Verify:

which unzip
which tar
Enter fullscreen mode Exit fullscreen mode

Retry:

compact update
Enter fullscreen mode Exit fullscreen mode

If it still fails:

rm -rf ~/.compact
Enter fullscreen mode Exit fullscreen mode

Then reinstall.

Port 6300 already in use

Cause: An earlier proof server container is still running.

Fix: Find and stop it:

docker ps
docker stop <container_id>
Enter fullscreen mode Exit fullscreen mode

Or run the proof server on an alternate port and update your app config to match:

docker run -p 6301:6300 midnightntwrk/proof-server:8.0.3 midnight-proof-server -v
Enter fullscreen mode Exit fullscreen mode

yarn test:local hangs indefinitely

Cause: The proof server is not running, or Docker is not accessible from WSL2.

Fix: Confirm the proof server terminal is active and showing the listening log. Confirm docker ps returns results from your WSL2 terminal. If Docker is not visible, re-check the WSL integration setting in Docker Desktop.

Working .wslconfig reference

Save this file at C:\Users\<YourUsername>\.wslconfig:

[wsl2]
# Memory: minimum 4GB for proof server, 8GB recommended
memory=8GB

# CPU cores available to WSL2
processors=4

# Optional swap space
swap=2GB

# Allow localhost forwarding between Windows and WSL2 (needed for Docker port access)
localhostForwarding=true
Enter fullscreen mode Exit fullscreen mode

After saving, always run wsl --shutdown from a Windows terminal and restart Ubuntu for changes to take effect.

Next steps

Your environment is configured and verified. Next:

If you find an outdated step, leave a comment or ask in the Midnight Discord. If you publish your own build notes, tag @midnightntwrk.

Top comments (0)