{"record":{"id":"caf2696bc7bbbc95","repo":"oxc-project/oxc","slug":"exporting-mutable-kind-str-binding-use-const","errorCode":null,"errorMessage":"Exporting mutable '{kind_str}' binding, use 'const' instead.","messagePattern":"Exporting mutable '(.+?)' binding, use 'const' instead\\.","errorType":"validation","errorClass":"OxcDiagnostic","httpStatus":null,"severity":"warning","filePath":"crates/oxc_linter/src/rules/import/no_mutable_exports.rs","lineNumber":16,"sourceCode":"use oxc_ast::{\n    AstKind,\n    ast::{\n        Declaration, Expression, ModuleExportName, VariableDeclaration, VariableDeclarationKind,\n    },\n};\nuse oxc_diagnostics::OxcDiagnostic;\nuse oxc_macros::declare_oxc_lint;\nuse oxc_semantic::ReferenceId;\nuse oxc_span::Span;\n\nuse crate::{context::LintContext, rule::Rule};\n\nfn no_mutable_exports_diagnostic(span: Span, kind: VariableDeclarationKind) -> OxcDiagnostic {\n    let kind_str = if kind == VariableDeclarationKind::Var { \"var\" } else { \"let\" };\n    OxcDiagnostic::warn(format!(\"Exporting mutable '{kind_str}' binding, use 'const' instead.\"))\n        .with_help(format!(\"Replace '{kind_str}' with 'const' to export an immutable binding.\"))\n        .with_label(span)\n}\n\n// <https://github.com/import-js/eslint-plugin-import/blob/v2.31.0/docs/rules/no-mutable-exports.md>\n#[derive(Debug, Default, Clone)]\npub struct NoMutableExports;\n\ndeclare_oxc_lint!(\n    /// ### What it does\n    ///\n    /// Forbids the use of mutable exports with var or let.\n    ///\n    /// ### Why is this bad?\n    ///\n    /// In general, we should always export constants\n    ///\n    /// ### Examples","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/oxc-project/oxc/blob/e1e7af627c8843ab64044ed466b128fcc21a035b/crates/oxc_linter/src/rules/import/no_mutable_exports.rs#L1-L34","documentation":"Diagnostic from the oxlint rule import/no-mutable-exports (style category). It fires when a variable declaration with kind `let` or `var` is exported (`export let x` / `export var x`). Mutable export bindings are confusing: consumers see live bindings whose value can change at any time, and bundlers/CJS interop handle mutation inconsistently, so the rule demands immutable `const` exports. The message names the exact kind (var vs let) and the help repeats it in the fix suggestion.","triggerScenarios":"`export let counter = 0;` or `export var config = {};` — exported VariableDeclarations whose kind is not Const. Function and class exports are not flagged. Emitted from no_mutable_exports_diagnostic at crates/oxc_linter/src/rules/import/no_mutable_exports.rs:16, which maps Var → \"var\" and everything else (let) → \"let\".","commonSituations":"State exported from modules (counters, caches, feature flags) that authors expected to mutate; converting CJS `module.exports.x = let-variable` to ESM; interop with bundlers that snapshot export values, causing the mutation to be invisible downstream.","solutions":["Change the declaration to `const` when the binding is never reassigned (mutating object properties is still fine)","If mutation is the point, export a getter or functions instead: `export const getState = () => state` or export an object with methods","Export an immutable snapshot and keep mutation internal to the module"],"exampleFix":"// before\nexport let config = { debug: false };\n\n// after\nexport const config = { debug: false }; // mutate properties, never the binding","handlingStrategy":"validation","validationCode":"// rg -n \"^export\\\\s+(let|var)\\\\s\" src\n// .oxlintrc.json: { \"rules\": { \"import/no-mutable-exports\": \"warn\" } }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Export const bindings; mutate object internals, never the binding","Model changing state with exported functions/getters instead of reassigning exports","Remember CJS consumers and some bundlers snapshot export values — mutation is not portable"],"tags":["lint","oxlint","imports","export","mutability","esm","style"],"backgroundTag":"mutable-export-binding","analyzedSha":"e1e7af627c8843ab64044ed466b128fcc21a035b","analyzedAt":"2026-08-20T07:01:07.079Z","contentChangedAt":"2026-08-20T07:01:07.079Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}