Zero-dependency JavaScript/TypeScript library for ASON (Array-Schema Object Notation) — a token-efficient, schema-driven data format for LLM interactions and large-scale data transfer.
ason-js is the official runtime for both JavaScript and TypeScript users. It ships ESM/CJS builds and bundled .d.ts type declarations in a single package, so there is no separate ason-ts package to install.
Works in browsers, Node.js, Deno, Bun and any JS framework: Vue, React, Svelte, SolidJS, etc.
ASON separates schema from data, eliminating repeated key names found in JSON. The schema is declared once; each data row carries only values:
JSON (100 tokens):
{"users":[{"id":1,"name":"Alice","active":true},{"id":2,"name":"Bob","active":false}]}
ASON (~35 tokens, 65% saved):
[{id:int, name:str, active:bool}]:(1,Alice,true),(2,Bob,false)
| Aspect | JSON | ASON |
|---|---|---|
| Token efficiency | 100% | 30–70% ✓ |
| Key repetition | Every object | Declared once ✓ |
| Human readable | Yes | Yes ✓ |
| Type annotations | None | Built-in ✓ |
| Data size | 100% | 40–55% ✓ |
npm install ason-jsOr copy dist/ason.min.js directly into a web page (exposes a global ASON object).
TypeScript users do not need a separate stub package. npm run build emits dist/index.d.ts, and the package exports it via the types field.
import { encode, encodeTyped, encodePretty, encodePrettyTyped,
decode, encodeBinary, decodeBinary } from 'ason-js';
const users = [
{ id: 1, name: 'Alice', score: 9.5 },
{ id: 2, name: 'Bob', score: 7.2 },
];
// Schema is inferred automatically — no schema string needed
const text = encode(users); // untyped schema
const textTyped = encodeTyped(users); // typed schema (use for typed round-trip)
const pretty = encodePretty(users); // pretty + untyped
const prettyTyped = encodePrettyTyped(users);// pretty + typed
const blob = encodeBinary(users); // binary (schema inferred internally)
console.log(decode(textTyped)); // original array restored
console.log(decode(prettyTyped)); // same from pretty
console.log(decodeBinary(blob, '[{id:int, name:str, score:float}]')); // binary decodeNote on
encodevsencodeTypedencode(obj)emits an untyped schema ({id,name}) so the output is shorter. When decoded, all values without explicit types are returned as strings. UseencodeTyped(obj)when you need the round-trip to preserve numeric and boolean types.
| JS value | Inferred ASON type |
|---|---|
integer number |
int |
fractional number |
float |
boolean |
bool |
string |
str |
null / undefined |
str? (optional) |
Note: Schema is inferred from the first element of an array. To make a field optional (
str?), ensure the first element hasnullfor that field.
Serialize a plain object or array to ASON text with an inferred untyped schema. All values are written without type annotations. When decoded, all fields come back as strings:
encode({ id: 1, name: 'Alice' });
// → '{id,name}:\n(1,Alice)\n'
encode([{ id: 1 }, { id: 2 }]);
// → '[{id}]:\n(1),\n(2)\n'
decode(encode({ id: 1, name: 'Alice' }));
// → { id: '1', name: 'Alice' } ← all strings when schema is untypedUse encodeTyped when you need decode to restore the original types.
Same as encode but emits an inferred typed schema. Use this when you want decode() to restore the original types:
encodeTyped({ id: 1, name: 'Alice', active: true });
// → '{id:int,name:str,active:bool}:\n(1,Alice,true)\n'Pretty-printed ASON text with inferred untyped schema.
Pretty-printed ASON text with inferred typed schema.
Deserialize ASON text. The schema is embedded in the text itself:
const rec = decode('{id:int, name:str}:\n(1,Alice)\n');
const rows = decode('[{id:int, name:str}]:\n(1,Alice),\n(2,Bob)\n');Serialize to binary format. Schema is inferred internally — no schema string needed:
const data = encodeBinary(rows);Deserialize from binary format. Schema is required because the binary wire format carries no embedded type information:
const rows = decodeBinary(data, '[{id:int, name:str}]');| Schema type | JS value | Example |
|---|---|---|
int |
number (integer) | 42, -100 |
uint |
number (non-negative integer) | 0, 9007199254740991 |
float |
number | 3.14, -0.5 |
bool |
boolean | true, false |
str |
string | Alice, "Carol Smith" |
T? |
value or null |
hello / null |
Optional fields: append ? to any type (str?, int?, float?, bool?, uint?).
<script src="dist/ason.min.js"></script>
<script>
const text = ASON.encodeTyped([{id:1, name:'Alice'}]);
console.log(ASON.decode(text));
</script><script type="module">
import { encodeTyped, decode } from './dist/index.js';
const text = encodeTyped([{id:1, name:'Alice'}]);
console.log(decode(text));
</script>Works as a regular npm package — just import and use:
// Vue composable example
import { encodeTyped, decode } from 'ason-js';
export function useAson() {
const serialize = (data: object[]) => encodeTyped(data);
const deserialize = (text: string) => decode(text);
return { serialize, deserialize };
}Little-endian layout, byte-identical to ason-rs and ason-go:
| Type | Bytes |
|---|---|
int |
8 (i64 LE) |
uint |
8 (u64 LE) |
float |
8 (f64 LE) |
bool |
1 |
str |
4-byte length LE + UTF-8 bytes |
| optional | 1-byte tag (0=null, 1=present) + value |
| slice | 4-byte count LE + elements |
npm install
npm run build # generates dist/index.js, dist/index.cjs, dist/index.d.ts, dist/ason.min.js
npm test # vitest, 46 testsnode examples/basic.js # 9 scenarios, basic usage
node examples/complex.js # 20 scenarios, edge cases
node examples/bench.js # performance vs JSON.parse / JSON.stringifyASON JS produces 50–55% smaller output than JSON. Because JSON.parse / JSON.stringify are implemented in C, raw speed is slower — but:
- Network bandwidth is typically the bottleneck — 50% smaller payload saves more time than parse overhead costs
- LLM token cost — 30–70% fewer tokens = lower API cost and faster responses
- Binary format —
encodeBinary/decodeBinaryis fastest for machine-to-machine transfer
For latency-sensitive hot paths, use the Rust or Go implementations if your stack supports them.
MIT
Measured on this machine with Node 24.14.0.
Headline numbers:
- Flat 1,000-record dataset: ASON text
58,539 Bvs JSON121,451 B(51.8%smaller) - Flat 5,000-record dataset: ASON serialize
8.93msvs JSON13.27ms, but deserialize20.10msvs JSON16.92ms - Large 10,000-record dataset: ASON serialize
37.86msvs JSON20.23ms, deserialize37.25msvs JSON33.82ms - Throughput summary on 10,000-record-style text path: ASON text serialize ran at
0.30 M records/svs JSON0.75 M-class baseline, and deserialize was roughly at parity in this run - Binary path is mainly useful for decode and transport size here: on 1,000 records, BIN deserialize
4.68msvs JSON2.08ms, with payload72,784 Bvs JSON121,451 B