Serialize JavaScript Values
serialize-javascript is a utility library designed to convert JavaScript values, including complex types like functions, regular expressions, dates, Maps, Sets, BigInt, and URLs, into a string representation that is a superset of JSON. This serialized string is valid literal JavaScript code, suitable for embedding directly into HTML `<script>` tags or saving as `.js` files. Unlike `JSON.stringify()`, it gracefully handles these non-JSON-native types and automatically escapes HTML characters and JavaScript line terminators to prevent Cross-Site Scripting (XSS) vulnerabilities when embedded in HTML. The package is actively maintained, with the current stable version being 7.0.5, and typically sees regular maintenance updates and major version releases as needed. It originated as an internal module for `express-state` before becoming an independent npm package.
Common errors
-
The engine "node" is incompatible with this module. Expected version "20.0.0" or higher.
cause Attempting to install or run `serialize-javascript` version 7.x or later on a Node.js environment older than v20.0.0.fixUpgrade your Node.js runtime to version 20.0.0 or newer. You can use tools like `nvm` (Node Version Manager) to manage multiple Node.js versions. -
TypeError: serialize is not a function
cause Incorrectly importing the `serialize` function as a named import (`import { serialize } from 'serialize-javascript'`) when it is a default export, or attempting to destructure `require` in CommonJS.fixFor ESM, use `import serialize from 'serialize-javascript';`. For CommonJS, use `const serialize = require('serialize-javascript');`. -
SyntaxError: Unexpected token 'function'
cause Attempting to use `JSON.stringify()` on an object containing functions, regular expressions, or other non-JSON-standard JavaScript types. `JSON.stringify` does not serialize these types correctly, resulting in functions being omitted and regexps becoming empty objects.fixUse `serialize-javascript` instead of `JSON.stringify()` when needing to preserve functions, regexps, dates, maps, sets, BigInt, or URLs during serialization.
Warnings
- breaking Version 7.0.0 introduced a breaking change by requiring Node.js v20.0.0 or greater. Projects running on older Node.js versions must upgrade Node.js or remain on `serialize-javascript` v6.x.
- breaking Versions prior to 3.1.0 were vulnerable to Remote Code Execution (RCE) via insecure deserialization, specifically related to the `deleteFunctions` within `index.js` (CVE-2020-7660). An attacker could inject arbitrary code by crafting malicious payloads.
- breaking Versions up to 7.0.2 were vulnerable to Code Injection (GHSA-5c6j-r48x-rmvq) due to incomplete sanitization of `RegExp.flags` and `Date.prototype.toISOString()` output. Attackers could inject malicious JavaScript via these properties if they controlled the input to `serialize()`, leading to RCE when the output was `eval()`ed or embedded in `<script>` tags. This was an incomplete fix for CVE-2020-7660.
- gotcha Versions prior to 7.0.5 could lead to a Denial of Service (DoS) via CPU exhaustion when serializing specially crafted 'array-like' objects (objects inheriting from `Array.prototype` with a very large `length` property). This could cause the process to hang indefinitely.
- gotcha While `serialize-javascript` can serialize functions, it is generally unsafe and strongly discouraged to use this package to pass arbitrary functions to worker threads. Serialized functions often rely on their surrounding scope (closed-over variables, imports), which are not serialized and will lead to unexpected runtime behavior or errors in a worker thread environment.
- gotcha The `unsafe` option can be passed to `serialize()` to disable automatic HTML character escaping. This bypasses a critical security feature designed to prevent XSS. Use this option only when the serialized output is guaranteed not to be embedded directly into HTML or when custom, external escaping is applied.
Install
-
npm install serialize-javascript -
yarn add serialize-javascript -
pnpm add serialize-javascript
Imports
- serialize
import { serialize } from 'serialize-javascript';import serialize from 'serialize-javascript';
- serialize
const { serialize } = require('serialize-javascript');const serialize = require('serialize-javascript'); - serialize
import serialize from 'serialize-javascript'; // ... later usage ... const output = serialize(myObject, { is)unsafe: true });import serialize from 'serialize-javascript'; // ... later usage ... const output = serialize(myObject, { unsafe: true });
Quickstart
import serialize from 'serialize-javascript';
const dataToSerialize = {
str : 'hello world <script>',
num : 123.45,
obj : { key: 'value', nested: { foo: 'bar' } },
arr : [1, null, new Date(), /test/gi],
bool : false,
nil : null,
undef: undefined,
inf : Infinity,
date : new Date('2023-10-27T10:00:00Z'),
map : new Map([['id', 1], ['name', 'Example']]),
set : new Set([10, 20, 30]),
fn : function greet(name) { return `Hello, ${name}!`; },
re : /^user_\d+$/i,
big : BigInt(9007199254740991n),
url : new URL('https://example.com/path?query=param&id=123'),
nestedFunc: { action: () => console.log('This will be serialized') }
};
// Serialize with default options (pretty print with 2 spaces)
const serializedData = serialize(dataToSerialize, { space: 2 });
console.log('Serialized Data:\n', serializedData);
// Example of deserialization (requires eval, use with caution on untrusted input)
// In a real application, you would typically embed this in a script tag
// or use it in a server-side rendering context where the source is trusted.
try {
const deserializedData = eval('(' + serializedData + ')');
console.log('\nDeserialized Function Output:', deserializedData.fn('Registry'));
console.log('Deserialized Regex Test:', deserializedData.re.test('user_123'));
} catch (e) {
console.error('\nError during deserialization:', e.message);
}