Add an APT Repository Safely with add-apt-repository
Someone hands you a one-line command to paste into a root shell so you can install a package, and add-apt-repository is usually what runs behind it. This walks through previewing a source, adding it in an explicit format, checking what is enabled, and removing it again later. Allow about ten minutes, plus whatever time it takes to verify the repository is one you trust.
The route
Jump straight to the step you need, or tick off Done means at the end.
- 1. Check the installed command
- 2. Preview a full source entry
- 3. Add the reviewed repository
- 4. Refresh APT metadata deliberately
- 5. List enabled repositories
- 6. Add source packages only when needed
- 7. Add a Launchpad PPA only after checking its owner
- 8. Remove a repository and understand the boundary
- Common traps
The examples target the add-apt-repository supplied by software-properties-common 0.99.49.4 on this machine. The alias apt-add-repository uses the same installed manual page and behaviour.
Warning
Adding a repository changes system configuration and can make packages from another publisher available to APT. Read the publisher's instructions and signing-key policy first. Do not paste an unreviewed command from a web page straight into a root shell.
1. Check the installed command
Confirm which executable will run and inspect its supported options. These checks do not change APT configuration:
$ command -v add-apt-repository
/usr/bin/add-apt-repository
$ add-apt-repository --help
usage: add-apt-repository [-h] [-d] [-r] [-s] [-c COMPONENT] [-p POCKET] [-y]
[-n] [-l] [--dry-run] [-L] [-P PPA] [-C CLOUD]
[-U URI] [-S SOURCESLIST [SOURCESLIST ...]]
[line ...]
The command accepts exactly one repository selector at a time: a PPA, Cloud Archive, URI, full one-line source entry, or the older positional LINE form. The positional form still exists for compatibility, but the manual calls it deprecated because autodetection can be ambiguous.
2. Preview a full source entry
Use --dry-run before making a change. This example uses the reserved example.invalid host, so it is a syntax and file-name preview rather than a real repository:
$ add-apt-repository --dry-run --no-update -S 'deb https://packages.example.invalid/ubuntu noble main'
Repository: 'deb https://packages.example.invalid/ubuntu noble main'
Description:
Archive for codename: noble components: main
More info: https://packages.example.invalid/ubuntu
Adding repository.
DRY-RUN mode: no modifications will be made
Adding deb entry to /etc/apt/sources.list.d/archive_uri-https_packages_example_invalid_ubuntu-noble.list
Adding disabled deb-src entry to /etc/apt/sources.list.d/archive_uri-https_packages_example_invalid_ubuntu-noble.list
The exact description and generated file name depend on the source you give it. The line that actually matters is DRY-RUN mode: no modifications will be made. --no-update also suppresses the package-cache refresh that normally follows an add, which is handy when you want to review the resulting source and run apt update separately.
3. Add the reviewed repository
Replace every placeholder with values documented by the repository publisher. The command below needs elevated privileges because it writes under /etc/apt; keep the whole source line quoted so the shell passes it as one argument:
$ sudo add-apt-repository --no-update -S 'deb https://repo.example.invalid/ubuntu noble main'
- Match the codename and components to the host. Use the distribution codename and components this host actually needs.
- Add components with
-c. It can be repeated with a URI; without it, the manual says the component defaults tomain. - Only add a pocket if the publisher documents it.
-pselects a release or updates pocket, but guessing at one is asking for trouble.
After the write completes, inspect the source files before refreshing metadata:
$ grep -R --line-number --fixed-strings 'https://repo.example.invalid/ubuntu' /etc/apt/sources.list /etc/apt/sources.list.d 2>/dev/null
/etc/apt/sources.list.d/archive_uri-https_repo_example_invalid_ubuntu-noble.list:1:deb https://repo.example.invalid/ubuntu noble main
Your file name may differ. If the source is wrong, stop here and remove it before asking APT to download metadata.
4. Refresh APT metadata deliberately
Run the update as a separate checkpoint once the source and signing-key arrangement are correct:
$ sudo apt update
Read the warnings and errors instead of treating a non-zero result as a minor inconvenience. A missing release file, wrong suite, unreachable host or signature error means the source is not ready for package installation. Do not bypass signature checks to force an unfamiliar repository to work. If you used a placeholder host from this guide, the update will fail, because that host is deliberately not real.
5. List enabled repositories
Use --list to inspect enabled entries without changing anything:
$ add-apt-repository --list
By default this shows binary deb entries only, not disabled entries and not source deb-src entries. Add --enable-source when you also need to see enabled source entries:
$ add-apt-repository --list --enable-source
Do not assume every line in /etc/apt/sources.list.d is active just because the file exists; inspect the rendered entries and look for comments or disabled source lines.
6. Add source packages only when needed
Use --enable-source when the repository should also provide source packages. With a repository selector, it adds and enables a matching deb-src line:
$ sudo add-apt-repository --no-update --enable-source -U 'https://repo.example.invalid/ubuntu'
The URI form takes one archive URI; if it is detected as a PPA, the command handles it as a PPA. For a precise source entry, prefer -S and give the complete line. Be careful with a bare --enable-source: without a repository it operates on existing entries, and running it twice can add missing source entries for existing binary entries you did not mean to touch.
7. Add a Launchpad PPA only after checking its owner
A PPA is a publisher-specific trust decision, not just a shorter URL. Verify the owner, supported distribution and packages before using this form:
$ sudo add-apt-repository --no-update --ppa ppa:USER/PPA
The manual also accepts USER/PPA, and defaults a missing PPA name to ppa. The command downloads the PPA's public GPG key and adds it to APT's keyring. Private PPAs additionally need --login and an account subscribed to that PPA. Treat any keyring or authentication prompt as security-sensitive, and check it refers to the PPA you actually intended.
8. Remove a repository and understand the boundary
Removal changes files under /etc/apt, so inspect the exact selector first, then use sudo. For the example URI:
$ sudo add-apt-repository --remove --uri 'https://repo.example.invalid/ubuntu'
- No extra flags. Removal covers the repository, its source lines and all components.
- With
--enable-source. Onlydeb-srclines are disabled. - With
--component. Only the named components are removed, and the repository itself goes only once no components remain.
A file in sources.list.d may be deleted by the command when it ends up with only empty or commented lines. For a PPA, repeat the same selector used to add it:
$ sudo add-apt-repository --remove --ppa ppa:USER/PPA
Verify the result, then refresh metadata if the removed source had been enabled:
$ add-apt-repository --list
$ sudo apt update
Removing a source does not uninstall packages already installed from it. If those must go too, review their dependencies and use your normal package-removal process separately.
Common traps
- Do not stack selectors. Never combine
-P,-C,-U,-Sand the positionalLINEform; the command accepts only one repository selector. - Do not trust
--listto show everything. It deliberately lists enabled entries only; add--enable-sourcefor source entries. - Do not use
-yblind. It assumes yes to every query, so review the source and prompts first. - Do not confuse
--no-updatewith validation. It only skips the automatic cache refresh after adding; you still need a deliberateapt update. - Do not use the deprecated positional syntax in new scripts. A full
-Sline or an explicit-U,-Por-Cselector is easier to review later.
Done means
- You previewed it. The exact source was checked with
--dry-runfirst. - You checked trust. The publisher, suite, components and signing-key arrangement were verified.
- You added it deliberately. The source was added with an explicit selector, with elevated privileges used only for the system change.
- You inspected what is enabled. Enabled entries were checked before running
apt update. - You know the source state. Whether source packages are enabled and whether the cache was refreshed is not a guess.
- You can remove it cleanly. The same selector removes the entry without assuming installed packages disappear too.