Cursor upgrade guides
Upgrading Cursor safely takes three moves: record a baseline of the current build (its version, extensions, MCP servers, and the project’s test results), update and compare the new build against that baseline, and keep a hash-checked copy of the previous build so a bad update costs minutes. Cursor updates itself by default.
This page is for the developer whose Cursor updated itself overnight and the tech lead who has to decide whether the team follows. The morning after an update, the agent stops using a project rule, one extension fails to load, and the Postgres MCP server shows no tools. Without a record of how things looked yesterday, you cannot tell whether the update broke them or they were already broken.
What you get from this Cursor upgrade guide
Section titled “What you get from this Cursor upgrade guide”- A five-minute pre-update routine that archives your Cursor data and records a baseline you can diff against.
- A copy-paste prompt that makes the agent record that baseline, and a second one that re-runs it on the new build and reports every difference.
- A pass criterion that comes from exit codes and lists, not from reading the agent’s output line by line.
- Rollback steps for macOS, Linux and Windows that install a previous build whose SHA-256 hash, or on Windows its code signature, you check first.
- A recovery entry for each common update failure, and a third prompt that turns a regression into a bug report.
Which Cursor build are you running?
Section titled “Which Cursor build are you running?”Record the build before anything changes. Run this in a terminal:
cursor --versionThe first line is the version, the second is the commit hash of the build, and the third is the CPU architecture. Write all three down with the date. The commit hash matters most for rollback: Cursor’s download URLs are keyed by it, and the Homebrew cask records it for each release the cask was bumped to.
If cursor is not on your PATH, fix that first with the steps in installing Cursor. The rest of this page uses the command.
How do you control when Cursor updates?
Section titled “How do you control when Cursor updates?”Cursor downloads and installs its own updates. The Homebrew cask marks it auto_updates, which is why brew upgrade leaves it alone: the app, not your package manager, decides when a new build arrives.
Cursor is built on VS Code, which controls updates with the update.mode setting. Cursor’s macOS build, however, ships its own updater: the cask removes ToDesktop’s ShipIt cache and a cursor-updater cache when it uninstalls Cursor. So treat the key as something to test on your build, not a guarantee. Add it to your user settings.json (open the Command Palette and run Preferences: Open User Settings (JSON)):
{ "update.mode": "manual"}| Value | What VS Code’s setting does | Use it when |
|---|---|---|
default | Checks for updates automatically and periodically | You want updates as they arrive and have a baseline recorded |
start | Checks only on startup | You restart Cursor at a predictable time, such as Monday morning |
manual | No background checks; updates only when you check yourself | You are holding on a known-good build during a deadline or after a rollback |
none | Disables updates | Never on a daily machine: you also stop receiving security fixes |
These values and meanings come from VS Code’s source. Confirm that your Cursor build honours the key: after you set manual, the Settings search for update.mode should show the value you chose, and Cursor should not offer a restart-to-update prompt until you check for updates yourself. If a restart prompt appears anyway, your build ignores the key; the only reliable hold is then the rollback below, repeated whenever it updates.
Back up Cursor before you update
Section titled “Back up Cursor before you update”On macOS, of the paths the Homebrew cask deletes when it removes Cursor completely, two hold your own data; Linux and Windows keep the same two in VS Code’s usual places: the application-data directory (settings, keybindings, snippets, and per-workspace state) and ~/.cursor (which holds the global ~/.cursor/mcp.json). Archive both while Cursor is closed.
-
Quit Cursor completely, not only its window. On macOS, use Cursor › Quit Cursor.
-
Archive both directories, and save the build and extension list next to the archive:
Terminal window STAMP=$(date +%Y%m%d)mkdir -p ~/cursor-backupstar -czf ~/cursor-backups/cursor-$STAMP.tgz \-C ~ ".cursor" "Library/Application Support/Cursor"cursor --version > ~/cursor-backups/version-$STAMP.txtcursor --list-extensions --show-versions > ~/cursor-backups/extensions-$STAMP.txtTerminal window STAMP=$(date +%Y%m%d)mkdir -p ~/cursor-backupstar -czf ~/cursor-backups/cursor-$STAMP.tgz -C ~ .cursor .config/Cursorcursor --version > ~/cursor-backups/version-$STAMP.txtcursor --list-extensions --show-versions > ~/cursor-backups/extensions-$STAMP.txtTerminal window $stamp = Get-Date -Format yyyyMMdd$dir = "$HOME\cursor-backups"New-Item -ItemType Directory -Force $dir | Out-NullCompress-Archive -Path "$env:APPDATA\Cursor", "$HOME\.cursor" `-DestinationPath "$dir\cursor-$stamp.zip"cursor --version > "$dir\version-$stamp.txt"cursor --list-extensions --show-versions > "$dir\extensions-$stamp.txt"The archive can be large. Keep the last two and delete older ones. On Windows PowerShell 5.1,
Compress-Archivecannot store a file over 2 GB, and the application data directory holds large caches; use PowerShell 7, usetar -czf(tar.exeships with Windows 10 and later), or leave out theCacheandCachedDatafolders. -
Commit the project’s Cursor configuration. Rules, skills, hooks and
.cursor/mcp.jsonbelong in the repository, wheregit diffshows any change an update or a teammate makes. Ifgit statusshows uncommitted files under.cursor/, commit them on a branch now. -
Record the agent baseline with the prompt below, in a fresh chat on the current build.
Read the baseline once, before you update. A rule, server or tool that is missing today is not the update’s fault, and you want to know that now rather than tomorrow.
Update Cursor and prove the new build works
Section titled “Update Cursor and prove the new build works”With a baseline on disk, the update itself is the easy part: check for updates from the Command Palette (Check for Updates, or search the palette for “update”) or accept Cursor’s restart prompt. The work is proving the result, and the proof is a set of comparisons that either match or do not.
-
Confirm the build changed: run
cursor --versionand compare the commit hash with the one you saved. The same hash means the update has not installed. -
Compare extensions with the saved list. Run this in the backup directory:
Terminal window diff extensions-YYYYMMDD.txt <(cursor --list-extensions --show-versions)Terminal window Compare-Object (Get-Content extensions-YYYYMMDD.txt) (cursor --list-extensions --show-versions)Replace
YYYYMMDDwith the stamp from your backup. Version changes are normal. A line that starts with<(in PowerShell, marked<=) and has no matching>(=>) line for the same extension is an extension that is no longer installed. An installed extension that fails to activate does not show up in this diff; it shows up in the comparison prompt or in Developer: Show Running Extensions. -
Check that the project’s MCP file still parses. A malformed file is easy to miss in the UI, so check it from the terminal:
Terminal window python3 -m json.tool .cursor/mcp.json > /dev/null && echo "mcp.json OK" -
Open a fresh chat on the new build and run the comparison prompt below.
-
Run the project’s test command yourself, in your own terminal rather than through the agent, and check its exit code with
echo $?(PowerShell:$LASTEXITCODE). Running it yourself means the key gate does not rest on the agent’s own report. -
Decide. The build passes when the commit changed, no extension is missing,
mcp.jsonparses, your own test run exits0, and every row of the comparison table says MATCH. Any difference goes to the rollback decision table before you work on anything else.
This is how you judge the update without reading the agent’s work: the table either says MATCH on every row or names the row that changed. The developer approves the update on their own machine. For a team, the tech lead signs off only after the canary tasks in the version-history routine also pass on the new build, and the same evidence-over-diffs idea is explained in reading evidence instead of code.
When should you roll back instead of fixing forward?
Section titled “When should you roll back instead of fixing forward?”Roll back when the regression blocks work you must ship this week and has no quick fix. Fix forward when the cause is in your own configuration.
| What the comparison shows | Most likely cause | Do this |
|---|---|---|
A rule or skill is missing, and its file is unchanged in git diff | The new build reads rule or skill files differently | Roll back, then check the file against Cursor’s current Rules or Skills documentation on a spare machine |
| An MCP server shows no tools, and its command fails in a terminal too | Your runtime (npx, uvx, docker) or its credentials, not Cursor | Fix forward with MCP setup in Cursor |
| An MCP server shows no tools, but its command works in a terminal | The new build | Restart Cursor fully once; if it persists, roll back |
| Tests or lint fail on the same commit that passed in the baseline | The agent’s environment changed, for example the integrated terminal’s PATH | Compare echo $PATH in Cursor’s terminal and in your own; roll back if you cannot fix it within 30 minutes |
| One extension no longer loads | The extension, not Cursor | Update or disable that extension; roll back only if you cannot work without it |
Roll back to a previous Cursor build
Section titled “Roll back to a previous Cursor build”A rollback reinstalls the previous build and leaves your data where it is. You need the previous version number and commit hash, which you saved in version-YYYYMMDD.txt, and the matching SHA-256 hash. The Homebrew cask’s history on GitHub (Homebrew/homebrew-cask, file Casks/c/cursor.rb) lists the releases the cask was bumped to, each with its version, commit and a sha256 for macOS (Apple silicon and Intel) and Linux (x86_64 and aarch64), whether or not you installed through Homebrew. It may skip a release that came and went between bumps. On Windows, winget’s manifest carries the installer hash instead, but only for the releases winget packaged, and it packages far fewer than Cursor ships.
-
Open the history of
Casks/c/cursor.rbin the Homebrew cask repository and find the commit that set the version you saved. Copy the version, the commit hash, and thesha256for your platform. -
Quit Cursor completely.
-
Download the previous build, check its hash, and install it:
Terminal window CURSOR_COMMIT=PREVIOUS_COMMIT_HASHARCH=arm64 # x64 on Intel Macscurl -fL -o Cursor.zip \"https://downloads.cursor.com/production/$CURSOR_COMMIT/darwin/$ARCH/Cursor-darwin-$ARCH.zip"shasum -a 256 Cursor.zip # must equal the cask's sha256 for your archunzip -q Cursor.zipmv /Applications/Cursor.app ~/cursor-backups/Cursor-bad.appmv Cursor.app /Applications/Terminal window CURSOR_VERSION=PREVIOUS_VERSIONCURSOR_COMMIT=PREVIOUS_COMMIT_HASHARCH=x64; AARCH=x86_64 # on ARM: ARCH=arm64; AARCH=aarch64curl -fL -o "Cursor-$CURSOR_VERSION-$AARCH.AppImage" \"https://downloads.cursor.com/production/$CURSOR_COMMIT/linux/$ARCH/Cursor-$CURSOR_VERSION-$AARCH.AppImage"sha256sum "Cursor-$CURSOR_VERSION-$AARCH.AppImage" # compare with the caskchmod +x "Cursor-$CURSOR_VERSION-$AARCH.AppImage"Move the new AppImage aside and put the old one at the path your launcher or desktop entry starts (the Homebrew cask links it as
Cursor.AppImage); then start it and confirm withcursor --version. Ifcursoris not on yourPATHwith an AppImage install, run./Cursor-$CURSOR_VERSION-$AARCH.AppImage --versioninstead, or install the shell command as described in installing Cursor. If you installed Cursor from a.debor.rpmpackage, run the AppImage directly until your package manager offers the older version again. Keep the AppImage you used before each update instead of deleting it, so rolling back next time means running the older file.First check whether winget packaged your previous version:
Terminal window winget show --id Anysphere.Cursor --exact --versionsIf it is listed, install it through winget, which checks the installer against the manifest’s SHA-256 hash:
Terminal window winget uninstall --id Anysphere.Cursor --exactwinget install --id Anysphere.Cursor --exact --version PREVIOUS_VERSIONwinget often trails Cursor by several releases, so in the common case your previous version is not listed. Then you have two routes:
- Go back further, with a hash check. Install the newest version winget lists that is older than the broken build, with the same two commands. It is more than one release back, so run the comparison prompt afterwards rather than assuming it behaves like the build you had.
- Download your exact previous build. Every winget manifest points at
downloads.cursor.com/production/<commit>/win32/<arch>/user-setup/CursorUserSetup-<arch>-<version>.exe, so the commit and version you saved locate it. No published SHA-256 exists for a release winget skipped, so the script checks the installer’s Authenticode signature instead and deletes the file unless Windows reports itValidand the certificate’s organization (O=) is Anysphere:
Terminal window $v = 'PREVIOUS_VERSION'; $c = 'PREVIOUS_COMMIT_HASH'$a = 'x64' # arm64 on Windows on ARM$f = "CursorUserSetup-$a-$v.exe"Invoke-WebRequest -UseBasicParsing -OutFile $f `-Uri "https://downloads.cursor.com/production/$c/win32/$a/user-setup/$f"$sig = Get-AuthenticodeSignature $fif ($sig.Status -ne 'Valid' -or $sig.SignerCertificate.Subject -notmatch '(^|,\s*)O="?Anysphere\b') {Remove-Item $f; throw "Do not run ${f}: signature $($sig.Status), signer '$($sig.SignerCertificate.Subject)'"}"Signed by $($sig.SignerCertificate.Subject)"Validmeans the file is unchanged since signing and the certificate chains to a root Windows trusts, so the subject names exactly who signed it. It does not prove that the signer is Anysphere, which is why the script also checks the organization. The subject on Cursor’s installer certificates was not verified, because downloads.cursor.com could not be reached;Anysphereis the publisher in winget’s package metadata, which is not the certificate subject. If the script refuses a build you expected to pass, read the signer it printed and do not loosen the check. Once it printsSigned by, uninstall the current build and run it with& ".\$f". If Cursor was installed for all users, set$fto"CursorSetup-$a-$v.exe"and replaceuser-setupwithsystem-setupin the URL. If the download returns 404, that build is no longer served; go back further instead.PREVIOUS_VERSIONandPREVIOUS_COMMIT_HASHare the first two lines of your savedversion-YYYYMMDD.txt. If the hash check prints a different value, stop and delete the download. -
Set
"update.mode": "manual"before you start the old build, or Cursor installs the new build again at its next update check. Cursor is closed at this point, so edit the user settings file directly:~/Library/Application Support/Cursor/User/settings.jsonon macOS,~/.config/Cursor/User/settings.jsonon Linux, or%APPDATA%\Cursor\User\settings.jsonon Windows. Keep the installer, zip or AppImage of the build you rolled back to: if the hold does not take and Cursor updates itself again, you can undo that update the same way without searching the cask history a second time. -
Start Cursor, run
cursor --versionto confirm the old commit, and run the comparison prompt again. Every row should say MATCH. -
Restore the data archive only if the comparison still fails. Quit Cursor, move the current data directories aside, and extract the archive in their place, as the commands below do. Moving aside rather than deleting keeps anything you created after the backup.
Terminal window mv "$HOME/Library/Application Support/Cursor" "$HOME/Library/Application Support/Cursor.pre-restore"mv ~/.cursor ~/.cursor.pre-restoretar -xzf ~/cursor-backups/cursor-YYYYMMDD.tgz -C ~Terminal window mv ~/.config/Cursor ~/.config/Cursor.pre-restoremv ~/.cursor ~/.cursor.pre-restoretar -xzf ~/cursor-backups/cursor-YYYYMMDD.tgz -C ~Terminal window $tmp = "$HOME\cursor-restore"Expand-Archive "$HOME\cursor-backups\cursor-YYYYMMDD.zip" -DestinationPath $tmpRename-Item "$env:APPDATA\Cursor" Cursor.pre-restoreRename-Item "$HOME\.cursor" .cursor.pre-restoreCopy-Item "$tmp\Cursor" "$env:APPDATA\Cursor" -RecurseCopy-Item "$tmp\.cursor" "$HOME\.cursor" -RecurseCompress-Archivestores each folder under its own name at the top of the zip, so the two copies putCursorand.cursorback where the backup took them from.
Remove the hold deliberately. Put a date on it, such as “until the next release that mentions the regression”, and set update.mode back when that release has passed the comparison on a spare machine.
What breaks during a Cursor update, and how do you recover?
Section titled “What breaks during a Cursor update, and how do you recover?”- The update downloads but never installs, or the restart prompt keeps returning. Quit Cursor completely, including any window on another desktop, and start it again. If the build does not change, install the current release from your package manager or from Cursor’s download page over the existing one. Your data directories are not touched.
- Cursor runs hot after the update. Start it with extensions off:
cursor --disable-extensions. If the load disappears, re-enable extensions one at a time, or run Help: Start Extension Bisect from the Command Palette. If it does not disappear, test a clean profile withcursor --user-data-dir /tmp/cursor-clean --extensions-dir /tmp/cursor-clean-ext, and report the build to Cursor if the clean profile is also slow. - The agent ignores a rule after the update. The comparison table names the missing rule. Check that its file is unchanged with
git log -p -- .cursor/, then roll back or fix the file against Cursor’s current Rules documentation. Project rules in Cursor covers the file format. - MCP servers show no tools. Run the server’s
commandandargsfrommcp.jsonin a terminal. If that fails, the problem is the runtime or its credentials; MCP setup in Cursor has the fix for each symptom. If it works, quit and restart Cursor fully so it reloadsmcp.json. - You rolled back and Cursor updated itself again.
update.modewas not set before the old build started, or your build ignores it. Set it, reinstall the old build, and confirm withcursor --versionafter a full restart. - Chat history or workspace state is gone. Quit Cursor and restore the archive from step 6 of the rollback. Without an archive there is no copy to restore, which is the reason the backup runs before every update.
- One teammate is fine and another is broken on the same build. Compare their
cursor --versionoutput and extension lists line by line. Different commit hashes mean they are not on the same build, whatever the version line says.
Post the report with both commit hashes. A report that names two builds and one reproduction is one the vendor can act on; “it broke after updating” is not.
How should a team roll out a Cursor update?
Section titled “How should a team roll out a Cursor update?”A team adds one rule to everything above: nobody’s machine is the first to meet a new build during a deadline. The tech lead owns the routine, which is written out in the Cursor version history: read the release notes against committed config, run the canary tasks on the old and new builds, move one volunteer first, then everyone. This page supplies the parts that routine assumes: the per-machine baseline and comparison, and a rollback that works in minutes. Record the approved build as its commit hash in the team’s onboarding doc, because two machines can show the same version line and differ underneath.
Where to go next after a Cursor update
Section titled “Where to go next after a Cursor update”The other tools handle updates differently: see Claude Code upgrade procedures and staying current with Codex.