Tools: Breaking: Midnight Development on Windows via WSL2: Complete Setup Guide

Tools: Breaking: Midnight Development on Windows via WSL2: Complete Setup Guide

series: null

Midnight Development on Windows via WSL2: Complete Setup Guide

Prerequisites

Part 1: Installing WSL2

Enable WSL2

Install Ubuntu (Recommended)

Configure .wslconfig

Part 2: Docker Desktop Configuration

Install Docker Desktop

Verify Docker in WSL

Part 3: Midnight Toolchain Setup

Install Node.js

Install Compact Compiler

Install Midnight MCP

Setup Docker Stack for Local Development

Part 4: End-to-End Verification

Create Your First Midnight Contract

Compile the Contract

Deploy to Local Devnet

Part 5: What Does NOT Work

❌ Native Windows PowerShell

❌ Windows-native Node.js/npm

❌ Windows Docker without WSL2

❌ VSCode Remote-WSL Without Proper Setup

Part 6: Troubleshooting

Proof Server Out of Memory (OOM)

Docker Access Denied

Compact Command Not Found

PATH Issues Between Windows and WSL

Network Connectivity Issues

Disk Space Issues

Performance Optimization

Common Error Messages

Conclusion

Quick Reference Commands title: "Midnight Development on Windows via WSL2: Complete Setup Guide"

published: truedescription: "A comprehensive guide to setting up Midnight development environment on Windows using WSL2"tags: ["midnight", "wsl2", "blockchain", "zkshield", "web3"]cover_image: https://images.unsplash.com/photo-1629654297299-c8506221ca97?w=800

canonical_url: null Midnight's toolchain is designed to run on Linux and macOS, which presents a challenge for Windows developers. While native Windows development isn't supported, WSL2 (Windows Subsystem for Linux) provides an excellent workaround. This tutorial walks you through setting up a complete Midnight development environment on Windows 10/11. Before we begin, ensure you have: First, open Windows PowerShell as Administrator and run: ⚠️ WSL Terminal: These commands run in Windows PowerShell After installation, restart your computer. On restart, Ubuntu will automatically install. Create your Linux username and password when prompted. If WSL installed a different distribution, install Ubuntu explicitly: This is the most critical step for Midnight development. The default WSL2 memory allocation (usually 2GB) is insufficient for the proof server, which requires at least 4GB. Create or edit .wslconfig in your Windows user home directory: Windows Terminal (not WSL): Add the following content: Important: After saving .wslconfig, restart WSL from PowerShell: Open a new WSL terminal and verify Docker is accessible: 💡 Pro Tip: If you get "permission denied while trying to connect to the Docker daemon," add your user to the docker group: Midnight requires Node.js 18+. Install using nvm for version management: Install the Midnight Compact compiler: ⚠️ Common Issue: If compact command is not found after installation, manually add it to your PATH: The Midnight MCP (Model Context Protocol) provides essential tooling: Create a docker-compose file for the Midnight local stack: Create docker/docker-compose.yml: Create a new project: Edit contract.compact with a simple counter contract: If successful, you'll see: Note: For deployment, you'll need the Lace wallet browser extension installed and configured with testnet tokens. See the Midnight Documentation for details. Understanding what doesn't work is crucial to avoid frustration: If you see errors like "memory allocation failed": Detailed fix for OOM: If you get "Cannot connect to Docker daemon": If compact is not recognized: If proof server cannot connect to indexer: WSL2 can consume significant disk space. Clean up periodically: For faster development: You now have a fully functional Midnight development environment running on Windows via WSL2. The key takeaways are: With this setup, you can now develop privacy-preserving DApps on Midnight directly from your Windows machine. The initial setup takes about 30-45 minutes, but you'll have a production-ready development environment. Published on Dev.to | #MidnightforDevs | @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

Command

Copy

# Enable required Windows features wsl ---weight: 500;">install # Enable required Windows features wsl ---weight: 500;">install # Enable required Windows features wsl ---weight: 500;">install # WSL Terminal wsl ---weight: 500;">install -d Ubuntu-22.04 # WSL Terminal wsl ---weight: 500;">install -d Ubuntu-22.04 # WSL Terminal wsl ---weight: 500;">install -d Ubuntu-22.04 # Create the config file notepad $env:USERPROFILE\.wslconfig # Create the config file notepad $env:USERPROFILE\.wslconfig # Create the config file notepad $env:USERPROFILE\.wslconfig [wsl2] # Allocate 6GB memory to WSL2 (adjust based on your RAM) memory=6GB # Use all available processors processors=8 # Set appropriate swap size swap=4GB # Enable DNS tunneling dnsTunneling=true # Enable automatic memory reclamation autoMemoryReclaim=gradual # Enable local port forwarding localhostForwarding=true # Set localhostForwarding localhostForwarding=true [wsl2] # Allocate 6GB memory to WSL2 (adjust based on your RAM) memory=6GB # Use all available processors processors=8 # Set appropriate swap size swap=4GB # Enable DNS tunneling dnsTunneling=true # Enable automatic memory reclamation autoMemoryReclaim=gradual # Enable local port forwarding localhostForwarding=true # Set localhostForwarding localhostForwarding=true [wsl2] # Allocate 6GB memory to WSL2 (adjust based on your RAM) memory=6GB # Use all available processors processors=8 # Set appropriate swap size swap=4GB # Enable DNS tunneling dnsTunneling=true # Enable automatic memory reclamation autoMemoryReclaim=gradual # Enable local port forwarding localhostForwarding=true # Set localhostForwarding localhostForwarding=true wsl --shutdown wsl --shutdown wsl --shutdown # WSL Terminal -weight: 500;">docker --version -weight: 500;">docker-compose --version # Test Docker is running -weight: 500;">docker run hello-world # WSL Terminal -weight: 500;">docker --version -weight: 500;">docker-compose --version # Test Docker is running -weight: 500;">docker run hello-world # WSL Terminal -weight: 500;">docker --version -weight: 500;">docker-compose --version # Test Docker is running -weight: 500;">docker run hello-world # WSL Terminal -weight: 600;">sudo usermod -aG -weight: 500;">docker $USER newgrp -weight: 500;">docker # WSL Terminal -weight: 600;">sudo usermod -aG -weight: 500;">docker $USER newgrp -weight: 500;">docker # WSL Terminal -weight: 600;">sudo usermod -aG -weight: 500;">docker $USER newgrp -weight: 500;">docker # WSL Terminal # Install nvm if not already installed -weight: 500;">curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/-weight: 500;">install.sh | bash # Reload shell export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # Install and use Node.js 20 nvm -weight: 500;">install 20 nvm use 20 # Verify installation node --version # Should output v20.x.x -weight: 500;">npm --version # WSL Terminal # Install nvm if not already installed -weight: 500;">curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/-weight: 500;">install.sh | bash # Reload shell export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # Install and use Node.js 20 nvm -weight: 500;">install 20 nvm use 20 # Verify installation node --version # Should output v20.x.x -weight: 500;">npm --version # WSL Terminal # Install nvm if not already installed -weight: 500;">curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/-weight: 500;">install.sh | bash # Reload shell export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # Install and use Node.js 20 nvm -weight: 500;">install 20 nvm use 20 # Verify installation node --version # Should output v20.x.x -weight: 500;">npm --version # WSL Terminal -weight: 500;">curl --proto '=https' --tlsv1.2 -LsSf https://github.com/midnightntwrk/compact/releases/latest/download/compact-installer.sh | sh # Reload shell configuration source ~/.bashrc # Verify installation compact --version compact compile --version which compact # WSL Terminal -weight: 500;">curl --proto '=https' --tlsv1.2 -LsSf https://github.com/midnightntwrk/compact/releases/latest/download/compact-installer.sh | sh # Reload shell configuration source ~/.bashrc # Verify installation compact --version compact compile --version which compact # WSL Terminal -weight: 500;">curl --proto '=https' --tlsv1.2 -LsSf https://github.com/midnightntwrk/compact/releases/latest/download/compact-installer.sh | sh # Reload shell configuration source ~/.bashrc # Verify installation compact --version compact compile --version which compact # WSL Terminal echo 'export PATH="$HOME/.compact/bin:$PATH"' >> ~/.bashrc source ~/.bashrc # WSL Terminal echo 'export PATH="$HOME/.compact/bin:$PATH"' >> ~/.bashrc source ~/.bashrc # WSL Terminal echo 'export PATH="$HOME/.compact/bin:$PATH"' >> ~/.bashrc source ~/.bashrc # WSL Terminal -weight: 500;">npm -weight: 500;">install -g @midnight/mcp # WSL Terminal -weight: 500;">npm -weight: 500;">install -g @midnight/mcp # WSL Terminal -weight: 500;">npm -weight: 500;">install -g @midnight/mcp # WSL Terminal mkdir -p ~/midnight-project cd ~/midnight-project mkdir -p -weight: 500;">docker # WSL Terminal mkdir -p ~/midnight-project cd ~/midnight-project mkdir -p -weight: 500;">docker # WSL Terminal mkdir -p ~/midnight-project cd ~/midnight-project mkdir -p -weight: 500;">docker version: '3.8' services: proof-server: image: ghcr.io/midnightntwrk/proof-server:latest container_name: midnight-proof-server ports: - "8080:8080" environment: - PROOF_SERVER_PORT=8080 - RUST_LOG=info mem_limit: 4g mem_reservation: 2g shm_size: 2g volumes: - proof-data:/data networks: - midnight-network healthcheck: test: ["CMD", "-weight: 500;">curl", "-f", "http://localhost:8080/health"] interval: 30s timeout: 10s retries: 3 indexer: image: ghcr.io/midnightntwrk/indexer:latest container_name: midnight-indexer ports: - "3000:3000" depends_on: - proof-server environment: - PROOF_SERVER_URL=http://proof-server:8080 - NETWORK=devnet networks: - midnight-network volumes: proof-data: networks: midnight-network: driver: bridge version: '3.8' services: proof-server: image: ghcr.io/midnightntwrk/proof-server:latest container_name: midnight-proof-server ports: - "8080:8080" environment: - PROOF_SERVER_PORT=8080 - RUST_LOG=info mem_limit: 4g mem_reservation: 2g shm_size: 2g volumes: - proof-data:/data networks: - midnight-network healthcheck: test: ["CMD", "-weight: 500;">curl", "-f", "http://localhost:8080/health"] interval: 30s timeout: 10s retries: 3 indexer: image: ghcr.io/midnightntwrk/indexer:latest container_name: midnight-indexer ports: - "3000:3000" depends_on: - proof-server environment: - PROOF_SERVER_URL=http://proof-server:8080 - NETWORK=devnet networks: - midnight-network volumes: proof-data: networks: midnight-network: driver: bridge version: '3.8' services: proof-server: image: ghcr.io/midnightntwrk/proof-server:latest container_name: midnight-proof-server ports: - "8080:8080" environment: - PROOF_SERVER_PORT=8080 - RUST_LOG=info mem_limit: 4g mem_reservation: 2g shm_size: 2g volumes: - proof-data:/data networks: - midnight-network healthcheck: test: ["CMD", "-weight: 500;">curl", "-f", "http://localhost:8080/health"] interval: 30s timeout: 10s retries: 3 indexer: image: ghcr.io/midnightntwrk/indexer:latest container_name: midnight-indexer ports: - "3000:3000" depends_on: - proof-server environment: - PROOF_SERVER_URL=http://proof-server:8080 - NETWORK=devnet networks: - midnight-network volumes: proof-data: networks: midnight-network: driver: bridge # WSL Terminal cd ~/midnight-project/-weight: 500;">docker -weight: 500;">docker-compose up -d # Check services are running -weight: 500;">docker-compose ps -weight: 500;">docker-compose logs -f proof-server # WSL Terminal cd ~/midnight-project/-weight: 500;">docker -weight: 500;">docker-compose up -d # Check services are running -weight: 500;">docker-compose ps -weight: 500;">docker-compose logs -f proof-server # WSL Terminal cd ~/midnight-project/-weight: 500;">docker -weight: 500;">docker-compose up -d # Check services are running -weight: 500;">docker-compose ps -weight: 500;">docker-compose logs -f proof-server # WSL Terminal cd ~/midnight-project compact new hello-midnight cd hello-midnight ls -la # WSL Terminal cd ~/midnight-project compact new hello-midnight cd hello-midnight ls -la # WSL Terminal cd ~/midnight-project compact new hello-midnight cd hello-midnight ls -la // A simple counter contract for Midnight // Demonstrates basic state management and increment operations contract hello_midnight { // Store a counter value pub counter: u32; // Constructor - initialize counter to 0 pub fn new() -> Self { Self { counter: 0, } } // Increment the counter pub fn increment(self, mut ctx: Context) -> u32 { self.counter = self.counter + 1; return self.counter; } // Get current counter value pub fn get_counter(self, ctx: Context) -> u32 { return self.counter; } } // A simple counter contract for Midnight // Demonstrates basic state management and increment operations contract hello_midnight { // Store a counter value pub counter: u32; // Constructor - initialize counter to 0 pub fn new() -> Self { Self { counter: 0, } } // Increment the counter pub fn increment(self, mut ctx: Context) -> u32 { self.counter = self.counter + 1; return self.counter; } // Get current counter value pub fn get_counter(self, ctx: Context) -> u32 { return self.counter; } } // A simple counter contract for Midnight // Demonstrates basic state management and increment operations contract hello_midnight { // Store a counter value pub counter: u32; // Constructor - initialize counter to 0 pub fn new() -> Self { Self { counter: 0, } } // Increment the counter pub fn increment(self, mut ctx: Context) -> u32 { self.counter = self.counter + 1; return self.counter; } // Get current counter value pub fn get_counter(self, ctx: Context) -> u32 { return self.counter; } } # WSL Terminal cd ~/midnight-project/hello-midnight compact compile contract.compact # WSL Terminal cd ~/midnight-project/hello-midnight compact compile contract.compact # WSL Terminal cd ~/midnight-project/hello-midnight compact compile contract.compact ✓ Compiled successfully Output: build/contract.json ✓ Compiled successfully Output: build/contract.json ✓ Compiled successfully Output: build/contract.json # WSL Terminal # Ensure proof server is running -weight: 500;">curl http://localhost:8080/health # Deploy using the CLI (requires Lace wallet installed) compact deploy --network devnet --proof-server http://localhost:8080 # WSL Terminal # Ensure proof server is running -weight: 500;">curl http://localhost:8080/health # Deploy using the CLI (requires Lace wallet installed) compact deploy --network devnet --proof-server http://localhost:8080 # WSL Terminal # Ensure proof server is running -weight: 500;">curl http://localhost:8080/health # Deploy using the CLI (requires Lace wallet installed) compact deploy --network devnet --proof-server http://localhost:8080 # Windows PowerShell (Administrator) # Check current WSL memory allocation wsl -e cat /proc/meminfo # If you see less than 4GB available, -weight: 500;">update .wslconfig notepad $env:USERPROFILE\.wslconfig # Ensure these settings: [wsl2] memory=6GB swap=4GB # Windows PowerShell (Administrator) # Check current WSL memory allocation wsl -e cat /proc/meminfo # If you see less than 4GB available, -weight: 500;">update .wslconfig notepad $env:USERPROFILE\.wslconfig # Ensure these settings: [wsl2] memory=6GB swap=4GB # Windows PowerShell (Administrator) # Check current WSL memory allocation wsl -e cat /proc/meminfo # If you see less than 4GB available, -weight: 500;">update .wslconfig notepad $env:USERPROFILE\.wslconfig # Ensure these settings: [wsl2] memory=6GB swap=4GB # WSL Terminal # Check if Docker is running -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">status -weight: 500;">docker # Start Docker if needed -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">start -weight: 500;">docker # Add user to -weight: 500;">docker group -weight: 600;">sudo usermod -aG -weight: 500;">docker $USER # Log out and back in, or run: newgrp -weight: 500;">docker # Alternative: Use Docker without systemd -weight: 600;">sudo -weight: 500;">service -weight: 500;">docker -weight: 500;">start # WSL Terminal # Check if Docker is running -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">status -weight: 500;">docker # Start Docker if needed -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">start -weight: 500;">docker # Add user to -weight: 500;">docker group -weight: 600;">sudo usermod -aG -weight: 500;">docker $USER # Log out and back in, or run: newgrp -weight: 500;">docker # Alternative: Use Docker without systemd -weight: 600;">sudo -weight: 500;">service -weight: 500;">docker -weight: 500;">start # WSL Terminal # Check if Docker is running -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">status -weight: 500;">docker # Start Docker if needed -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">start -weight: 500;">docker # Add user to -weight: 500;">docker group -weight: 600;">sudo usermod -aG -weight: 500;">docker $USER # Log out and back in, or run: newgrp -weight: 500;">docker # Alternative: Use Docker without systemd -weight: 600;">sudo -weight: 500;">service -weight: 500;">docker -weight: 500;">start # WSL Terminal # Check if it's installed ls -la ~/.compact/bin/ # Add to PATH manually export PATH="$HOME/.compact/bin:$PATH" echo 'export PATH="$HOME/.compact/bin:$PATH"' >> ~/.bashrc # Reload source ~/.bashrc # Verify with full path ~/.compact/bin/compact --version # WSL Terminal # Check if it's installed ls -la ~/.compact/bin/ # Add to PATH manually export PATH="$HOME/.compact/bin:$PATH" echo 'export PATH="$HOME/.compact/bin:$PATH"' >> ~/.bashrc # Reload source ~/.bashrc # Verify with full path ~/.compact/bin/compact --version # WSL Terminal # Check if it's installed ls -la ~/.compact/bin/ # Add to PATH manually export PATH="$HOME/.compact/bin:$PATH" echo 'export PATH="$HOME/.compact/bin:$PATH"' >> ~/.bashrc # Reload source ~/.bashrc # Verify with full path ~/.compact/bin/compact --version # Check Docker network -weight: 500;">docker network ls -weight: 500;">docker network inspect midnight-network # Restart services cd ~/midnight-project/-weight: 500;">docker -weight: 500;">docker-compose down -weight: 500;">docker-compose up -d # Check logs -weight: 500;">docker-compose logs --tail=50 # Check Docker network -weight: 500;">docker network ls -weight: 500;">docker network inspect midnight-network # Restart services cd ~/midnight-project/-weight: 500;">docker -weight: 500;">docker-compose down -weight: 500;">docker-compose up -d # Check logs -weight: 500;">docker-compose logs --tail=50 # Check Docker network -weight: 500;">docker network ls -weight: 500;">docker network inspect midnight-network # Restart services cd ~/midnight-project/-weight: 500;">docker -weight: 500;">docker-compose down -weight: 500;">docker-compose up -d # Check logs -weight: 500;">docker-compose logs --tail=50 # WSL Terminal # Clean Docker -weight: 500;">docker system prune -a # Clean WSL wsl --shutdown # Then run Disk Cleanup on Windows and select "Clean up system files" > "Windows Update Cleanup" # WSL Terminal # Clean Docker -weight: 500;">docker system prune -a # Clean WSL wsl --shutdown # Then run Disk Cleanup on Windows and select "Clean up system files" > "Windows Update Cleanup" # WSL Terminal # Clean Docker -weight: 500;">docker system prune -a # Clean WSL wsl --shutdown # Then run Disk Cleanup on Windows and select "Clean up system files" > "Windows Update Cleanup" # Recommended VSCode extensions for Midnight development: # - Remote - WSL # - Compact # - Docker # - GitLens # Recommended VSCode extensions for Midnight development: # - Remote - WSL # - Compact # - Docker # - GitLens # Recommended VSCode extensions for Midnight development: # - Remote - WSL # - Compact # - Docker # - GitLens # Start development wsl # Enter WSL cd ~/midnight-project/-weight: 500;">docker && -weight: 500;">docker-compose up -d # Compile contract cd ~/midnight-project/hello-midnight compact compile contract.compact # Deploy (requires Lace wallet) compact deploy --network devnet # Check proof server -weight: 500;">curl http://localhost:8080/health # Stop development -weight: 500;">docker-compose down exit # Exit WSL # Start development wsl # Enter WSL cd ~/midnight-project/-weight: 500;">docker && -weight: 500;">docker-compose up -d # Compile contract cd ~/midnight-project/hello-midnight compact compile contract.compact # Deploy (requires Lace wallet) compact deploy --network devnet # Check proof server -weight: 500;">curl http://localhost:8080/health # Stop development -weight: 500;">docker-compose down exit # Exit WSL # Start development wsl # Enter WSL cd ~/midnight-project/-weight: 500;">docker && -weight: 500;">docker-compose up -d # Compile contract cd ~/midnight-project/hello-midnight compact compile contract.compact # Deploy (requires Lace wallet) compact deploy --network devnet # Check proof server -weight: 500;">curl http://localhost:8080/health # Stop development -weight: 500;">docker-compose down exit # Exit WSL - Windows 10 (version 2004+) or Windows 11 - At least 8GB RAM (16GB recommended) - 20GB free disk space - Administrator access on your Windows machine - Download Docker Desktop from -weight: 500;">docker.com - During installation, check "Use WSL2 instead of Hyper-V" - Start Docker Desktop - Go to Settings → Resources → WSL Integration - Enable integration with your Ubuntu distribution - The Compact compiler does not work in Windows PowerShell or CMD - All compilation must happen inside WSL2 - Even with WSLg (WSL GUI), some tools may behave unexpectedly - Do not -weight: 500;">install Node.js directly on Windows - Use Node.js only inside WSL2 - Windows -weight: 500;">npm packages may have binary dependencies that won't work - Docker Desktop without WSL2 backend is not supported - Ensure Docker is using WSL2 backend (check Docker Desktop settings) - When using VSCode with Remote-WSL extension, ensure your terminal is actually in WSL - Always verify with uname -a showing "Linux" - Verify .wslconfig has sufficient memory allocation (minimum 4GB, recommended 6GB) - Restart WSL: wsl --shutdown in PowerShell - Restart Docker Desktop - Check container memory: -weight: 500;">docker stats - Never mix Windows and WSL paths - Always use /home/username/ not C:\Users\... paths inside WSL - VSCode Remote-WSL will handle path translation automatically - If VSCode opens files in Windows temp directory, use code . from WSL terminal - Use VSCode Remote-WSL - Best development experience - Enable WSL2 localhost forwarding - Reduces network latency - Store projects in WSL - Not on Windows filesystem - Use SSD for WSL - If possible, store WSL on SSD - Always use WSL2 - Never try to run Midnight tools directly on Windows - Configure .wslconfig - Allocate sufficient memory (6GB recommended) - Use Docker with WSL2 backend - Not Hyper-V or native Windows - Keep all development inside WSL - Including Node.js, -weight: 500;">npm, and Compact - Use VSCode Remote-WSL - For the best development experience - Explore the Midnight Documentation - Join the Midnight Discord - Try the Hello World Tutorial - Build your first privacy-preserving DApp!