Tools: Setting up Midnight on Windows via WSL2: The Complete Guide (2026)

Tools: Setting up Midnight on Windows via WSL2: The Complete Guide (2026)

What does not work on Windows

Step 1: Install and configure WSL2

Step 2: Configure WSL2 memory with .wslconfig

Step 3: Set up Docker Desktop with the WSL2 backend

Step 4: Install Node.js inside WSL2

Step 5: Install the Compact compiler

Install a package manager

Step 6: Start the proof server

Step 7: Install the Compact VS Code extension

Step 8: Deploy the Hello World contract

Fix the docker-compose.yml before running

Troubleshooting

Proof server crashes or goes silent

docker: command not found inside WSL

compact: command not found after installation

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

Port 6300 already in use

yarn test:local hangs indefinitely

Working .wslconfig reference

Next steps 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. 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. You cannot run the Midnight toolchain natively on Windows. The following approaches all fail: 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]. [Windows terminal: run PowerShell as Administrator] 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: You should see Ubuntu listed with Version 2. If it shows Version 1, upgrade it: 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. Open Notepad (or any text editor) and create the file at C:\Users\<YourUsername>\.wslconfig: Save the file, then restart WSL2 from a Windows terminal: 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. 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. Verify Docker is accessible from inside WSL2: 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. 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. Install and activate Node.js v22: 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. Run the official Compact installer: The installer downloads the Compact binary and adds it to your PATH. Reload your shell config so the PATH change takes effect: Verify the installation: All three commands should return valid output. If compact: command not found appears, the PATH was not updated. Add it manually: Update to the latest compiler version: Warning: If compact update fails with: your WSL environment is missing required system tools (for example unzip or tar). Install them before retrying: The Hello World example later in this tutorial uses yarn. Install it with npm: 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). The proof server generates ZK proofs for your transactions. It runs as a Docker container on port 6300. Make sure Docker Desktop is running (check your Windows system tray for the Docker icon). Then start the proof server: 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: 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. 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. Download the VSIX package: Install it in VS Code: Alternatively, install it manually through the VS Code UI: Verification: Open the Extensions panel and confirm Compact Language Support appears in your installed extensions list. 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: If nothing meaningful appears, create a directory for your development work: The -p flag makes this safe to run: 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: You should see a path like: Now clone the Hello World example: [WSL terminal: new window] 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: 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: Create the contract file: Open contracts/hello-world.compact in VS Code and paste the following: A quick breakdown of what this contract does: Compile the contract. The compact compile command expects paths relative to the contracts/ directory, so navigate into it first: After compilation completes, navigate back to the project root before running the next commands: 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: In your second terminal, deploy and run the test: A successful run looks like this: Your Midnight dev environment is now working on Windows. 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. 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. Cause: The PATH update was not applied to the current shell session. Cause: Missing system utilities (unzip, tar, etc.) in WSL. Cause: An earlier proof server container is still running. Fix: Find and stop it: Or run the proof server on an alternate port and update your app config to match: 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. Save this file at C:\Users\<YourUsername>\.wslconfig: After saving, always run wsl --shutdown from a Windows terminal and restart Ubuntu for changes to take effect. 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. Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse

Code Block

Copy

wsl --install wsl --install wsl --install wsl --list --verbose wsl --list --verbose wsl --list --verbose wsl --set-version Ubuntu 2 wsl --set-version Ubuntu 2 wsl --set-version Ubuntu 2 # .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 # .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 # .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 wsl --shutdown wsl --shutdown wsl --shutdown docker --version docker --version docker --version curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash source ~/.bashrc source ~/.bashrc source ~/.bashrc nvm install 22 nvm use 22 node --version # should output v22.x.x nvm install 22 nvm use 22 node --version # should output v22.x.x nvm install 22 nvm use 22 node --version # should output v22.x.x curl --proto '=https' --tlsv1.2 -LsSf \ https://github.com/midnightntwrk/compact/releases/latest/download/compact-installer.sh | sh curl --proto '=https' --tlsv1.2 -LsSf \ https://github.com/midnightntwrk/compact/releases/latest/download/compact-installer.sh | sh curl --proto '=https' --tlsv1.2 -LsSf \ https://github.com/midnightntwrk/compact/releases/latest/download/compact-installer.sh | sh source ~/.bashrc # or, if you use zsh: source ~/.zshrc source ~/.bashrc # or, if you use zsh: source ~/.zshrc source ~/.bashrc # or, if you use zsh: source ~/.zshrc compact --version compact compile --version which compact compact --version compact compile --version which compact compact --version compact compile --version which compact export PATH="$HOME/.compact/bin:$PATH" echo 'export PATH="$HOME/.compact/bin:$PATH"' >> ~/.bashrc source ~/.bashrc export PATH="$HOME/.compact/bin:$PATH" echo 'export PATH="$HOME/.compact/bin:$PATH"' >> ~/.bashrc source ~/.bashrc export PATH="$HOME/.compact/bin:$PATH" echo 'export PATH="$HOME/.compact/bin:$PATH"' >> ~/.bashrc source ~/.bashrc compact update compact update compact update Failed to spawn artifact extraction command No such file or directory (os error 2) Failed to spawn artifact extraction command No such file or directory (os error 2) sudo apt update sudo apt install -y unzip tar gzip curl sudo apt update sudo apt install -y unzip tar gzip curl npm install -g yarn npm install -g yarn npm install -g yarn yarn --version yarn --version yarn --version docker run -p 6300:6300 midnightntwrk/proof-server:8.0.3 midnight-proof-server -v docker run -p 6300:6300 midnightntwrk/proof-server:8.0.3 midnight-proof-server -v docker run -p 6300:6300 midnightntwrk/proof-server:8.0.3 midnight-proof-server -v INFO actix_server::server: starting service: "actix-web-service-0.0.0.0:6300", workers: 4, listening on: 0.0.0.0:6300 INFO actix_server::server: starting service: "actix-web-service-0.0.0.0:6300", workers: 4, listening on: 0.0.0.0:6300 INFO actix_server::server: starting service: "actix-web-service-0.0.0.0:6300", workers: 4, listening on: 0.0.0.0:6300 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 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 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 code --install-extension compact.vsix code --install-extension compact.vsix code --install-extension compact.vsix mkdir -p ~/dev cd ~/dev mkdir -p ~/dev cd ~/dev mkdir -p ~/dev cd ~/dev /home/<your-username>/dev /home/<your-username>/dev /home/<your-username>/dev git clone https://github.com/midnightntwrk/example-hello-world.git cd example-hello-world git clone https://github.com/midnightntwrk/example-hello-world.git cd example-hello-world git clone https://github.com/midnightntwrk/example-hello-world.git cd example-hello-world 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 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 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 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 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 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 yarn install yarn install yarn install touch contracts/hello-world.compact code . # opens VS Code for the current working directory touch contracts/hello-world.compact code . # opens VS Code for the current working directory touch contracts/hello-world.compact code . # opens VS Code for the current working directory pragma language_version >= 0.22; export ledger message: Opaque<"string">; export circuit storeMessage(newMessage: Opaque<"string">): [] { message = disclose(newMessage); } pragma language_version >= 0.22; export ledger message: Opaque<"string">; export circuit storeMessage(newMessage: Opaque<"string">): [] { message = disclose(newMessage); } pragma language_version >= 0.22; export ledger message: Opaque<"string">; export circuit storeMessage(newMessage: Opaque<"string">): [] { message = disclose(newMessage); } cd contracts compact compile hello-world.compact managed/hello-world.compact cd contracts compact compile hello-world.compact managed/hello-world.compact cd contracts compact compile hello-world.compact managed/hello-world.compact Compiling 1 circuits: circuit "storeMessage" (k=6, rows=26) Compiling 1 circuits: circuit "storeMessage" (k=6, rows=26) Compiling 1 circuits: circuit "storeMessage" (k=6, rows=26) yarn env:up yarn env:up yarn env:up yarn test:local yarn test:local yarn test:local [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 [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 [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 export PATH="$HOME/.compact/bin:$PATH" echo 'export PATH="$HOME/.compact/bin:$PATH"' >> ~/.bashrc source ~/.bashrc export PATH="$HOME/.compact/bin:$PATH" echo 'export PATH="$HOME/.compact/bin:$PATH"' >> ~/.bashrc source ~/.bashrc export PATH="$HOME/.compact/bin:$PATH" echo 'export PATH="$HOME/.compact/bin:$PATH"' >> ~/.bashrc source ~/.bashrc sudo apt update sudo apt install -y unzip tar gzip curl sudo apt update sudo apt install -y unzip tar gzip curl sudo apt update sudo apt install -y unzip tar gzip curl which unzip which tar which unzip which tar which unzip which tar compact update compact update compact update rm -rf ~/.compact rm -rf ~/.compact rm -rf ~/.compact docker ps docker stop <container_id> docker ps docker stop <container_id> docker ps docker stop <container_id> docker run -p 6301:6300 midnightntwrk/proof-server:8.0.3 midnight-proof-server -v docker run -p 6301:6300 midnightntwrk/proof-server:8.0.3 midnight-proof-server -v docker run -p 6301:6300 midnightntwrk/proof-server:8.0.3 midnight-proof-server -v [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 [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 [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 - Windows 10 (version 2004+) or Windows 11 - Administrator access - stable internet connection. - 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. - Download and install Docker Desktop. - During installation, select Use WSL2 instead of Hyper-V when prompted. - After installation, open Docker Desktop and go to Settings → General. Confirm that Use the WSL2 based engine is checked. - Go to Settings → Resources → WSL Integration. Enable integration for your Ubuntu distribution. - Click Apply & Restart. - Open VS Code - Go to Extensions (Ctrl+Shift+X) - Click the ... menu at the top right of the Extensions panel - Select Install from VSIX... - Navigate to and select the downloaded compact.vsix file - It creates parent directories if they do not exist. - It does not fail if the directory already exists. - 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. - 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. - Read the Compact language reference to understand how to model privacy in smart contracts. - Explore the full examples library for DApps with more complex state and circuit logic. - Join the Midnight developer forum and Discord for community support and announcements.