| |

How to Update Claude Code Without Breaking a Running Agent Fleet (2026)

update claude code featured

Learning how to update Claude Code takes about nine seconds. You run claude update, it tells you it moved from one version to the next, and you get on with your day. That part is genuinely solved, and I’m not going to pad it out to look clever.

What isn’t solved is everything that happens after the command returns. I run ten Claude Code containers on cron. An update that lands badly at 03:00 doesn’t inconvenience one developer with a coffee. It takes out a publishing fleet, and nobody finds out until the morning when the logs are already cold.

So this guide does the commodity part fast and correct, then spends its body on the part nobody publishes: pinning, staged rollout, the Docker path, what actually breaks between versions, and a rollback runbook you’d trust at 3am. Along the way I’ll show you the exact moment my own fleet silently stopped updating for fifteen days while cheerfully reporting that auto-updates were enabled.

The right way to update Claude Code for your install method

how to update claude code

There is no single update command. There are four, and which one you need depends entirely on how Claude Code got onto the machine in the first place. Get this wrong and you’ll run a command that succeeds, reports nothing unusual, and leaves you on the same version.

Native install (the default)

If you installed with the official script, updates happen in the background on their own. To force one immediately:

claude update

On success it prints Successfully updated from <old version> to version <new version>. If you’re already current it prints Claude Code is up to date (<version>). Homebrew, WinGet and apk installs report Claude is up to date! instead, which is a useful tell for working out what you’re actually running.

npm global install

npm install -g @anthropic-ai/claude-code@latest

Note the @latest tag. It is load-bearing, and the next section is entirely about why. One more thing the docs are blunt about: never prefix this with sudo. It causes permission problems and it’s a security risk. If you’re reaching for sudo, the real fix is your npm prefix, not more privilege.

Since v2.1.198 the npm package wants Node.js 22 or later. On an older Node you’ll get an EBADENGINE warning rather than a failure, and the install completes anyway, because the package pulls down a native binary that doesn’t use your Node at runtime. Convenient, but it means a stale Node can sit in your stack for months without ever announcing itself.

Homebrew

brew upgrade claude-code
# or, if you installed the latest-channel cask:
brew upgrade claude-code@latest

Homebrew picks your release channel by cask name rather than by setting: claude-code tracks stable, claude-code@latest tracks latest. Homebrew also keeps old versions on disk after upgrades, so run brew cleanup occasionally unless you enjoy donating gigabytes to history.

WinGet and Linux package managers

winget upgrade Anthropic.ClaudeCode

Homebrew, WinGet, apt, dnf and apk do not auto-update by default. For Homebrew and WinGet you can opt in by setting CLAUDE_CODE_PACKAGE_MANAGER_AUTO_UPDATE to 1, and Claude Code will run the upgrade for you in the background and prompt for a restart. On WinGet that upgrade can fail while Claude Code is running, because Windows locks the executable; you’ll get the manual command instead. apt, dnf and apk stay manual because they need elevated privileges.

Installing one exact version

The native installer takes a channel or a literal version number, and this is the command that matters most for the rollback runbook later:

curl -fsSL https://claude.ai/install.sh | bash            # latest
curl -fsSL https://claude.ai/install.sh | bash -s stable  # stable channel
curl -fsSL https://claude.ai/install.sh | bash -s 2.1.89  # one exact build

On Windows PowerShell that’s irm https://claude.ai/install.ps1 | iex. Whatever channel you choose at install time becomes your default for auto-updates, which catches a lot of people out six weeks later.

The npm update -g trap that most guides still recommend

Here’s the thing worth the price of admission. The official documentation says this, in plain language:

To upgrade an npm installation, run npm install -g @anthropic-ai/claude-code@latest. Avoid npm update -g, which respects the semver range from the original install and may not move you to the newest release.

That’s the whole failure mode. npm update -g honours the semver range recorded when you first installed. If that range was pinned or narrow, npm will happily “update” you to the newest version inside that range, report success, and leave you exactly where you were. It is the single most common reason people say “I updated and the version didn’t change.”

Now, I scraped page one for this keyword before writing, because I don’t trust my own memory on other people’s articles. Of the four text results ranking alongside the official docs, three recommend the exact command the docs warn against:

  • One titles its section “The Standard Update Command” and the command underneath it is npm update -g @anthropic-ai/claude-code. Its auto-update cron snippet wraps the same command.
  • Another labels it “Method 1: NPM Update (Recommended)”.
  • A third opens with it as “the standard update (works 95% of the time)”. That page is 645 words, which makes it the thinnest result on page one and still the one most confidently stating a number it cannot possibly have measured.

This isn’t me dunking on three blogs for sport. It’s a pattern worth internalising: on a commodity how-to keyword, the ranking pages copy each other, and a mistake propagates through the whole SERP faster than the correction does. The official docs are result #1 and say the opposite, and it changed nothing. When you’re stuck on a technical answer, read the primary source before you read the guides about the primary source. The guides are downstream of each other, not of the truth.

One more thing about that SERP, since we’re being honest about it: three of the ten results are YouTube videos, and one of the text results is an affiliate funnel that interrupts its own tutorial four separate times with a “free credits for startups” block. You’re not competing with expertise out here. You’re competing with volume.

Free AI Playbook for operators

Get the AI Playbook

The systems I actually run, written up as receipts rather than theory. One email, straight to your inbox.

Lead Magnet - AI Playbook

Check your version first, and what claude doctor tells you that --version won’t

Checking the Claude Code version and update health before updating

Everyone starts with:

claude --version

Which on the container I’m writing this from returns 2.1.266 (Claude Code). Useful, and almost useless. It tells you where you are. It tells you nothing about whether you can get anywhere else.

The command that actually matters is:

claude doctor

Run it and you get the install method, the platform, the resolved binary path, whether auto-updates are on, which channel you’re following, and the one line nobody quotes in any guide I’ve read: the result of the most recent update attempt. Here’s the real output from my container, trimmed:

Running: npm-global (2.1.266)
Platform: linux-x64
Path: /usr/lib/node_modules/@anthropic-ai/claude-code/bin/claude.exe
Auto-updates: enabled
Auto-update channel: latest
Last update attempt: failed (no_permissions) — 2026-09-09

Read those last three lines together. Auto-updates: enabled. Channel: latest. Last attempt: failed, fifteen days ago. Every one of those statements is true at the same time, and the combination is the whole problem. Make claude doctor the first thing you run, not the thing you run after something has already gone wrong.

Auto-updates: when to leave them on, and when they will hurt you

Unattended servers updating overnight with no operator watching

Claude Code checks for updates on startup and periodically while running. New versions download and install in the background, then take effect the next time you start it. For a human at a keyboard this is close to ideal: you get fixes without thinking about it, and the worst case is you notice something moved.

For anything unattended, the calculus inverts. My containers start a fresh Claude Code process on a schedule, twenty-two times a week per brand across twelve daily and ten weekly cron slots. “Takes effect the next time you start Claude Code” means every single scheduled run is a potential version boundary. There’s no session continuity to protect me. If a release changes behaviour I depend on, I don’t find out during a debugging session. I find out from a blog post that didn’t publish.

The honest rule I’ve settled on:

  • Interactive work on your own machine: leave auto-updates on. The upside is real, the blast radius is you, and you’ll notice breakage in seconds.
  • Anything on a schedule, in CI, or in a container: turn them off and move the version to something you control deliberately. Not because updates are bad, but because “changed itself at 3am” and “unattended” are a bad pairing regardless of the software.

To disable them, set DISABLE_AUTOUPDATER in the env key of your settings file:

{
  "env": {
    "DISABLE_AUTOUPDATER": "1"
  }
}

This is the same reasoning I applied to running Claude Code agents in production, where the operating principle is that unattended systems need fewer moving parts, not more clever ones.

My fleet froze on one version for fifteen days and told me updates were enabled

A fleet of containers frozen on a single version

Here’s the receipt, and it’s embarrassing enough to be useful.

My container image installs Claude Code at build time, as root:

RUN npm install -g @anthropic-ai/claude-code

Then, sixty-odd lines later, it does the correct security thing and drops privileges for runtime:

USER agent

Both lines are individually right. Together they produce a trap. The npm global directory at /usr/lib/node_modules is owned by root with 755 permissions. The process that wants to write a new version there runs as uid 1001. It cannot. So every auto-update attempt since the image was built on 2026-09-09 has failed with no_permissions, and the fleet has been running 2.1.266 for fifteen days.

Nothing was broken, exactly. That’s what makes it interesting. claude --version answered normally. Every cron job ran. Across 1,389 recorded runs since June there is not one log line anywhere that says “I tried to update and couldn’t,” because that message surfaces as a one-time startup notice and in claude doctor, and a cron job neither reads notices nor runs doctor.

Two lessons, and the second is the bigger one.

First: containers pin by accident. If you install a tool as root and run as a non-root user, you have pinned that tool’s version to your image build date whether you meant to or not. That is arguably the correct behaviour for a fleet. It just shouldn’t be a surprise, and it certainly shouldn’t be reported to you as “auto-updates: enabled.”

Second: “no error” is not “working.” This is the same class of failure I keep finding in my own stack, and it’s the one that costs the most. A silent success message over a failed operation is worse than a loud crash, because a crash gets fixed on the day it happens. I’ve written about this pattern before in the context of having Claude review its own work: the failures that survive are the ones that look like successes.

If you take one action from this entire article, make it this: run claude doctor on every machine you have that runs Claude Code unattended, and read the “Last update attempt” line. I’d put money on at least one of them surprising you.

Jon Jones

⚡ GET THE AI EDGE

Weekly AI tips that actually save you time and money. No fluff, no hype — just what works.

Newsletter Signup - Blog CTA

Pinning on purpose: autoUpdatesChannel, minimumVersion, and why operators pin

Accidental pinning is a bug. Deliberate pinning is a strategy, and Claude Code has proper support for it that almost nobody uses because the docs explain the mechanism without ever explaining the motive.

Release channel. Two options, set in settings.json or via /config → Auto-update channel:

{
  "autoUpdatesChannel": "stable"
}

"latest" is the default and gets you new features the moment they ship. "stable" puts you on a build that’s typically about a week old, skipping releases with major regressions. That one-week lag is the cheapest insurance in this entire article. You are letting other people’s Tuesday be your regression test.

Version floor. minimumVersion sets a floor that background updates and claude update refuse to go below:

{
  "autoUpdatesChannel": "stable",
  "minimumVersion": "2.1.100"
}

The practical use is exactly the transition above. If you’re on a newer latest build and you switch to stable, the floor stops that switch from silently downgrading you. Switching via /config prompts you and sets the floor to your current version if you choose to stay put.

Hard boundaries. minimumVersion only constrains updates. If you need Claude Code to outright refuse to start outside a version range, that’s requiredMinimumVersion and requiredMaximumVersion in managed settings. Updates respect the maximum ceiling too. For a team or a fleet, managed settings enforce an org-wide channel that user and project settings cannot override, which is the difference between a policy and a suggestion.

Why bother? Because the cost asymmetry is brutal. A new feature landing three days later costs you nothing. A behaviour change landing mid-run across ten containers costs you a day of forensics on cold logs. Pin, then promote on your schedule.

How to update Claude Code inside Docker containers on a cron schedule

Scheduled container updates running on a cron timetable

This is the section that doesn’t exist anywhere else on page one, so here’s the approach that actually survives contact with a running fleet.

Don’t update inside a running container. It’s the obvious move and it’s wrong. You get a mutable container that no longer matches its image, the change vanishes on the next docker compose up, and you’ve created a machine whose state exists only in your memory. Treat the running container as immutable.

Pin the version in the Dockerfile. Make the version an explicit, reviewable, diffable line:

ARG CLAUDE_CODE_VERSION=2.1.266
RUN npm install -g @anthropic-ai/claude-code@${CLAUDE_CODE_VERSION}

Now the version lives in version control instead of in whatever npm felt like serving on build day. Bumping it is a one-line commit, which means it’s reviewable, attributable, and revertible. Two identical builds three weeks apart now produce identical containers, which is the entire point of building images in the first place.

Disable the auto-updater explicitly. Don’t rely on the permissions accident to do it for you. Set DISABLE_AUTOUPDATER=1 so the intent is stated rather than implied, and so nobody “fixes” your permissions six months from now and quietly reintroduces 3am version drift.

Never update during a scheduled window. Find the real gap in your cron table and rebuild there. Mine runs jobs at 00:07, 07:07, 09:07, 11:07, 12:07, 14:07, 16:07, 18:07, 20:07, 21:07, 22:07 and 23:37, with the longest timeout at 90 minutes. The honest quiet window is roughly 02:00 to 06:00. Work out yours before you touch anything, and account for job timeouts rather than start times.

If you’re building this kind of scheduled agent infrastructure from scratch, I’ve documented the whole hosting layer in my guide to running a self-hosted AI server, and the remote operations side in Claude Code remote control.

Staged rollout: update one container, verify, then promote

Ten containers on the same version is a single point of failure wearing a fleet costume. Updating all ten at once converts a possible problem into a certain outage. So: canary.

  1. Pick the cheapest brand as canary. Lowest traffic, most forgiving failure mode, shortest jobs. Not your best performer.
  2. Bump the pinned version in that container only. One ARG, one rebuild, one container restarted.
  3. Let it run a full cycle. Not one job. A full day, so every skill type touches the new binary. My fleet spans twenty job types and they exercise wildly different surfaces: file editing, shell, MCP servers, subagents, long-running background tasks. One successful run proves almost nothing.
  4. Diff the logs, not the exit codes. This is where most rollouts lie to you. Exit code 0 with no output is the signature failure of an agent run, and I’ve got 18 historical logs that exited clean while producing nothing at all. Compare log length and the presence of your own result markers against the previous week’s runs.
  5. Promote in two waves. Half the fleet, another full day, then the rest. If something version-specific is going to surface, it surfaces on volume.

The whole procedure costs about three days of calendar time and roughly zero attention, because each step is a rebuild and a wait. Compare that with debugging nine simultaneously broken containers on a Sunday. If you’d rather not build this scaffolding yourself, this is exactly the kind of thing I set up on a done-for-you automation build, and the rollout discipline is usually the part clients didn’t know they were missing.

The rollback runbook

Rolling Claude Code back to a known-good version

At 3am you do not want to be reading documentation. You want four lines you already trust. Write these down somewhere that isn’t this article.

1. Establish what you’re on and what happened.

claude --version
claude doctor

2. Go back to the exact known-good build. Native install:

curl -fsSL https://claude.ai/install.sh | bash -s 2.1.89

npm install:

npm install -g @anthropic-ai/claude-code@2.1.89

Confirm with claude --version, which prints the exact version you asked for.

3. Stop it climbing back up. A rollback that auto-updates itself forward again in twenty minutes is not a rollback. Set DISABLE_AUTOUPDATER=1, or set minimumVersion to the build you just installed, before you walk away.

4. Record the known-good version somewhere durable. The Dockerfile ARG is the right place, because it’s the same value your next build will use. A note in a chat thread is not a runbook.

One native-install detail worth knowing before you need it: on macOS and Linux the launcher at ~/.local/bin/claude is a symlink into ~/.local/share/claude/versions/. Every installed version stays on disk, so rolling back is a matter of pointing at a different directory rather than re-downloading anything. If you replace that launcher with your own script, Claude Code leaves it alone from v2.1.207 onward, installs new versions alongside, and lets your launcher decide what runs. Before 2.1.207 the auto-updater overwrote a custom launcher on every update, which is a fun one to discover retroactively.

What actually breaks between versions, and FAQ

The release notes will tell you what was added. They’re less forthcoming about what moved. In practice, for anyone running agents rather than typing at them, the surfaces that bite are: hook behaviour and firing order, the settings.json schema, how skills and subagents are discovered and loaded, permission-mode defaults, and MCP server connection handling. None of these break loudly. They change shape, and your automation quietly does something slightly different at 3am.

Your post-update checklist should therefore be: run claude doctor and read the warnings section, confirm your settings file still parses without complaint, fire one job from each category, and compare the output length against last week’s. On my own container claude doctor is currently flagging a malformed MCP entry (leading whitespace in an auth header) that no other command has ever mentioned. That’s the sort of thing that sits there for months.

How often should I update Claude Code?

Interactive use: whenever it offers, which is roughly weekly. Unattended fleets: monthly, deliberately, on the stable channel, with a canary. Chasing every release on a fleet buys you features you weren’t waiting for at the price of surprises you weren’t expecting.

Why didn’t my version change after updating?

In order of likelihood: you ran npm update -g instead of npm install -g ...@latest; the npm global directory isn’t writable by the user running the update; you have multiple installs and your PATH resolves to a different one (check which claude against the Path line in claude doctor); or you’re on a package manager that doesn’t auto-update and needs its own upgrade command.

Do I need to re-authenticate after updating?

Normally no. Credentials and settings live outside the binary. If auth does break after an update, treat it as a symptom of a partially-applied update rather than an auth problem, and check claude doctor first.

Can I update Claude Code without npm?

Yes, and on a server you probably should. The native installer is a single curl command, takes an explicit version number, and keeps old versions on disk for instant rollback. The npm route mainly makes sense when npm is already how you manage tooling on that box.

Will updating reset my settings or skills?

No. Settings, skills and project configuration live in your settings files and project directories, not in the installed package. What can change is how those files are interpreted, which is why a settings-file parse check belongs in your post-update routine.

Final thoughts

The command is claude update. The discipline is everything around it.

If you’re one person on one laptop, take the two-minute version: run claude doctor occasionally, use npm install -g @anthropic-ai/claude-code@latest rather than npm update -g, and let auto-updates do their job.

If you’re running agents unattended, take the whole thing. Pin the version in your Dockerfile. Disable the auto-updater on purpose instead of by accident. Canary one container, wait a full cycle, then promote. Know your rollback command before you need it.

And go run claude doctor on your production boxes right now. I thought my fleet was current for fifteen days. It wasn’t, it never told me, and I only found out because I sat down to write this. Nothing about running autonomous systems is passive. It’s leveraged, which is a very different thing, and the difference is exactly this kind of check.

If you’d rather have this built and monitored properly instead of discovering your own version drift in a blog post, book an automation strategy session and we’ll go through your setup. And if you’re still weighing up the tool itself, start with Claude Code alternatives and Claude vs Claude Code, or see what it looks like pointed at real work in building websites with Claude Code.

Open a terminal. Type claude doctor. Ten seconds. Let’s build.

Free AI Playbook for operators

Steal My Operator Playbook

Real builds, real logs, real numbers from a fleet of autonomous containers. No fluff, no filler.

Lead Magnet - AI Playbook
The AI Playbook — Free Download

📥 FREE: THE AI PLAYBOOK

The exact tools and workflows I use to run a one-person agency. 25 years of marketing experience distilled into an actionable guide. Yours free.

Lead Magnet - AI Playbook

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *