skip to content

On a Linux system, what is the difference between the low-level package installer (dpkg on Debian-family systems, rpm on RHEL-family systems) and the higher-level dependency resolver layered on top of it, and why does installing a downloaded .deb or .rpm file directly so often fail?

level: juniorimportance: must knowfreq 65%

answer

  1. two layers, not two competing tools
  2. one installs, the other plans
  3. repository metadata lives above the installer
  4. unmet dependency is reported, not solved
  5. a package file names deps, never carries them

basics

~20 s

Low-level tools (dpkg, rpm) install exactly the one file you hand them and merely report unmet dependencies. The resolver above them (apt, dnf, zypper) reads repository metadata, computes a complete transaction, fetches the missing packages, and only then calls the low-level tool.

solid answer

~50 s

Linux package management is two layers, not two competing tools. `dpkg` and `rpm` are the *installers*: they own the local package database, unpack a package's payload, run its maintainer scripts, and record which files belong to which package. They know nothing about repositories, so when a package declares a dependency that is absent they can only stop and report it — `dpkg` will leave the package unpacked but unconfigured, `rpm` will refuse the transaction outright. `apt`, `dnf` and `zypper` are the *resolvers*: they read the metadata indexes published by the configured repositories, solve for a set of packages that satisfies every declared relationship, download them in the right order, and hand them to the low-level tool. A `.deb` or `.rpm` downloaded from a website carries only its own files plus a list of *names* it needs — never the dependencies themselves — so installing it directly fails whenever those names are not already satisfied on the machine.

code

bash · 9 lines
bash
# The low-level tool sees only this one file and the local database
dpkg -i ./myapp_1.2.3_amd64.deb

# The resolver sees the repositories and can complete the transaction
apt-get install -f

# Which package owns a file? Answered from the local database, offline
dpkg -S /usr/bin/ssh
rpm -qf /usr/bin/ssh

go deeper

for a junior

Say plainly that dpkg and rpm install the one file you give them, while apt, dnf and zypper read repository metadata, work out everything else that is needed, and fetch it before calling the installer.

for a middle

Explain the division of labour: the installer owns the local package database, unpacking and maintainer scripts; the resolver owns metadata, the dependency solve and download ordering. Note that a package declares dependency names, never ships them.

for a senior

Describe what a half-finished transaction looks like on a real host — files unpacked but the package unconfigured — and how you recover it by letting the resolver complete the transaction rather than forcing past the error and desynchronising the database.

for a principal

Argue about distribution channels, not commands: an artifact installed by hand has no signature chain, no upgrade path and no inventory record, so the real decision is whether to operate an internal repository and make every host's normal update path the only way software arrives.

## The two layers Every mainstream Linux distribution splits package management into two cleanly separated layers, and almost every confusing failure in this area comes from not knowing which layer produced the message. The **low-level installer** — `dpkg` on Debian-family systems, `rpm` on RHEL/Fedora/SUSE-family systems — operates on a package *file* that already exists on disk. Its job is mechanical: - verify the file's integrity (and, for RPM, its signature, if the signing key has been imported), - check the declared relationships against what the local database says is installed, - unpack the payload into the filesystem, - run the package's maintainer scripts at the defined points, - record every installed path in the local package database, so the system can later answer "which package owns this file?" and "what did this package install?". That database is the OS's inventory of installed software: `/var/lib/dpkg/` on the Debian side, `/var/lib/rpm/` on the RPM side. It is authoritative and local — it contains no knowledge of what exists on the internet. The **resolver** — `apt`, `dnf`, `zypper` — sits above that. Its job is informational and planning-oriented: - fetch and cache repository *indexes*, which list every package a repository offers with its version, dependencies, and content hash, - verify those indexes cryptographically, - compute a transaction: given what is installed and what you asked for, which packages must be added, upgraded or removed so that every declared relationship holds, - download the chosen package files, - invoke the low-level tool to install them, in an order that satisfies pre-dependencies. ## Why the split exists The split is deliberate. Dependency solving is a hard combinatorial problem that needs a view of the whole universe of available packages; unpacking a `.deb` is a small, deterministic operation that must work identically whether the file came from a mirror, a build server, or a USB stick. Keeping the installer ignorant of networks also means the machine's inventory can never be changed by a network operation alone — something has to write a file to disk first. It also explains a family of everyday behaviours: - `dpkg` and `rpm` can query and verify packages on a host that has no repositories configured at all. - A resolver can plan a transaction, print it, and let you abort before a single file is touched, because planning happens entirely above the installer. - A build pipeline can produce a package and install it with the low-level tool for a smoke test without publishing it anywhere. ## Why a downloaded package file fails A binary package contains its own files and a list of *relationship names* it needs — `libc6 (>= 2.34)`, `libssl3`, `python3.11` — and nothing else. It never bundles the packages it depends on. So handing that file to the low-level tool succeeds only if the machine already satisfies every name. On the Debian side the failure is particularly confusing because it is *partial*: `dpkg` unpacks the files, then refuses to configure the package, leaving it in an "unpacked, awaiting configuration" state. The binary may even be on disk and broken. The correct recovery is to let the resolver finish the job — it can see the repositories and can fetch what is missing — not to force the install past the error, which leaves the package database describing a system that does not exist. On the RPM side, `rpm` refuses the whole transaction up front with a list of unsatisfied requirements, which is blunter but leaves less mess. ``` # dpkg unpacks, then stops: # dpkg: dependency problems prevent configuration of myapp: # myapp depends on libssl3 (>= 3.0.0); however: # Package libssl3 is not installed. ``` ## What this means in practice The practical rule for a server fleet is that hand-installed local package files are a smell. Such an artifact has no repository behind it, therefore no upgrade path, no signature chain a client can verify against a trusted key, and no record of *where* it came from. The scalable answer is an internal repository: publish the package, let every host's resolver see it, and the dependency, signature and upgrade problems all solve themselves through the normal machinery.

  • After a failed direct install, how would you tell whether a package is fully installed or only unpacked?
    Query the local package database rather than looking for the binary on disk. Debian's status field distinguishes `install ok installed` from `install ok unpacked` / `half-configured`; anything other than fully installed means maintainer scripts have not completed, so the package must not be treated as working. On the RPM side a refused transaction leaves nothing partially applied, so presence in the database means it is configured.
  • Why should a team stand up an internal repository instead of distributing .deb or .rpm files by hand?
    A repository gives three things a loose file cannot: a signature chain clients can verify against a trusted key, an upgrade path so the next version is found automatically, and a single place that records what versions exist. Hand-distributed files bypass all three, and the hosts that received them become invisible to your patching process.
  • Does the low-level tool skip signature checking when you install a file directly?
    Not necessarily. `rpm` verifies a package's embedded GPG signature at install time if the corresponding key has been imported into its database, and will warn or fail if it cannot. Debian packages are normally not signed individually at all — the trust chain lives in the signed repository index — so a loose `.deb` genuinely has nothing to verify, which is exactly why it is a weaker distribution channel.

The low-level tool is a warehouse worker who will shelve exactly the crate you wheel in and complain if a labelled part is missing; the resolver is the logistics planner who reads the catalogue, orders every missing part, and sequences the deliveries.

saying these in an interview costs you the question

  • Claiming dpkg and apt are interchangeable tools
  • Saying the low-level installer downloads missing dependencies itself
  • Thinking a downloaded package file contains its dependencies
  • Believing repository metadata lives inside the package file
  • Assuming forcing an install past dependency errors is harmless

context