# Incremental migration from cosmiconfig

> Swap cosmiconfig for seniority in one import, then move to discover() and resolve() when you want precedence and provenance — and what changes at each step.

Source: https://seniority.interlace.tools/docs/recipes/incremental-migration

## 1. Change the import

```diff
- import { cosmiconfig } from 'cosmiconfig';
+ import { cosmiconfig } from 'seniority';
```

The explorer is cosmiconfig's (`search`, `load`, `clearCaches`), graded 186 of 243 by
cosmiconfig's own suite. The gap is YAML. If your config can be YAML, pass the parser:

```js
import yaml from 'js-yaml';
import { cosmiconfig } from 'seniority';

const explorer = cosmiconfig('mytool', { loaders: { '.yaml': (_path, text) => yaml.load(text), '.yml': (_path, text) => yaml.load(text) } });
```

For lilconfig the swap is `seniority/lilconfig`, graded 77 of 77, and `npx burgee migrate`
makes it for you.

## 2. Resolve instead of merging by hand

A cosmiconfig caller usually merges the file with flags and the environment itself, in an order
written once per program. `discover` plus `resolve` replaces that code, and keeps the record:

```js title="migrated.mjs"
import { writeFileSync } from 'node:fs';

import { cosmiconfig, discover, explain, resolve } from 'seniority';

writeFileSync('mytool.config.json', '{ "region": "eu-2", "retries": 3 }\n');
const env = { MYTOOL_RETRIES: '5' };
const flags = { region: 'ap-1' };

// Before: find the file, then merge by hand.
const found = await cosmiconfig('mytool', { searchPlaces: ['mytool.config.json'] }).search();
const before = { ...found.config, ...(env.MYTOOL_RETRIES && { retries: Number(env.MYTOOL_RETRIES) }), ...flags };
console.log('before:', before);

// After: one order, and the answer to "why".
const specs = { region: { type: 'string' }, retries: { type: 'number' } };
const result = resolve(specs, { flags, env, envPrefix: 'MYTOOL', config: await discover({ name: 'mytool', cwd: '.', env }) });
console.log('after: ', result.values);
process.stdout.write(explain('retries', result));
```

```text title="node migrated.mjs"
before: { region: 'ap-1', retries: 5 }
after:  { region: 'ap-1', retries: '5' }
retries = "5"   from env MYTOOL_RETRIES
         candidates: flag --retries (unset), config file mytool.config.json:1 3, default (unset)
```

Note the one difference in the output: the environment value is the string `"5"`. `resolve`
converts only booleans from the environment. Declare the shape and run `validate` (see
[Validation](/docs/guides/validation)) to catch a number that arrives as a string, or convert
it where you read it.

What changes when you move:

- **The order is fixed:** flag, env, config, `package.json`, default.
- **The environment reaches declared options only**, under the prefix.
- **`discover` looks in fewer places** than cosmiconfig's default search places: an explicit
  file, `<NAME>_CONFIG`, `<name>.config.*` in the working directory, and the user config
  directory. It walks upward only when asked.
