Visual Studio Code installs easily enough on Fedora: grab the .rpm from Microsoft’s website, double-click it (or run rpm -i), and moments later you have a working editor. On Windows and macOS, the equivalent download also brings its own updater along, so new versions arrive automatically. On Fedora, that’s where the trouble starts.
On several of my machines, VS Code installed this way has no idea how to update itself. The “Check for Updates” option in the Help Menu (as well as the big blue Update button that eventually appears) simply open Microsoft’s website so you can download a fresh RPM and do the whole dance again. My ThinkPad P15 is currently sitting on version 1.129.1 doing exactly that. Not ideal.
Why this happens
Unlike its Windows and Mac siblings, VS Code on Linux never updates itself. That’s by design: on Linux, software updates are the package manager’s job, and Microsoft respects that. The app merely checks whether a newer version exists, and if it can’t see a system-managed update path, it falls back to pointing you at the download page.
The missing link is Microsoft’s package repository. When you install the standalone RPM, the repository definition that would let DNF fetch future versions doesn’t reliably get registered on your system, so DNF has no idea where VS Code updates live. The .deb package on Debian and Ubuntu actually asks during installation whether you’d like the apt repository added; the RPM route on Fedora often leaves you with the editor but without the repo. The fix is to register the repository yourself. It takes two commands, and afterwards VS Code updates arrive with your regular dnf upgrade like every other package on the system.
Step 1: Import Microsoft’s signing key
DNF verifies package signatures before installing anything, so first we teach RPM to trust Microsoft’s GPG key:
sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc
Step 2: Add the repository
Next we create a repo definition in /etc/yum.repos.d/. Microsoft’s official documentation suggests a rather hairy echo -e one-liner; I find a heredoc easier to read and to verify:
sudo tee /etc/yum.repos.d/vscode.repo > /dev/null <<'EOF'
[code]
name=Visual Studio Code
baseurl=https://packages.microsoft.com/yumrepos/vscode
enabled=1
autorefresh=1
type=rpm-md
gpgcheck=1
gpgkey=https://packages.microsoft.com/keys/microsoft.asc
EOF
A quick word on why it’s sudo tee rather than sudo echo > file: the redirection is performed by your shell before sudo ever runs, so the unprivileged you would be the one trying to write into /etc/yum.repos.d/ — and failing. With tee, the elevated process itself does the writing. The > /dev/null merely suppresses tee’s habit of echoing everything back at you.
You might also notice this avoids dnf config-manager entirely. That’s deliberate: the config-manager syntax changed between DNF 4 and DNF 5 (current Fedora releases ship DNF 5), so half the tutorials out there quote commands that no longer work. A plain repo file is version-proof.
Step 3: Install — or just update
On a fresh system, refresh the metadata and install:
dnf check-update
sudo dnf install code
If VS Code is already installed from the standalone RPM, there’s nothing to uninstall. The package in Microsoft’s repository is the very same code package, so DNF simply adopts it. The next time you run a system update, VS Code comes along for the ride:
sudo dnf upgrade code
Verifying it worked
To confirm the repository is registered and serving packages:
dnf repolist | grep -i code
dnf list --installed code
The first command should show the code repository as enabled; the second shows the installed version. From now on, VS Code updates arrive through DNF with everything else — no more browser detours. Inside the editor, “Check for Updates” will still tell you when a new version exists, but the actual updating is now the package manager’s business, exactly as it should be on Linux.
One small bonus: the same repository also carries code-insiders if you fancy the preview builds. Both editions install side by side without conflict.
Here’s the victory log, courtesy of my 2011 MacBook Pro (which had the same issue, and yes — it runs Fedora too): a successful update replaces the previous rpm (from an “unknown” source) with our new one from the custom repo. That <unknown> in the Repository column is the fingerprint of the whole problem — DNF had no record of where the old package came from, while the new one is properly attributed to the code repo we just registered.
Arch Version Repository Size
Upgrading:
code x86_64 0:1.133.0-1786488022.el8 code 1.0 GiB
replacing code x86_64 0:1.130.0-1784734628.el8 <unknown> 1.1 GiB
Transaction Summary:
Upgrading: 1 package
Replacing: 1 package
Total size of inbound packages is 330 MiB. Need to download 330 MiB.
After this operation, 66 MiB will be freed (install 1 GiB, remove 1 GiB).
Is this ok [y/N]: y
[1/1] code-0:1.133.0-1786488022.el8.x86_64 100% | 18.5 MiB/s | 330.4 MiB | 00m18s
-----------------------------------------------------------------------------------------------------------------
[1/1] Total 100% | 18.4 MiB/s | 330.4 MiB | 00m18s
Running transaction
[1/4] Verify package files 100% | 0.0 B/s | 1.0 B | 00m06s
[2/4] Prepare transaction 100% | 3.0 B/s | 2.0 B | 00m01s
[3/4] Upgrading code-0:1.133.0-1786488022.el8.x86_64 100% | 76.1 MiB/s | 1.0 GiB | 00m13s
[4/4] Removing code-0:1.130.0-1784734628.el8.x86_64 100% | 534.0 B/s | 2.3 KiB | 00m04s
Complete!
Addendum: the heredoc that never ends
A few weeks after publishing, my MacBook Air volunteered for the same procedure and promptly took the heredoc hostage. Pasting the command from this very article produced a lone > prompt that never went away — no matter how long I waited, nothing executed.
That > is bash’s continuation prompt: the shell believes it’s still inside the heredoc and is waiting for one very specific thing — a line that says exactly EOF, alone, at column zero, with no spaces before or after. Until it sees that, everything you type is swallowed as “more file content”, forever.
So how did the terminator go missing? The clipboard ate the newlines. Somewhere between browser and terminal, the entire heredoc arrived as one long line, which changes its meaning completely. Bash parsed <<'EOF' as the heredoc redirect, then treated every remaining word — [code], name=Visual, baseurl=... and friends — as additional filename arguments to tee. The heredoc body, meanwhile, hadn’t even started. Typing EOF by hand on its own line closed the (now empty) heredoc, at which point tee dutifully tried to write that empty body to a file named after every word:
tee: 'baseurl=https://packages.microsoft.com/yumrepos/vscode': No such file or directory
tee: 'gpgkey=https://packages.microsoft.com/keys/microsoft.asc': No such file or directory
Only the two lines containing URLs failed — the slashes made tee treat them as paths through directories that don’t exist. The innocent-looking words succeeded, leaving a scattering of empty, root-owned files in my working directory with names like enabled=1 and type=rpm-md. Check with ls -la and clean up like so (the quotes around [code] matter, since bash would otherwise treat it as a glob):
sudo rm -i './[code]' 'name=Visual' Studio Code 'enabled=1' 'autorefresh=1' 'type=rpm-md' 'gpgcheck=1'
The flattened clipboard even sabotaged my fallback attempt of creating the file manually in nano: dnf complained about “Text after section on line 1”, because the paste had once again landed everything on a single line — section header followed by trailing text. Splitting each key back onto its own line (and finishing the file with a newline, as one should) fixed it for good.
The lesson: if a pasted heredoc greets you with >, don’t wait it out — your clipboard has probably lost its newlines. Type EOF and press Enter to break free (then check what tee actually wrote), or sidestep the delimiter theatrics entirely with sudo nano /etc/yum.repos.d/vscode.repo and paste the eight lines into an editor that doesn’t care about terminators.