Modular DNF Behavior

This page captures the key behaviors of modular DNF.


  • Ursine ("bare") packages are those that are not part of any module.

  • A module’s "context" is a unique hash value generated by the build system to distinguish binaries built for different Fedora releases as a result of stream expansion. See [module-stream-expansion].


  • Existing use of RPM-based operations must not change and must continue to work just as they always have.

  • DNF install/update commands can be invoked by using syntax of either dnf module <command> $modspec …​ or dnf <command> @$modspec …​.

  • The "platform" pseudo-module cannot be explicitly enabled, installed, deleted, or have its stream changed.

  • A module is specified by its name, stream, version, context, and architecture (e.g., "module:stream:version:context:arch").

    • If a module has a default stream defined on a system, "stream" may be omitted. Otherwise, "stream" must be explicitly provided.

    • For a given "module:stream", "version" can always be omitted. If "version" is not explicitly provided, the latest "version" for the given "module:stream" will be chosen.

    • If the module "context" is not specified, DNF will use heuristics to determine the appropriate "context". See [module-stream-expansion].

    • If the module "arch" is not specified, the system’s base architecture will be used.

    • Specifying a non-existent "module" name should fail.

    • Specifying a non-existent "stream" (for a valid "module") should fail.

    • Specifying specifying a non-existent "version" (for a valid "module:stream") should fail.

    • Specifying specifying a non-existent "context" (for a valid "module:stream:version") should fail.

    • Specifying a non-existent "arch" (for a valid "module:stream:version:context") should fail.

System modular defaults

  • DNF must look for modular default stream and installation profile data in the repodata of the package installation repos—​which is sourced from [fedora-module-defaults-repo] during the Fedora build and release process.

  • DNF must look for override data for modular default stream and installation profile on the local system in /etc/dnf/modules.defaults.d/.

Module listing

  • DNF must be able to list all modular content (modules, streams, enabled streams, default streams, profiles, module packages, profile packages).

Module enablement

  • Enabling a module stream makes all of its packages available on the system, but does not install them.

  • At most one stream of a module may be enabled at a time on a system.

  • Enabling a different stream of a module must be confirmed by the user (or "--assumeyes").

  • Enabling a different stream of a module will automatically disable the old stream.

Module Auto-enablement

  • If an uninstalled/unenabled module has a valid default stream configured, DNF will consider the default stream of the module and all of its packages available for resolving dependencies—​and will automatically enable the default stream of that module if any packages from it are installed directly or indirectly (to resolve dependencies).

  • If an uninstalled/unenabled module:stream is listed as a runtime dependency of another module being installed or enabled, DNF will automatically enable that dependency.

  • Once a particular stream of a module has been enabled, DNF may not automatically enable a different stream.

Module/package installation

  • Installing a module enables the specified stream (or default stream, if not specified) and installs all of the packages associated with the specified profile (or "default" profile, if not specified).

  • If a module does not explicitly have a "default" profile specified it its modulemd, DNF must pretend that it exists and is empty. See [mmd-spec-v2].

  • Each profile of a module stream must be able to be installed. However, a module’s profiles may conflict amongst themselves such that they cannot all be installed at the same time. (A hypothetical example would be a module that provides something analogous to the coreutils and coreutils-single packages in different profiles. The coreutils packages provide the same functionality, but conflict.)

Module update

  • Updating a module will update all installed packages that belong to the enabled module stream—​regardless if the packages were installed by an install profile or ad hoc.

Module disablement

  • Disabling a module does not remove any packages that belong to the module.

  • Disabling a module disables modules that depend on it—​unless they still have packages installed.

Module removal

  • Uninstalling a module removes all the packages that belong to the module and disables it.

  • Ad hoc removal of all packages from an installed module does not disable the module.

Module locking

  • A locked module cannot have a different stream enabled or be disabled—​without first unlocking it.

Stream expansion and contexts


  • Any package in an enabled module takes priority over any ursine RPM with the same package name, regardless of which repositories those modules and packages may be in.

  • If there’s an ursine or modular RPM with a higher NVR than the hotfix one, the ursine or modular one wins. This is to ensure new proper updates override the temporary hotfix RPMs.