Windows-Specific Gemini CLI
This appendix is a desk reference for Windows developers. It covers setup quirks, path syntax, environment variable management, WSL2 interop, Docker Desktop configuration, and a troubleshooting table for the 15 most common Windows-specific issues. No quiz, no progress bar — just the facts, organized for quick lookup.
Installation Options #
Three package managers can install Node.js (the Gemini CLI runtime) on Windows. Choose based on what you already use.
winget
Built into Windows 10/11. No separate install needed.
winget install OpenJS.NodeJS.LTS
Chocolatey
Established Windows package manager. Requires choco installed first.
choco install nodejs-lts
Scoop
User-scoped installs, no admin required. Good for dev machines.
scoop install nodejs-lts
After installing Node.js, install Gemini CLI globally:
# Install Gemini CLI globally
npm install -g @google/gemini-cli
# Verify installation
gemini --version
# If "gemini" is not recognized after install, reload PATH:
$env:PATH = [System.Environment]::GetEnvironmentVariable("PATH", "Machine") + ";" +
[System.Environment]::GetEnvironmentVariable("PATH", "User")
PowerShell Execution Policy Fix
# Check current policy
Get-ExecutionPolicy -List
# Fix: allow scripts from the internet that are signed, and local scripts
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force
# Verify
Get-ExecutionPolicy -Scope CurrentUser
# Output: RemoteSigned
Gemini CLI requires Node.js 18.0.0 or later. Run node --version to check. If you have an older version, use nvm-windows (winget install CoreyButler.NVMforWindows) to install and switch Node versions without affecting other tools.
WSL2 as an Alternative
# Enable WSL2
wsl --install
# After reboot, install Ubuntu 22.04
wsl --install -d Ubuntu-22.04
# Inside WSL2 (Ubuntu), install Node.js and Gemini CLI:
# curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
# sudo apt-get install -y nodejs
# npm install -g @google/gemini-cli
WSL2 gives you a full Linux environment. Gemini CLI behaves identically to macOS/Linux in WSL2, making Bash examples in this course work without adaptation.
@ Path Syntax #
Gemini CLI's @ file references work with both Windows and Unix paths, but there are nuances.
# Relative path (preferred — works everywhere)
gemini -p "@./src/auth.ts review this"
# Absolute path with forward slashes (works in most contexts)
gemini -p "@C:/Users/vara/project/src/auth.ts review"
# Absolute path with quotes (required for paths with spaces)
gemini -p "@`"C:\Users\vara\my project\auth.ts`" review"
# Use $PWD for absolute paths portably
gemini -p "@$PWD/src/auth.ts review this file"
# Loop: pass each file as an @ reference
Get-ChildItem src/ -Filter "*.ts" | ForEach-Object {
gemini -p "@$($_.FullName) add JSDoc" --yolo --no-interactive
}
If your path contains spaces (e.g., C:\My Projects\app.ts), always wrap it in double quotes inside the @ reference. In PowerShell, escape the quotes with backtick: @`"C:\My Projects\app.ts`".
Relative vs Absolute
Prefer relative paths (@./file.ts) in all prompts you share with teammates or check into GEMINI.md. Absolute paths include your username and machine structure, making them non-portable.
Environment Variables #
Three Ways to Set GEMINI_API_KEY
1. Session only (PowerShell) — lost when terminal closes:
$env:GEMINI_API_KEY = "your-key-here"
2. Persistent user-level — survives reboots, visible to your user only:
[System.Environment]::SetEnvironmentVariable(
"GEMINI_API_KEY",
"your-key-here",
"User"
)
# Open a new terminal to pick up the change
3. System-level — visible to all users including scheduled tasks (requires admin):
[System.Environment]::SetEnvironmentVariable(
"GEMINI_API_KEY",
"your-key-here",
"Machine"
)
# Restart Task Scheduler service to pick up Machine-scope changes:
Restart-Service "Schedule"
.env File Loading
# Load .env into current session
Get-Content .env | Where-Object { $_ -notmatch "^#" -and $_ -match "=" } | ForEach-Object {
$parts = $_ -split "=", 2
[System.Environment]::SetEnvironmentVariable($parts[0].Trim(), $parts[1].Trim(), "Process")
}
Add .env to your .gitignore immediately. Gemini CLI reads the key from environment variables — never hardcode it in GEMINI.md or any committed file.
WSL2 Interoperability #
You can run Gemini CLI from WSL2 and access files on your Windows filesystem using the /mnt/c/ mount point.
# Your Windows C: drive is mounted at /mnt/c
cd /mnt/c/Users/vara/myproject
# Run Gemini CLI on a Windows-hosted file
gemini -p "@./src/auth.ts review" --no-interactive
# Access Windows env vars from WSL2
# (they're not automatically inherited)
export GEMINI_API_KEY=$(cmd.exe /c "echo %GEMINI_API_KEY%" 2>/dev/null | tr -d '\r')
Windows Terminal UNC Paths
For Windows paths from within WSL2, use the /mnt/ prefix. UNC paths (\\server\share) are accessible at /mnt/\\server\share but performance is poor — copy files to WSL2 filesystem first for heavy processing.
Gemini CLI runs significantly faster on WSL2 when files are in the WSL2 filesystem (~/projects/) rather than accessed via /mnt/c/. Use cp -r /mnt/c/Users/vara/project ~/project for intensive sessions, then copy changes back.
Docker Desktop for Sandbox #
Recommended Settings
For gemini --sandbox to work reliably on Windows:
- Backend: Settings → General → "Use the WSL 2 based engine" (faster than Hyper-V)
- WSL Integration: Settings → Resources → WSL Integration → enable your distro
- File Sharing: Settings → Resources → File Sharing → add your project drive (
C:\) - Memory: Settings → Resources → Memory → minimum 4GB recommended for sandbox workloads
Hyper-V vs WSL2 Backend
| Feature | WSL2 | Hyper-V |
|---|---|---|
| Startup speed | Fast (~2s) | Slower (~5-10s) |
| CPU overhead | Low | Moderate |
| File I/O (on Linux FS) | Native speed | Slower |
| Windows Home support | Yes | No |
By default, WSL2 can use up to 80% of your RAM. If Docker Desktop feels sluggish, cap WSL2 memory in %USERPROFILE%\.wslconfig:[wsl2]memory=4GBprocessors=4
Troubleshooting Reference #
15 common Windows-specific issues, their causes, and fixes.
| Error | Cause | Fix |
|---|---|---|
| 'gemini' is not recognized | npm global bin not in PATH | Run npm config get prefix, add that path + \bin to your User PATH. Restart terminal. |
| PSSecurityException: script is not digitally signed | Execution policy blocking script | Set-ExecutionPolicy RemoteSigned -Scope CurrentUser |
| GEMINI_API_KEY is not set | Key set in wrong scope or terminal not restarted | Set as User-level env var via System Properties → Advanced. Open a new terminal. |
| ENOENT: no such file — long path | Windows MAX_PATH (260 char) limit hit | Enable long paths: reg add "HKLM\SYSTEM\CurrentControlSet\Control\FileSystem" /v LongPathsEnabled /t REG_DWORD /d 1 /f then reboot. |
| CRLF in generated files causes lint errors | Git or editors inserting Windows line endings | Add .gitattributes: * text=auto eol=lf. Or configure: git config --global core.autocrlf input |
| --sandbox: Docker not found | Docker Desktop not installed or not running | Install Docker Desktop. Start it. Wait for "Docker Desktop is running" tray icon before using --sandbox. |
| Docker: WSL2 backend not available | WSL2 not installed or Hyper-V not enabled | wsl --install from an admin PowerShell, reboot. Or switch Docker to Hyper-V backend if on Windows Pro/Enterprise. |
| Access is denied (file read) | Antivirus scanning or file locked by another process | Add your project directory to antivirus exclusions. Check for other processes locking the file with handle.exe from Sysinternals. |
| Corporate proxy blocks API calls | HTTPS proxy required in corporate network | Set $env:HTTPS_PROXY = "http://proxy:8080" and $env:NODE_EXTRA_CA_CERTS = "C:\certs\corp-root.pem" |
| Git hook not executing on Windows | Hook file has no execute permission or wrong interpreter | Hook files must start with #!/usr/bin/env bash (for Git Bash) or invoke pwsh.exe via a shell wrapper. No file extension on the hook file name. |
| Scheduled task runs but GEMINI_API_KEY is empty | Key set as User env var; task runs as SYSTEM | Set the key as a System environment variable (Machine scope) via [System.Environment]::SetEnvironmentVariable(..., "Machine"). |
| @path reference fails with "file not found" | Path uses backslashes that Gemini CLI doesn't interpret | Use forward slashes: @./src/file.ts or @C:/Users/vara/project/file.ts |
| node: 'ERR_MODULE_NOT_FOUND' | Global npm install corrupted or multiple Node versions | Uninstall and reinstall: npm uninstall -g @google/gemini-cli then npm install -g @google/gemini-cli. If using nvm-windows, ensure the active version matches the one used for install. |
| FileSystemWatcher stops firing after ~2 hours | Windows power management suspending background processes | Set the PowerShell process to prevent sleep: add [System.Threading.Thread]::CurrentThread.IsBackground = $false at the top of the watcher script. |
| WSL2: "/mnt/c" I/O very slow | Cross-filesystem overhead between Windows and WSL2 | Copy the project to the WSL2 native filesystem (~/), work there, then sync back. Or use \\wsl$\Ubuntu\home\user\project from Windows Explorer to access WSL2 files from Windows. |
PowerShell Profile — Aliases & Helpers #
Add these to your PowerShell $PROFILE (notepad $PROFILE to open it) for a smoother Gemini CLI experience in every session.
# ── Gemini CLI Aliases ──────────────────────────────────────────────────
# Quick non-interactive prompt
function gask { param([string]$Prompt) gemini -p $Prompt --no-interactive }
# Review a file for issues
function greview { param([string]$File) gemini -p "@$File Review this file for bugs, security issues, and improvements" --no-interactive }
# Generate tests for a file
function gtest { param([string]$File) gemini -p "@$File Generate comprehensive tests for this file" --yolo --no-interactive }
# Explain a file
function gexplain { param([string]$File) gemini -p "@$File Explain what this code does in plain English. Use bullet points." --no-interactive }
# Quick commit message from staged diff
function gcommit {
$diff = git diff --cached
if (-not $diff) { Write-Warning "Nothing staged"; return }
$msg = $diff | gemini -p "Write a conventional commit message for this diff. Output only the message." --no-interactive
Write-Host "Suggested: $msg" -ForegroundColor Cyan
$confirm = Read-Host "Use this message? (y/n/edit)"
if ($confirm -eq "y") { git commit -m $msg }
elseif ($confirm -eq "edit") { git commit }
}
# Load project .env into session
function loadenv {
if (-not (Test-Path .env)) { Write-Warning "No .env file found"; return }
Get-Content .env | Where-Object { $_ -notmatch "^#" -and $_ -match "=" } | ForEach-Object {
$parts = $_ -split "=", 2
[System.Environment]::SetEnvironmentVariable($parts[0].Trim(), $parts[1].Trim(), "Process")
}
Write-Host ".env loaded into session" -ForegroundColor Green
}
# ── Auto-complete for gemini (tab completion) ──
Register-ArgumentCompleter -Native -CommandName gemini -ScriptBlock {
param($wordToComplete, $commandAst, $cursorPosition)
@('--no-interactive','--yolo','--sandbox','--quiet','-p','--model',
'--temperature','--version','extensions','--help') |
Where-Object { $_ -like "$wordToComplete*" } |
ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }
}
| Command | Usage | Description |
|---|---|---|
gask "question" | gask "What is a JWT?" | Quick non-interactive question |
greview file.ts | greview src/auth.ts | Review a file for issues |
gtest file.ts | gtest src/users.ts | Auto-generate tests for a file |
gexplain file.py | gexplain main.py | Plain-English file explanation |
gcommit | gcommit | AI-generated commit message from staged diff |
loadenv | loadenv | Load .env into current session |
Windows Terminal Setup #
Windows Terminal with custom settings makes Gemini CLI sessions faster to navigate and easier to read.
{
"profiles": {
"list": [
{
"name": "Gemini CLI",
"guid": "{your-guid-here}",
"commandline": "pwsh.exe -NoLogo",
"startingDirectory": "%USERPROFILE%\\projects",
"font": {
"face": "Cascadia Code",
"size": 12
},
"colorScheme": "One Half Dark",
"tabColor": "#4285F4",
"icon": "ms-appx:///ProfileIcons/{61c54bbd-c2c6-5271-96e7-009a87ff44bf}.png",
"padding": "8, 8",
"scrollbarState": "hidden",
"experimental.retroTerminalEffect": false
},
{
"name": "Gemini CLI (WSL2)",
"source": "Windows.Terminal.Wsl",
"tabColor": "#8B5CF6",
"startingDirectory": "//wsl$/Ubuntu/home/vara/projects"
}
]
},
"keybindings": [
{ "command": "newTab", "keys": "ctrl+t" },
{ "command": { "action": "splitPane", "split": "vertical" }, "keys": "ctrl+shift+d" },
{ "command": { "action": "splitPane", "split": "horizontal" }, "keys": "ctrl+shift+minus" }
]
}
Recommended Pane Layout for Coding Sessions
- Left pane (wide): Gemini CLI interactive session — main coding pane
- Top-right pane: File explorer or
git status— context pane - Bottom-right pane: Test runner watching (
vitest --watch/pytest-watch)
Cascadia Code (Microsoft's coding font, free) renders Gemini CLI's box-drawing characters and Unicode correctly. Install it via winget install Microsoft.CascadiaCode. Set it in both your Windows Terminal profile and your VS Code integrated terminal ("terminal.integrated.fontFamily": "Cascadia Code") for a consistent experience.