What Are Dependencies in Linux Software Installation?

Learn what software dependencies are in Linux, why they exist, how package managers handle them automatically, and how to resolve dependency errors when they arise.

What Are Dependencies in Linux Software Installation?

A dependency in Linux software installation is a separate software package that a program requires in order to run correctly. When you install an application, it often relies on shared libraries, utilities, or other packages that provide functionality the application uses but does not include itself. Linux package managers like APT and DNF automatically detect and install all required dependencies when you install a program, so the vast majority of the time you never need to think about them — they are handled transparently in the background.

Introduction: Why Software Does Not Come Alone

You decide to install a video editor on your Linux system. You run sudo apt install kdenlive and watch the terminal scroll through a list of packages being installed. There is kdenlive itself, of course — but also libmlt7, frei0r-plugins, movit, libebur128, librtmp1, and a dozen other packages you have never heard of and did not ask for. What are all of these, and why do they need to be installed alongside the application you actually wanted?

The answer is dependencies — and understanding them reveals one of the most elegant design decisions in the Linux software ecosystem. The mystery of why installing one program installs many others, why occasionally the package manager reports a conflict, why some programs fail to launch with cryptic error messages about missing libraries — all of these situations become clear once you understand how and why Linux software is built on a foundation of shared, reusable components.

This article explains what dependencies are from the ground up, why the dependency system exists and what problems it solves, how the different types of dependencies work, how package managers handle them automatically, what happens when dependencies conflict or break, and how to diagnose and resolve dependency problems when they arise. By the end, you will have a thorough understanding of the dependency ecosystem that underlies every software installation on your Linux system.

The Foundational Concept: Shared Code

To understand dependencies, you need to understand why software is built the way it is.

The Problem with Self-Contained Software

Imagine if every application included its own complete copy of every piece of code it uses. Your web browser would include its own copy of the code for handling cryptography (for HTTPS). Your email client would include its own copy. Your file manager would include its own copy. Every application that needs to read a JPEG image file would include its own JPEG parsing code. Every application that displays text would include its own font rendering code.

The result would be enormous: applications would each be hundreds of megabytes larger than they are now, consuming vastly more disk space and memory. When a security vulnerability was found in the cryptography code, every single application that had included its own copy would need to be individually updated. Developers would waste enormous effort reinventing and maintaining code that already exists and works in other applications.

This approach was actually how early software worked — programs were largely self-contained. As software became more complex and the number of applications grew, the redundancy became untenable.

The Solution: Shared Libraries

The solution is shared libraries — reusable collections of code that multiple applications can use simultaneously. Instead of each application including its own cryptography code, there is one shared cryptography library (like OpenSSL or libgcrypt) installed once on the system. Every application that needs cryptographic functionality links to this shared library and uses it directly. The library code is loaded into memory once and shared among all applications that need it at any given time.

This shared library model delivers three major benefits:

Storage efficiency: The library code exists in exactly one place on disk rather than being duplicated in every application that uses it. OpenSSL is approximately 1.5 MB. If 50 applications each bundled their own copy, that would be 75 MB of identical code. With a shared library, it is 1.5 MB regardless of how many applications use it.

Memory efficiency: When multiple applications that use the same shared library are running simultaneously, the library code occupies memory only once. The operating system loads it once and maps it into the address space of each application that needs it.

Centralized security updates: When a vulnerability is discovered in a shared library, updating that single library fixes the vulnerability for every application that uses it simultaneously. No application-by-application patching required — one sudo apt update && sudo apt upgrade fixes everything that depended on the vulnerable library.

What Dependencies Are

A dependency is this relationship formalized: application A depends on library B. When you install application A, the package manager sees that it depends on library B, checks whether library B is already installed, and installs it if not. Library B may itself depend on library C, which the package manager also installs if needed. This chain of dependencies — application depends on library, library depends on other library — is the dependency graph.

The dependency concept extends beyond shared libraries. An application might depend on another complete program (a text editor might depend on a spell checker), a data file (a locale package), a virtual package representing a capability (any program providing email sending functionality), or a specific version or version range of a dependency.

Types of Dependencies

Linux package managers recognize several distinct types of dependencies, each expressing a different kind of requirement.

Required Dependencies (Depends)

A required dependency (called Depends in Debian/Ubuntu packaging) is a package that must be installed for the software to function at all. If a required dependency is not present, the application will fail to start or crash immediately with an error about missing libraries.

When you install software through APT or DNF, required dependencies are always automatically installed. You cannot install a package with unmet required dependencies through a package manager — it will refuse and explain the problem.

Example: The video player mpv requires the library libmpv2 to run. When you install mpv, the package manager automatically installs libmpv2 if it is not already present, because without it, mpv simply does not work.

Recommended Dependencies (Recommends)

A recommended dependency is a package that significantly enhances the software’s functionality but is not strictly required for basic operation. The software will run without it, but with reduced capabilities.

APT installs recommended packages by default (this behavior is configurable). DNF does not install weak dependencies by default.

Example: A media player might recommend a package providing additional codec support. The player works without it (playing common formats), but cannot play certain formats that the recommended package would enable.

To skip recommended packages in APT:

Bash
$ sudo apt install --no-install-recommends package-name

This produces a more minimal installation — useful on servers or resource-constrained systems where you want only what is strictly necessary.

Suggested Dependencies (Suggests)

A suggested dependency is a package that complements the software in some way but is entirely optional. APT does not install suggested packages by default — they are only mentioned in package information to let you know related software exists.

Example: A programming language package might suggest an integrated development environment. The language works perfectly without the IDE, but if you plan to write code in that language, the IDE would be useful to know about.

View suggestions for a package:

Bash
$ apt show package-name | grep Suggests

Conflicts

A conflict is the opposite of a dependency — it specifies packages that cannot be installed simultaneously. Two packages conflict when they provide the same functionality in incompatible ways, when they share files that would overwrite each other, or when running both simultaneously would cause problems.

Example: Multiple mail transport agents (MTAs) conflict with each other. You can have postfix or sendmail installed as your system’s MTA, but not both simultaneously — they would both try to handle the same mail delivery role and conflict over system resources and configuration.

When the package manager encounters a conflict, it refuses to install both conflicting packages and explains the conflict, asking you to choose which one to keep.

Breaks and Replaces

Breaks indicates that installing this package will cause a specified other package to malfunction (even without a direct file conflict).

Replaces indicates that this package supersedes another — it may install files that replace files from the other package. This is used when packages are renamed or when one package absorbs the functionality of another.

Virtual Packages

A virtual package is a name that represents a capability rather than a specific package. Multiple real packages can “provide” the same virtual package, and a dependency on the virtual package is satisfied by any of them.

Example: mail-transport-agent is a virtual package. Both postfix and sendmail provide mail-transport-agent. If another application depends on mail-transport-agent, either postfix or sendmail satisfies that dependency. The package manager does not care which specific MTA you have — it just needs you to have something that provides that capability.

How Package Managers Resolve Dependencies

The process by which a package manager calculates what needs to be installed when you request a package is called dependency resolution. It is one of the most computationally interesting problems in software distribution.

Building the Dependency Graph

When you run sudo apt install vlc, APT does not simply look at VLC’s direct dependencies. It builds a complete dependency graph:

VLC depends on package A (version ≥ 1.2) and package B. Package A depends on package C. Package B depends on package C (version ≥ 2.0) and package D. Package C is available in version 2.5, satisfying both requirements. Package D is already installed.

APT traverses this graph recursively until it has identified every package needed to satisfy all dependencies at every level. It then checks which of these are already installed (at the required versions), identifies what needs to be downloaded and installed, and presents its plan.

Dependency Conflicts and Resolution

The challenge arises when the dependency graph contains contradictions. Consider: package X requires library L version ≥ 2.0, and package Y requires library L version < 2.0. You cannot install both X and Y simultaneously, because no single version of L satisfies both requirements.

When such a conflict arises, the package manager cannot automatically resolve it — it has no basis for choosing between X and Y without your input. It reports the conflict, explains what the incompatibility is, and asks you to make a choice: which package do you want?

In practice, major dependency conflicts are rare on well-maintained distributions. The distribution’s packaging team works to ensure that packages in the repository are mutually compatible. Conflicts more commonly arise when mixing packages from different sources — official repository packages mixed with PPAs, third-party repositories, or manually installed packages.

SAT Solvers in Modern Package Managers

Dependency resolution is, formally, a variant of the Boolean satisfiability problem (SAT) — determining whether a set of constraints (dependency requirements) can all be satisfied simultaneously. Modern package managers including APT (through its dependency resolver) and DNF use SAT solver algorithms to find solutions to complex dependency graphs.

This mathematical foundation means package managers can handle arbitrarily complex dependency webs — resolving hundreds of packages with thousands of interdependencies — and either find a valid installation plan or prove that no valid plan exists given the current constraints. When no valid plan exists (a genuine conflict), the package manager explains exactly what is conflicting and why, rather than simply failing with an uninformative error.

The Dependency Ecosystem in Practice

What You See When Installing

When you install a package through APT or DNF, the terminal output reflects the dependency resolution in action. A typical sudo apt install kdenlive might show:

Bash
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  frei0r-plugins libavfilter9 libebur128-1 libfftw3-double3
  libmlt7 libmovit10 librtmp1 libswscale7 movit
Suggested packages:
  frei0r-plugins-dev kdenlive-data
The following NEW packages will be installed:
  frei0r-plugins kdenlive libavfilter9 libebur128-1
  libfftw3-double3 libmlt7 libmovit10 librtmp1 libswscale7 movit
0 upgraded, 10 newly installed, 0 to remove and 0 not upgraded.
Need to get 18.4 MB of archives.
After this operation, 52.3 MB of additional disk space will be used.

The “additional packages will be installed” section shows all the dependencies the package manager will automatically install alongside your requested package. The “suggested packages” line shows optional enhancements you could install separately if desired.

Reading this output gives you insight into what your application depends on. In this case, kdenlive depends on libmlt (a multimedia framework), movit (GPU-accelerated video processing), libebur128 (audio loudness measurement), and several other libraries.

Shared Libraries in the Running System

After installation, you can see exactly which shared libraries a program depends on using the ldd command:

Bash
$ ldd /usr/bin/firefox
	linux-vdso.so.1 (0x00007ffd12345000)
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0
	libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2
	libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6

ldd shows each shared library the program links against and where that library is found on the system. This is useful for diagnosing “missing library” errors — if a library shows “not found” in ldd output, that library needs to be installed.

Finding Which Package Provides a File

Sometimes you know you need a specific file (perhaps a library file with a particular name) but do not know which package contains it. APT provides a tool for this:

Bash
$ apt-file search libssl.so.3
libssl3: /usr/lib/x86_64-linux-gnu/libssl.so.3

apt-file searches the repository index for which package provides any given file. Install it first: sudo apt install apt-file && sudo apt-file update.

On Fedora/DNF systems:

Bash
$ dnf provides libssl.so.3

This capability is invaluable when a program fails with an error like “error while loading shared libraries: libssl.so.3: cannot open shared object file: No such file or directory” — apt-file search or dnf provides immediately tells you which package to install.

Finding What a Package Depends On

Bash
$ apt depends vlc
vlc
  Depends: libvlc5 (= 3.0.20-3build1)
  Depends: vlc-bin (= 3.0.20-3build1)
  Depends: vlc-data (= 3.0.20-3build1)
  Depends: vlc-plugin-base (= 3.0.20-3build1)
  Recommends: vlc-plugin-video-output
  Recommends: vlc-plugin-audio-output
  Suggests: vlc-plugin-notify

This shows VLC’s direct dependencies. To see the full dependency tree (all transitive dependencies):

Bash
$ apt-cache depends --recurse vlc | grep "Depends:" | sort -u

Finding What Depends on a Package

The reverse query — which packages require a given package as a dependency — is also useful:

Bash
$ apt rdepends libssl3
libssl3
Reverse Depends:
  curl
  openssl
  libcurl4
  wget
  git
  [many more...]

This is important when considering whether to remove a package. If many other packages depend on it, removing it would require removing them too (or would break them).

Dependency Problems: Causes and Solutions

Despite package managers handling dependencies automatically most of the time, dependency problems occasionally arise. Understanding their causes makes them much easier to diagnose and resolve.

Broken Packages

A broken package is one whose dependencies cannot be satisfied — either a required dependency is not installed, is at the wrong version, or conflicts with something else installed. This state can arise from:

  • A failed installation that was interrupted mid-way
  • Manually removing a package that others depended on
  • Adding a third-party repository that provides packages incompatible with official packages
  • A package that was removed from the repository after being installed

Diagnosing broken packages:

Bash
$ sudo apt --fix-broken install

This is the standard first-response command for most APT dependency problems. It attempts to fix broken package states by installing missing dependencies or removing packages with unresolvable dependencies.

Bash
$ sudo dpkg --configure -a

This reconfigures any partially installed packages — useful after an interrupted installation.

For a comprehensive diagnosis:

Bash
$ sudo apt check

Reports broken dependencies in the installed package database.

On Fedora/DNF systems:

Bash
$ sudo dnf check
$ sudo dnf distro-sync

dnf distro-sync synchronizes all installed packages with the versions in the repository — a comprehensive repair operation.

Missing Libraries at Runtime

When a program is launched and a required shared library is not found, you see an error like:

Bash
error while loading shared libraries: libexample.so.1: cannot open shared object file: No such file or directory

Diagnosing the problem:

Bash
$ ldd /usr/bin/problematic-program

Look for lines showing “not found” — these are the missing libraries.

Finding which package provides the missing library:

Bash
$ apt-file search libexample.so.1
$ dnf provides libexample.so.1

Installing the missing library:

Bash
$ sudo apt install libexample1     # The package name from apt-file search

Version Conflicts

Sometimes you need software that requires a newer version of a library than what your distribution provides, or two pieces of software require conflicting versions of the same library.

Option 1: Use a newer distribution version that packages the required library version. If you are running Ubuntu 22.04 and software requires a library not available until Ubuntu 24.04, upgrading the distribution resolves this.

Option 2: Use Flatpak or Snap. Universal package formats bundle their own dependencies rather than using system libraries. A Flatpak version of a program brings its own library versions, completely bypassing system library conflicts.

Option 3: Build from source. Installing a library from source code to a local directory (/usr/local) can coexist with the system’s older version, though this requires careful configuration to ensure the right version is used.

Option 4: Use a PPA or third-party repository that backports newer library versions to your distribution. The risk is that the third-party library version may conflict with other packages.

Dependency Hell: When Conflicts Are Severe

“Dependency hell” is the informal term for a situation where installing or updating one package requires changes to others in a cascading, unresolvable way — pulling in incompatible versions, requiring removal of important packages, or creating circular dependencies. Well-maintained distributions minimize this through careful packaging policies, but it can arise when mixing software from many different sources.

The practical resolution for severe dependency hell is usually:

First, identify the conflicting packages and decide which you can live without. Use apt show, apt depends, and apt rdepends to understand the relationships.

Second, consider switching to universal package formats (Flatpak/Snap) for applications that cause conflicts, separating them from the system’s library ecosystem entirely.

Third, if a third-party repository is the source of conflicts, removing that repository and reverting to official packages often resolves the situation:

Bash
$ sudo add-apt-repository --remove ppa:problematic/ppa
$ sudo apt install ppa-purge
$ sudo ppa-purge ppa:problematic/ppa

Pinning Packages: Preventing Unwanted Updates

Sometimes you want to keep a specific version of a package even when newer versions are available — perhaps because a newer version introduced a regression, or because a specific version is needed for compatibility.

Holding a package at its current version (APT):

Bash
$ sudo apt-mark hold package-name

Releasing a hold:

Bash
$ sudo apt-mark unhold package-name

Viewing held packages:

Bash
$ apt-mark showhold

On DNF systems:

Bash
$ sudo dnf versionlock add package-name
$ sudo dnf versionlock delete package-name

Why Universal Packages (Flatpak, Snap, AppImage) Change the Picture

The universal package formats discussed in the previous article — Flatpak, Snap, and AppImage — represent a fundamentally different approach to the dependency problem.

The Bundling Philosophy

Instead of relying on system-provided shared libraries and managing complex dependency graphs, universal packages bundle all their dependencies directly into the package itself. A Flatpak of GIMP includes the specific versions of all libraries GIMP needs, independent of whatever versions are installed on the host system.

This approach has direct implications for dependency management:

No dependency conflicts with system packages. Because a Flatpak application uses its own bundled libraries rather than system libraries, it cannot conflict with system packages or other Flatpak applications. Each application is isolated in its own runtime environment.

Consistent behavior across distributions. Because the application brings its own dependencies, it behaves identically whether installed on Ubuntu, Fedora, Arch, or any other supported distribution. There is no “it works on Fedora but not Ubuntu because of a different library version” problem.

No automatic dependency installation. When you install a Flatpak, only the specific runtime environment it needs is installed — no dependency resolution across the system package graph.

Tradeoffs. The bundling approach has costs: packages are much larger (each application includes its own copy of libraries that other applications might share), updates must include the application’s bundled libraries as well as the application itself, and security updates to bundled libraries require each application to release an update separately.

When to Choose System Packages vs. Universal Packages

Prefer system packages (apt/dnf) when:

  • The software is available in official repositories
  • You want the most integrated, efficient installation
  • You value automatic security updates through the system update mechanism
  • Disk space efficiency matters

Prefer Flatpak when:

  • The software is not in official repositories
  • You need a specific version the distribution does not package
  • You want isolation from system library changes
  • Cross-distribution compatibility matters

Prefer Snap when:

  • On Ubuntu or Ubuntu-based systems where Snap is well-supported
  • The application requires automatic, self-contained updates
  • The software is only available through the Snap Store

Prefer AppImage when:

  • You want zero installation (just download and run)
  • You need to run without root privileges
  • You want complete portability

Viewing the Dependency Landscape of Your System

Understanding what is installed and how packages relate to each other helps you maintain a clean, efficient system.

Listing All Installed Packages

Bash
$ dpkg --list                           # All installed packages (Debian/Ubuntu)
$ dpkg --list | grep "^ii" | wc -l     # Count installed packages
$ rpm -qa                               # All installed packages (Fedora/RHEL)
$ pacman -Q                             # All installed packages (Arch)

Finding Orphaned Packages

Orphaned packages are packages that were installed as dependencies but whose parent packages have since been removed. They take up disk space without serving any purpose.

Bash
$ sudo apt autoremove --dry-run        # Show what would be removed
$ sudo apt autoremove                  # Remove orphaned packages
Bash
$ sudo dnf autoremove                  # Fedora

On Arch:

Bash
$ pacman -Qdtq                         # List orphaned packages
$ sudo pacman -Rs $(pacman -Qdtq)     # Remove all orphaned packages

Why Large Removals Happen

Occasionally, removing a package triggers the removal of many other packages. This happens because the package you are removing was a dependency of many others. APT’s dependency system ensures that removing a library removes everything that depended on it — rather than leaving broken packages behind.

If you see that removing one package would remove fifteen others, investigate with apt rdepends package-name to understand what depended on it. Sometimes this reveals that you inadvertently installed a meta-package (a package with no files of its own, existing only to pull in other packages as dependencies) and removing the meta-package correctly removes its dependents.

Dependency Information Quick Reference

CommandWhat It DoesDistribution
apt depends pkgShow what pkg depends onUbuntu/Debian
apt rdepends pkgShow what depends on pkgUbuntu/Debian
apt show pkgShow full package info including depsUbuntu/Debian
apt list --upgradableShow packages with available updatesUbuntu/Debian
apt-file search filenameFind which package provides a fileUbuntu/Debian
sudo apt --fix-broken installFix broken dependenciesUbuntu/Debian
sudo apt autoremoveRemove unneeded dependency packagesUbuntu/Debian
dnf info pkgShow package info including depsFedora/RHEL
dnf provides filenameFind which package provides a fileFedora/RHEL
dnf checkCheck for dependency problemsFedora/RHEL
sudo dnf autoremoveRemove unneeded dependenciesFedora/RHEL
ldd /path/to/programShow shared library dependenciesAll
apt-mark hold pkgPrevent a package from being upgradedUbuntu/Debian
dnf versionlock add pkgLock a package versionFedora/RHEL

Real-World Example: Tracing a Dependency Chain

Let us trace a real dependency chain to make this concrete. When you install git on Ubuntu, what actually gets installed?

Bash
$ apt depends git
git
  Depends: libcurl3-gnutls (>= 7.76.1)
  Depends: libexpat1 (>= 2.0.1)
  Depends: libpcre2-8-0 (>= 10.22)
  Depends: zlib1g (>= 1:1.2.1.2)
  Depends: libgit2-1.5 (>= 1.5.0)
  Depends: perl
  Recommends: ca-certificates
  Recommends: less
  Suggests: gettext
  Suggests: git-daemon-run | git-daemon-sysvinit
  Suggests: git-doc
  Suggests: git-email
  Suggests: git-gui
  Suggests: gitk
  Suggests: gitmagic

Git directly depends on:

  • libcurl3-gnutls — the libcurl networking library (for fetching from remote repositories)
  • libexpat1 — an XML parsing library
  • libpcre2-8-0 — the Perl Compatible Regular Expressions library
  • zlib1g — the zlib compression library (for pack files)
  • libgit2-1.5 — the core git library implementation
  • perl — the Perl programming language (for git’s helper scripts)

Each of these in turn has its own dependencies. The perl package alone depends on dozens of other packages. By the time everything is resolved, installing git on a minimal system requires installing well over 100 packages total — yet APT handles this entire chain automatically and transparently.

This example illustrates why understanding dependencies helps you appreciate what your software is built from. Git is not simply one program — it is an application that leverages the work of dozens of other projects, assembled by the distribution’s package system into a coherent, installable whole.

Conclusion: Dependencies as Infrastructure

The dependency system is the invisible infrastructure that makes Linux software work. It allows developers to build sophisticated applications by standing on the shoulders of existing libraries rather than reinventing everything from scratch. It ensures that security fixes propagate to all dependent software through a single update. It manages the complexity of thousands of interdependent software components, keeping them organized and consistent.

For most everyday Linux use, the dependency system works entirely in the background — you install a program, the package manager resolves its dependencies silently, and everything works. The times when you need to think about dependencies directly are the exception: when installing software from outside official repositories, when troubleshooting a runtime error about missing libraries, when resolving conflicts between incompatible packages, or when maintaining a clean system by removing orphaned packages.

Understanding what dependencies are and why they exist transforms these occasional friction points from mysterious obstacles into solvable technical problems. The library error message that once seemed cryptic now points directly to a specific missing package you know how to install. The package conflict that once seemed unresolvable now reveals a clear choice between options you can evaluate intelligently.

The dependency ecosystem is not a flaw in Linux software distribution — it is one of its greatest strengths. The ability to share code efficiently, update security fixes centrally, and build complex applications from reusable components is precisely what makes Linux such a robust and maintainable platform for everything from personal desktops to global infrastructure.

Share:
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments

Discover More

Setting Up Your JavaScript Development Environment: Editors and Tools

Learn how to set up your JavaScript development environment, from choosing editors to using tools…

How Dangerous Is It to Work with Robots?

Learn about safety risks in robotics and how to protect yourself. Understand electrical hazards, mechanical…

MIT Technology Review Predicts 2026 Breakthrough Tech Trends

MIT Technology Review reveals 2026’s transformative technologies including AI companions, commercial space stations, and personalized…

Nvidia’s Groq Licensing Play Shows Big Tech’s New M&A Workaround For AI Chips

Nvidia’s Groq licensing deal spotlights how inference performance and deal structures are redefining the AI…

Understanding Op-Amps: The Swiss Army Knife of Analog Electronics

Understanding Op-Amps: The Swiss Army Knife of Analog Electronics

Discover what operational amplifiers are, how they work, and why they’re essential in analog electronics.…

Creating an Impressive Data Science GitHub Repository

Learn how to build a standout GitHub repository for your data science portfolio. Discover best…

Click For More
0
Would love your thoughts, please comment.x
()
x