Gentoo USE Flags Are a Build Contract: Choosing Global vs Per-Package
USE flags are a build-time contract, not a runtime toggle. Where you set a flag — profile, make.conf, or package.use — decides how much of the system gets rebuilt.
12 Jan 2026, 14:10 UTC

A headless server that keeps pulling in a desktop
You run emerge --ask for one small utility on a server with no display, and the dependency list includes GTK, X11 libraries, and a font package. Nothing is misconfigured in the usual sense. The ebuild for that package has optional features, and the profile you inherited turns some of them on by default. Those optional features are USE flags, and turning them off is the normal fix.
The decision that actually matters is not which flag to change but where to change it. Gentoo lets you set the same flag at three levels, and the level you choose determines how much of the system gets rebuilt and how much future maintenance you have signed up for.
What a USE flag controls, and what it does not
A USE flag is a boolean switch that Portage evaluates when it plans a package installation. Depending on the ebuild, a flag can:
- add or remove an optional dependency,
- pass a
--with-…or--enable-…option to the package's configure step, - apply or skip a patch.
It is a build-time contract, not a runtime toggle. Setting X for app-editors/vim means the binary is compiled with X11 support and links against X libraries. Unsetting it later does not change the installed binary until you rebuild. That is why a flag change is followed by an emerge command rather than a config reload.
Three levels, resolved in order
Portage resolves a flag's final value from most general to most specific:
- Profile defaults. The profile selected by your
eselect profilechoice ships a default flag set. You do not edit these directly. - Global flags in
/etc/portage/make.conf. AUSE="..."line here applies to every package that knows the flag. Prefix a name with-to disable it. - Per-package flags in
/etc/portage/package.use. A line likeapp-editors/vim Xapplies only to that package and overrides the global setting.
/etc/portage/package.use may be a single file or a directory of files; Portage reads all of them. Using a directory with one file per reason ("desktop-tools", "printing") makes each decision reversible by deleting one file.
Reading the flags before you commit
Two commands cover most of what you need. The first comes from app-portage/gentoolkit; the second is Portage itself.
equery uses app-editors/vim
emerge --pretend --verbose app-editors/vim
equery uses lists the flags the ebuild knows about, with descriptions and the final setting after all overrides are applied. emerge -pv shows the flags Portage will actually build with, plus the dependency list they produce — which is the part you care about, since a flag can pull in packages you were trying to avoid.
If a combination is invalid, Portage tells you before building. Ebuilds can declare REQUIRED_USE, a constraint such as "at most one of these flags may be enabled", and Portage refuses the merge with an error rather than producing a broken binary. Treat that error as information about the ebuild, not as a bug.
Worked example: one GUI tool on a headless box
Suppose the server should stay free of X11 and GTK, but one package genuinely needs X support. Set the global default off, then re-enable it for that package alone.
# /etc/portage/make.conf
USE="-X -gtk"
# /etc/portage/package.use/desktop-tools
app-editors/vim X
Then rebuild only what the change affects:
emerge --ask --verbose --update --deep --newuse @world
Run this as root, or with whatever privilege escalation your system uses for Portage. The --newuse (-N) option is what makes Portage rebuild packages whose flag set changed. Without it, Portage updates versions but leaves already-installed packages built with the old flags.
Check the result with equery uses app-editors/vim — the X row should show as set — and with emerge -pv app-editors/vim, where the dependency list should now include the X libraries for that package. If unrelated packages show new dependencies, your global line was broader than you intended.
The trade-off: flags are a maintenance surface
Every flag you set is a decision you may have to revisit. Enabling a large set increases build time and disk usage, and each flag change can trigger a rebuild of that package plus anything depending on it. On a source-based distribution that cost is real, especially on a machine that also runs the desktop you are compiling for.
Two practical limits are worth knowing:
--changed-use(-U) is the cheaper sibling of--newuse. It skips rebuilds when the only change is a flag that no longer exists in the tree, so it produces fewer rebuilds. The trade-off is that your installed set can drift from what the current tree would produce.- USE flags are not only booleans.
USE_EXPANDvariables such asPYTHON_TARGETS,VIDEO_CARDS, andCPU_FLAGS_X86are grouped flag sets written inmake.conf.CPU_FLAGS_X86in particular controls per-instruction-set compiler options for packages that use them; theapp-portage/cpuid2cpuflagstool prints a suggested line for your CPU, which you should read before pasting rather than trusting blindly.
One more consequence: if you use a binary package host, a flag set that differs from the one the binaries were built with means Portage falls back to compiling from source. Flags and prebuilt binaries are coupled.
Reverting a flag change
Because this changes installed state, know the way back. Delete the relevant line from /etc/portage/make.conf, or remove the file from /etc/portage/package.use/, then re-run the same emerge -uDN @world command. Portage rebuilds the affected packages with the previous flag set. If the flag had added a dependency, that dependency becomes eligible for removal by emerge --depclean — review that list before confirming, since depclean removes anything nothing depends on.
A short checklist
- Set the flag at the narrowest scope that solves the problem: per-package before global.
- Preview with
emerge -pvand read the dependency list, not just the flag list. - Rebuild with
--newuse; consider--changed-useonly if you accept the drift. - Verify with
equery usesand by confirming the unwanted dependencies are gone. - Keep
package.useas a directory so each decision is one deletable file.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.