skip to content

Chocolatey — Windows Package Manager

Install, upgrade, pin, and script software installs on Windows with the choco CLI, packages.config files, and custom sources.

15 min read 66 snippets deep dive

Chocolatey — Windows Package Manager#

What it is#

Chocolatey (choco) is a community-driven Windows package manager built on NuGet and PowerShell, maintained by Chocolatey Software, Inc. and the community via the chocolatey/choco repository. It wraps almost every Windows installer — MSI, EXE, ZIP, MSIX, even silent PowerShell scripts — so a single choco install produces the same result on a developer laptop, a CI runner, and a freshly provisioned VM. Reach for choco when you need broader coverage and packaging hooks than winget (a Chocolatey package is just a .nupkg you can self-host), or when you need a managed package for software that isn’t on the Microsoft community repo; the main alternatives are winget (first-party, narrower but bundled) and scoop (user-scope, dev-tools-focused, no admin).

What’s new in 2026#

Chocolatey is on a v2.x / v1.x dual track — v2 is the modern .NET-based line, v1.4.x is the legacy support branch for older Windows. As of May 2026 the current versions are:

TrackLatestReleasedNotes
Stable (v2.x)2.7.22026-05-12log4net 3.3.1, 7-Zip 26.01 bundled
Support (v1.4.x)1.4.62026-05-127-Zip 26.01 bundled — patch-only branch

Highlights from the v2.7 series:

  • choco list accepts --ignore-pinned to skip pinned packages — handy when scripting bulk upgrades.
  • New choco license and choco support commands expose licensed-extension state and produce a support bundle.
  • choco info now displays the install path and the source location that was used when the package was installed.
  • Hash calculation is now reliable for packages >2 GB.
  • A new --ignore-http-cache flag forces a network round-trip and bypasses the local HTTP request cache (useful when a CDN serves stale package metadata).
  • Authenticating sources now accept passwords with non-ASCII characters (a long-standing pain point in Asian and European locales).
  • The Chocolatey GUI also got a major bump to v3.1.0 (May 2026); the licensed extension is at v8.1.0.

Upgrade:

# Run as Administrator
choco upgrade chocolatey -y

Install#

Chocolatey installs itself with a one-shot bootstrap script that must be run in an elevated PowerShell session. The installer writes to C:\ProgramData\chocolatey\ and adds that directory to $env:Path for all users.

# Run as Administrator
Set-ExecutionPolicy Bypass -Scope Process -Force
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))

Output:

Downloading https://community.chocolatey.org/api/v2/package/chocolatey
Getting Chocolatey from https://community.chocolatey.org/...
Extracting C:\Users\Alice\AppData\Local\Temp\chocolatey\chocInstall\chocolatey.zip to C:\Users\Alice\AppData\Local\Temp\chocolatey\chocInstall...
Installing Chocolatey on the local machine
Creating ChocolateyInstall as an environment variable
Restricting write permissions to Administrators
We are setting up the Chocolatey package repository.
Chocolatey (choco.exe) is now ready.
You can call choco from anywhere, command line or powershell by typing choco.
Run choco /? for a list of functions.

Verify the install:

choco --version

Output:

2.3.0

Syntax#

choco follows a verb noun args pattern with consistent flags across commands. -y (or --yes) auto-accepts every prompt, which is essential for scripted installs; without it, Chocolatey asks before running any PowerShell script bundled with a package.

choco <command> [<arg>...] [--<option>=<value>] [-y]

Output: (none — exits 0 on success)

Essential commands#

These are the verbs you’ll use 95% of the time. The full list is choco -?; every command has its own -? help.

CommandMeaning
choco install <pkg>Install one or more packages
choco upgrade <pkg> / upgrade allUpdate packages to latest
choco uninstall <pkg>Remove a package
choco listList installed packages on this machine
choco search <term>Search the configured sources
choco info <pkg>Show full metadata for a package
choco pin add --name <pkg>Prevent a package from being upgraded
choco source list / add / removeManage repositories
choco config list / setManage global config (cache dir, timeout)
choco apikeySet API keys for private feeds
choco pack <nuspec>Build a .nupkg from a nuspec
choco push <nupkg>Upload to a feed
choco outdatedList packages with available updates
choco featureToggle Chocolatey features (autoUninstaller, etc.)

Install#

choco install resolves a package from the configured sources (Chocolatey Community by default), downloads the bundled installer or script, and runs it silently. Add -y for unattended runs and --no-progress in CI to suppress the progress bar that pollutes logs.

choco install git -y

Output:

Chocolatey v2.3.0
Installing the following packages:
git
By installing, you accept licenses for the packages.

Progress: Downloading git.install 2.44.0... 100%
Progress: Downloading git 2.44.0... 100%

git.install v2.44.0 [Approved]
git.install package files install completed. Performing other installation steps.
The package git.install wants to run 'chocolateyInstall.ps1'.
Note: If you don't run this script, the installation will fail.
Installing 64-bit git...
git has been installed.
 The install of git.install was successful.
  Software installed to 'C:\Program Files\Git\'

Chocolatey installed 2/2 packages.
 See the log for details (C:\ProgramData\chocolatey\logs\chocolatey.log).

Install multiple packages at once:

choco install git vscode 7zip nodejs-lts python -y

Output:

Chocolatey installed 5/5 packages.

Pin to a specific version (use --version; quote anything with dots and hyphens):

choco install nodejs-lts --version=20.12.2 -y

Output:

Chocolatey v2.3.0
Installing the following packages:
nodejs-lts
nodejs-lts v20.12.2 [Approved]
The install of nodejs-lts was successful.
Chocolatey installed 1/1 packages.

Package parameters and install arguments#

Some packages accept custom switches at install time — for example, the git package supports an editor choice and credential helper via --params. Anything in --install-arguments is passed verbatim to the underlying MSI/EXE; --params is parsed by the package’s chocolateyInstall.ps1.

# Git with custom params parsed by the package script
choco install git -y --params="/GitOnlyOnPath /NoShellIntegration /NoCredentialManager"

# 7-Zip installed to a custom location via install-arguments passed to the MSI
choco install 7zip -y --install-arguments="INSTALLDIR=D:\Tools\7zip" --override-arguments

# Both at once
choco install vscode -y --params="/NoDesktopIcon /NoQuicklaunchIcon" --install-arguments="/SILENT"

Output:

git v2.44.0 [Approved]
git package files install completed. Performing other installation steps.
Successfully installed git to 'C:\Program Files\Git' with custom params: /GitOnlyOnPath /NoShellIntegration /NoCredentialManager

Upgrade#

choco upgrade updates a single package to the latest version that satisfies version pins. choco upgrade all is the workhorse for keeping a machine in shape — run it on a schedule.

choco upgrade git -y

Output:

Chocolatey v2.3.0
Upgrading the following packages:
git
By upgrading, you accept licenses for the packages.

git v2.44.0 is the latest version available based on your source(s).
Chocolatey upgraded 0/1 packages.

Upgrade everything except pinned packages:

choco upgrade all -y --no-progress

Output:

Chocolatey v2.3.0
Upgrading the following packages:
all

git v2.44.0 is the latest version available based on your source(s).
nodejs-lts v20.12.2 → 20.13.1
7zip v23.01 is the latest version available based on your source(s).
vscode v1.88.1 → 1.89.0

Chocolatey upgraded 2/4 packages.

List packages with available upgrades (without installing):

choco outdated

Output:

Outdated Packages
 Output is package name | current version | available version | pinned?

nodejs-lts|20.12.2|20.13.1|false
vscode|1.88.1|1.89.0|false

Chocolatey has determined 2 package(s) are outdated.

Search and info#

choco search queries every configured source and returns matching package IDs and versions. Add --exact for an ID lookup; without it, Chocolatey returns partial-match results sorted by relevance.

choco search firefox

Output:

Chocolatey v2.3.0
Firefox 125.0.1 [Approved]
Firefox-LANGUAGE 125.0.1 [Approved]
FirefoxESR 115.10.0esr [Approved]
firefox-ja 125.0.1 [Approved]
...
27 packages found.
choco info nodejs-lts

Output:

Chocolatey v2.3.0
nodejs-lts 20.12.2 [Approved]
 Title: Node.js (LTS) | Published: 4/15/2026
 Package approved as a trusted package on 4/15/2026.
 Package tested status: Passing on 4/15/2026.
 Number of Downloads: 27,481,920 | Downloads for this version: 142,012
 Package Checksum: '9b1c…'
 Description: Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.
 Tags: node nodejs javascript runtime lts
 Software Site: https://nodejs.org/
 Software License: https://nodejs.org/static/legal/

List installed#

choco list shows only what is installed on the local machine. Add --local-only --include-programs (legacy --lo --ip) to also surface non-Chocolatey installs detected from Add/Remove Programs.

choco list

Output:

Chocolatey v2.3.0
7zip.install 23.01.0
chocolatey 2.3.0
git 2.44.0
git.install 2.44.0
nodejs-lts 20.12.2
python 3.12.3
vscode 1.88.1
vscode.install 1.88.1

8 packages installed.
choco list --include-programs | Select-String -Pattern "^[A-Za-z]" -CaseSensitive | Select-Object -First 12

Output:

7zip.install 23.01.0
git.install 2.44.0
nodejs-lts 20.12.2
python 3.12.3
vscode.install 1.88.1
Programs and features:
Microsoft Edge|125.0.2535.51|Microsoft Corporation
Microsoft Edge Update|1.3.185.31|Microsoft Corporation
Microsoft Edge WebView2 Runtime|125.0.2535.51|Microsoft Corporation
Microsoft Visual Studio Installer|3.10.2154.59760|Microsoft Corporation

Pin#

Pinning prevents choco upgrade all from touching a package — useful when you’ve manually installed a specific version (e.g. a Node.js LTS that matches a project’s .nvmrc).

choco pin add --name="nodejs-lts" --version=20.12.2
choco pin list

Output:

Chocolatey v2.3.0
nodejs-lts|20.12.2

Chocolatey has pinned 1 package.

Remove a pin:

choco pin remove --name="nodejs-lts"

Output:

Chocolatey v2.3.0
Chocolatey has removed pin for nodejs-lts.

Uninstall#

choco uninstall runs the package’s chocolateyUninstall.ps1 (or, if autoUninstaller is enabled, infers the silent uninstall from Add/Remove Programs). -x (--force-dependencies) also removes any unused dependencies.

choco uninstall vscode -y

Output:

Chocolatey v2.3.0
Uninstalling the following packages:
vscode
vscode v1.88.1
 Removed from programs and features
 vscode has been successfully uninstalled.
Chocolatey uninstalled 1/1 packages.

Sources (package feeds)#

A source is a NuGet-compatible URL that hosts .nupkg files. The default chocolatey source is the community feed at https://community.chocolatey.org/api/v2/. Add private feeds for internal-only packages — Azure Artifacts, ProGet, JFrog Artifactory, Sonatype Nexus, or just a folder share.

choco source list

Output:

chocolatey - https://community.chocolatey.org/api/v2/ | Priority 0|Bypass Proxy - False|Self-Service - False|Admin Only - False.
# Add a private feed (with API key)
choco source add --name="myfeed" --source="https://proget.example.com/nuget/chocolatey/" --priority=1 --user="alice" --password="secret"

# Disable / enable a source
choco source disable --name="chocolatey"
choco source enable  --name="chocolatey"

# Remove
choco source remove  --name="myfeed"

Output:

Chocolatey v2.3.0
Added myfeed - https://proget.example.com/nuget/chocolatey/ (Priority 1)

Configuration#

choco config exposes Chocolatey’s global settings — cache directory, web request timeout, proxy server. Tweak these once per machine; values are persisted in C:\ProgramData\chocolatey\config\chocolatey.config.

choco config list

Output:

Settings
 - cacheLocation = 'C:\ProgramData\chocolatey\cache' | The location of the cache used by Chocolatey.
 - commandExecutionTimeoutSeconds = '2700' | Default timeout for command execution.
 - webRequestTimeoutSeconds = '30'
 - proxy = '' | Proxy server URL
 - proxyUser = ''
 - proxyPassword = ''

Features
 - allowGlobalConfirmation = Disabled | Prompt for confirmation in scripts or use --yes.
 - autoUninstaller = Enabled | Uninstall via Add/Remove Programs when no uninstall script.
 - checksumFiles = Enabled
 - usePackageExitCodes = Enabled
# Auto-confirm every install for the current shell (avoids needing -y)
choco feature enable --name="allowGlobalConfirmation"

# Use a corporate proxy
choco config set proxy "http://proxy.example.com:8080"
choco config set proxyUser "alice"
choco config set proxyPassword "secret"

Output:

Chocolatey v2.3.0
Enabled allowGlobalConfirmation
Updated proxy = http://proxy.example.com:8080

Scripted installs with packages.config#

packages.config is a NuGet-style XML manifest listing the exact packages and versions to install. Drop one in a Git repo, commit it next to your provisioning script, and a fresh machine is set up with a single choco install.

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="git"           version="2.44.0" />
  <package id="vscode"        />
  <package id="nodejs-lts"    version="20.12.2" />
  <package id="python"        />
  <package id="7zip"          />
  <package id="microsoft-windows-terminal" />
  <package id="powershell-core" />
  <package id="gh"            />
  <package id="docker-desktop" />
</packages>

Output: (config file only — no shell output)

Install everything in one shot:

choco install packages.config -y

Output:

Chocolatey v2.3.0
Installing the following packages:
git;vscode;nodejs-lts;python;7zip;microsoft-windows-terminal;powershell-core;gh;docker-desktop

Chocolatey installed 9/9 packages.

Local-only and folder feeds#

A “feed” can be just a folder full of .nupkg files. Useful for air-gapped networks: build packages on a machine with internet, copy them to an offline share, and point Chocolatey at the share.

# Add a folder as a source
choco source add --name="offline" --source="\\fileserver\choco-packages"

# Install only from the offline source
choco install git -y --source="offline"

# Install bypassing the community feed entirely
choco install git -y --source="\\fileserver\choco-packages"

Output:

Chocolatey v2.3.0
git v2.44.0 [Approved]
The install of git was successful.
Chocolatey installed 1/1 packages.

Authoring a package#

A Chocolatey package is a NuGet .nupkg containing one .nuspec (metadata) and a tools\chocolateyInstall.ps1 (the actual install logic). Useful when you need to wrap an internal tool, vendored binary, or a script.

choco new mytool

Output:

Chocolatey v2.3.0
Creating new package specification files at .\mytool
Successfully generated mytool package specification files at '.\mytool'.

mytool.nuspec:

<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd">
  <metadata>
    <id>mytool</id>
    <version>1.0.0</version>
    <title>mytool</title>
    <authors>Alice Dev</authors>
    <projectUrl>https://example.com/mytool</projectUrl>
    <licenseUrl>https://example.com/license</licenseUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>Internal utility for the Alice team.</description>
    <tags>internal cli</tags>
  </metadata>
  <files>
    <file src="tools\**" target="tools" />
  </files>
</package>

Output: (nuspec file only — no shell output)

tools\chocolateyInstall.ps1:

$ErrorActionPreference = "Stop"
$packageName = "mytool"
$url         = "https://example.com/releases/mytool-1.0.0-x64.zip"
$checksum    = "9B1C0DA63A4B…"
$toolsDir    = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)"

Install-ChocolateyZipPackage `
  -PackageName $packageName `
  -Url         $url `
  -Checksum    $checksum `
  -ChecksumType "sha256" `
  -UnzipLocation $toolsDir

Output: (script file only — runs on choco install)

Build and publish:

choco pack .\mytool.nuspec
choco apikey --key="abcdef123" --source="https://proget.example.com/nuget/chocolatey/"
choco push mytool.1.0.0.nupkg --source="https://proget.example.com/nuget/chocolatey/"

Output:

Successfully created package 'mytool.1.0.0.nupkg'
Attempting to push mytool.1.0.0.nupkg to https://proget.example.com/nuget/chocolatey/
mytool was pushed successfully to https://proget.example.com/nuget/chocolatey/

choco vs winget vs scoop#

A practical rule of thumb for picking a Windows package manager — all three coexist on the same machine without conflict.

Questionwingetchocoscoop
First-party?Yes (Microsoft)No (community)No (community)
Bundled with Windows?Yes (11)NoNo
Admin required?SometimesYes (default)No
Install locationPer-app installers (Program Files)Per-app installers + C:\ProgramData\chocolatey%USERPROFILE%\scoop\ (per-user)
Custom install dirs / paramsLimitedYes (--params, --install-arguments)Limited
Self-host a feedDifficultEasy (any NuGet feed)Easy (a bucket is just a Git repo)
Package countLarger but narrowerLargest (10k+)Smallest, dev-focused
Strongest forConsumer appsEnterprise / scripted setupCLI dev tools

Common pitfalls#

  1. Not running elevatedchoco install needs administrator unless every package has PortablePackage install logic. Open Terminal as Administrator.
  2. Missing -y — without it, every package prompts “Do you want to run the install script?”. Scripts hang forever in CI.
  3. upgrade all upgrades pinned packages — only if you forgot the pin. Always choco pin list before scheduled upgrades.
  4. Community feed rate limiting — anonymous downloads are throttled. Add an API key or self-host the packages you care about.
  5. Two packages for one app — packages often come in pairs (vscode is the meta-package, vscode.install is the real installer). Remove only the meta-package, not both, or you’ll uninstall reinstall the underlying app.
  6. --params not being applied — only certain packages support params; check choco info <pkg> first. If unsupported, the param is silently ignored.
  7. Locked configuration on managed machines — corporate Group Policy often locks C:\ProgramData\chocolatey to admins, breaking the chocolatey-licensed self-update path; use a private feed instead.
  8. Wrong source priority — a private feed at priority 0 with no version of a package will block the community feed at priority 1 from supplying it; lower numbers win.

Real-world recipes#

Self-bootstrapping setup script for a new dev machine#

A single PowerShell script that installs Chocolatey if missing, then installs the team’s standard toolset. Run it once on every new machine.

# bootstrap.ps1 — run elevated
$ErrorActionPreference = "Stop"

if (-not (Get-Command choco -ErrorAction SilentlyContinue)) {
  Set-ExecutionPolicy Bypass -Scope Process -Force
  [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor 3072
  iex ((New-Object Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
}

choco feature enable --name="allowGlobalConfirmation"

@(
  "git"
  "gh"
  "vscode"
  "microsoft-windows-terminal"
  "powershell-core"
  "nodejs-lts"
  "python"
  "docker-desktop"
  "7zip"
  "firefox"
) | ForEach-Object {
  choco install $_ --no-progress
}

choco upgrade all -y --no-progress

Output:

Chocolatey installed 10/10 packages.
Chocolatey upgraded 0/10 packages.

Scheduled task that keeps the machine up to date weekly#

A simple schtasks definition that runs choco upgrade all -y every Sunday at 03:00 and writes a transcript.

$action  = New-ScheduledTaskAction -Execute "pwsh.exe" -Argument '-NoProfile -Command "Start-Transcript -Path C:\logs\choco-update.log -Append; choco upgrade all -y --no-progress; Stop-Transcript"'
$trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Sunday -At 3am
$prin    = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest

Register-ScheduledTask `
  -TaskName "Choco Weekly Upgrade" `
  -Action   $action `
  -Trigger  $trigger `
  -Principal $prin `
  -Description "Runs choco upgrade all weekly"

Output:

TaskPath                                       TaskName                          State
--------                                       --------                          -----
\                                              Choco Weekly Upgrade              Ready

Air-gapped mirror — download once, install on N machines#

Build a portable cache on a machine with internet, sync the cache to a file share, then point all offline machines at it. Each machine installs from \\fileserver\choco-packages and never reaches the internet.

# On the internet-connected machine:
choco install package-internalizer -y       # licensed feature in choco Pro, or use:
choco download git vscode 7zip nodejs-lts python --internalize --output-directory C:\offline-packages

# Copy to the offline share
robocopy C:\offline-packages \\fileserver\choco-packages /MIR

# On every offline machine:
choco source add --name="offline" --source="\\fileserver\choco-packages" --priority=1
choco source disable --name="chocolatey"
choco install git vscode 7zip nodejs-lts python -y --source="offline"

Output:

Chocolatey installed 5/5 packages.

Reproducible setup as code — packages.config checked into Git#

Treat the dev toolset like infrastructure: commit packages.config and bootstrap.ps1 to a Git repo named dotwin. Onboarding a new engineer is git clone + pwsh bootstrap.ps1.

dotwin/
├── bootstrap.ps1
├── packages.config
└── README.md
# bootstrap.ps1 — install Chocolatey, then everything in packages.config
if (-not (Get-Command choco -ErrorAction SilentlyContinue)) {
  iex ((New-Object Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
}
choco install packages.config -y --no-progress

Output:

Chocolatey installed 12/12 packages.

Diagnose a misbehaving package#

-d (debug) and -v (verbose) print every PowerShell line executed and the full HTTP traffic. Combined with the per-run log under C:\ProgramData\chocolatey\logs\, this is enough to triage almost any failure.

choco install some-flaky-package -y -dv 2>&1 | Tee-Object -FilePath C:\Users\Alice\flaky-install.log

# Or just inspect the log of the most recent run
Get-Content C:\ProgramData\chocolatey\logs\chocolatey.log -Tail 200

Output:

[DEBUG] - Running 'Get-PowerShellExitCode' from 'C:\ProgramData\chocolatey\helpers\functions\Get-ExitCode.ps1'
[VERBOSE] Performing the operation "Install" on target "some-flaky-package 1.0.0".
[ERROR] Could not find a part of the path 'C:\ProgramData\chocolatey\lib\some-flaky-package\tools\config.ini'.
Chocolatey installed 0/1 packages. 1 packages failed.

Combine choco with PowerShell Desired State Configuration#

For full-fledged config management, DSC’s cChoco module wraps choco so you can describe the package set declaratively and have DSC enforce it.

Configuration DevMachine {
  Import-DscResource -ModuleName cChoco

  Node "localhost" {
    cChocoInstaller installChoco {
      InstallDir = "C:\ProgramData\chocolatey"
    }

    cChocoPackageInstaller installGit {
      Name      = "git"
      DependsOn = "[cChocoInstaller]installChoco"
    }

    cChocoPackageInstaller installNode {
      Name      = "nodejs-lts"
      Version   = "20.12.2"
      DependsOn = "[cChocoInstaller]installChoco"
    }
  }
}

DevMachine -OutputPath C:\dsc
Start-DscConfiguration -Path C:\dsc -Wait -Verbose

Output:

PSComputerName                  : localhost
Status                          : Success
PSDscRunAsCredential            :
DependsOn                       : {[cChocoInstaller]installChoco}
ConfigurationName               : DevMachine

Sources#