Skip to main content
interlace
Plugin: modernizationRules

prefer-template-literal

Prefer template literals over string concatenation with runtime values

Keywords: template literal, string concatenation, plus operator, interpolation, ESLint rule, ES2015, auto-fix, LLM-optimized

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

AspectDetails
SeverityWarning (modern JavaScript)
Auto-Fix✅ Yes (replaces + chain with a template literal)
CategoryModernization
ESLint MCP✅ Optimized for ESLint MCP integration
Best ForES2015+ codebases, cleaner string building

Rule Details

Template literals with string 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

IssueImpactSolution
📖 ReadabilityMixed + chains are hard to scanUse template literals with interpolation
🐛 Implicit coercion+ coerces operands unpredictablyInterpolation is unambiguous
🔄 ConsistencyMultiple string-building styles in codebaseStandardize 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";

Auto-fix

ESLint can fix this automatically. Running eslint --fix rewrites the concatenation chain into a single template literal — no manual edits required.

Before

const msg = "Hello, " + name + "!";
const path = "/api/v1/" + resource + "/" + id;

After

const msg = `Hello, ${name}!`;
const path = `/api/v1/${resource}/${id}`;

The fixer joins all operands into one template literal, promoting any plain string segments to static parts and wrapping runtime values in ${...} expressions.

Configuration Examples

Basic Usage

{
  rules: {
    'modernization/prefer-template-literal': 'warn'
  }
}

Further Reading

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 addition

Mitigation: 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 tracked

Mitigation: Ensure imported string values are typed as string in TypeScript so the rule can flag the concatenation.

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.