If you run Debian or Ubuntu long enough, you eventually hit the same tension:
- the distro version is stable and boring, which is good
- one package is too old, which is annoying
- a third-party repo solves that problem, which is dangerous
That is exactly where APT pinning helps.
Done well, pinning lets you prefer the packages you trust, pull only the packages you actually want, and avoid surprise upgrades from the wrong repository.
Done badly, it turns package management into archaeology.
This guide stays on the safe side: practical patterns, complete examples, and verification steps you can run before changing anything.
What APT pinning actually does
APT assigns a priority to each available package version. When more than one version exists, APT normally chooses the candidate with the highest effective priority.
A few facts matter immediately:
- installed versions usually have priority 100
- uninstalled versions from normal repositories usually have priority 500
- a target release can get priority 990
- priorities above 1000 can force a downgrade
- priorities below 0 prevent installation
That behavior is documented in apt_preferences(5) and is the reason pinning is powerful enough to help or hurt.
First: inspect your current priorities
Before writing any pin, look at what APT already believes.
apt-cache policy
That shows repository-level priorities.
To inspect a specific package:
apt-cache policy neovim
Example output will look something like this:
neovim:
Installed: 0.7.2-7
Candidate: 0.7.2-7
Version table:
0.9.5-6~bpo12+1 100
100 https://deb.debian.org/debian bookworm-backports/main amd64 Packages
*** 0.7.2-7 500
500 https://deb.debian.org/debian bookworm/main amd64 Packages
100 /var/lib/dpkg/status
That tells you three useful things:
- what is installed
- what APT would install next (
Candidate) - why it chose that version
If you skip this step, you are guessing.
Where pin files live
Use files under:
/etc/apt/preferences.d/
Example naming:
/etc/apt/preferences.d/80-backports-neovim.pref
/etc/apt/preferences.d/90-vendor-limit.pref
Keep them small and descriptive. One purpose per file is easier to reason about and easier to undo.
Pattern 1: prefer one package from backports
This is the safest and most common use case.
You want a newer version of one package, but you do not want your entire system drifting toward backports.
Step 1: confirm the package exists there
apt update
apt-cache policy neovim
Step 2: create a package-specific pin
sudo install -d -m 0755 /etc/apt/preferences.d
sudo tee /etc/apt/preferences.d/80-neovim-backports.pref >/dev/null <<'EOF'
Package: neovim
Pin: release a=bookworm-backports
Pin-Priority: 900
EOF
Step 3: refresh and verify
sudo apt update
apt-cache policy neovim
You should now see the backports version become the candidate.
Step 4: install it
sudo apt install neovim
Why 900?
A priority of 900 says:
- prefer this source strongly
- but do not cross the line into forced downgrade behavior
That is usually what you want for a package-specific preference.
Pattern 2: block automatic upgrades from a third-party repo, but allow one package
This is the pattern I trust most when adding vendor repositories.
Say you add a repo because you need one package. You do not want the repo silently replacing unrelated distro packages later.
Step 1: inspect the repo identity
Run:
apt-cache policy
Look for the repository lines and note values such as:
origin-
o=(Origin from the Release file) -
a=(archive) -
n=(codename) -
l=(label)
Step 2: set a low default priority for that repo
Replace the example values below with what apt-cache policy actually shows on your machine.
sudo tee /etc/apt/preferences.d/90-example-vendor-limit.pref >/dev/null <<'EOF'
Package: *
Pin: origin packages.example.com
Pin-Priority: 1
Package: example-agent
Pin: origin packages.example.com
Pin-Priority: 700
EOF
What this does:
- every package from that repo is effectively deprioritized
- except
example-agent, which is allowed to upgrade normally
After that:
sudo apt update
apt-cache policy example-agent
Also test another package that exists in both the distro repo and the third-party repo. The distro version should still win.
Pattern 3: explicitly prevent a package version or source
Sometimes you do not want a package coming from a specific place at all.
Example:
sudo tee /etc/apt/preferences.d/90-no-unstable-foo.pref >/dev/null <<'EOF'
Package: foo
Pin: release a=unstable
Pin-Priority: -1
EOF
That tells APT not to install foo from unstable.
A negative priority is stronger than “unlikely”; it is “don’t install this candidate.”
Pattern 4: one-time install from another repo without permanent preference
Sometimes you do not need persistent pinning. You just need a one-off install.
Example:
sudo apt install -t bookworm-backports neovim
That can be cleaner than a permanent pin if:
- you are testing
- you only need one install once
- you do not want future upgrades to keep following that repo automatically
This is often the better first move.
apt-mark hold is not the same thing
A lot of guides blur these together. They are different tools.
Use apt-mark hold when you want to freeze a package in place:
sudo apt-mark hold docker-ce
apt-mark showhold
Use pinning when you want APT to prefer or avoid a source/version according to policy.
In practice:
- hold = “do not change this package automatically”
- pinning = “choose candidates according to these repository/version rules”
They can be combined, but they solve different problems.
A safe workflow for creating pins
Here is the workflow I recommend on real machines.
1. Update metadata
sudo apt update
2. Inspect repo and package priorities
apt-cache policy
apt-cache policy neovim
3. Add the smallest possible pin
Prefer package-specific pins over broad repo-wide pins unless you genuinely need repo-wide behavior.
4. Refresh APT metadata
sudo apt update
5. Verify the candidate changed the way you expected
apt-cache policy neovim
6. Simulate before installing
sudo apt -s install neovim
The -s simulation is cheap insurance. It lets you inspect dependency changes before they happen.
Common mistakes that cause pain
1. Pinning too broadly
This is the classic foot-gun:
Package: *
Pin: release a=testing
Pin-Priority: 900
That may be intentional in a lab. On a stable production machine, it is how you slowly stop having a stable production machine.
2. Using 1001 casually
A priority above 1000 can force downgrades. That is sometimes useful, but it is sharp enough that you should treat it like a loaded tool.
If 900 solves the problem, use 900.
3. Not checking apt-cache policy before and after
If you do not verify the candidate package, you have not confirmed that the policy works.
4. Mixing releases without understanding the compatibility risk
Pinning controls selection, but it does not magically make packages from different releases compatible.
Debian’s own documentation is pretty direct here: mixing releases carelessly can produce uninstallable or broken systems.
Rollback: how to undo a pin cleanly
If a pin causes trouble, remove the file and refresh APT.
sudo rm /etc/apt/preferences.d/80-neovim-backports.pref
sudo apt update
apt-cache policy neovim
If you also want to move back to the distro version:
sudo apt install neovim/bookworm
Or install an explicit version after checking what is available:
apt-cache policy neovim
sudo apt install neovim=0.7.2-7
If the package was held:
sudo apt-mark unhold docker-ce
My practical rules of thumb
If you want the short version, this is mine:
- use one-off
-tinstalls for experiments - use package-specific pins for long-term exceptions
- keep third-party repos low priority by default
- avoid broad cross-release pinning on stable systems
- check
apt-cache policybefore and after every change - simulate upgrades with
apt -swhen the package is important - reserve
Pin-Priority: 1001for deliberate, documented cases
APT pinning is one of those Linux tools that rewards restraint. The goal is not to outsmart the package manager. The goal is to make your intent explicit enough that future-you can still trust the machine.
References
- Debian manpages:
apt_preferences(5)— https://manpages.debian.org/testing/apt/apt_preferences.5.en.html - Debian Wiki: AptConfiguration — https://wiki.debian.org/AptConfiguration
- Debian manpages:
apt-cache(8)— https://manpages.debian.org/testing/apt/apt-cache.8.en.html - Debian manpages:
apt-mark(8)— https://manpages.debian.org/testing/apt/apt-mark.8.en.html - Debian Administrator’s Handbook,
apt-cache policyexamples — https://www.debian.org/doc/manuals/debian-handbook/sect.apt-cache.en.html
Top comments (0)