You cloned a repo and the build failed
You just cloned a repository from GitHub. The README says "Run make to build." You type make and the terminal replies bash: make: command not found. You installed Fedora six months ago, you know how to update packages, but the system feels bare compared to the toolchain you had before. You need C compilers, Python virtual environments, a Go runtime, and maybe Rust, but you are not sure which packages provide what without breaking the system.
Fedora keeps development tools separate by default
Fedora Workstation ships with a clean desktop. It does not include compilers, package managers for other languages, or database servers by default. This keeps the system small and secure. You have to opt-in to development tools. The package manager dnf handles the dependencies. When you install a language runtime, dnf pulls in the shared libraries and headers required to link against them. You are building a toolchain layer on top of the base OS.
Run dnf groupinfo 'Development Tools' to see exactly what you are installing. Blind installs hide missing dependencies.
Install the C and C++ toolchain
Most development tools on Linux are written in C or C++. The Development Tools group installs the compiler, linker, build automation tools, and the standard headers. This is the foundation for compiling almost any software from source.
sudo dnf groupinstall 'Development Tools'
# WHY: Installs gcc, make, autoconf, and the standard C/C++ headers.
# WHY: This group is the foundation for compiling almost any C-based software.
sudo dnf install gcc gcc-c++ make cmake ninja-build git curl wget
# WHY: Adds specific compilers and build systems that some projects require.
# WHY: git, curl, and wget are essential for fetching source code and dependencies.
Fedora packages are signed and verified. When you install from the repositories, dnf checks the GPG signature of every package. This prevents tampered binaries from entering your system.
Run dnf upgrade --refresh weekly to keep your toolchain current. This command forces a metadata refresh before checking for updates, ensuring you get the latest package versions even if the cache is stale.
Set up Python with isolation
Fedora includes a system Python used by package management and desktop tools. Installing packages globally with pip can break system utilities. Always use python3 -m venv to create isolated environments for your projects. The python3-virtualenv package provides the virtualenv command, which is faster than the built-in venv module for large environments.
sudo dnf install python3 python3-pip python3-virtualenv
# WHY: python3 provides the interpreter and standard library.
# WHY: python3-pip installs the package manager for Python libraries.
# WHY: python3-virtualenv creates isolated environments so dependencies don't clash.
Create a virtual environment for each project. Activate it before installing dependencies. This keeps your project requirements separate from the system Python and from other projects.
Source your environment files after every change. The shell won't reload your profile on its own.
Manage Node.js versions with NVM
Fedora packages Node.js, but the version in the repositories may lag behind the latest releases. Node Version Manager (NVM) lets you install multiple Node.js versions in your home directory and switch between them without root access. This is useful when you need to test an application against different LTS versions.
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
# WHY: Downloads the NVM installer script and pipes it to bash for execution.
# WHY: NVM installs in your home directory, so you don't need sudo for updates.
source ~/.bashrc
# WHY: Reloads the shell configuration to activate the nvm command immediately.
nvm install --lts
# WHY: Fetches the latest Long Term Support version of Node.js.
# WHY: LTS releases are stable and recommended for production work.
NVM modifies your shell profile to add the nvm function. If you open a new terminal and nvm is not found, check that ~/.bashrc or ~/.zshrc contains the lines added by the installer.
Install Go and Rust
Go is available directly from the Fedora repositories. The package includes the compiler and standard library, integrated with the system toolchain. Rust uses rustup as the community standard. rustup manages the compiler, standard library, and additional toolchains like clippy and rustfmt. It also allows you to install nightly versions for experimental features.
sudo dnf install golang
# WHY: Installs the Go compiler and standard library from Fedora repositories.
# WHY: Fedora packages Go with security patches and integration with the system toolchain.
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# WHY: Downloads the rustup installer with strict TLS and protocol checks.
# WHY: rustup manages multiple Rust toolchains and keeps them up to date.
source ~/.cargo/env
# WHY: Adds cargo and rustc to your PATH so the shell can find them.
If you see bash: rustc: command not found after installing rustup, you forgot to reload your shell. Run source ~/.cargo/env. The installer modifies your profile, but the change only applies to new sessions.
Configure editors and Git
Fedora does not include VS Code in the default repositories because it is proprietary software. You must add the Microsoft repository manually. The repository file tells dnf where to fetch the RPM package and how to verify its signature. Without the GPG key, dnf will refuse to install the package to prevent tampering.
sudo dnf install neovim
# WHY: Installs Neovim, a modern fork of Vim with better extensibility.
sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc
# WHY: Imports the GPG key so dnf can verify the signature of VS Code packages.
sudo sh -c 'echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com/yumrepos/vscode\nenabled=1\ngpgcheck=1\ngpgkey=https://packages.microsoft.com/keys/microsoft.asc" > /etc/yum.repos.d/vscode.repo'
# WHY: Creates a repository file pointing to Microsoft's official VS Code packages.
# WHY: Placing the file in /etc/yum.repos.d ensures dnf sees it on every update.
sudo dnf install code
# WHY: Downloads and installs VS Code from the new repository.
git config --global user.name "Your Name"
# WHY: Sets your name for all commits made on this machine.
git config --global user.email "you@example.com"
# WHY: Associates your email with your commits for identity tracking.
git config --global core.editor nvim
# WHY: Tells Git to open Neovim when it needs you to write a commit message.
ssh-keygen -t ed25519 -C "you@example.com"
# WHY: Generates a modern Ed25519 SSH key pair for secure authentication.
# WHY: Ed25519 is faster and more secure than the older RSA keys.
cat ~/.ssh/id_ed25519.pub
# WHY: Prints the public key so you can copy it to GitHub or GitLab.
Edit configuration files in /etc/. Files in /usr/lib/ belong to packages and will be overwritten on upgrade. If you modify a file in /usr/lib/, your changes will vanish the next time you run dnf upgrade.
Start databases safely
PostgreSQL requires an initialization step before the service can start. This creates the data directory and sets up the default database cluster. MariaDB initializes automatically on first start.
sudo dnf install postgresql postgresql-server
# WHY: Installs the PostgreSQL client tools and the server daemon.
sudo postgresql-setup --initdb
# WHY: Initializes the database cluster and creates the default data directory.
# WHY: This step is required before the service can start for the first time.
sudo systemctl enable --now postgresql
# WHY: Starts the service immediately and configures it to start on boot.
sudo dnf install mariadb-server
# WHY: Installs the MariaDB server and client tools.
sudo systemctl enable --now mariadb
# WHY: Starts MariaDB and enables it to run on boot.
PostgreSQL will fail to start if you skip the initialization step. The error postgresql-setup: error: data directory is not empty means you tried to initialize a database that already exists. Check /var/lib/pgsql/data before running --initdb.
Initialize the database before enabling the service. A service that starts on an empty data directory will crash immediately.
Use containers for mutable development
Toolbox creates a container that shares your home directory and user ID with the host. You can install packages inside the container without sudo on the host. This is useful when you need a package that conflicts with the system version, or when you want to test a configuration without risking the host system. Podman is pre-installed for full container workflows.
sudo dnf install toolbox
# WHY: Installs the toolbox command for creating mutable development containers.
toolbox create
# WHY: Creates a container based on the current Fedora release with your home directory mounted.
toolbox enter
# WHY: Drops you into a shell inside the container where you can install packages freely.
podman run -it --rm fedora:latest bash
# WHY: Runs a temporary Fedora container for testing or isolated builds.
# WHY: The --rm flag removes the container automatically when you exit.
Toolbox is especially valuable on Fedora Silverblue, where the host filesystem is immutable. On Workstation, it provides a safe sandbox for experimenting with packages that might conflict with system dependencies.
Verify the toolchain
Run version checks to confirm every tool is installed and accessible. A missing tool breaks the build chain silently.
gcc --version
# WHY: Confirms the C compiler is installed and prints the version number.
python3 --version
# WHY: Checks the Python interpreter version to ensure it matches your project requirements.
node --version
# WHY: Verifies the Node.js runtime is active and accessible.
go version
# WHY: Displays the Go toolchain version and build information.
rustc --version
# WHY: Shows the Rust compiler version managed by rustup.
git --version
# WHY: Ensures Git is installed and reports the version for compatibility checks.
If you see Error: Transaction test error: package python3-3.12.x conflicts with python3-3.13.y, the conflict is intentional. Fedora manages Python versions carefully. Do not force the installation. Check if your project requires a specific version and use a virtual environment instead.
Common errors and how to fix them
VS Code updates can break if the GPG key expires. If dnf upgrade complains about a signature error for code, re-import the key from the Microsoft repository page. Run sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc and try the upgrade again.
Check journalctl -xeu postgresql if the database service fails to start. The x flag adds explanatory context and the e flag jumps to the end of the log, saving you from scrolling through boot messages. SELinux denials show up in journalctl -t setroubleshoot with a one-line summary. Read those before disabling SELinux.
Check journalctl -xe first. Read the actual error before guessing.
Choose the right tool for your workflow
Use the Development Tools group when you need a complete C/C++ toolchain for compiling system software. Use rustup when you want to manage multiple Rust versions and switch between stable and nightly toolchains. Use NVM when you need to test Node.js applications against different LTS versions without root access. Use Toolbox when you want to install packages locally without affecting the host system configuration. Use Podman when you are building container images or running services in isolated environments. Stay on the Fedora package versions when you want security updates managed automatically by dnf upgrade.
Trust the package manager. Manual file edits drift, snapshots stay.