Precedence and Conflicts
Declare the same key in both config files and the kit stops and names both rather than picking a winner. No merge, no "the typed config wins", no order to remember. Delete the duplicate from one of them.
the-i18n-cli status
ERROR defaultLocale is declared in both
/app/i18n-kit.config.ts
/app/.i18n-mcp.json
Neither wins — a reader cannot tell which one took effect. Delete the duplicate from one of them.
The command exits 1 without doing any work, and the same message comes back as a
machine-readable error object carrying the code CONFIG_ERROR, so an agent gets
the file paths rather than a truncated stack.
Two files may both exist. What is rejected is the same key in both — the check
compares the keys that are actually present, ignoring the JSON-only $schema.
Split by key and both files are read: glossary in one and protectedLocales
in the other works, because the two sets are disjoint and there is nothing to
choose between.
Where Precedence Is Resolved
Two hand-written files are at the same level, so neither wins. Precedence is resolved only between sources at different levels:
| Sources | Winner | Why the ordering is obvious |
|---|---|---|
--baseUrl flag, I18N_BASE_URL, providerBaseUrl in config | Flag, then env var, then config | A flag is typed for this run; config is the standing default |
| Declared config vs. a value read out of a framework's config file | Declared | You wrote one of them for the kit specifically |
| A config in an app directory vs. one in the repository root | The nearest one, outright | The same rule ESLint and tsconfig.json use |
| Locale directory probing vs. a directory named in a framework config | The framework config | It states where the files are; probing guesses |
Blank values count as unset in the base URL chain, so an unset shell variable expanding to an empty string does not shadow the config below it.
Nuxt: Checked at Build Time
@the-i18n-kit/nuxt validates your config during the build, where a diagnostic
lands next to the code that caused it. It reads every place policy can be
declared — both i18n-kit.config.* and .i18n-mcp.json — so a key declared
twice fails the build rather than being discovered later by a command.
The module also rejects the keys it derives. locales, localeDirs and
defaultLocale in a hand-written config are an error in a Nuxt project, because
Nuxt already answers them and keeping both means two sources of truth with no
way to tell which won:
ERROR "defaultLocale" is derived from your Nuxt config. Remove it from
.i18n-mcp.json — this module publishes what Nuxt resolved.
The build then fails, listing every problem it found. Set
i18nKit.failOnInvalidConfig to false to report without failing — the
diagnostics are still printed; the flag only decides whether they stop you.
nuxt.config.ts. The module's options are
enabled and failOnInvalidConfig; everything else lives in one of the two
config files, which the CLI reads directly.Limits
- The conflict check is per key, not per subkey. Declaring
glossaryin both files is an error even when the two objects contain different terms; there is no per-term merge. - The error names the two files and the offending keys, not the line numbers.
- Multiple
i18n-kit.config.*files in one directory are a warning rather than an error: the first by extension order is used and the others are named as ignored. - Nothing checks across directories. A config in an app directory shadows the root one silently — the root file is not read at all, so a key in it cannot conflict with anything.
Next: which values the kit reads out of your framework's own files rather than you writing them — see declared vs. derived config.