prefer-template-literal
Prefer template literals over string concatenation with runtime values
Prefer template literals over string concatenation with + when at least one operand is a runtime value. This rule is part of eslint-plugin-modernization.
Quick Summary
| Aspect | Details |
|---|---|
| Severity | Warning (modern JavaScript) |
| Auto-Fix | ✅ Yes (replaces + chain with a template literal) |
| Category | Modernization |
| ESLint MCP | ✅ Optimized for ESLint MCP integration |
| Best For | ES2015+ codebases, cleaner string building |
Rule Details
Template literals with ${} interpolation are more readable and less error-prone than concatenating strings with +. This rule flags any + expression that mixes string literals with runtime values (variables, member expressions, function calls, etc.) and rewrites the entire chain as a single template literal.
Pure string-literal concatenation ("foo" + "bar") and numeric addition (1 + 2) are intentionally ignored.
Why This Matters
| Issue | Impact | Solution |
|---|---|---|
| 📖 Readability | Mixed + chains are hard to scan | Use a ${expr} placeholder |
| 🐛 Implicit coercion | + coerces operands unpredictably | Interpolation is unambiguous |
| 🔄 Consistency | Multiple string-building styles in codebase | Standardize on template literals |
Examples
❌ Incorrect
// String concatenation with runtime value
const greeting = "Hello, " + name + "!";
const path = "/api/v1/" + resource + "/" + id;
const message = "Error: " + err.message;✅ Correct
// Template literal with interpolation
const greeting = `Hello, ${name}!`;
const path = `/api/v1/${resource}/${id}`;
const message = `Error: ${err.message}`;
// Pure string concat is fine (no runtime values)
const url = "https://" + "example.com";Configuration Examples
Basic Usage
{
rules: {
'modernization/prefer-template-literal': 'warn'
}
}Related Rules
prefer-at- Modern array element accessprefer-event-target- Modern event handling
Further Reading
- Template literals - MDN - MDN reference
- ES2015 Features - ECMAScript specification
Known False Negatives
The following patterns are not detected due to static analysis limitations:
Dynamic Variable References
Why: Static analysis cannot always determine whether a variable holds a string or a number at the point of + use.
// ❌ NOT DETECTED - ambiguous operand type
const result = a + b; // could be numeric additionMitigation: Add TypeScript types so the linter has enough signal, or review concatenation chains manually.
Imported Values
Why: When values come from imports, the rule cannot analyze their origin or construction.
// ❌ NOT DETECTED - Value from import
import { prefix } from './constants';
const path = prefix + resource; // Cross-file origin not trackedMitigation: Ensure imported string values are typed as string in TypeScript so the rule can flag the concatenation.
Use this rule
npm install -D oxlint-plugin-modernization{ "jsPlugins": ["oxlint-plugin-modernization"], "rules": { "modernization/prefer-template-literal": "error" }}import { defineConfig } from 'vite-plus';export default defineConfig({ lint: { jsPlugins: ['oxlint-plugin-modernization'], rules: { 'modernization/prefer-template-literal': 'error', }, },});oxlint-plugin-modernization re-exports eslint-plugin-modernization/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.