How to Add CLI Update Notifications
Check for a newer version on npm and notify the user, so they know to upgrade without blocking the command.
On this page
Introduction
The hardest part of notify on new version is not writing the code — it is deciding what the code is allowed to reject. A update notifier setup that accepts everything is easy to ship and expensive to operate, because every malformed input becomes a production surprise. The discipline is to enumerate the shapes the system actually receives, encode them in update notifier, and let the library reject the rest loudly. This keeps the happy path fast and the failure path visible.
Most teams adopt update notifier for notify on new version after an incident teaches them that unvalidated input is load-bearing. The incident is the expensive way to learn the lesson; a quarterly review of the input shapes is the cheap way. Pin the shapes with update notifier, refuse the deploy that breaks the pin, and treat the pin as a contract the rest of the system can rely on. A contract that is not enforced is a wish.
The sections below walk through the concrete decisions: where to put the update notifier check, how to keep it fast under load, what to do when the contract changes, and how to test the failure paths so they degrade on purpose instead of by accident.
Check npm registry
Check npm registry is the first decision because it determines what the rest of the update notifier pipeline can assume. A wrong choice here turns into notify on new version under load, and the invariant you thought update notifier guaranteed no longer holds. Measure the impact before committing, because the cost of a bad choice is paid in incidents, not in a code review.
The test for Check npm registry is the one most teams skip: drive update notifier to the failing condition and assert the system degrades gracefully. Write it with a fake clock for time-based logic, a stub for the failure path, and an assertion on the user-visible outcome. A test that passes by timing out is a hope, not a test.
import updateNotifier from 'update-notifier';
import pkg from './package.json' with { type: 'json' };
updateNotifier({ pkg, updateCheckInterval: 86400000 }).notify();
The javascript above is the shape to ship for notify on new version. It is small enough to audit and specific enough that the failure behavior is obvious. Adapt the constants to your traffic and latency budget, and resist the urge to handle cases the system has not seen yet.
Compare versions
The mechanism behind Compare versions is straightforward in update notifier, but the consequences ripple. A wrong choice here turns into notify on new version under load, and the invariant you thought update notifier guaranteed no longer holds. Measure the impact before committing, because the cost of a bad choice is paid in incidents, not in a code review.
The test for Compare versions is the one most teams skip: drive update notifier to the failing condition and assert the system degrades gracefully. Write it with a fake clock for time-based logic, a stub for the failure path, and an assertion on the user-visible outcome. A test that passes by timing out is a hope, not a test.
Show a non-blocking hint
Show a non-blocking hint is where most update notifier implementations leak performance. A wrong choice here turns into notify on new version under load, and the invariant you thought update notifier guaranteed no longer holds. Measure the impact before committing, because the cost of a bad choice is paid in incidents, not in a code review.
The test for Show a non-blocking hint is the one most teams skip: drive update notifier to the failing condition and assert the system degrades gracefully. Write it with a fake clock for time-based logic, a stub for the failure path, and an assertion on the user-visible outcome. A test that passes by timing out is a hope, not a test.
test('notifies on newer version', () => {
expect(notifier.update).toBeDefined();
});
Pin the behavior with this test. A update notifier setup that passes this test degrades on purpose instead of by accident, which is the difference between a managed failure and an incident.
Throttle the check
The hard part of Throttle the check is not the happy path — it is what happens when update notifier fails halfway. A wrong choice here turns into notify on new version under load, and the invariant you thought update notifier guaranteed no longer holds. Measure the impact before committing, because the cost of a bad choice is paid in incidents, not in a code review.
The test for Throttle the check is the one most teams skip: drive update notifier to the failing condition and assert the system degrades gracefully. Write it with a fake clock for time-based logic, a stub for the failure path, and an assertion on the user-visible outcome. A test that passes by timing out is a hope, not a test.
Do not block the command
Do not block the command should be observable without a debugger. A wrong choice here turns into notify on new version under load, and the invariant you thought update notifier guaranteed no longer holds. Measure the impact before committing, because the cost of a bad choice is paid in incidents, not in a code review.
The test for Do not block the command is the one most teams skip: drive update notifier to the failing condition and assert the system degrades gracefully. Write it with a fake clock for time-based logic, a stub for the failure path, and an assertion on the user-visible outcome. A test that passes by timing out is a hope, not a test.
Test the notifier
Test the notifier is a trade, not a winner. A wrong choice here turns into notify on new version under load, and the invariant you thought update notifier guaranteed no longer holds. Measure the impact before committing, because the cost of a bad choice is paid in incidents, not in a code review.
The test for Test the notifier is the one most teams skip: drive update notifier to the failing condition and assert the system degrades gracefully. Write it with a fake clock for time-based logic, a stub for the failure path, and an assertion on the user-visible outcome. A test that passes by timing out is a hope, not a test.
Common pitfalls
The common pitfalls in notify on new version all reduce to one mistake: treating update notifier as a formality instead of a contract. The contract is the thing the rest of the system relies on, and a weak contract propagates weakness everywhere.
- Skipping the update notifier boundary so notify on new version enters unvalidated.
- Assuming update notifier is fast without measuring the tail latency under load.
- Letting notify on new version fail silently instead of failing loudly with a metric.
- Testing only the happy path so the update notifier failure surfaces in production.
- Sharing mutable state across requests so one bad input poisons the next.
Conclusion
Do not conflate the conclusion with the implementation. They look similar from the outside but the failure modes differ: update notifier fails fast and the caller knows, while an unchecked path fails slow and the caller guesses. Choose the one whose failure mode your system can absorb, and document the choice at the call site.
Self-check: write a test that drives update notifier to the failing condition and assert the system degrades gracefully. Then notify on new version is a property you maintain, not a feature you hope for.
Sources: update-notifier, npm registry
FAQ
- Check interval?
- Daily. Do not check on every run — it adds latency.
- Block?
- Never. Show the hint after the command completes.
Report a problem with this articleOpens a pre-filled issue on GitHub.