Running Parallel Stacks: AppStream Modularity on CentOS Stream
AppStream modularity on CentOS Stream allows you to run specific versions of software like Node.js without replacing the base OS. Learn how to manage module streams and verify your environment.
08 Jul 2025, 10:19 UTC

The problem: one OS, two stacks
A team needs Node.js 18 for a legacy application, but the system default is Node.js 20. Rebuilding the base OS or managing manual binaries is risky and tedious. On CentOS Stream, AppStream modularity is the practical engineering answer: dnf can install a specific module stream, leave the rest of the system untouched, and allow you to switch versions without reinstalling the operating system.
Modularity is the decision to treat the operating system as a set of versioned streams rather than a single, monolithic package set. This approach allows the OS to remain stable while the application stack moves at its own pace.
What AppStream modularity actually does
CentOS Stream, following the RHEL model, splits packages into BaseOS (the core minimal OS) and AppStream (user-facing software). For packages that require multiple supported versions, Red Hat publishes modules. A module is a named collection of package versions, and a stream corresponds to a specific version line, such as Node.js 18 or Node.js 20.
By enabling a specific stream, you tell the package manager to prioritize that version line over the default. This prevents the "dependency hell" typically associated with installing multiple versions of the same runtime on a single system.
Verify your environment
Before modifying modules, you must confirm your distribution identity. Run the following commands on your terminal:
cat /etc/os-release
cat /etc/centos-releaseYou must know if you are running CentOS Stream 8, 9, or a later release, as module names and available streams differ between major versions. Next, verify that the AppStream repository is active:
dnf repolistLook for appstream in the output. If it is missing, modularity will not function.
Worked Example: Selecting a Node.js Stream
Suppose you need Node.js 18 on CentOS Stream 9. Follow these steps using root or sudo permissions:
- List available streams: Identify which versions are offered by the repository.
- Inspect a specific stream: Check the details of the version you intend to use.
- Switch the stream: Reset the current module state to clear defaults, enable the target stream, and install.
- Verify the installation: Confirm the binary version and the RPM package.
dnf module list nodejsdnf module info nodejs:18sudo dnf module reset nodejs
sudo dnf module enable nodejs:18
sudo dnf install nodejsnode --version
rpm -q nodejsRisk Note: The dnf module commands change the system state. Always execute these on a staging environment before applying them to production servers.
Trade-offs and Limitations
Modularity provides flexibility, but it introduces a management overhead. If you do not explicitly pin a stream, a future dnf update might pull a different version if the default stream changes. The best practice is to explicitly enable the stream in your configuration management (e.g., Ansible or Terraform) rather than relying on defaults.
Furthermore, CentOS Stream is a rolling preview for RHEL. Unlike the legacy CentOS Linux, it is not a fixed-point release. Continuous updates mean that regressions can occur between point-in-time snapshots. For production stability, you must validate updates on a schedule.
Finally, modularity does not solve conflicts between different modules that provide the same package; you must choose one. For those still using CentOS Linux 7 or 8, remember these are End of Life (EOL). While the CentOS Vault preserves packages for reproducibility, these archives receive no security updates, requiring explicit risk acceptance for legacy use.
Practical Verification
To confirm the operation was successful and persists, run:
dnf module list --enabled nodejsThe output should clearly show the stream you selected as [e] (enabled). The final actionable check is to launch your application and perform a smoke test to ensure the specific runtime version is compatible with your code.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.