DEV Community

Cover image for Package Managers Explained: From apt to Homebrew to winget (and Everything In Between)
Adrian Jiga
Adrian Jiga

Posted on

Package Managers Explained: From apt to Homebrew to winget (and Everything In Between)

Before I used Linux, I installed software the way most people do. You open a browser, search for the thing you want, find the official website, download an installer, click through a wizard, and eventually the software appears on your system. Sometimes it takes five minutes. Sometimes you download something from the wrong site and end up with a toolbar you didn’t ask for. Sometimes the installer asks you to restart your computer to install a text editor.

It works. But it doesn’t scale, and it doesn’t age well. After a while you have no idea what’s installed on your machine, where it came from, or how to update it cleanly. And updating is the part that really shows the cracks. You find out a new version is available because the software told you, you go back to the website, download the new installer, click through the wizard again, and hope it cleans up after itself properly.

Package managers solve this. And once you’ve used one properly, going back to the old way feels like a step backward.

What is a package manager, actually?

A package manager is a tool that handles installing, updating, and removing software on your system. Instead of you hunting down the right installer for the right version on the right website, you just tell the package manager what you want, and it handles the rest. It knows where to get the software, what version to grab, and what other software it needs to work.

That last part is important. Most software depends on other software. A video editor might need a specific audio library. A web framework might need a particular runtime version. A database client might need a specific version of a driver that itself needs a specific version of something else. When you install things manually, you’re responsible for tracking all of that yourself, and it’s exactly as painful as it sounds.

A package manager does it automatically. You ask for one thing, it figures out the entire chain of dependencies, and installs everything in the right order.

Think of it like ordering from a restaurant versus going to three different grocery stores to buy ingredients, then cooking everything from scratch, then figuring out mid-recipe that you’re missing something. Both approaches get you fed. One is a lot less effort.

Windows: the platform that came late to this

For most of its history, Windows didn’t have a built-in package manager. You installed software by downloading executables and running them. Each installer did whatever it wanted: some added themselves to the PATH, some didn’t, some left behind registry entries when you uninstalled, some didn’t. Some bundled additional software you didn’t want and hoped you’d miss the checkbox.

That changed with winget, which Microsoft released in 2020 and has been steadily improving since. It’s built into modern Windows and lets you install software straight from the terminal:

winget install Mozilla.Firefox
winget install Git.Git
winget install Microsoft.VSCode
winget install Spotify.Spotify
Enter fullscreen mode Exit fullscreen mode

It’s not as mature as what Linux has had for decades, but it’s a real package manager with a real repository and it works well for common tools. You can even export your installed packages to a file and use it to restore your entire setup on a new machine, something that would have taken an afternoon doing manually before.

Before winget, the community filled the gap. Chocolatey has been around since 2011 and has a massive package repository. It’s still widely used, especially in corporate environments where IT teams need to automate software deployments across hundreds of machines. Scoop is another popular option, leaning more toward developer tools and command-line utilities, and it installs everything to your user directory without needing admin privileges, useful if you’re on a work machine where you don’t have full admin access.

If you’re a developer on Windows, any of these will improve your life compared to the download-and-run approach.

macOS: Homebrew became the de facto standard

macOS doesn’t ship with a package manager for general software either. Apple gives you the App Store for GUI apps and that’s about it. For developers who need command-line tools, libraries, and utilities, the App Store isn’t the answer.

The community built one that became so widely adopted it’s essentially assumed to be installed on any developer’s Mac.

Homebrew is that tool. You install it with a single command, and then the whole thing just works:

brew install git
brew install node
brew install ffmpeg
brew install wget
brew install imagemagick
Enter fullscreen mode Exit fullscreen mode

Homebrew calls its packages “formulae” for command-line tools and “casks” for GUI applications. Want to install a desktop app without touching a browser?

brew install --cask firefox
brew install --cask visual-studio-code
brew install --cask vlc
brew install --cask discord
Enter fullscreen mode Exit fullscreen mode

It handles updates cleanly too. brew update refreshes the package list, brew upgrade upgrades everything outdated. One command and your whole system is current. Compare that to opening five different applications, clicking “check for updates” in each one, and waiting for them to download and restart individually.

MacPorts is the older alternative that predates Homebrew and some people still prefer it, particularly for certain scientific or research tools. But Homebrew won the adoption battle years ago. If you’re on a Mac, Homebrew is almost certainly already there.

Linux: this is where it gets interesting

Linux distributions have had package managers since the 1990s. It’s baked into how the whole system works, not bolted on afterward. On Linux, the package manager isn’t a convenience, it’s the primary way you’re expected to interact with software. The entire operating system, including the kernel, the desktop environment, and every tool installed on it, is managed through it.

That means when you run a system update on Linux, you’re not just updating one application. You’re updating everything at once, in one command, in a consistent and predictable way.

The package manager you get depends on which distribution you’re using, because Linux distros are built around different packaging formats and different philosophies about how software should be distributed.

Debian and Ubuntu use apt (Advanced Package Tool). It manages .deb packages and is probably the most widely recognized Linux package manager:

sudo apt install git
sudo apt install vlc
sudo apt install htop
sudo apt update && sudo apt upgrade
Enter fullscreen mode Exit fullscreen mode

The update command refreshes the list of available packages. The upgrade command actually installs newer versions. It’s a two-step process, which trips up newcomers who run apt update and wonder why nothing changed.

Fedora and Red Hat use dnf, which manages .rpm packages. The commands are similar enough that switching between them doesn’t take long to get used to:

sudo dnf install git
sudo dnf install vlc
sudo dnf upgrade
Enter fullscreen mode Exit fullscreen mode

Arch Linux (and Arch-based distros like CachyOS, Manjaro, or EndeavourOS) use pacman. It’s fast, minimal, and does exactly what you ask with no ceremony:

sudo pacman -S git
sudo pacman -S vlc
sudo pacman -Syu
Enter fullscreen mode Exit fullscreen mode

The -Syu flag is the one you’ll type constantly on Arch: it syncs the package database, updates all packages, and upgrades the system in one shot. Rolling release distributions like Arch stay current by design, so running this regularly is just part of the workflow. Think of it like a standing order. Rather than manually restocking your pantry item by item whenever something runs out, you’ve arranged for everything to be automatically topped up at once.

openSUSE uses zypper. Void Linux uses xbps. Alpine uses apk. Every major Linux distribution has its own tool, but the underlying concept is always the same: a central repository of packages, a tool to interact with it, and automatic dependency resolution.

The AUR: Arch’s unique addition

If you use Arch or an Arch-based distro, you’ll eventually hear about the AUR, the Arch User Repository. It’s worth understanding because it’s unlike anything the other ecosystems have.

The official Arch repositories contain software that the Arch team maintains and packages. The AUR is a community repository where anyone can submit a PKGBUILD, a script that describes how to download, build, and install a piece of software. It’s not precompiled packages you install directly. It’s instructions that your machine uses to build the software locally from source.

The result is that practically anything you could want is available on Arch. Obscure tools, proprietary software, niche utilities, things that haven’t made it into official repositories anywhere. If it exists, someone has probably written a PKGBUILD for it. Tools like yay or paru let you interact with both the official repos and the AUR with the same syntax, so in practice you barely notice the distinction.

The AUR is a bit like a community cookbook where anyone can contribute recipes. The official repos are the curated menu, tested, maintained, guaranteed to work. The AUR is the full cookbook, vastly more options, but you’re expected to use some judgment about what you try.

BSD: the same idea, different world

BSD systems, FreeBSD, NetBSD, OpenBSD, have their own package managers. FreeBSD uses pkg, which manages binary packages similar to how apt or pacman works:

pkg install git
pkg install vim
pkg upgrade
Enter fullscreen mode Exit fullscreen mode

FreeBSD also has the Ports collection, which is conceptually similar to the AUR: a collection of build scripts for thousands of pieces of software that you compile from source on your own machine. It’s been around since the early 1990s and was actually an inspiration for how Arch’s own packaging system was later designed.

If you ever find yourself on a BSD system, the commands are a little different but the mental model is exactly the same. Same restaurant, slightly different menu, same way of ordering.

Language-level package managers

Here’s something worth pointing out: once you start writing code, you’ll use package managers that have nothing to do with your operating system.

npm manages JavaScript packages. pip manages Python packages. cargo manages Rust crates. composer manages PHP dependencies. gem manages Ruby libraries. These all work on the same principle as system package managers, a central registry, version resolution, automatic dependency management, but they operate at the language level rather than the system level.

The npm install you run inside a project is the same concept as apt install on your system. The pip install requests you run in a Python script is the same concept as brew install wget on your Mac. Same idea, different scope.

Once you see that pattern, it sticks. Every new package manager you encounter, no matter the language or platform, immediately makes sense. The commands are different, but you already understand what’s happening underneath.

And that’s really the point of understanding any of this. Not to memorize the flags, but to understand what the tool is actually doing. When you do, the rest follows naturally.

Top comments (0)