NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
npm · #3845 most downloaded on npm
base library for oclif CLIs
Last release 17 days ago
31 Aug 2026
Ships fairly regularly
a new release about every 2 weeks
Nearly every release is documented
notes for 60 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
6 years old
479 releases · first in 2020
One column per quarter.
W-17692101: migrate to eslint 9
deps: bump ansis from 3.8.1 to 3.9.0
deps: bump ansis from 3.6.0 to 3.8.1
deps: bump ansis from 3.5.2 to 3.6.0
deps: bump ansis from 3.4.0 to 3.5.2
### Features * add finally hook
### Bug Fixes * export action from ux
### Features * add atLeastOne flag property
deps: bump nanoid from 3.3.6 to 3.3.8
deps: bump lilconfig from 3.1.2 to 3.1.3
deps: bump debug from 4.3.7 to 4.4.0
### Bug Fixes * typo in ux module README
deps: bump cross-spawn from 7.0.3 to 7.0.6
add env var to disable link warning
Revert "fix: bump is-wsl to v3 (#1211)" (#1235) (fa76792), closes #1211 #1235
fix aliases in config.commandIDs missing the default topic separator
improve solution for handling circular json
remove circular references when colorizing json
add respectNoCacheDefault to help options
### Bug Fixes * bump is-wsl to v3
### Bug Fixes * deprecated aliases bug
use topic separator for deprecated alias warnings in help
warn about node version mismatch
deps: bump path-to-regexp from 6.2.1 to 6.3.0
deps: bump debug from 4.3.6 to 4.3.7
### Bug Fixes * handle large throughput writes
deps: bump micromatch from 4.0.7 to 4.0.8
ts-path: use file url to import tsx at runtime
deps: bump ansis from 3.3.1 to 3.3.2
deps: bump requirejs from 2.3.6 to 2.3.7
### Bug Fixes * ignore escaped delimiters
### Bug Fixes * husky 9.1.1 fix
deps: bump ansis from 3.2.1 to 3.3.1
deps: bump ansis from 3.2.0 to 3.2.1
### Bug Fixes * export ArgDefinition
use colorize to ensure proper TTY detection
correctly identify powershell on windows
deps: bump minimatch from 9.0.4 to 9.0.5
ignore cache when reading user pjson (#1124) (6038c5c), closes #1125
single command cli symbol on help output
deps: bump braces from 3.0.2 to 3.0.3
### Bug Fixes * use lilconfig
### Bug Fixes * export parser related types
### Bug Fixes * add export for parser
### Bug Fixes * parsed args regression
…access the debug logs in the console. The only breaking change will be that the namespace for all the logs with be prefixed with a root namespace, ocl…
ux moduleAs described here, we're removing most of the methods in the ux module. We're simply unable to adequately support the feature set that ux offers and think that most people would benefit from using dedicated libraries that are better supported.
We are, however, keeping some of the functionality. The new ux module will contain the following:
colorizeerrorexitaction - will be unchanged from previous version except that the spinner color will be configurable using themes.warnstdout - rename of ux.logstderr - rename of ux.logToStderrcolorizeJson - Apply color theme to arbitrary JSON.annotationanykeyconfirmdebugdone (use ux.action.stop() instead)flush (still available via @oclif/core/flush)info (use ux.stdout instead)progresspromptstyledHeaderstyledJSONstyledObjecttabletracetreeurlwaitYou will need to replace everything that ux was doing with dedicated libraries. Here are a few suggestions:
The color of the spinner can now be customized using the spinner key in your theme.
The JSON output can also now be customized with these keys:
brace
bracket
colon
comma
key
string
number
boolean
null
In the current major version, we exclusively use debug for debug logs. In the next major, we're going to export a Logger interface that will allow you to provide a custom logger for @oclif/core to use. This will be useful if you want all the @oclif/core debug logs to go through your own logger.
The default logger will continue to use debug under the hood. So if you choose to use the default, you can continue to use the DEBUG environment variable to access the debug logs in the console. The only breaking change will be that the namespace for all the logs with be prefixed with a root namespace, oclif.
So if you're used to using DEBUG=config:* my-cli do stuff, you'll need to start doing this instead: DEBUG=oclif:config:* my-cli do stuff
export type Logger = {
debug: (formatter: unknown, ...args: unknown[]) => void
error: (formatter: unknown, ...args: unknown[]) => void
info: (formatter: unknown, ...args: unknown[]) => void
trace: (formatter: unknown, ...args: unknown[]) => void
warn: (formatter: unknown, ...args: unknown[]) => void
child: (namespace: string) => Logger
namespace: string
}
// oclif-logger.ts
import { format } from 'node:util';
import { Interfaces } from '@oclif/core';
import { Logger } from './my-cli-logger';
export const customLogger = (namespace: string): Interfaces.Logger => {
const myLogger = new Logger(namespace);
return {
child: (ns: string, delimiter?: string) => customLogger(`${namespace}${delimiter ?? ':'}${ns}`),
debug: (formatter: unknown, ...args: unknown[]) => myLogger.debug(format(formatter, ...args)),
error: (formatter: unknown, ...args: unknown[]) => myLogger.error(format(formatter, ...args)),
info: (formatter: unknown, ...args: unknown[]) => myLogger.info(format(formatter, ...args)),
trace: (formatter: unknown, ...args: unknown[]) => myLogger.trace(format(formatter, ...args)),
warn: (formatter: unknown, ...args: unknown[]) => myLogger.warn(format(formatter, ...args)),
namespace,
};
};
export const logger = customLogger('sf');
// bin/run.js
#!/usr/bin/env node
async function main() {
const {execute} = await import('@oclif/core');
const { logger } = await import('../dist/oclif-logger.js');
await oclif.execute({
dir: import.meta.url,
loadOptions: {
root: import.meta.dirname,
logger,
},
});
}
await main();
You can also provide the logger to Config, in the event that you instantiate Config before calling run or execute
import {Config, run} from '@oclif/core'
const config = await config.load({
logger,
});
await run(process.argv.slice(2), config)
rc filesCurrently the configuration for oclif must live inside the oclif section of your CLI or plugin's package.json. This can be difficult if you have a large amount of configuration, you want to dynamically change the configuration, or want to ensure that your configuration is correctly typed.
To solve this, we can now use lilconfig to read in a variety of rc files.
Despite being able to use an rc file, @oclif/core will still be dependent on your package.json to get the name, version, and dependencies. We could ask that you put those value in your rc file, but duplicating that information across two files feels like something people would rather not do.
If you choose to use an rc file, one thing you must consider is that there will be a slight performance hit due to needing to search for the rc file in addition to the package.json.
This is the list of supported files. Please feel free to create a PR to add support for other files
.oclifrc
.oclifrc.json
.oclifrc.js
.oclifrc.mjs
.oclifrc.cjs
oclif.config.js
oclif.config.mjs
oclif.config.cjs
We'll have top level exports for:
argscommandconfigerrorsexecuteflagsflushhandlehelphooksinterfacesloggerperformancerunsettingsutil/idsuxThe current way of accessing these looks like this:
import {run, flush, handle} from '@oclif/core'
With top level exports, you could access those like this:
import run from '@oclif/core/run'
import flush from '@oclif/core/flush'
import handle from '@oclif/core/handle'
The benefit of this is that you'll be able to import those utilities without also importing everything else that @oclif/core exports.
As a result of this change, deep imports (e.g. import {Command} from '@oclif/core/lib/command.js) will no longer work.
In case you missed it, we introduced new command discovery strategies that make bundling possible. In order to do that, the location of commands and hooks needed to be configured using a target (i.e. a file or directory containing the commands or hooks) and an identifier (i.e. the name of the export inside the target).
This change originally only worked for commands and hooks but now also works for custom help classes so that those can be bundled as well.
We enabled exactOptionalPropertyTypes (fixes #960) for improved type safety
Interfaces.PJSON has now been simplified to a single type instead of Interfaces.PJSON.CLI and Interfaces.PJSON.Plugin
There's a new Interfaces.OclifConfiguration that represents everything that could be added to the oclif section of your package.json (or rc file). This is particularly helpful if you want to use a .oclifrc.ts and ensure that your oclif configuration matches the expected type.
tsxIf your ESM plugin has a devDependency on tsx, then you oclif can now auto-transpile the code at runtime
isolate supports-color for testing
support tsx for runtime transpilation
support tsx for runtime transpilation
check supports-color in colorize
### Bug Fixes * allow empty ux.stdout
### Bug Fixes * update hook type
improve types and ProdOnlyCache
### Bug Fixes * restore baseFlags support
### Bug Fixes * clarify types (64b7669) ### Features * remove baseFlags
improved types and top-level exports
revert ignoreDuplicates in warn
# 4.0.0-beta.5 (2024-05-06) ### Features * support rc files (#1067) (6af9c71) # 4.0.0-beta.4 (2024-04-25) # 4.0.0-beta.3 (2024-04-24) ### Bug Fixes *
### Features * support rc files
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →