DNF-PRE-TRANSACTION-ACTIONS(8)

πŸ“¦ version 4.7.0, in centos-stream 10

πŸ’… dnf4-pre-transaction-actions(8) β€” the pre-transaction-actions plugin, explained

okay so this is the <pink>dnf4-pre-transaction-actions</pink> manual page, straight out of the dnf-plugins-core fam. it's a plugin page, it's giving "small but powerful", and we're gonna read it together 🫢


✨ NAME ✨

dnf4-pre-transaction-actions β€” the DNF pre transaction actions Plugin. that's the whole name bestie, no notes πŸ’…


🌸 DESCRIPTION 🌸

so here's the vibe: this plugin lets you define actions that get executed right when an RPM transaction starts. like, the moment the transaction kicks off, not after. got it? πŸ‘‘

each action can define a filter rule β€” glob-like, we love a glob β€” on either the package NEVRA or the package files. and it also cares whether the package was installed or removed. yep, that's a thing you get to specify.

and where do all these actions live? in action files. of course. everything's a file. slay.


πŸŽ€ CONFIGURATION πŸŽ€

the plugin config lives at /etc/dnf/plugins/pre-transaction-actions.conf β€” write that down πŸ“

and heads up: all the configuration options go in the [main] section. all of them. no cap.

  • enabled β€” whether the plugin is on or off. default value is True. so yeah, she's enabled by default, main character energy from the start ✨
  • actiondir β€” path to the directory that holds your action files. important: those action files must have the .action extension, or they don't count, periodt. default value is "/etc/dnf/plugins/pre-transaction-actions.d/".

πŸ¦‹ ACTION FILE FORMAT πŸ¦‹

okay so inside the action files:

empty lines? ignored. lines that start with a # character? also ignored. we love a comment, we love whitespace, we love a clean aesthetic πŸ’–

every non-comment line defines exactly one action, and it's built from three items separated by colons:

package_filter:transaction_state:command

let's break down each piece ⬇️

πŸ“ package_filter

a (glob-like) filtering rule that gets applied on the package NEVRA β€” that includes the shortened forms too β€” or on the package files. flexible, iconic.

🌈 transaction_state

this one filters packages based on their state in the transaction. three flavors:

  • in β€” packages that will appear on the system. that's downgrade, install, obsolete, reinstall, upgrade πŸ’š
  • out β€” packages that will disappear from the system. that's downgraded, obsoleted, remove, upgraded πŸ’”
  • any β€” literally all packages. no filter, no thoughts, head empty 🫧

⭐ command

any shell command you want. and here's the cute part β€” the following variables inside the command get substituted for you:

  • ${name}, $name β€” package name
  • ${arch}, $arch β€” package arch
  • ${ver}, $ver β€” package version
  • ${rel}, $rel β€” package release
  • ${epoch}, $epoch β€” package epoch
  • ${repoid}, $repoid β€” package repository id
  • ${state}, $state β€” the change of package state in the transaction, and the possible values are: "downgrade", "downgraded", "install", "obsolete", "obsoleted", "reinstall", "reinstalled", "remove", "upgrade", "upgraded"

so the shell command gets evaluated for each package that matched both the package_filter and the transaction_state. but β€” and this is the part people miss 😭 β€” after the variable substitution happens, any duplicate commands get removed, and each command only gets executed once per transaction. once. that's it. don't come for her.

the order of execution of the commands follows the order in the action files, but it may differ from the order of packages in the transaction. i know, i know. in other words (and the page literally spells it out): when you define several action lines for the same package_filter, those lines get executed in the order they were defined in the action file when the package_filter matches a package during the trasaction_state state. however β€” the order of when a particular package_filter gets invoked depends on the position of the corresponding package in the transaction. so it's a vibe, not a guarantee, iykyk πŸ”₯


🧚 an example action file 🧚

here it is, verbatim bestie, we're copying it exactly:

# log all packages (state, nevra, repo) in transaction into a file.
*:any:echo '${state} ${name}-${epoch}:${ver}-${rel}.${arch} repo ${repoid}' >>/tmp/pre-trans-actions-trans.log

# The same shell command (after variables substitution) is executed only once per transaction.
*:any:echo '${repoid}' >>/tmp/pre-trans-actions-repos
# will write each repo only once to /tmp/pre-trans-actions-repos, even if multiple packages from
# the same repo were matched

look at that. the first line logs every package (state, nevra, repo) in the transaction into a file. the second one writes each repo only once to /tmp/pre-trans-actions-repos, even if multiple packages from the same repo got matched. dedupe queen πŸ‘‘


πŸ‘‘ AUTHOR πŸ‘‘

See AUTHORS in your Core DNF Plugins distribution. that's where the credit lives πŸ’œ


2026, Red Hat, Licensed under GPLv2+. respect the license, it's the law, periodt.


<div align="center">πŸŽ€ ✨ πŸŽ€</div>

so yeah β€” that was dnf4-pre-transaction-actions(8) from dnf-plugins-core, version 4.7.0, dated Aug 10, 2026, and if you read all the way here you're genuinely my favorite person 🌸 go write an action file, you're gonna eat πŸ«ΆπŸ’–

πŸ“¦ where this page comes from