JSON.stringify Escape Behavior — What It Actually Does With Quotes
- JSON.stringify escapes only what JSON requires — quotes, backslashes, and control characters.
- It does not escape forward slashes, single quotes, or unicode characters above U+007F.
- For embedding in HTML, SQL, or shells, you usually need an extra escape layer on top.
Table of Contents
JSON.stringify is JavaScript's built-in JSON serializer. It handles quote and backslash escaping automatically — but only what JSON itself requires. Anything beyond that (HTML safety, SQL safety, shell safety) is on you. Understanding what stringify does and doesn't cover saves a lot of head-scratching.
What JSON.stringify Always Escapes
Six things get escape characters added every time:
- Double quote →
\" - Backslash →
\\ - Backspace (U+0008) →
\b - Form feed (U+000C) →
\f - Newline (U+000A) →
\n - Carriage return (U+000D) →
\r - Tab (U+0009) →
\t - Other control characters (U+0000 to U+001F) →
\u00XX
This is the JSON spec's required escape set. Any compliant stringify implementation does these.
JSON.stringify({ msg: 'She said "hi"\nand left.' })
// '{"msg":"She said \"hi\"\nand left."}'
What JSON.stringify Does NOT Escape
Things that stringify will leave alone, even though they sometimes cause problems downstream:
- Forward slash (
/) — the JSON spec says it MAY be escaped but doesn't require it. JSON.stringify leaves it raw. - Single quote (
') — not special in JSON. Stringify ignores it. - Less-than / greater-than (
<>) — not special in JSON. But if you embed JSON inside HTML, these can break out of script tags. - Ampersand (
&) — not special in JSON. But also a problem in HTML embedding. - Unicode characters above U+007F — emoji, accented characters, non-Latin scripts all stay as their raw UTF-8 form.
- Line separator (U+2028) and paragraph separator (U+2029) — valid JSON but break JavaScript string literals if you ever paste the JSON back into JS code.
For pure JSON-to-JSON storage and transmission, none of these are problems. They become problems when JSON crosses into HTML, SQL, shell, or JS source code contexts.
Sell Custom Apparel — We Handle Printing & Free ShippingWhen You Need More Escaping Than stringify Provides
Three contexts where stringify alone isn't enough:
Embedding JSON in HTML script tags. The string "</script>" inside your JSON will close the script tag if pasted raw. Mitigations: escape < as \u003c after stringify, or use JSON.stringify(data).replace(/</g, '\\u003c'). Modern frameworks like Next.js do this automatically.
Embedding JSON in HTML attributes. Quotes inside the JSON conflict with the attribute's own quotes. Use HTML entity encoding (") on top of JSON escaping.
Passing JSON as a shell argument. Single quotes, dollar signs, backticks all have shell meaning. Wrap the JSON in single quotes and escape any single quotes inside.
The pattern: stringify gives you valid JSON. Whatever container the JSON lands in (HTML, shell, SQL) needs its own escape layer applied after.
Customizing JSON.stringify Behavior
JSON.stringify takes optional second and third arguments that change the output:
JSON.stringify(value, replacer, indent)
Replacer: a function or array that filters which keys get serialized. Useful for stripping sensitive fields before sending data anywhere.
JSON.stringify(user, (key, val) => key === 'password' ? undefined : val)
Indent: a number (spaces) or string (any whitespace) for pretty-printing. JSON.stringify(obj, null, 2) is the standard "pretty print with 2-space indent" pattern.
Neither of these changes what gets escaped — both options work on top of the standard escape behavior. If you want different escape rules (escape forward slashes, escape unicode, escape HTML-unsafe characters), you need a custom serializer or a post-process pass.
When stringify Will Fail Silently
Three things JSON.stringify drops without warning:
- Functions. Object methods get omitted entirely from the output.
JSON.stringify({fn: () => 1})returns"{}". - undefined. Object properties with undefined values are omitted. Array elements with undefined become
null. - Symbols. Symbol-keyed properties and symbol values are skipped.
One thing it throws on instead of silently dropping: circular references. const a = {}; a.self = a; JSON.stringify(a) throws TypeError: Converting circular structure to JSON.
For data that includes any of these, do the cleanup before stringify — either with a replacer function or by converting the data to a plain JSON-safe shape first.
Escape JSON Beyond stringify
For when stringify's defaults are not enough — paste JSON, get every escape applied.
Open Free JSON Escape / Unescape ToolFrequently Asked Questions
Why does JSON.stringify escape some quotes but not others?
It escapes only what JSON syntax requires inside a string — primarily double quotes and backslashes. Single quotes, forward slashes, and other characters are valid raw and stay raw.
How do I make JSON.stringify escape forward slashes?
Use a post-process step: JSON.stringify(data).replace(/\//g, \\/). Some HTML embedding contexts want this for safety.
Why does JSON.stringify leave my unicode characters as-is?
JSON allows raw unicode above U+007F. If you need them as \u escapes, use a library like json-stringify-safe with the appropriate options or post-process the output.
Does stringify escape HTML characters like < and >?
No. For HTML-safe JSON embedding, post-process to convert < to \u003c and > to \u003e.

