dnf module streams on Rocky and Alma 9
Read the [d] and [e] markers in dnf module list, pick or switch an AppStream stream on Rocky and Alma 9, and see what EL10 deprecation means for upgrades.
What a dnf module stream is on Rocky and Alma 9
A dnf module stream is one version line of an application in the AppStream repository on Rocky Linux 9 and AlmaLinux 9. You pick a stream, and dnf offers you only that stream's packages. Use dnf module list to see the streams, dnf module enable or dnf module install to pick one, and dnf module switch-to to move to another.
AppStream (Application Stream) is the repository that carries user-space applications on Enterprise Linux (EL) 9. Red Hat's documentation for RHEL 9 (Red Hat Enterprise Linux 9) says content in AppStream can be available in multiple versions, and those versions are module streams. AlmaLinux's own AppStream guide adds that the repository holds both modular and non-modular packages. Many packages you install are plain packages, and the stream rules never touch them.
DNF's documentation calls a stream "a virtual repository": a collection of packages, written as name:stream. Two rules from the same page explain almost every surprise in this guide:
- Only one stream of a module can be active at a time.
- A stream is active if it is marked as the default, or if a user enabled it.
Rocky and Alma rebuild RHEL 9, but the modules and streams on offer depend on the minor release and on the repository state on the day you look. So this guide does not name streams for you. Every command below prints them from your own server. In the commands, NAME is a module name, STREAM is a stream, and PACKAGE is a package name. Replace them with what dnf module list shows you.
If you come to Rocky or Alma from Debian or Ubuntu, the dnf and apt command equivalents cover the everyday commands. Streams are an extra layer on top of those.
How do I list module streams with dnf?
dnf module list
dnf module list NAME
dnf module list --enabled
dnf module list --installedThe first command lists every module stream, with its profiles and its state. Add a module name to see one module. --enabled shows only enabled streams. --installed shows the streams that have an installed profile. A profile is a named set of packages inside a stream. Some streams have one profile and some have several.
The output carries a legend line. Copy the markers from it, not from memory:
Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalledRead the markers like this, following Red Hat's own nodejs example:
[d]after a stream: the distribution marked this stream as the default.[d]after a profile: this is the default profile of that stream.[e]after a stream: this stream was enabled, by you or by a command you ran.[x]: the module is disabled, so none of its streams are available.[i]after a profile: this profile is installed.
A module where no stream carries [d] or [e] has no active stream. Its packages are not in the set dnf offers, because only an active stream adds its packages to that set. This is why dnf install can fail to find a package that dnf module list clearly shows: the stream exists, but nothing has made it active.
Read a stream before you pick it: dnf module info
dnf module info NAME
dnf module info NAME:STREAM
dnf module info --profile NAME:STREAMdnf module info prints detailed information about a stream. With --profile it prints detailed information about the stream's profiles, including the packages each one installs. Read this before you enable anything, because a profile can pull in more packages than its name suggests.
The DNF docs accept a module in the form NAME:STREAM:VERSION:CONTEXT:ARCH/PROFILE, and shorter forms of it, such as NAME, NAME:STREAM or NAME/PROFILE. These are forms you type on the command line. The output of dnf module info does not echo them back as one string, so read the details from the lines it prints on your server. If you leave out the stream, dnf uses the enabled stream first and the default stream second. So dnf module info NAME on an enabled module shows you the stream you chose.
Enable a stream, then install from it
sudo dnf module enable NAME:STREAM
dnf module list NAMEenable makes the stream's RPMs (the package files) available in the package set. It installs nothing. The second command should now show [e] next to the stream you picked. If another stream of the same module is already enabled, dnf cannot hold both, because only one stream can be active. Use switch-to for that case, which is covered below.
To install from the stream, either install the package by its name as usual, or install a profile:
sudo dnf module install NAME:STREAM
sudo dnf module install NAME:STREAM/PROFILEdnf module install installs profiles with their packages. Without a profile it installs all default profiles of the stream. The DNF docs say module streams get enabled accordingly, so you do not need a separate enable first. Red Hat's RHEL 9 docs add that installing a profile or packages from a stream can enable further module streams. Check what you ended up with:
dnf module list --enabled
dnf module list --installedBoth lists should match what you meant to do. A stream in --enabled that you never asked for came in with the one you did ask for.
Once a stream is active, the package set holds only that stream's builds of its packages, which means a normal sudo dnf upgrade moves you to newer builds inside the stream and not to the next stream. That is the point of streams. If you need an exact version inside a stream to stay put, pinning one package version with dnf versionlock is the tool for that job.
Change streams with dnf module switch-to
First check that your dnf has the subcommand:
dnf module switch-to --helpThe help text should describe switch-to. If it does not, your dnf is older than this guide assumes, and you should read your release's own documentation before you change streams.
The DNF docs describe switch-to like this: it switches to, or enables, a stream, changes installed packages to the versions the new stream provides, and removes packages of the old stream that the new stream no longer has. Red Hat's RHEL 9 docs say that when you switch to a later stream, all respective packages are replaced with their later versions, and they advise a backup of your data first. dnf replaces packages. It does not convert an application's data files, so a backup is the step that lets you go back.
Look at the transaction before you run it:
sudo dnf module switch-to NAME:STREAM --assumeno
sudo dnf module switch-to NAME:STREAM
dnf module list NAMEThe first line prints what would change and what would be removed, then answers no for you. Read the removal list carefully. The last line should show [e] on the new stream. The switch is one dnf transaction, so it appears in dnf history. Before you count on rolling back a dnf transaction with dnf history, test the undo on a copy of the server, because a stream switch changes module state as well as packages.
Reset or disable a module
sudo dnf module reset NAME
sudo dnf module disable NAMEreset returns the module to its initial state: neither enabled nor disabled. Red Hat's RHEL 9 docs say it erases the enabled stream and the installed-profile record, and that it removes no installed content. If the module has a default stream, that default becomes active again, because a module with a default stream always has one stream active.
The upstream DNF docs word reset differently from Red Hat's, so check on your own server. Run rpm -q PACKAGE before and after, and run sudo dnf upgrade --assumeno before a real upgrade. Packages from the old stream can still be installed while the package set now offers a different stream, and the dry run shows you what dnf would do about that.
disable disables the module, and all its streams become unavailable. Red Hat's docs say this also removes no installed content. dnf module list should show [x] on the module afterwards.
Is this package from a module? Reading the release field
A common question on EL9 is why some packages carry a long release string, with parts joined by + signs, while most packages do not. Do not guess from the string. Ask dnf first:
dnf module provides PACKAGEdnf module provides lists the modular packages that match the name, from all modules, including disabled ones. If it prints nothing, no module ships a package by that name, so the stream rules do not apply to it. If it prints a module and stream, you have found a modular package.
Now print its release field, and the release field of a plain package next to it:
rpm -q --qf '%{NAME} %{VERSION} %{RELEASE}\n' PACKAGE
dnf repoquery --qf '%{name} %{version} %{release} %{reponame}' PACKAGE
rpm -q --qf '%{NAME} %{VERSION} %{RELEASE}\n' bashrpm -q reads the installed package. dnf repoquery reads the repositories, so it also works for a package you have not installed. If a tag name is rejected, dnf repoquery --querytags lists the tags your dnf knows. To see every package one stream ships, run dnf module repoquery NAME:STREAM.
Then compare the two release strings. The plain package's release is short, a number followed by an el9 tag, while the modular package carries extra parts joined by +. Rocky Linux's CVE hygiene guide breaks down an example modular release string from EL8, pcs-0.10.12-6.el8.6.0+7105+f31cb332.x86_64. After the package name, the upstream version, the RPM release number 6 and el8, it reads .6.0 as the module stream built for the 8.6 minor release, +7105 as the module build sequence number, and +f31cb332 as the context hash identifying the module build. The same guide notes that the stream suffix indicates when the module was built, not the security content of the package. For practical work, dnf module provides is the answer that counts.
Why does a package from another repo disappear?
This is the module behaviour that hurts most in daily use. The DNF docs say non-modular packages are filtered out when their name or provide matches a modular package name. In practice, a third-party repository can ship a package with the same name as a modular one in AppStream, and dnf hides the third-party package. dnf install then offers the modular build, or nothing at all.
The EPEL and CRB repos on Rocky and Alma guide covers this case for EPEL. The check is the same for any repository:
dnf module provides PACKAGE
dnf list --showduplicates PACKAGEIf the first command names a module, that module is the reason the other repository's package is hidden. The second command lists the versions dnf is willing to offer you.
A repository can opt out of this filtering. The DNF option module_hotfixes is a boolean, and its default is false. Setting it true disables module RPM filtering and makes all RPMs from that repository available. Add it to the repository's own section in its file under /etc/yum.repos.d/:
[REPOID]
# keep the existing lines of this section as they are
module_hotfixes=1Then run dnf list --showduplicates PACKAGE again. The third-party version should now appear. Set this only on a repository you trust to replace the modular package, because from then on dnf treats that repository's builds as normal candidates.
What happens to dnf modules on Rocky and Alma 10?
Modules are deprecated in the 10 releases. The vendors describe deprecation, not removal.
Red Hat's RHEL 10.2 release notes say that modularity is deprecated in RHEL 10 and will be removed in a future major release, that the dnf module command prints a deprecation warning, and that no modular content is distributed with RHEL 10. The same notes say Red Hat does not intend to provide any Application Streams that use modularity as the packaging technology, and that the module Kickstart command is deprecated. The upstream DNF docs carry their own notice: modularity is deprecated, and the functionality will be removed in a future release of DNF5.
Rocky Linux's 10.0 release notes say DNF modularity is deprecated and that Rocky does not intend to provide AppStream content as modules in Rocky Linux 10. Those notes also describe the dnf module command as phased out, which is stronger wording than Red Hat's deprecation warning. AlmaLinux's 10.0 release notes list Alma's own changes against RHEL, do not mention modules, and point to the upstream RHEL release notes for the full list of changes.
The commands in this guide were not run on a 10 system. If you have one, check it yourself:
cat /etc/os-release
dnf --version
dnf module listThe first line confirms the release. The second shows which dnf you have, because the vendor pages quoted here do not settle that. The third shows what your dnf does with the module command today, whether that is a warning or an error.
What do modules mean for an ELevate upgrade from 9 to 10?
ELevate is AlmaLinux's in-place upgrade tool. Its page lists upgrades from 9.x to 10.x within the same distribution, and its quickstart names AlmaLinux 9 or CentOS Stream 9 as the source for an upgrade to 10. The same page says ELevate no longer supports Rocky Linux, and Rocky's own 10.0 notes say Rocky does not support upgrades to any major release. On Rocky 9, the path to 10 is a fresh install with your data moved across, and securing a new Rocky Linux server covers the first steps on that new box.
The ELevate quickstart and wiki say nothing about modules. They do say two things that matter here: EPEL support is available only for upgrades to AlmaLinux, and EL 9 packages that are unavailable for the new release remain on the system after the upgrade. Put that next to Red Hat's note that no modular content ships with RHEL 10, and one inference follows. This is not a vendor statement. A package you installed from a 9 stream has no stream to land in on 10, so it either gets replaced by a plain package of the same name, or it stays behind as a leftover EL 9 package.
So record your module state before the upgrade, while the commands still behave as they do on 9:
dnf module list --enabled > ~/modules-enabled-before-upgrade.txt
dnf module list --installed > ~/modules-installed-before-upgrade.txtAfter the upgrade, check each package that came from those streams with rpm -q --qf '%{NAME} %{VERSION} %{RELEASE}\n' PACKAGE. A release that still carries the el9 tag, or the +-joined module parts shown earlier, marks a package left over from a 9 stream. Replace each leftover before you trust the server. The full procedure is in upgrading AlmaLinux 9 to 10 with ELevate.
FAQ
What do [d], [e] and [x] mean in dnf module list?
dnf module list prints the legend Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalled. [d] on a stream marks the distribution's default stream, and on a profile it marks the default profile. [e] marks the stream that was enabled. [x] means the module is disabled, so none of its streams are available. [i] marks an installed profile. A module with no [d] or [e] has no active stream, so its packages are not offered.
Why can't dnf find a package from EPEL or another repo on Rocky or Alma 9?
dnf filters out non-modular packages whose name or provide matches a modular package name, so a third-party package can be hidden by an AppStream module. Run dnf module provides PACKAGE to see whether a module claims the name. If you trust that repository, add module_hotfixes=1 to its section under /etc/yum.repos.d/, which turns off module filtering for that repository only.
How do I switch a dnf module to a different stream on Rocky or Alma 9?
Run dnf module switch-to --help first to confirm your dnf has the subcommand. Back up the application's data, then preview with sudo dnf module switch-to NAME:STREAM --assumeno and run it again without --assumeno. dnf changes installed packages to the new stream's versions and removes old-stream packages the new stream does not have. dnf module list NAME should then show [e] on the new stream.
Are dnf modules gone in Rocky Linux 10 and AlmaLinux 10?
They are deprecated. Red Hat's RHEL 10.2 release notes say modularity is deprecated and will be removed in a future major release, and that no modular content ships with RHEL 10. Rocky's 10.0 notes say Rocky does not intend to provide AppStream content as modules. Run dnf --version and dnf module list on your own 10 system to see how your dnf treats the command.