Coming from cosmiconfig
A cosmiconfig alternative with zero dependencies: import { cosmiconfig } from seniority, graded 242 / 243 by cosmiconfig's own suite, level with cosmiconfig itself — with provenance, so every resolved value can say where it came from, as text, --json data or an agent event.
seniority is a cosmiconfig alternative that also covers what dotenv, rc and
find-up do beside it: one resolution for flags, environment, config files, a
package.json field and defaults, in a fixed order, with no dependencies.
Migrate from cosmiconfig in one import
- import { cosmiconfig } from 'cosmiconfig';
+ import { cosmiconfig } from 'seniority';The root export carries cosmiconfig's surface: cosmiconfig, cosmiconfigSync, Explorer,
ExplorerSync, defaultLoaders, defaultLoadersSync, getDefaultSearchPlaces,
globalConfigSearchPlaces and metaSearchPlaces — all three search strategies, both caches,
$import, and the meta-config merge.
YAML reads as it does in cosmiconfig. cosmiconfig takes js-yaml for .yaml, .yml and
extensionless files; seniority reads them with seniority/yaml, its own parser, loaded on the
first YAML file and never before. It returns what js-yaml 5 returns, and its errors carry
js-yaml's reason and position. npx burgee migrate makes the import swap for you.
Is seniority compatible with cosmiconfig?
Level with cosmiconfig on its own suite. cosmiconfig's own suite, vendored at 10.0.1 and unmodified
apart from the import specifier, runs against seniority beside a control that runs it
against real cosmiconfig:
| passing | rate | |
|---|---|---|
seniority | 242 / 243 | 99.6% |
| cosmiconfig itself (control) | 242 / 243 | 99.6% |
From Compatibility, which npm run compat:page generates from the
oracle's last run; that page is the authority, and it names every case that leaves the gate.
The one case not passing fails for cosmiconfig too: the harness reaching for a file path the
vendored copy does not have. The XDG global-directory pair, which registers only on Linux,
passes for both: a global search ends in $XDG_CONFIG_HOME/<name> when that is set, as
cosmiconfig's does. On macOS the pair does not register, and both read 240 of 241.
Level with the control is the claim, and it is a grade, not the word compatible.
The same page grades seniority/lilconfig (lilconfig's own suite), seniority/dotenv and
seniority/rc.
What you gain over cosmiconfig
cosmiconfig finds a file. seniority resolves the value, and keeps the receipt:
- Provenance on every value.
resolve()returns each option's winning source and every candidate it beat.explain('region', result)printsregion = "eu-2" from config file ./app.config.jsonwith the unset flag and env candidates beneath it. - The same record for agents.
explanationJson()is that record as--jsondata, andexplanationEvent()is it as an agent event — generated by the code that picked the value, so neither can drift from the text. - An order nobody can rearrange.
flag > env > config file > package.json field > default, exported asORDER. A plugin can add a source between them and can never beat the flag the user typed — so the agent reading your--schemaand the person reading your--helpcan reason about it from the outside. resolveis pure. No filesystem, noprocess.env: the environment is passed in, so it is testable without a process.
When to switch from cosmiconfig
- "Why is this set to that?" is a question your users or agents ask, and nobody can answer it without reading the source.
- You want config, env and flags in one precedence rather than three hand-written ones.
- You do not need YAML, or you are content to pass the parser in.
The API, the discovery rules and the other drop-in paths are on seniority.
Compatibility
How seniority's four drop-ins are graded by their incumbents' own suites — lilconfig 77 / 77, rc 1 / 1 (one bit), cosmiconfig 242 / 243 (level with cosmiconfig itself), dotenv 197 / 197 (level with dotenv 18 itself) — and the differences that remain.
Coming from dotenv
A dotenv alternative with a drop-in path: import dotenv from seniority/dotenv, graded 197 / 197 by dotenv 18's own test suite, level with dotenv itself — then the same package resolves every value across flags, env, config files and defaults, with provenance as text, --json data or an agent event.