Config file
Instead of repeating --rules, --ignore, --fail-on, and --weights on every invocation, put them in a svelte-vitals.config file at your project root. The CLI, the MCP server, and the Vite plugin all read it automatically (the MCP server inherits it because it calls the same analyzeProject function as the CLI; the Vite plugin reads it directly — see Using the config file with the Vite plugin below).
Run svelte-vitals install --client config-file to scaffold one with every option below commented out.
Where it lives
Section titled “Where it lives”svelte-vitals looks for one of these, in this order, in the analyzed directory only (no upward search into parent directories — the analyzed directory is the SvelteKit project root, the same place vite.config.* lives):
svelte-vitals.config.mjssvelte-vitals.config.jssvelte-vitals.config.ts
The first match wins. If none exist, svelte-vitals runs with its built-in defaults, same as before this feature existed.
install --client config-file picks between .ts and .mjs for you: .ts (using defineConfig for real type-checking/autocomplete) when the current Node supports loading it natively, the project looks TypeScript-oriented (a tsconfig.json or a vite.config.ts at the project root), and svelte-vitals is a declared dependency (the defineConfig import resolves at load time, so an npx-only project must not get it) — the case a TypeScript SvelteKit project with svelte-vitals installed falls into. Otherwise it falls back to the safe .mjs default, which works on every Node version svelte-vitals supports with no flag and no dependency. Regenerating an existing file with --force always keeps that file’s own extension rather than switching formats underneath you.
Example
Section titled “Example”import { defineConfig } from 'svelte-vitals';
export default defineConfig({ treatDynamicAs: 'warn', metaComponents: ['Seo'], rules: { SEO008: 'off' }, failOn: 'warning', weights: { seo: 2 }});export default { treatDynamicAs: 'warn', metaComponents: ['Seo'], rules: { SEO008: 'off' }, failOn: 'warning', weights: { seo: 2 }};defineConfig is just an identity helper that merges your object over the built-in defaults — it exists for type-checking and editor autocomplete in a .ts file. A plain export default {...} object works exactly the same at runtime with or without it; in a .mjs/.js file there’s no type-checking to gain either way, so a bare object (as the JavaScript tab shows) is just as good there — and, unlike the import, it works even when svelte-vitals is only ever run via npx and isn’t in your node_modules.
The defineConfig import in a .ts config is a runtime import — it resolves when svelte-vitals loads the file, not just at type-check time — so it requires svelte-vitals to be a declared dependency of your project. Import it from svelte-vitals — the package you actually installed. (It is re-exported from @svelte-vitals/core too, but that package is normally a transitive dependency, and a strict node_modules layout — pnpm’s default — won’t let your project resolve a transitive dependency directly.)
Available options
Section titled “Available options”| Option | Type | Default | Description |
|---|---|---|---|
treatDynamicAs |
'pass' | 'warn' | 'fail' |
'pass' |
How to score routes where a metadata value is set dynamically |
metaComponents |
string[] |
[] |
Custom component names that emit <head> metadata |
rules |
Record<string, 'off' | 'critical' | 'warning' | 'info'> |
{} |
Per-rule overrides — disable a rule or change its severity |
failOn |
'critical' | 'warning' | 'info' |
'critical' |
Minimum severity that fails the run (exit code 1) |
weights |
Partial<Record<Category, number>> |
every category 1 |
Per-category weights for the combined Health score |
Category is 'seo' | 'performance' | 'correctness' | 'security' | 'architecture'.
A weight of 0 is valid — it excludes that category from the Health average entirely (the category’s own score still appears in the output, and findings / exit-code behavior are unaffected). Setting every present category to 0 is an error, though: there is nothing left to average, so the run stops with exit 2.
Precedence
Section titled “Precedence”For each field, the first of these that is set wins: CLI flag > config file > built-in default. This is per field, not all-or-nothing — a one-off --fail-on info does not discard the rest of your config file.
One exception: rules is replaced as a whole, not merged key-by-key. If you pass --rules or --ignore on the command line, the flag-built rule set replaces the config file’s rules entirely for that run — it does not merge with it.
Validation
Section titled “Validation”- Invalid and svelte-vitals stops (exit
2): the file can’t be loaded (syntax error, no default export, or a.tsfile on a Node version that can’t load it — see below); an unknown rule id insiderules; an unknown category or a negative/non-numeric value insideweights. - Invalid but ignored, with a warning (analysis still runs): an unrecognized
treatDynamicAsorfailOnvalue (falls back to flag/default); an unrecognized top-level key (forward-compatible with future config fields).
TypeScript configs
Section titled “TypeScript configs”svelte-vitals.config.ts works out of the box on Node 22.18+ or 23.6+ (that’s when Node’s native TypeScript type-stripping became unflagged). svelte-vitals’ floor is Node 22.13, so on 22.13–22.17 loading a .ts config fails with a descriptive error; pick one of:
- Upgrade to Node 22.18+ (still the same 22 LTS line).
- Re-run with
node --experimental-strip-types. - Rename the file to
.mjsor.js— plain JavaScript works on every supported Node version, with no flag.
Using the config file with the Vite plugin
Section titled “Using the config file with the Vite plugin”@svelte-vitals/vite reads svelte-vitals.config.* the same way the CLI does — no extra wiring needed. Both the build-time gate (vite build) and the live dashboard (vite dev) resolve it from the project root (cwd passed to svelteVitals({ ... }), or the Vite config root when cwd is omitted), with the same per-field precedence as the CLI: an explicit svelteVitals({ ... }) option wins, otherwise the config file’s value, otherwise the built-in default. This includes weights, which now flows into the plugin’s Health score exactly like it does for the CLI and MCP server.
import { sveltekit } from '@sveltejs/kit/vite';import { svelteVitals } from '@svelte-vitals/vite';
export default { plugins: [sveltekit(), svelteVitals({ report: 'console' })]};With a svelte-vitals.config file (any of the three supported extensions) in the project root, the plugin above picks up its treatDynamicAs / metaComponents / rules / failOn / weights automatically — no need to import the file yourself in vite.config.ts. Non-fatal config-file warnings (unknown top-level keys, invalid enum values) are logged to the console with a svelte-vitals: prefix, the same wording the CLI uses.