Fedora Workstation vs Fedora Server vs Fedora IoT

Which Edition Do You Need?

Fedora publishes three major editions — Workstation for desktop users, Server for headless infrastructure, and IoT for embedded and edge devices — each optimized for a different hardware and use-case profile.

You downloaded the ISO and the installer asked you to pick an edition

You mount the Fedora image, start the installer, and the screen asks you to choose between Workstation, Server, and IoT. The names sound straightforward until you realize they share the exact same package repository, the same kernel, and the same six-month release cycle. You pick Server for a home lab, boot into a blinking cursor, and wonder where your desktop went. You pick IoT for a Raspberry Pi, try to install a text editor, and get a transaction error. The confusion comes from assuming these are different operating systems. They are not. They are different default configurations built on the same foundation.

What is actually happening

Fedora packages everything into a single upstream repository. The editions are just curated starting points. Workstation ships with a graphical target, a display server, and a mutable filesystem. Server strips the GUI, enables remote management tools, and stays mutable. IoT flips the filesystem to read-only, replaces the package manager with an atomic updater, and expects you to run workloads in containers. The underlying RPM packages are identical. The difference is how the system boots, how it updates, and what tools expect to find on disk.

Think of it like a car manufacturer. The engine, transmission, and chassis are the same. Workstation comes with leather seats, a navigation screen, and a sunroof. Server comes with a roll cage, heavy-duty suspension, and no radio. IoT comes stripped to the frame with a specialized telemetry system and a sealed engine bay. You can swap parts between them, but the factory defaults dictate how you drive.

How the filesystem and boot process differ

The core distinction lies in mutability. Workstation and Server use a traditional Linux filesystem layout. You can edit files in /etc/, install packages with dnf, and remove them later. The system state changes incrementally. This is the standard Linux model. You install a package, the files land in /usr/, and the package manager tracks them in a local database.

IoT uses a transactional, immutable filesystem. The root filesystem is mounted read-only. You cannot run dnf install to add packages directly to the host. Instead, the system uses rpm-ostree to compose a new bootable image that includes your changes. The old image stays on disk as a rollback point. This model prevents configuration drift and ensures the system always boots to a known-good state.

Convention aside: dnf upgrade --refresh is the normal weekly maintenance command for mutable systems. It forces a metadata refresh before applying updates. dnf system-upgrade is a different command entirely. Use dnf system-upgrade only when crossing major Fedora releases. They do the same thing under the hood, but the flags and safety checks differ.

Managing mutable systems

Both Workstation and Server use a traditional mutable filesystem. You can edit files in /etc/, install packages with dnf, and remove them later. The system state changes incrementally. This is the standard Linux model. You install a package, the files land in /usr/, and the package manager tracks them in a local database.

Here is how you install a package on a mutable system and start the service.

# Install a package on a mutable system
sudo dnf install nginx
# WHY: dnf resolves dependencies, downloads RPMs, and writes them to the filesystem.
#      The system state changes immediately.
sudo systemctl enable --now nginx
# WHY: Enables the service to start on boot and starts it immediately.
#      systemd creates the symlink in /etc/systemd/system/ automatically.

Workstation and Server differ only in their default target and preinstalled software. Workstation boots to graphical.target and includes GNOME, Xorg, and multimedia codecs. Server boots to multi-user.target and includes Cockpit, firewalld, and infrastructure packages. You can install a desktop on Server or strip the GUI from Workstation, but the default boot target and service configuration will match the edition you chose.

Convention aside: systemctl status <unit> shows recent log lines AND state in one view. Always check status before restart. If the service is failing, restarting it without reading the logs just repeats the error.

Managing immutable systems

IoT uses a transactional, immutable filesystem. The root filesystem is mounted read-only. You cannot run dnf install to add packages directly to the host. Instead, the system uses rpm-ostree to compose a new bootable image that includes your changes. The old image stays on disk as a rollback point. This model prevents configuration drift and ensures the system always boots to a known-good state.

Here is how you add a package to the immutable image and activate it.

# Add a package to the immutable image
sudo rpm-ostree install nginx
# WHY: rpm-ostree stages the package into a new boot tree.
#      It does not modify the running filesystem.
sudo reboot
# WHY: The new image only activates after a reboot.
#      The bootloader switches to the new tree automatically.

After the reboot, the system verifies the new image using greenboot. If the health checks pass, the system stays on the new image. If they fail, it automatically rolls back to the previous tree. You never manually edit files in /usr/lib/. You deploy containers or use rpm-ostree overlays for custom files. The host stays clean.

Convention aside: journalctl -xe reads better than journalctl alone. The x flag adds explanatory text and the e flag jumps to the end. Most sysadmins type journalctl -xeu <unit> muscle-memory style. On immutable systems, check journalctl -u greenboot after a reboot to see if the health checks passed.

Verifying the update mechanism

The biggest mistake new users make is running the wrong update command. Mutable systems expect dnf. Immutable systems expect rpm-ostree. Running dnf upgrade on IoT will print a transaction error because the root filesystem is read-only. Running rpm-ostree upgrade on Workstation will fail because the transactional tool is not installed.

Here is how you check which package manager handles OS updates.

# Check which package manager handles OS updates
rpm -q rpm-ostree 2>/dev/null && echo "Immutable" || echo "Mutable"
# WHY: Checks if the rpm-ostree package is installed.
#      Its presence indicates an immutable base image.

If the output says Immutable, you must use rpm-ostree upgrade. If it says Mutable, you must use dnf upgrade. Verify the update succeeded by checking the deployment status or the package version.

Here is how you verify the current deployment on immutable systems.

# Verify the current deployment on immutable systems
rpm-ostree status
# WHY: Shows the current boot tree, pending deployments, and rollback options.
#      Look for the "Deployments" section to confirm the active version.

Check the active deployment hash. Compare it to the pending hash if you just ran an upgrade. The system will automatically switch to the new tree on the next reboot. Trust the package manager. Manual file edits drift, snapshots stay.

Common pitfalls and error messages

You will hit a wall if you try to force mutable commands onto an immutable system. The error is explicit.

Error: Transaction test error:
  file /usr/lib/systemd/system/nginx.service from install of nginx-1:1.24.0-1.fc39.x86_64 conflicts with file from package rpm-ostree-2024.1-1.fc39.x86_64

This error means you are trying to modify a read-only tree. Stop. Use rpm-ostree install instead. The same applies to configuration files. Files in /etc/ are user-modified. Files in /usr/lib/ ship with the package. Edit /etc/. Never edit /usr/lib/. On immutable systems, /etc/ is a symlink to /etc/ managed by rpm-ostree overlays. Changes persist across reboots because they are baked into the next boot tree.

Another common trap is assuming Cockpit works the same way on all editions. Cockpit is a web console that talks to systemd and dnf. On Workstation, it manages desktop services. On Server, it manages infrastructure roles. On IoT, it is usually disabled by default because the system expects container orchestration or SSH management. If you need a web UI on IoT, you will have to enable it manually and accept that it cannot trigger atomic updates.

Convention aside: firewall-cmd --reload after every rule change. Otherwise the runtime config and the persistent config diverge. This applies to all editions. If you add a service on Server and forget to reload, remote connections will fail until you reboot.

SELinux denials show up in journalctl -t setroubleshoot with a one-line summary. Read those before disabling SELinux. Fedora ships with SELinux enforcing by default on all editions. Disabling it breaks the security model and often masks the real configuration error.

When to use each edition

The choice depends on your hardware, your update tolerance, and your management style. Use Workstation when you sit at the keyboard and need a graphical environment for development or daily tasks. Use Server when you are deploying a headless machine that you will manage over SSH or Cockpit and need traditional package management. Use IoT when you are deploying to ARM or other edge hardware and need reliable, field-updatable OS images with automatic rollback. Stay on the upstream Workstation if you only deviate from the defaults occasionally. Switch to Server if you are running services and not a desktop. Pick IoT if your workload runs in containers and the host must stay frozen.

Reboot before you debug. Half the time the symptom is gone.

Where to go next