How to Use dnf history

`dnf history` tracks every package transaction on your Fedora system, letting you review, undo, or replay any past install, upgrade, or removal.

You upgraded and now the system is broken

You ran dnf upgrade last night. This morning the desktop fails to start, or a critical service refuses to bind to a port. You need to know exactly what changed, when, and how to reverse it without reinstalling the OS. Or perhaps you installed a development toolchain three weeks ago and now you want to audit which packages it pulled in as dependencies. dnf history is your audit log. It tracks every package change, every version bump, and every removal. It is the only reliable way to reverse a bad transaction or investigate a dependency drift.

What is actually happening

DNF operates as a transactional package manager. A transaction is a grouped set of changes that either all succeed or all fail. When you run dnf install or dnf upgrade, DNF calculates the dependency tree, downloads the payloads, applies the changes, and writes the result to an SQLite database at /var/lib/dnf/history.sqlite. Each transaction receives a unique ID number. This ID is your handle for inspection, undo, and replay.

The history database grows over time. It is small, usually a few megabytes, but it contains the complete state history of your package manager. If you delete it, you lose the ability to undo. Treat it like a journal. You do not throw away your journal because it got thick.

Think of dnf history like version control for your system state. Every transaction is a commit. You can inspect the diff, revert a commit, or replay a commit. The difference is you cannot merge branches. You can only move forward or backward along the timeline. Undoing a transaction creates a new transaction that reverses the changes. This means you can undo the undo. This safety net exists because reversions can sometimes introduce new conflicts.

Check the ID before you act. Blindly undoing a transaction can break dependencies you did not notice in the summary.

Inspect and reverse transactions

Start by listing recent transactions. You need the ID to do anything useful. The ID column appears on the far left of the output.

# List the last 10 transactions. The ID column on the left is your handle for all other commands.
# No sudo needed here. This only reads the local database.
# The output shows ID, Command line, Date and time, and Altered.
dnf history

Before you undo, look at what happened. info shows the packages, versions, and the command that triggered the transaction. Always inspect before acting. A transaction might look harmless in the summary but contain a critical library downgrade in the details.

# Show full details for transaction 42.
# sudo is required to read the full package list and version strings.
# The output lists every package installed, upgraded, downgraded, or erased.
# Look for "Upgraded:" and "Downgraded:" sections to spot version changes.
sudo dnf history info 42

Reversing a transaction restores the system to the state exactly before that transaction ran. DNF downgrades upgraded packages and reinstalls removed packages. This creates a new transaction in the history log.

# Reverse transaction 42.
# DNF will downgrade upgraded packages and reinstall removed packages.
# This restores the system to the state exactly before transaction 42 ran.
# A new transaction ID will be created for this undo operation.
sudo dnf history undo 42

Rolling back undoes every transaction after a specified ID. Use this when multiple updates caused a cascade of issues and you want to return to a known good state.

# Roll back to the state after transaction 40.
# This undoes every transaction with an ID greater than 40.
# Use this when multiple updates caused a cascade of issues.
# Be cautious: this can downgrade many packages at once.
sudo dnf history rollback 40

Replaying re-applies a transaction. This is useful when a transaction failed due to a transient network error and you want to retry the exact same payload. DNF checks if packages are already installed and skips them if so.

# Replay transaction 42.
# Useful if a transaction failed mid-way and you want to retry the exact same set.
# DNF checks if the packages are already installed and skips them if so.
# This is safer than re-typing the command, which might resolve dependencies differently.
sudo dnf history replay 42

Filtering helps you track specific packages or actions. Use list with filters to narrow the view.

# List only transactions that installed packages.
# Helps track when a specific package first appeared on the system.
# Useful for auditing when a dependency was introduced.
dnf history list --action=install

# List transactions involving a specific package.
# Shows every time firefox was touched, upgraded, or removed.
# Use this to trace the lifecycle of a package across updates.
dnf history list firefox

Run journalctl -xe after a failed undo. The error message will tell you if a dependency is missing or if a file conflict blocked the reversion.

Verify the state

After an undo or rollback, verify the new transaction. The history log records the reversion as a new entry. Check the details to confirm the package versions returned to the expected state.

# Check the new transaction created by the undo.
# The ID will be higher than the one you undid.
# Verify the package versions returned to the expected state.
# "last" is a shorthand for the most recent transaction ID.
dnf history info last

Reboot before you debug. Half the time the symptom is gone after the kernel or library versions align.

Common pitfalls and error patterns

Undoing a transaction that installed a new kernel does not remove the old kernel automatically. It reinstalls the old kernel. You might end up with two kernels. The bootloader might still point to the new one. Check /boot and run dnf remove for the unwanted kernel if needed. Also, undo can fail if dependencies have changed since the original transaction. DNF tries to resolve this, but if a package was removed from the repository, the undo will abort. You cannot undo into a state that requires a package no longer available in your enabled repos.

The dnf history undo command will refuse to proceed and print Error: Transaction test error: package X conflicts with Y. This often happens during undo if the current state has diverged significantly. Check the repo status. If the repo is disabled, re-enable it temporarily. Run dnf upgrade --refresh to sync metadata before attempting the undo again.

The history database can grow large on systems with frequent updates. Use dnf history clean to trim old entries. This removes transactions from the database but does not affect the current system state. You lose the ability to undo those old transactions.

# Keep only the last 20 transactions in the history database.
# This frees disk space and speeds up history queries.
# You cannot undo transactions older than the kept count.
# Use this periodically on systems with high update frequency.
sudo dnf history clean 20

Convention aside: dnf upgrade --refresh is the normal weekly maintenance command. dnf system-upgrade is for crossing major Fedora releases. Both create history entries. system-upgrade entries are marked differently in the database. You can undo a system-upgrade, but it is safer to use a snapshot for major release rollbacks.

Snapshot the system before the upgrade. Future-you will thank you.

When to use history vs alternatives

Use dnf history undo when you need to reverse a single transaction that broke a specific application or driver. Use dnf history rollback when a batch of updates caused system instability and you want to return to a known good state. Use dnf history replay when a transaction failed due to a transient network error and you want to retry the exact same payload. Use dnf history info when you need to audit what changed during an upgrade or investigate a dependency conflict. Use dnf history list with filters when you are tracking the lifecycle of a specific package across multiple updates. Use Btrfs snapshots when you need to recover the entire filesystem state, including configuration files and user data, not just packages.

Where to go next