extensions
Ensure consistent use of file extensions in imports
💼 This rule is enabled in the following configs: recommended, typescript.
🔧 This rule is automatically fixable by the --fix CLI option.
Rule Details
Enforces a configured convention for writing file extensions on relative specifiers. Package specifiers are not checked.
The policy for an extension is, most specific first: your pattern[ext],
your default, the rule's own pattern (js, jsx, ts, tsx: never;
json, css, scss, svg, png, jpg: always), then never.
- A written extension under
neveris reported (and fixed) when removing it resolves to the same file. It is not reported when it is load-bearing:./width.jsnamingwidth.tsis the spellingmoduleResolution: NodeNextrequires, and./only.mjscannot be written without its extension. A specifier that does not resolve proves nothing and is not reported. - A missing extension is judged by the file the specifier resolves to:
./depnamingdep.tsis reported when the policy fortsisalways. A specifier that does not resolve, or that only resolves as a directory (./libnaminglib/index.ts), is not reported. - A dot in a file name is not an extension:
./source.confignamingsource.config.tsis a specifier with no extension written. Only extensions the rule ships defaults for, or that you name inpattern, count.
Every spelling is checked: import, side-effect imports, export { a } from,
export * from, import(), require() and TS import x = require().
// { default: 'always', pattern: { ts: 'never' } }
// ❌ Incorrect
import { real } from './real'; // real.js: js is `always`
import { dep } from './dep.ts'; // ts is `never`
// ✅ Correct
import { real } from './real.js';
import { dep } from './dep';
import { width } from './width.js'; // names width.ts: load-bearingOptions
[
{
"type": "object",
"properties": {
"pattern": {
"type": "object",
"additionalProperties": {
"type": "string",
"enum": [
"always",
"never"
]
}
},
"default": {
"type": "string",
"enum": [
"always",
"never"
]
}
},
"additionalProperties": false
}
]Implementation
OWASP Foundation
- Category: A00:2021 - General Security
Use this rule
npm install -D oxlint-plugin-import-next{ "jsPlugins": ["oxlint-plugin-import-next"], "rules": { "import-next/extensions": "error" }}import { defineConfig } from 'vite-plus';export default defineConfig({ lint: { jsPlugins: ['oxlint-plugin-import-next'], rules: { 'import-next/extensions': 'error', }, },});oxlint-plugin-import-next re-exports eslint-plugin-import-next/oxlint: the same rules under the same IDs, and no ESLint install. Why oxlint.
Did this rule catch something? Star the repo to get new CWE coverage as we ship it — or follow the AI-code-security benchmarks behind these rules.