Auto-Updating CLIs Without Annoying Developers
CLI updates should be invisible until they matter. Background checks, cached notifications, self-update commands, and CI version pinning keep developers in flow.

A CLI tool forced an update mid-deploy. The developer was running a deployment script that included a CLI command. The CLI checked for updates, found one, downloaded it, restarted itself, and broke the script because the updated version changed a command's output format. The deployment failed. The developer switched to a different tool.
This story captures the tension in CLI updates. Developers need the latest version for security patches, bug fixes, and new features. But they also need their tool to behave predictably, especially in automated workflows. Forcing updates destroys trust. Never updating leaves developers on buggy versions. The solution is in between: make updates visible, optional, and non-disruptive.
Background version checks

Our CLI checks for updates on every startup. But the check runs in a background goroutine that finishes after the main command has already completed. The update check adds zero latency to command execution.
Here is the flow: the developer runs a command. The CLI starts the command and simultaneously spawns a background goroutine that checks the update server. The command runs and outputs its result. After the output, if the background check finished and found a new version, a single notification line prints:
$ nowah bookings get bkg_abc123
Booking bkg_abc123: confirmed, 2 passengers, JFK→CDG Jun 15-22
...
💡 Nowah CLI v2.4.0 is available. Run 'nowah update' to upgrade.The notification prints after the command output, not before. It never interrupts the flow. It never blocks execution. If the background check has not finished by the time the command completes, no notification appears — the developer is not waiting for an update check.
The check result caches for 24 hours. A developer running 50 commands per day hits the update server once. The cache is a simple file in the config directory with a timestamp. If the cache is fresh, the background goroutine returns immediately without a network call.
The self-update command
`nowah update` is an explicit, developer-initiated update. It downloads the correct binary for the current operating system and architecture, verifies the SHA-256 checksum, replaces the current binary, and prints a summary of what changed.
The update command shows a brief changelog — the two or three most important changes in the new version — so the developer knows what they are getting. If the update includes breaking changes (a command renamed, an output format changed), the changelog highlights this with migration instructions.
Rollback is built in. `nowah update --rollback` restores the previous version. The CLI keeps one previous version on disk for this purpose. If an update causes problems, the developer can roll back in seconds without hunting for an older binary.
Version pinning for CI

Automated environments need deterministic behavior. A CI pipeline that works on Monday should work on Tuesday without surprise changes from a CLI update.
Setting the `NOWAH_CLI_VERSION` environment variable pins the CLI to a specific version. When this variable is set:
- The startup version check is completely disabled.
- The `nowah update` command refuses to run.
- If the installed CLI version does not match the pinned version, the CLI prints a warning but continues execution.
This gives CI owners full control. They choose when to update by changing the environment variable, not by hoping the auto-updater behaves.
We recommend pinning in CI and not pinning in local development. Local developers benefit from staying current. CI pipelines benefit from stability.
Breaking change communication
Major version updates require extra care. If version 3.0.0 renames commands, changes output formats, or removes deprecated features, the passive notification line is not enough.
When a major version is available, the notification includes a "what's changed" summary and a link to the full migration guide:
⚠️ Nowah CLI v3.0.0 is available (major update).
See migration guide: docs.nowah.com/cli/v3-migration
Run 'nowah update' to upgrade, or 'nowah update --pin 2.x' to stay on v2.The `--pin 2.x` option pins to the latest 2.x version, receiving bug fixes and minor updates within the 2.x line without jumping to 3.x. This gives developers who are not ready to migrate a way to stay secure and functional on the previous major version.
We maintain the previous major version with security patches for at least six months after a new major version releases. This is the same philosophy as our API versioning: give developers time to migrate without forcing them.
Testing the update flow
We test the update mechanism itself in CI. The test downloads a known version, runs the update command to upgrade to a newer known version, verifies the binary changed, verifies the changelog printed correctly, then rolls back and verifies the original version is restored.
We also test the version check caching: run a command, verify the cache file is created, run another command immediately, verify no network call was made. These are not glamorous tests, but they prevent regressions in a feature that every developer interacts with.
The update flow is one of those features that is nearly invisible when it works correctly. The developer gets a quiet nudge about new versions, updates when it is convenient, and never has their workflow interrupted. That invisibility is the goal. The best update experience is one the developer barely notices.
Nowah is an AI travel agent that searches and books real flights and hotels through conversation — no filters, no thirty open tabs. Plan your next trip.