For anything you ship, use manifest mode. It declares dependencies in a vcpkg.json file in your repository and is required for version constraints, baselines and overrides. Classic mode installs packages into one shared tree with one version of each port, which makes builds depend on whatever is installed on the machine.
The difference in one table
| Question | Manifest mode | Classic mode |
|---|---|---|
| Where are dependencies declared? | vcpkg.json in the project | Install commands, in your head or a script |
| Version pinning | Baselines, constraints and overrides | Not available |
| Install location | vcpkg_installed next to the manifest | One global installed folder |
| Versions per library | Separate per project | One per port |
Microsoft's documentation recommends manifest mode for most users and states that versioning and custom registries require it. It also says per-manifest install trees separate dependencies between projects and avoid classic mode's limit of one version of each port.
Why this matters for security
Three practical effects:
- Reviewability. A change to vcpkg.json is a commit. You can see who raised or lowered a version and when.
- Reproducibility. Two developers and CI use the same baseline, so they link the same library versions.
- Isolation. A security fix for project A does not accidentally change project B, and project B cannot be blocked from a fix by project A.
Classic mode has none of these. Two machines can have different libraries with no record in the repository, and the global tree changes whenever someone installs something.
There is one more catch. A manifest without a baseline behaves as classic mode with respect to versions. The versioning reference says that without a builtin-baseline, and with no registries configured, the install follows the classic algorithm and ignores versioning information. So being in manifest mode is not enough: add the baseline.
A concrete scenario
Suppose a compression library gets a fix. In manifest mode, you raise the constraint in vcpkg.json, open a pull request, and CI builds against the new version in a clean vcpkg_installed folder. Reviewers see the change, and the merge is your evidence. In classic mode, somebody runs an upgrade on a build machine, nobody records which machine, and a developer laptop keeps the old copy until it is refreshed. The fix exists, but you cannot show where it landed.
Moving a project over
- Create vcpkg.json with the names you currently install.
- Add an initial baseline using the add-initial-baseline option of the update-baseline command.
- Build clean and compare library versions with your old install.
- Remove the global install from CI images so nothing falls back to it.
- Commit and document how to update the baseline.
Try it yourself
Open the demo and compare an inventory to what you would see from a manifest. A declared file is the easiest starting point for a complete list.
Click through it at your own pace, or open it full screen.
Quick check
Is classic mode wrong for experiments?
It is fine for quick trials. Do not ship a product from it.
Does manifest mode pin versions automatically?
Only with a builtin-baseline. Without one, versioning is ignored.
Safeguard's SBOM and dependency scanning can build an inventory of the components in a repository, and the free scan at gold.safeguard.sh/scan is a quick way to see what turns up.
Sources
Last reviewed: 19 October 2026.