# Cursor upgrade guides

URL: https://developertoolkit.ai/en/cursor-ide/reference/upgrade-guides/
Description: Update Cursor without losing a working setup, prove the new build against a recorded baseline, and roll back to a hash-checked previous build.

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 this page checked, and when**

Covers the Cursor 3.x line, checked on 26 September 2026. cursor.com could not be fetched that day, so the checks below rest on the sources named after it. On 12 October 2026 cursor.com answered, and Cursor's release notes and CLI pages confirm the version and CLI facts in the section "Which Cursor build are you running?"; every other claim on this page still rests on the 26 September check. Command Palette names on this page are VS Code's; Cursor inherits most of them, but they were not re-checked in Cursor on this date. The download URLs, hashes, the macOS application-data paths, the updater caches and the `cursor` launcher were checked against the Homebrew cask (`Casks/c/cursor.rb`); the Linux and Windows paths follow VS Code's user-data convention (`~/.config/<App>`, `%APPDATA%\<App>`); the `update.mode` values were checked against VS Code's source (`update.config.contribution.ts`); and the Windows rollback relies on winget's manifest for `Anysphere.Cursor` (`microsoft/winget-pkgs`, `manifests/a/Anysphere/Cursor`), which carries the installer hash. That manifest trails Cursor's releases: on 2 October 2026 winget's newest entry trailed the Homebrew cask by several releases. The Windows download URL pattern on this page is the one every winget manifest uses; downloads.cursor.com itself could not be reached from the checking environment. The `cursor` command is VS Code's `code` launcher under another name: the cask links that binary as `cursor`.

## 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?

Record the build before anything changes. Run this in a terminal:

```bash
cursor --version
```

The 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.

Cursor's [release notes](https://cursor.com/docs/release-notes) number the desktop app by minor version. On 2026-10-12 the current release was Cursor 3.24 (2026-10-09), and about one minor a week has shipped since 3.19 (2026-09-02). The Cursor CLI uses date versions instead: its latest build on 2026-10-12 was v2026.10.08. `agent` is the CLI's command, not the `cursor` launcher above: check it with `agent --version` and update it with `agent update` (Cursor's CLI installation page, checked 2026-10-12).

If `cursor` is not on your `PATH`, fix that first with the steps in [installing Cursor](/en/cursor-ide/quick-start/installation-setup/). The rest of this page uses the command.

## 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)**):

```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.

**Pre-release builds belong on a spare machine**

If your Cursor build offers a pre-release or early-access update option, leave it off on the machine where you do paid work. Run pre-release builds on a second machine or user account, with the same repository checked out, so a broken build never sits between you and a deadline.

## 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.

1. Quit Cursor completely, not only its window. On macOS, use **Cursor › Quit Cursor**.

2. Archive both directories, and save the build and extension list next to the archive:

     **macOS**

       ```bash
       STAMP=$(date +%Y%m%d)
       mkdir -p ~/cursor-backups
       tar -czf ~/cursor-backups/cursor-$STAMP.tgz \
         -C ~ ".cursor" "Library/Application Support/Cursor"
       cursor --version > ~/cursor-backups/version-$STAMP.txt
       cursor --list-extensions --show-versions > ~/cursor-backups/extensions-$STAMP.txt
       ```

     **Linux**

       ```bash
       STAMP=$(date +%Y%m%d)
       mkdir -p ~/cursor-backups
       tar -czf ~/cursor-backups/cursor-$STAMP.tgz -C ~ .cursor .config/Cursor
       cursor --version > ~/cursor-backups/version-$STAMP.txt
       cursor --list-extensions --show-versions > ~/cursor-backups/extensions-$STAMP.txt
       ```

     **Windows**

       ```powershell
       $stamp = Get-Date -Format yyyyMMdd
       $dir = "$HOME\cursor-backups"
       New-Item -ItemType Directory -Force $dir | Out-Null
       Compress-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-Archive` cannot store a file over 2 GB, and the application data directory holds large caches; use PowerShell 7, use `tar -czf` (`tar.exe` ships with Windows 10 and later), or leave out the `Cache` and `CachedData` folders.

3. Commit the project's Cursor configuration. Rules, skills, hooks and `.cursor/mcp.json` belong in the repository, where `git diff` shows any change an update or a teammate makes. If `git status` shows uncommitted files under `.cursor/`, commit them on a branch now.

4. Record the agent baseline with the prompt below, in a fresh chat on the current build.

**Copy-paste prompt: record a Cursor upgrade baseline**

```text
I am about to update Cursor. Record a baseline I can compare against after the
update. Do not change any tracked file.

1. List every rule you have loaded for this project, with its file path.
2. List every skill you can use, with its name and source directory.
3. List every MCP server you can reach and the exact names of its tools.
   Call one read-only tool on each server (for Postgres: list the tables) and
   record whether the call succeeded.
4. Run the project's test, type-check and lint commands (read them from
   package.json, Makefile or the README). Record each command and its exit code.

Write the result to .cursor-baseline.md in the repository root as four
sections with plain lists, one item per line, so the file diffs cleanly.
Then check that .cursor-baseline.md is listed in .gitignore; if it is not,
tell me instead of editing .gitignore.
```

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

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.

1. Confirm the build changed: run `cursor --version` and compare the commit hash with the one you saved. The same hash means the update has not installed.

2. Compare extensions with the saved list. Run this in the backup directory:

     **macOS and Linux**

       ```bash
       diff extensions-YYYYMMDD.txt <(cursor --list-extensions --show-versions)
       ```

     **Windows**

       ```powershell
       Compare-Object (Get-Content extensions-YYYYMMDD.txt) (cursor --list-extensions --show-versions)
       ```

   Replace `YYYYMMDD` with 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**.

3. 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:

   ```bash
   python3 -m json.tool .cursor/mcp.json > /dev/null && echo "mcp.json OK"
   ```

4. Open a fresh chat on the new build and run the comparison prompt below.

5. 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.

6. Decide. The build passes when the commit changed, no extension is missing, `mcp.json` parses, your own test run exits `0`, and every row of the comparison table says MATCH. Any difference goes to [the rollback decision table](#when-should-you-roll-back-instead-of-fixing-forward) before you work on anything else.

**Copy-paste prompt: compare the updated Cursor with the baseline**

```text
Cursor was just updated. Read .cursor-baseline.md in the repository root, then
repeat the four checks that produced it: loaded rules, usable skills, MCP
servers with their tool names and one read-only call each, and the test,
type-check and lint commands with their exit codes. Compare what you get now
with the results recorded in the file.

Output one table with columns: check, baseline, now, MATCH or DIFFERENT.
For every DIFFERENT row, add the exact error text or the missing item.
Do not fix anything, do not edit any file, and do not retry a failing command
more than once.
```

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](/en/cursor-ide/reference/changelog/) also pass on the new build, and the same evidence-over-diffs idea is explained in [reading evidence instead of code](/en/ladder/evidence-not-diffs/).

## 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](/en/cursor-ide/quick-start/mcp-setup/) |
| 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

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.

1. Open the history of `Casks/c/cursor.rb` in the Homebrew cask repository and find the commit that set the version you saved. Copy the version, the commit hash, and the `sha256` for your platform.

2. Quit Cursor completely.

3. Download the previous build, check its hash, and install it:

     **macOS**

       ```bash
       CURSOR_COMMIT=PREVIOUS_COMMIT_HASH
       ARCH=arm64          # x64 on Intel Macs
       curl -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 arch
       unzip -q Cursor.zip
       mv /Applications/Cursor.app ~/cursor-backups/Cursor-bad.app
       mv Cursor.app /Applications/
       ```

     **Linux**

       ```bash
       CURSOR_VERSION=PREVIOUS_VERSION
       CURSOR_COMMIT=PREVIOUS_COMMIT_HASH
       ARCH=x64; AARCH=x86_64   # on ARM: ARCH=arm64; AARCH=aarch64
       curl -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 cask
       chmod +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 with `cursor --version`. If `cursor` is not on your `PATH` with an AppImage install, run `./Cursor-$CURSOR_VERSION-$AARCH.AppImage --version` instead, or install the shell command as described in [installing Cursor](/en/cursor-ide/quick-start/installation-setup/). If you installed Cursor from a `.deb` or `.rpm` package, 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.

     **Windows**

       First check whether winget packaged your previous version:

       ```powershell
       winget show --id Anysphere.Cursor --exact --versions
       ```

       If it is listed, install it through winget, which checks the installer against the manifest's SHA-256 hash:

       ```powershell
       winget uninstall --id Anysphere.Cursor --exact
       winget install --id Anysphere.Cursor --exact --version PREVIOUS_VERSION
       ```

       winget 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 it `Valid` and the certificate's organization (`O=`) is Anysphere:

       ```powershell
       $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 $f
       if ($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)"
       ```

       `Valid` means 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; `Anysphere` is 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 prints `Signed by`, uninstall the current build and run it with `& ".\$f"`. If Cursor was installed for all users, set `$f` to `"CursorSetup-$a-$v.exe"` and replace `user-setup` with `system-setup` in the URL. If the download returns 404, that build is no longer served; go back further instead.

   `PREVIOUS_VERSION` and `PREVIOUS_COMMIT_HASH` are the first two lines of your saved `version-YYYYMMDD.txt`. If the hash check prints a different value, stop and delete the download.

4. 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.json` on macOS, `~/.config/Cursor/User/settings.json` on Linux, or `%APPDATA%\Cursor\User\settings.json` on 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.

5. Start Cursor, run `cursor --version` to confirm the old commit, and run the comparison prompt again. Every row should say MATCH.

6. 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.

     **macOS**

       ```bash
       mv "$HOME/Library/Application Support/Cursor" "$HOME/Library/Application Support/Cursor.pre-restore"
       mv ~/.cursor ~/.cursor.pre-restore
       tar -xzf ~/cursor-backups/cursor-YYYYMMDD.tgz -C ~
       ```

     **Linux**

       ```bash
       mv ~/.config/Cursor ~/.config/Cursor.pre-restore
       mv ~/.cursor ~/.cursor.pre-restore
       tar -xzf ~/cursor-backups/cursor-YYYYMMDD.tgz -C ~
       ```

     **Windows**

       ```powershell
       $tmp = "$HOME\cursor-restore"
       Expand-Archive "$HOME\cursor-backups\cursor-YYYYMMDD.zip" -DestinationPath $tmp
       Rename-Item "$env:APPDATA\Cursor" Cursor.pre-restore
       Rename-Item "$HOME\.cursor" .cursor.pre-restore
       Copy-Item "$tmp\Cursor" "$env:APPDATA\Cursor" -Recurse
       Copy-Item "$tmp\.cursor" "$HOME\.cursor" -Recurse
       ```

       `Compress-Archive` stores each folder under its own name at the top of the zip, so the two copies put `Cursor` and `.cursor` back 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?

- **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 with `cursor --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](/en/cursor-ide/quick-start/project-rules/) covers the file format.
- **MCP servers show no tools.** Run the server's `command` and `args` from `mcp.json` in a terminal. If that fails, the problem is the runtime or its credentials; [MCP setup in Cursor](/en/cursor-ide/quick-start/mcp-setup/) has the fix for each symptom. If it works, quit and restart Cursor fully so it reloads `mcp.json`.
- **You rolled back and Cursor updated itself again.** `update.mode` was not set before the old build started, or your build ignores it. Set it, reinstall the old build, and confirm with `cursor --version` after 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 --version` output and extension lists line by line. Different commit hashes mean they are not on the same build, whatever the version line says.

**Copy-paste prompt: turn a Cursor regression into a bug report**

```text
Cursor regressed after an update and I need to report it. Using only facts you
can check in this session, draft a bug report with these sections:

1. Builds: ask me to paste `cursor --version` for the old and the new build.
2. What changed: the DIFFERENT rows from the baseline comparison, with the
   exact error text.
3. Minimal reproduction: the shortest sequence of steps in this repository
   that shows the difference, run once on the current build to confirm it.
4. What I ruled out: whether the problem remains with `cursor
   --disable-extensions`, and whether the MCP server command works in a
   terminal. Ask me for these results instead of guessing them.

Keep it under 250 words. Do not include file contents, tokens, environment
variables, or anything from .env files.
```

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?

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](/en/cursor-ide/reference/changelog/): 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

- [Staying current with Cursor](/en/cursor-ide/reference/) — The reference hub: which build and SDK each machine and pipeline runs
- [Cursor version history](/en/cursor-ide/reference/changelog/) — Verified milestones, renamed features, and the team release-to-rollout routine
- [Adopting new Cursor features](/en/cursor-ide/reference/feature-adoption/) — Trial what an update adds by blast radius, and prove it in CI
- [Installing Cursor](/en/cursor-ide/quick-start/installation-setup/) — Install channels, the cursor command, and migrating from VS Code

The other tools handle updates differently: see [Claude Code upgrade procedures](/en/claude-code/reference/upgrade-procedures/) and [staying current with Codex](/en/codex/reference/).
