How to Install and Manage GNOME Shell Extensions on Fedora

Install GNOME Shell extensions on Fedora using the `gnome-shell-extension-manager` GUI tool or the `gnome-extensions` CLI, then manage them via the GUI or command line.

The scenario

You just installed a fresh Fedora Workstation or finished a major release upgrade. You want better window tiling, a custom icon theme, or a quick toggle for screen recording. You find an extension on the GNOME website, download it, and suddenly your desktop session crashes back to the login screen. Or the extension installs silently but does nothing. GNOME Shell extensions are powerful, but they live in a tightly controlled environment. Fedora ships with strict security policies, a specific directory layout, and a rapid release cycle. Messing with the wrong path, ignoring the display protocol, or skipping version checks will break your desktop.

Run the commands below in a working terminal. If your session is already unstable, switch to a TTY with Ctrl+Alt+F3 before making changes.

How GNOME Shell extensions actually load

GNOME Shell does not load extensions like a web browser loads plugins. It expects a specific directory structure, a JSON manifest file, and JavaScript modules that match the exact GNOME Shell version running on your system. When you log in, the shell scans two locations. It checks the system-wide directory managed by the package manager, then it checks your user directory. If a manifest is missing, a JavaScript file throws an unhandled exception, or the SELinux context is wrong, the shell catches the error and refuses to activate the extension. On Wayland, a crashing extension can drop you straight to the GDM login screen. On X11, it usually just stays disabled.

Think of the extension system like a strict customs checkpoint. Every package needs the right paperwork, the right clearance, and the right version stamp. If one field is wrong, the package gets held.

The manifest file is the centerpiece. It lives at the root of the extension directory and is named metadata.json. It declares the extension name, unique identifier, description, and the shell-version array. GNOME Shell reads that array first. If your running version is not listed, the shell skips the extension entirely. The JavaScript files inside the directory handle the actual UI hooks and background logic. They rely on GNOME Shell's internal API, which changes every six months. That is why Fedora's release cadence matters. An extension built for GNOME 44 will fail on GNOME 46. The API shifts, function names change, and old scripts throw fatal errors.

Check the manifest before you install anything. Read the version array. Match it to your running shell. Skip the rest if they do not align.

Install and manage extensions the right way

Fedora provides three ways to handle extensions. The graphical manager is the safest for most users. The command line gives you precise control. Manual installation works when an extension is not in the official database or you are testing a developer build.

Start with the graphical manager. It handles version matching, downloads, and placement automatically. Install it if your system image did not include it.

sudo dnf install gnome-shell-extension-manager
# WHY: pulls the official manager package from Fedora repos
# WHY: sets up the local database of compatible extensions
# WHY: avoids manual file placement errors and path confusion

Launch it from the application menu or run the binary directly. Browse the integrated catalog, click install, and the tool places the files in the correct user directory. It also handles updates when a new GNOME Shell version ships. The manager queries the GNOME Extensions website, filters by your exact shell version, and downloads only compatible builds.

For terminal users, the gnome-extensions utility reads the same database and manipulates the enabled state without opening a window. List everything currently installed and whether it is active.

gnome-extensions list
# WHY: queries the local extension database
# WHY: prints the unique ID and current enabled state
# WHY: helps you identify the exact string for enable or disable commands

Enable or disable an extension using its full identifier. The identifier is usually a reverse-domain string followed by the author or project name.

gnome-extensions enable user-theme@gnome-shell-extensions.gcampax.github.com
# WHY: toggles the extension state in the user config database
# WHY: does not modify the actual extension files
# WHY: takes effect immediately on X11, requires session restart on Wayland

Some extensions ship as RPM packages in Fedora's official repositories. gsconnect for KDE Connect integration is a prime example. Installing via dnf places the files in the system directory and registers them with the package manager. This keeps them in sync with system updates and applies proper SELinux contexts automatically.

sudo dnf install gsconnect
# WHY: pulls the packaged extension from Fedora repos
# WHY: places files in /usr/share/gnome-shell/extensions/
# WHY: ensures automatic updates and correct security contexts

When you must install manually, download the zip file from the GNOME Extensions website. Extract it to your user extensions directory. Never place custom files in /usr/share/gnome-shell/extensions/. That path belongs to dnf. Package updates will overwrite your files or trigger merge conflicts. The user directory is designed for this exact workflow.

mkdir -p ~/.local/share/gnome-shell/extensions
unzip downloaded-extension.zip -d ~/.local/share/gnome-shell/extensions/
# WHY: creates the standard user extension directory if missing
# WHY: extracts the manifest and JS files to the correct location
# WHY: keeps user data separate from system-managed packages

After extraction, enable it with the CLI or the manager. The shell will pick it up on the next session start. Remember that config files in /etc/ are user-modified, while files in /usr/lib/ ship with the package. Edit /etc/. Never edit /usr/lib/. The same rule applies to extension directories. Keep system paths pristine.

Run dnf upgrade --refresh weekly to keep your base system current. Use dnf system-upgrade only when crossing major Fedora releases. They are different commands with different purposes.

Verify the extension is running

Confirm the extension loaded correctly before assuming it is broken. Check the journal for GNOME Shell messages during your current boot. Filter for the extension identifier or general shell errors.

journalctl -xeu gdm -b | grep -i extension
# WHY: pulls GDM and shell logs for the current boot
# WHY: the x flag adds explanatory context to error lines
# WHY: filters for extension-related messages to isolate the issue

Look for Extension loaded successfully or Extension disabled due to error. If you see a JavaScript stack trace, the extension version does not match your GNOME Shell release. Fedora updates GNOME Shell frequently. An extension built for GNOME 44 will fail on GNOME 46.

Most sysadmins type journalctl -xeu <unit> muscle-memory style. It reads better than plain journalctl and jumps straight to the end of the log. Use it here. Read the actual error before guessing.

Common pitfalls and what the error looks like

Extensions fail for three main reasons. Version mismatch, wrong installation path, or SELinux denials.

Version mismatch is the most common. GNOME Shell extensions are tightly coupled to the shell version. The manifest file contains a shell-version array. If your running version is not in that array, the shell refuses to load it. You will see a warning in the journal.

gnome-shell: Extension 'my-extension@domain.com' has an error: The extension is not compatible with this version of GNOME Shell.

Do not force it by editing the manifest. The JavaScript API changes between releases. Forcing an old extension will crash your session. Wait for the developer to update it, or find an alternative.

Path errors happen when users copy files to /usr/share/gnome-shell/extensions/ or /usr/lib/. Fedora treats /usr/lib/ and /usr/share/ as read-only package directories. User modifications belong in /etc/ for configuration or ~/.local/ for personal data. Placing extensions in the system directory breaks dnf transactions and triggers SELinux warnings.

SELinux blocks extensions when the files lack the correct context. If you manually downloaded an extension and placed it in the user directory, the context should already be correct. If you copied files to a system directory or used a custom build script, you might see denials.

ausearch -m avc -ts recent | grep -i gnome
# WHY: searches the audit log for recent access vector cache denials
# WHY: filters for GNOME-related processes
# WHY: identifies if SELinux is blocking file reads or network access

If you see denials, restore the default context for the directory. Do not disable SELinux. The default policy allows extensions to run. Custom contexts are only needed for highly modified setups.

sudo restorecon -Rv ~/.local/share/gnome-shell/extensions/
# WHY: recursively resets SELinux labels to policy defaults
# WHY: the v flag prints each file as it is relabeled
# WHY: fixes permission denials without altering file contents

Session restart behavior differs between display protocols. On X11, you can reload GNOME Shell without logging out. Press Alt+F2, type r, and hit Enter. On Wayland, that shortcut does nothing. Wayland sessions are isolated for security. You must log out and log back in to apply extension changes or recover from a crash.

Trust the package manager. Manual file edits drift, snapshots stay.

Which installation method to pick

Use the graphical extension manager when you want automatic version matching and one-click installation. Use the gnome-extensions CLI when you are managing a headless server with a remote desktop or scripting your desktop environment. Use dnf when the extension is packaged in Fedora's official repositories and you want automatic updates. Use manual zip installation when the extension is not in the official database or you are testing a developer snapshot. Stay on the official GNOME Extensions website for compatibility verification. Avoid third-party mirrors that host outdated builds.

Read the journal before you reinstall. Half the time the symptom is a missing dependency or a wrong path.

Where to go next