JavaScript Strict Mode ('use strict') Explained
Learn what JavaScript strict mode does, how to enable it with 'use strict', and why it catches silent errors that normal JavaScript ignores. Includes practical examples and real-world usage patterns.
JavaScript was designed to be forgiving. Misspell a variable name? JavaScript silently creates a global. Assign to a read-only property? JavaScript shrugs and moves on. This tolerance was useful in the early days of the web, but it became a source of hard-to-find bugs as applications grew.
Strict mode, introduced in ECMAScript 5, changes this behavior. When you opt into strict mode with 'use strict', JavaScript throws errors for actions it would normally ignore silently. Think of it like switching your code editor from "ignore all warnings" to "treat warnings as errors." The same code runs, but now the language actively tells you when something looks wrong.
This tutorial covers what strict mode does, how to enable it, the specific errors it catches, and when you should (and should not) use it in your projects.
What Is JavaScript Strict Mode?
Strict mode is a restricted variant of JavaScript that eliminates some silent errors, fixes mistakes that make it difficult for engines to perform optimizations, and prohibits syntax that may conflict with future ECMAScript versions. It does not add new features; it changes how existing features behave.
When strict mode is active, JavaScript:
- Throws errors instead of silently failing
- Prevents accidental creation of global variables
- Disallows duplicate parameter names
- Makes
evalandargumentsbehave more predictably - Blocks the use of deprecated or reserved syntax
Why Was Strict Mode Created?
JavaScript's original design allowed many operations that seemed convenient but caused real problems at scale:
| Problem | Normal Mode Behavior | Strict Mode Behavior |
|---|---|---|
| Assigning to an undeclared variable | Creates a global variable silently | Throws ReferenceError |
| Assigning to a read-only property | Fails silently | Throws TypeError |
| Deleting an undeletable property | Fails silently, returns false | Throws TypeError |
| Duplicate parameter names | Last value wins | Throws SyntaxError |
Using with statement | Allowed | Throws SyntaxError |
Octal numeric literals like 0644 | Interpreted as octal | Throws SyntaxError |
The ECMAScript committee could not simply change the default behavior because millions of existing websites depended on the lenient rules. Instead, they made strict mode opt-in so developers could adopt it file by file or function by function.
How to Enable Strict Mode
Strict mode is enabled by placing the string 'use strict'; (or "use strict";) at the very top of a script or function body. The position matters: it must be the first statement, before any other code.
Enabling Strict Mode for an Entire Script
Place 'use strict'; at the top of your JavaScript file, before any other statements:
'use strict';
let userName = 'Alice';
console.log(userName);
// This would throw a ReferenceError in strict mode:
// mistypedVariable = 'oops'; // ReferenceError: mistypedVariable is not definedEvery line of code in this file runs under strict mode rules. If any code violates those rules, the engine throws an error immediately instead of failing silently.
Enabling Strict Mode for a Single Function
If you only want strict mode inside a specific function, place the directive as the first statement inside the function body:
function processPayment(amount) {
'use strict';
// All code inside this function runs in strict mode
let total = amount * 1.08; // tax calculation
// Accidentally omitting 'let' would throw an error here:
// result = total; // ReferenceError: result is not defined
return total;
}
// Code outside the function runs in normal (sloppy) mode
globalVar = 'this still works out here'; // no error in normal modeThis approach is useful when you need strict mode in new code but are working within a codebase that relies on normal mode behavior elsewhere.
ES6 Modules Are Always in Strict Mode
If you write modern JavaScript using import and export syntax, your code is automatically in strict mode. You do not need the 'use strict' directive:
// This file uses ES6 module syntax, so strict mode is automatic
import { formatCurrency } from './utils.js';
export function calculateTotal(items) {
// Strict mode is already active here
let total = items.reduce((sum, item) => sum + item.price, 0);
return formatCurrency(total);
}ES6 Modules and Strict Mode
When using ES6 modules (files with import/export), strict mode is enabled automatically. Adding 'use strict' is harmless but redundant. This also applies to code inside class bodies, which always run in strict mode.
How Strict Mode Changes JavaScript Behavior
Strict mode modifies several key behaviors. Here are the most important changes, each with a concrete example.
Prevents Accidental Global Variables
In normal mode, assigning a value to a variable that was never declared creates a property on the global object. This is one of the most common sources of bugs in JavaScript:
'use strict';
function calculateShippingCost(weight, distance) {
// Typo: 'baseCost' instead of 'base_cost'
baseCost = weight * 0.5; // ReferenceError: baseCost is not defined
let base_cost = weight * 0.5;
let distanceFee = distance * 0.02;
return base_cost + distanceFee;
}
calculateShippingCost(10, 50);Without strict mode, baseCost would silently become a global variable, and the function would return NaN because base_cost is undefined. With strict mode, you get an immediate ReferenceError pointing directly at the typo.
Makes Assignment Failures Throw Errors
In normal mode, assigning to read-only properties, non-writable properties, or getters without setters fails silently:
'use strict';
const config = {};
Object.defineProperty(config, 'apiUrl', {
value: 'https://api.example.com',
writable: false,
});
// In normal mode, this silently fails. In strict mode:
config.apiUrl = 'https://hacked.com'; // TypeError: Cannot assign to read only property 'apiUrl'This also applies to built-in read-only properties:
'use strict';
undefined = 42; // TypeError: Cannot assign to read only property 'undefined'
NaN = 'not a number'; // TypeError: Cannot assign to read only property 'NaN'
Infinity = 0; // TypeError: Cannot assign to read only property 'Infinity'Prevents Deletion of Undeletable Properties
'use strict';
// Attempting to delete a non-configurable property
delete Object.prototype; // TypeError: Cannot delete property 'prototype' of function Object()Changes this Behavior in Functions
In normal mode, this inside a regular function call defaults to the global object (window in browsers, global in Node.js). In strict mode, this is undefined:
'use strict';
function showContext() {
console.log(this); // undefined (not the global object)
}
showContext();This change prevents a common class of bugs where methods accidentally modify the global object. It forces you to be explicit about what this refers to.
Disallows Duplicate Parameters
'use strict';
// SyntaxError: Duplicate parameter name not allowed in this context
function merge(obj, obj) {
// In normal mode, the second 'obj' silently shadows the first
return obj;
}Restricts eval Scope
In strict mode, variables declared inside eval do not leak into the surrounding scope:
'use strict';
eval('var leakyVariable = 42;');
console.log(typeof leakyVariable); // "undefined" (strict mode prevents leaking)
// In normal mode, leakyVariable would be 42Strict Mode vs Normal (Sloppy) Mode Comparison
| Feature | Normal Mode | Strict Mode |
|---|---|---|
| Undeclared variable assignment | Creates global variable | ReferenceError |
| Read-only property assignment | Fails silently | TypeError |
| Non-extensible object property | Fails silently | TypeError |
| Deleting undeletable property | Returns false silently | TypeError |
| Duplicate function parameters | Last parameter value wins | SyntaxError |
Octal literals (0644) | Interpreted as octal (420) | SyntaxError |
this in plain function calls | Global object | undefined |
eval variable scope | Leaks into surrounding scope | Contained within eval |
with statement | Allowed | SyntaxError |
arguments.callee | Returns the current function | TypeError |
Setting arguments properties | Allowed | No effect (disconnected from params) |
| Reserved words as variable names | Some allowed | SyntaxError for implements, interface, let, package, private, protected, public, static, yield |
Best Practices
Strict Mode Adoption Strategy
These practices help you adopt strict mode safely without breaking existing code.
Use ES6 modules whenever possible. Modules are strict by default, which eliminates the need to manually add 'use strict' to every file. If your project uses a bundler like Webpack or Vite, you are likely already writing modules.
Add 'use strict' to all non-module scripts. If you write scripts that load via <script> tags without type="module", place 'use strict' at the top of every file. This catches bugs early and prepares your code for eventual migration to modules.
Never place 'use strict' after code. The directive only works when it is the very first statement. If any expression or statement precedes it, the engine treats it as a regular string expression and ignores it.
Be cautious when concatenating strict and non-strict files. If you combine a strict-mode file and a non-strict-mode file into one bundle, the result depends on which file comes first. Bundlers handle this correctly for modules, but legacy concatenation scripts may not.
Test after enabling strict mode. When adding strict mode to an existing codebase, run your full test suite. Code that worked in normal mode may throw errors under strict mode, especially if it relies on implicit globals or sloppy this behavior.
Common Mistakes and How to Avoid Them
Watch Out for These Pitfalls
These mistakes trip up developers when they first start using strict mode.
Placing 'use strict' after a regular statement. The directive must be the first statement in a script or function. Even a simple variable declaration before it will silently disable it:
let x = 10;
'use strict'; // This is now just a string expression, NOT a directive
y = 20; // No error — strict mode is not activeAssuming this is always the global object. In strict mode, this is undefined in plain function calls. If your code accesses this.someProperty inside a utility function, it will throw a TypeError instead of reading from the global object.
Forgetting that eval behaves differently. Code using eval to create variables in the calling scope will break under strict mode because eval variables stay contained within the eval call.
Using octal literals for file permissions. If you work with file systems and use octal numbers like 0644, strict mode will throw a SyntaxError. Use the explicit 0o644 syntax instead, which is valid in both modes.
Not checking third-party libraries. Some older libraries rely on normal-mode behaviors like implicit globals. Wrapping them in a strict-mode context can cause unexpected ReferenceError exceptions.
When to Use (and Not Use) Strict Mode
| Scenario | Recommendation | Reason |
|---|---|---|
| New project with ES6 modules | No action needed | Modules are strict by default |
| New non-module script | Add 'use strict' | Catches bugs from day one |
| Legacy codebase migration | Add per-function first | Avoids breaking existing code |
| Third-party library wrapper | Do not force strict mode | May depend on normal-mode behavior |
| Node.js application | Use ES modules (.mjs) | Built-in strict mode |
Browser <script> tags | Add 'use strict' | Essential for bug prevention |
Next Steps
Practice identifying strict mode errors
Take an existing JavaScript file and add 'use strict' at the top. Run it and fix every error that appears. This hands-on exercise will teach you the most common patterns that strict mode catches.
Migrate a project to ES6 modules
Convert your <script> tags to <script type="module"> and refactor files to use import/export. This gives you strict mode automatically plus better dependency management.
Learn about common strict mode errors
Explore the specific error types that JavaScript strict mode catches to understand each enforcement rule in depth.
Set up a linter for automatic enforcement
Configure ESLint with the strict rule to automatically flag files missing the 'use strict' directive. This ensures consistency across your entire team.
Rune AI
Key Insights
- Opt-in enforcement: strict mode catches accidental globals, silent assignment failures, and deprecated syntax by throwing errors instead of ignoring them
- ES6 modules are strict by default: modern projects using
import/exportget strict mode automatically without the directive - Migration is incremental: you can enable strict mode per function, then per file, without rewriting an entire codebase at once
- Performance benefit: strict mode allows JavaScript engines to optimize more aggressively because the code has fewer ambiguous behaviors
- Always use it: there is no practical reason to write new JavaScript code in normal mode in 2026
Frequently Asked Questions
Does strict mode make JavaScript slower?
Can I use strict mode in just part of a file?
Do modern frameworks already use strict mode?
Is 'use strict' still needed in 2026?
What happens if I mix strict and non-strict code?
Conclusion
JavaScript strict mode transforms silent failures into explicit errors, making it one of the simplest and most effective tools for writing reliable code. By adding 'use strict' to your scripts or using ES6 modules (which are strict by default), you get immediate feedback on typos, unsafe assignments, and deprecated syntax that would otherwise cause subtle bugs in production.
More in this topic
OffscreenCanvas API in JS for UI Performance
Master the OffscreenCanvas API to offload rendering from the main thread. Covers worker-based 2D and WebGL rendering, animation loops inside workers, bitmap transfer, double buffering, chart rendering pipelines, image processing, and performance measurement strategies.
Advanced Web Workers for High Performance JS
Master Web Workers for truly parallel JavaScript execution. Covers dedicated and shared workers, structured cloning, transferable objects, SharedArrayBuffer with Atomics, worker pools, task scheduling, Comlink RPC patterns, module workers, and performance profiling strategies.
JavaScript Macros and Abstract Code Generation
Master JavaScript code generation techniques for compile-time and runtime metaprogramming. Covers AST manipulation, Babel plugin authorship, tagged template literals as macros, code generation pipelines, source-to-source transformation, compile-time evaluation, and safe eval alternatives.