Caution
This tool is in early development. It modifies system packages and can break your setup if something goes wrong. Always review the selection before confirming, and keep the generated rollback scripts. Test on a non-critical machine first.
Migrate your manually installed APT and snap packages to Homebrew on Linux. Keep your system package manager clean, manage user-space tools through brew.
Note
Help us expand package coverage! The tool matches APT/snap names to Homebrew formulae using alias files. Many packages have different names across package managers (e.g. fd-find in APT is fd in brew). The more aliases we have, the more packages can be migrated automatically. See Contributing aliases below -- it's just adding a line to a JSON file.
APT packages are system-wide and require sudo. Homebrew installs to user-space (/home/linuxbrew/), needs no root, and updates independently from the OS. apt2brew automates the migration: it scans what you have, finds the Homebrew equivalent, installs it, verifies it works, and only then removes the original.
cargo install --path .Add the apt2brew APT repository so apt update will pick up future releases:
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://apt2brew.federicoconticello.com/apt2brew.gpg.key \
| sudo gpg --dearmor -o /etc/apt/keyrings/apt2brew.gpg
echo "deb [signed-by=/etc/apt/keyrings/apt2brew.gpg] https://apt2brew.federicoconticello.com stable main" \
| sudo tee /etc/apt/sources.list.d/apt2brew.list
sudo apt update
sudo apt install apt2brewTo uninstall: sudo apt remove apt2brew && sudo rm /etc/apt/sources.list.d/apt2brew.list /etc/apt/keyrings/apt2brew.gpg.
cargo deb
sudo dpkg -i target/debian/apt2brew_*.deb- Linux with APT (Debian/Ubuntu)
- Homebrew for Linux installed and in your PATH
Analyze installed packages and show what can be migrated:
apt2brew scanOutputs a table with each package, its brew equivalent (if found), and a risk classification.
Interactive TUI to select and migrate packages:
apt2brew migrate- Browse packages with
j/k, toggle withSpace, filter withTab, search with/ - Press
Enterto confirm selection and start migration - The tool installs via brew, verifies the installation, then removes the APT/snap original
- A rollback script is generated before any removal
Non-interactive modes:
apt2brew migrate --dry-run # Show what would happen
apt2brew migrate --yes # Execute with pre-selected packagesUndo a migration -- reinstall packages via APT/snap and remove from brew:
apt2brew rollback- Main screen shows all brew packages with their APT counterpart
- Press
sto view rollback scripts in a modal - Select packages and press
Enterto rollback - Each package is reinstalled individually so one failure doesn't block the rest
Non-interactive:
apt2brew rollback --yes # Rollback latest script
apt2brew rollback --package <name> # Rollback a single packagePackages are classified as Low (safe to migrate) or High (should stay in APT) using 8 heuristic rules:
- Safety-net list (boot/init/coreutils -- cannot be detected by file analysis)
- Essential/required priority (
Priority: requiredin dpkg) - Systemd units or init.d scripts
- Binaries in
/sbinor/usr/sbin - Libraries (
lib*prefix) - High reverse dependency count (5+)
- Depended upon by essential packages
- System-level dpkg section (kernel, base, libs, drivers)
Low-risk packages with a brew match are pre-selected. High-risk packages are deselected and shown with the reason.
APT/snap names are matched to brew formulae through:
- Explicit aliases (
aliases/apt-to-brew.json,aliases/snap-to-brew.json) -- curated mappings - Exact name match in the Homebrew formula index
- Brew aliases (e.g.
nodejsis an alias fornodein Homebrew) - Fuzzy matching -- strips common APT suffixes (
-dev,-bin,-tools),libprefix,python3-prefix, version suffixes (python3->python@3)
- No APT/snap removal without a verified brew installation (
brew list <formula>) - Rollback script reserved before any system modification, then rewritten after every successful brew install -- a Ctrl-C or panic mid-migration leaves an on-disk rollback that matches actual brew state
apt removeis simulated first (apt-get -s remove); the migration aborts and reports the extras if removal would cascade beyond the packages you selected (e.g. picking a library other packages depend on)- Pre-existing brew copies are detected -- the install step is skipped and the result is annotated
(brew copy was pre-existing -- not refreshed)so you know your brew copy wasn't rebuilt - All package names are validated against a strict character set before reaching
brew/apt/sudoargv, with--end-of-options markers at every destructive call site - Snap packages are correctly separated from APT for both removal and rollback
- Sudo is requested only when needed (just before removal), not at startup
src/
domain/ Pure business logic (risk engine, data types)
application/ Use case orchestration (scan, migrate, rollback)
infrastructure/ System integration (dpkg, brew API, subprocess)
presentation/ CLI (clap) + TUI (ratatui)
aliases/ Curated package name mappings (JSON)
The alias files are the key to matching packages across package managers. Without an alias, the tool relies on fuzzy matching (stripping -dev, -bin, lib prefixes, etc.), which doesn't always work.
How to add an alias:
- Edit
aliases/apt-to-brew.json(for APT packages) oraliases/snap-to-brew.json(for snap packages) - Add a line mapping the source name to the brew formula name:
"fd-find": { "brew": "fd", "type": "formula" }- Open a PR
How to find the brew name: run brew search <keyword> or check formulae.brew.sh.
Every alias you add helps everyone who runs apt2brew on their machine.
MIT