CodableJSON
High-performance, no-dependencies, extensible, and declarative "anything to/from JSON" serializer.

Throw your data at it - open playground
Read the docs
Key Features
- 📝 Declarative: Modern decorators allowing you to mark "what to serialize", not "how to serialize it"
- 🔌 Type-rich & Extensible: By default handles almost every built-in JavaScript type. Easy to extend with custom handled types.
- ⚡️ High-performance: ~3x faster than SuperJSON (see benchmark)
- 🔒 Type-safe: Full TypeScript support with autocompletion and type inference
- 🎯 Zero dependencies: Fully standalone, no external dependencies. 7.3KB gziped.
- ✅ Well tested: Every feature is covered by tests. It passes most of SuperJSON tests moved into CodableJSON (including plenty of edge cases)
- 🔄 Framework agnostic: Works with any JavaScript/TypeScript project
- 🛡️ Secure: Built-in protection against prototype pollution
Installation
npm install codablejson
yarn add codablejson
pnpm add codablejson
Quick start
JSON Serialization
Extend JSON to handle JavaScript types that JSON can't serialize:
import { encode, decode } from "codablejson";
const data = {
date: new Date("2025-01-01"),
set: new Set(["a", "b", "c"]),
map: new Map([["key", "value"]]),
bigint: BigInt("1234567890123456789"),
regex: /hello/gi,
url: new URL("https://example.com"),
};
const encoded = encode(data);
const decoded = decode(encoded);
Declarative Class Serialization
Eliminate the dual-format problem with modern decorators
What declarative means here?
It means you mark "what to serialize", not "how to serialize it"
import { codableClass, codable, Coder } from "codablejson";
@codableClass("Player")
class Player {
@codable() name: string;
@codable() score: number;
constructor(data: Pick<Player, "name" | "score">) {
this.name = data.name;
this.score = data.score;
}
}
@codableClass("GameState")
class GameState {
@codable() players: Set<Player> = new Set();
@codable() createdAt = new Date();
@codable() activePlayer: Player | null = null;
addPlayer(player: Player) {
this.players.add(player);
this.activePlayer = player;
}
}
const coder = new Coder([GameState]);
const gameState = new GameState();
gameState.addPlayer(new Player({ name: "Alice", score: 100 }));
const encoded = coder.encode(gameState);
const decoded = coder.decode<GameState>(encoded);
Note: for classes to be automatically serialized, they need to have memberwise constructor (eg the same way like Swift Codable structs work). Read more about it here.
Built-in Types
CodableJSON automatically handles JavaScript types that standard JSON cannot serialize:
Date | { $$Date: "2025-01-01T00:00:00.000Z" } |
BigInt | { $$BigInt: "1234567890123456789" } |
Set | { $$Set: ["a", "b", "c"] } |
Map | { $$Map: [["key", "value"]] } |
RegExp | { $$RegExp: "/hello/gi" } |
Symbol | { $$Symbol: "test" } |
URL | { $$URL: "https://example.com/" } |
URLSearchParams | { $$URLSearchParams: "foo=bar&baz=qux" } |
Error | { $$Error: "Something went wrong" } |
undefined | "$$undefined" |
| Typed Arrays | { $$uint8array: [1, 2, 3] } |
| Special Numbers | "$$NaN", "$$Infinity", "$$-Infinity", "$$-0" |
Read more about supported types →
Of course, you can extend it with custom types.
Performance
CodableJSON is heavily optimized for performance:
- Encoding: ~3-3.5x faster than SuperJSON across all data sizes and types
- Decoding: Comparable to or faster than SuperJSON depending on the data type
View detailed benchmarks →
API Overview
Core Functions
import { encode, decode, stringify, parse, clone } from "codablejson";
const encoded = encode(data);
const decoded = decode(encoded);
const jsonString = stringify(data);
const restored = parse(jsonString);
const foo = { foo: "foo" };
const original = [foo, foo];
const cloned = clone(original);
Declarative Class Serialization
import { codableClass, codable, Coder } from "codablejson";
@codableClass("MyClass")
class MyClass {
@codable() property: string;
}
const coder = new Coder([MyClass]);
const encoded = coder.encode(instance);
const decoded = coder.decode<MyClass>(encoded);
Custom Types
You can also use lower-level API to create custom types and encode/decode them manually.
import { codableType, Coder } from "codablejson";
const $$custom = codableType(
"CustomType",
(value) => value instanceof CustomType,
(instance) => instance.data,
(data) => new CustomType(data),
);
const coder = new Coder([$$custom]);
const coder = new Coder();
coder.register($$custom);
Security
CodableJSON includes built-in security measures:
- Prototype Pollution Protection: Automatically filters dangerous properties (
constructor, __proto__, prototype)
- Safe Object Creation: Creates objects without modifying prototypes
- Format Safety: Automatic collision detection and escaping
Read more about security features →
Comparisons
Benchmark vs SuperJSON
You can run these benchmarks yourself by downloading the repository and running yarn codablejson bench. The benchmark code is available in benchmark.bench.ts.
Plain JSON Data (6MB)
| Encode | 🟢 3.68x faster than SuperJSON | 🟢 6.85x faster than SuperJSON |
| Decode | 🟢 1.29x faster than SuperJSON | 🟢 1.28x faster than SuperJSON |
Complex Data Structures
It includes deeply nested objects, with repeating references, Sets, Maps, and Dates
| Preserve refs | Copy refs | Preserve refs | Copy refs |
| Small | 🟢 3.89x faster | 🟢 6.98x faster | 🟢 1.68x faster | 🟢 1.66x faster |
| Average | 🟢 4.20x faster | 🟢 5.06x faster | 🟢 1.16x faster | 🟢 1.05x faster |
| Large | 🟢 4.01x faster | 🟢 7.54x faster | 🟢 1.19x faster | 🟢 1.83x faster |
| Huge | 🟢 4.08x faster | 🟢 6.43x faster | 🟢 1.31x faster | 🟢 2.37x faster |
Benchmark was run on a MacBook Pro M3 Max with 128GB of RAM.
Migration from SuperJSON
For simple JSON serialization, CodableJSON is almost a drop-in replacement for SuperJSON.
For custom types, please read about custom types in JSON Serialization section.
import { stringify, parse } from "superjson";
const serialized = stringify(data);
const deserialized = parse(serialized);
import { stringify, parse } from "codablejson";
const serialized = stringify(data);
const deserialized = parse(serialized);
Read complete comparison guide →
Documentation
Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature)
- Commit your changes (
git commit -m 'Add some amazing feature')
- Push to the branch (
git push origin feature/amazing-feature)
- Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.