boom-format 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,1079 @@
1
+ # BOOM
2
+
3
+ **Binary Object Optimised Markup**
4
+
5
+ A compact binary serialisation format with an optional human-readable debug mode. Smaller than JSON, faster to parse, yet still debuggable.
6
+
7
+ [![npm version](https://img.shields.io/npm/v/boom-format.svg)](https://www.npmjs.com/package/boom-format)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
+
10
+ **[Documentation](https://boomformat.dev)** | **[Getting Started](https://boomformat.dev/guide/getting-started.html)** | **[Playground](https://boomformat.dev/converter.html)** | **[Benchmarks](https://boomformat.dev/benchmarks.html)**
11
+
12
+ ## Features
13
+
14
+ - 🗜️ **40-70% smaller** than JSON
15
+ - 🧠 **50-85% fewer LLM tokens** - best-in-class for AI applications
16
+ - ⚡ **1.8-19x faster** than JSON (encode & decode)
17
+ - 📖 **299-entry dictionary** - single-byte encoding for common keys
18
+ - 🔍 **Human-readable debug format** - `.boom.txt`
19
+ - 🔄 **Self-describing** - no schema required
20
+ - 📦 **String interning** - automatic deduplication
21
+ - 🌍 **13 implementations** - JS, Go, Rust, PHP, Java, .NET, Swift, C++, Python
22
+ - 📝 **TypeScript-first** - full type safety
23
+ - 🏷️ **Script type support** - `<script type="text/boom">`
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ npm install boom-format
29
+ ```
30
+
31
+ ## Quick Start
32
+
33
+ ```typescript
34
+ import { encode, decode, stringify, parseText } from 'boom-format';
35
+
36
+ // Binary format
37
+ const data = {
38
+ name: 'Tom',
39
+ skills: ['TypeScript', 'Node.js'],
40
+ nested: { deep: { value: 42 } }
41
+ };
42
+
43
+ const binary = encode(data); // Uint8Array
44
+ const restored = decode(binary); // Back to object
45
+
46
+ // Text format (for debugging)
47
+ const text = stringify(data); // Human-readable
48
+ const parsed = parseText(text); // Back to object
49
+ ```
50
+
51
+ ## Command Line Interface
52
+
53
+ BOOM includes a CLI for converting files between JSON and BOOM formats:
54
+
55
+ ```bash
56
+ # Install globally
57
+ npm install -g boom-format
58
+
59
+ # Or use with npx
60
+ npx boom --help
61
+ ```
62
+
63
+ ### Basic Usage
64
+
65
+ ```bash
66
+ # Encode JSON to BOOM binary
67
+ boom encode data.json # Output: data.boom
68
+
69
+ # Encode JSON to BOOM text (human-readable)
70
+ boom encode data.json --text # Output: data.boom.txt
71
+
72
+ # Decode BOOM to JSON
73
+ boom decode data.boom # Output: data.json
74
+ boom decode data.boom.txt # Decode text format
75
+
76
+ # Show file info
77
+ boom info data.boom
78
+ ```
79
+
80
+ ### CLI Options
81
+
82
+ ```
83
+ Usage:
84
+ boom encode <input.json> [output] Encode JSON to BOOM format
85
+ boom decode <input.boom> [output.json] Decode BOOM to JSON
86
+ boom info <input.boom> Show info about a BOOM file
87
+ boom <input.json> Shorthand for encode
88
+
89
+ Output Formats:
90
+ --binary, -b Output BOOM binary format (default)
91
+ --text, -t Output BOOM text format (.boom.txt)
92
+ --json, -j Output JSON format (for decode)
93
+
94
+ Options:
95
+ --help, -h Show this help message
96
+ --version, -v Show version
97
+ --pretty, -p Pretty-print output (JSON and text)
98
+ --dict, -d Use shared dictionary (default: true)
99
+ --no-dict Disable shared dictionary
100
+ ```
101
+
102
+ ### Stdin/Stdout Support
103
+
104
+ ```bash
105
+ # Pipe from stdin
106
+ cat data.json | boom encode - > data.boom
107
+ cat data.boom | boom decode - > data.json
108
+
109
+ # Convert and pipe to another command
110
+ boom encode data.json | curl -X POST -H "Content-Type: application/x-boom" --data-binary @- https://api.example.com
111
+ ```
112
+
113
+ ### Sample Files
114
+
115
+ The package includes sample files in `samples/` to help you understand the format:
116
+
117
+ ```bash
118
+ # View sample files
119
+ cat node_modules/boom-format/samples/users.boom.txt
120
+
121
+ # Test round-trip conversion
122
+ boom decode node_modules/boom-format/samples/users.boom --pretty
123
+ ```
124
+
125
+ ## Size Comparison
126
+
127
+ ```typescript
128
+ import { compare } from 'boom-format';
129
+
130
+ const data = {
131
+ users: [
132
+ { id: 1, name: 'Alice', active: true },
133
+ { id: 2, name: 'Bob', active: false },
134
+ { id: 3, name: 'Charlie', active: true }
135
+ ],
136
+ count: 3,
137
+ page: 1
138
+ };
139
+
140
+ console.log(compare(data));
141
+ // {
142
+ // jsonSize: 156,
143
+ // jsonMinSize: 128,
144
+ // boomBinarySize: 52,
145
+ // boomTextSize: 98,
146
+ // savings: { vsJson: '66.7%', vsJsonMin: '59.4%' }
147
+ // }
148
+ ```
149
+
150
+ ## API Reference
151
+
152
+ ### Binary Format
153
+
154
+ #### `encode(value, options?): Uint8Array`
155
+
156
+ Encode a value to BOOM binary format.
157
+
158
+ ```typescript
159
+ const binary = encode({ hello: 'world' });
160
+ ```
161
+
162
+ #### `decode(buffer, options?): BoomValue`
163
+
164
+ Decode BOOM binary format to a value.
165
+
166
+ ```typescript
167
+ const value = decode(binary);
168
+ ```
169
+
170
+ ### Text Format
171
+
172
+ #### `stringify(value, options?): string`
173
+
174
+ Convert a value to BOOM text format.
175
+
176
+ ```typescript
177
+ const text = stringify({ name: 'Tom', age: 42 });
178
+ // {
179
+ // name: "Tom"
180
+ // age: 42
181
+ // }
182
+ ```
183
+
184
+ #### `parseText(input, options?): BoomValue`
185
+
186
+ Parse BOOM text format.
187
+
188
+ ```typescript
189
+ const value = parseText(`{
190
+ name: "Tom"
191
+ age: 42
192
+ tags: ["web" "ai"]
193
+ }`);
194
+ ```
195
+
196
+ ### JSON Interop
197
+
198
+ #### `fromJSON(json, options?): Uint8Array`
199
+
200
+ Convert JSON string to BOOM binary.
201
+
202
+ #### `toJSON(buffer, options?): string`
203
+
204
+ Convert BOOM binary to JSON string.
205
+
206
+ ### Options
207
+
208
+ ```typescript
209
+ interface BoomOptions {
210
+ maxDepth?: number; // Max nesting (default: 64)
211
+ maxStringLength?: number; // Max string bytes (default: 16MB)
212
+ maxArrayLength?: number; // Max array items (default: 1M)
213
+ enableInterning?: boolean; // String dedup (default: true)
214
+ }
215
+
216
+ interface BoomTextOptions extends BoomOptions {
217
+ compact?: boolean; // Single-line output
218
+ indentString?: string; // Indent chars (default: " ")
219
+ }
220
+ ```
221
+
222
+ ## Framework Integration
223
+
224
+ ### React
225
+
226
+ ```tsx
227
+ import { encode, decode } from 'boom-format';
228
+ import { useState, useEffect } from 'react';
229
+
230
+ // Custom hook for BOOM API calls
231
+ function useBoom<T>(url: string) {
232
+ const [data, setData] = useState<T | null>(null);
233
+ const [loading, setLoading] = useState(true);
234
+
235
+ useEffect(() => {
236
+ fetch(url, { headers: { Accept: 'application/x-boom' } })
237
+ .then(res => res.arrayBuffer())
238
+ .then(buf => setData(decode(new Uint8Array(buf)) as T))
239
+ .finally(() => setLoading(false));
240
+ }, [url]);
241
+
242
+ return { data, loading };
243
+ }
244
+
245
+ // Usage in component
246
+ function UserList() {
247
+ const { data: users, loading } = useBoom<User[]>('/api/users');
248
+
249
+ if (loading) return <div>Loading...</div>;
250
+ return <ul>{users?.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
251
+ }
252
+ ```
253
+
254
+ ### Next.js
255
+
256
+ ```typescript
257
+ // app/api/users/route.ts (App Router)
258
+ import { encode, decode } from 'boom-format';
259
+
260
+ export async function GET() {
261
+ const users = await db.users.findMany();
262
+ return new Response(encode(users), {
263
+ headers: { 'Content-Type': 'application/x-boom' }
264
+ });
265
+ }
266
+
267
+ export async function POST(req: Request) {
268
+ const body = decode(new Uint8Array(await req.arrayBuffer()));
269
+ const user = await db.users.create({ data: body });
270
+ return new Response(encode(user), {
271
+ headers: { 'Content-Type': 'application/x-boom' }
272
+ });
273
+ }
274
+
275
+ // Client component with Server Actions
276
+ 'use client';
277
+ import { boomFetch } from 'boom-format';
278
+
279
+ export default function Dashboard() {
280
+ const [users, setUsers] = useState([]);
281
+
282
+ useEffect(() => {
283
+ boomFetch('/api/users').then(setUsers);
284
+ }, []);
285
+
286
+ return <UserTable users={users} />;
287
+ }
288
+ ```
289
+
290
+ ### Vue 3
291
+
292
+ ```vue
293
+ <script setup lang="ts">
294
+ import { ref, onMounted } from 'vue';
295
+ import { decode } from 'boom-format';
296
+
297
+ const users = ref<User[]>([]);
298
+ const loading = ref(true);
299
+
300
+ onMounted(async () => {
301
+ const res = await fetch('/api/users', {
302
+ headers: { Accept: 'application/x-boom' }
303
+ });
304
+ users.value = decode(new Uint8Array(await res.arrayBuffer()));
305
+ loading.value = false;
306
+ });
307
+ </script>
308
+
309
+ <template>
310
+ <div v-if="loading">Loading...</div>
311
+ <ul v-else>
312
+ <li v-for="user in users" :key="user.id">{{ user.name }}</li>
313
+ </ul>
314
+ </template>
315
+ ```
316
+
317
+ ### Nuxt 3
318
+
319
+ ```typescript
320
+ // server/api/users.ts
321
+ import { encode, decode } from 'boom-format';
322
+
323
+ export default defineEventHandler(async (event) => {
324
+ const accept = getHeader(event, 'accept');
325
+ const users = await $fetch('/external-api/users');
326
+
327
+ if (accept === 'application/x-boom') {
328
+ setHeader(event, 'Content-Type', 'application/x-boom');
329
+ return encode(users);
330
+ }
331
+ return users;
332
+ });
333
+
334
+ // composables/useBoom.ts
335
+ export function useBoom<T>(url: string) {
336
+ return useFetch<T>(url, {
337
+ headers: { Accept: 'application/x-boom' },
338
+ transform: (data) => decode(new Uint8Array(data))
339
+ });
340
+ }
341
+ ```
342
+
343
+ ### Redux / Redux Toolkit
344
+
345
+ ```typescript
346
+ import { encode, decode } from 'boom-format';
347
+ import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
348
+
349
+ // Async thunk with BOOM encoding
350
+ export const fetchUsers = createAsyncThunk('users/fetch', async () => {
351
+ const res = await fetch('/api/users', {
352
+ headers: { Accept: 'application/x-boom' }
353
+ });
354
+ return decode(new Uint8Array(await res.arrayBuffer()));
355
+ });
356
+
357
+ // Persist Redux state with BOOM (40-70% smaller than JSON)
358
+ const persistBoom = {
359
+ save: (state: RootState) => {
360
+ localStorage.setItem('app-state',
361
+ btoa(String.fromCharCode(...encode(state)))
362
+ );
363
+ },
364
+ load: (): RootState | undefined => {
365
+ const saved = localStorage.getItem('app-state');
366
+ if (!saved) return undefined;
367
+ const bytes = Uint8Array.from(atob(saved), c => c.charCodeAt(0));
368
+ return decode(bytes) as RootState;
369
+ }
370
+ };
371
+ ```
372
+
373
+ ## Mobile Development
374
+
375
+ BOOM is ideal for mobile apps - smaller payloads mean faster loads on cellular networks and better battery life.
376
+
377
+ ### React Native
378
+
379
+ ```typescript
380
+ import { encode, decode } from 'boom-format';
381
+
382
+ // Custom fetch wrapper for React Native
383
+ async function boomRequest<T>(url: string, options?: RequestInit): Promise<T> {
384
+ const res = await fetch(url, {
385
+ ...options,
386
+ headers: {
387
+ ...options?.headers,
388
+ Accept: 'application/x-boom',
389
+ 'Content-Type': options?.body ? 'application/x-boom' : undefined,
390
+ },
391
+ body: options?.body ? encode(options.body) : undefined,
392
+ });
393
+
394
+ const buffer = await res.arrayBuffer();
395
+ return decode(new Uint8Array(buffer)) as T;
396
+ }
397
+
398
+ // Usage
399
+ const users = await boomRequest<User[]>('https://api.example.com/users');
400
+
401
+ // Offline storage with AsyncStorage (60% smaller than JSON)
402
+ import AsyncStorage from '@react-native-async-storage/async-storage';
403
+
404
+ const saveOffline = async (key: string, data: any) => {
405
+ const encoded = encode(data);
406
+ await AsyncStorage.setItem(key, btoa(String.fromCharCode(...encoded)));
407
+ };
408
+
409
+ const loadOffline = async <T>(key: string): Promise<T | null> => {
410
+ const saved = await AsyncStorage.getItem(key);
411
+ if (!saved) return null;
412
+ const bytes = Uint8Array.from(atob(saved), c => c.charCodeAt(0));
413
+ return decode(bytes) as T;
414
+ };
415
+ ```
416
+
417
+ ### iOS (Swift)
418
+
419
+ ```swift
420
+ import Boom
421
+
422
+ // Network request with BOOM
423
+ func fetchUsers() async throws -> [User] {
424
+ var request = URLRequest(url: URL(string: "https://api.example.com/users")!)
425
+ request.setValue("application/x-boom", forHTTPHeaderField: "Accept")
426
+
427
+ let (data, _) = try await URLSession.shared.data(for: request)
428
+ return try Boom.decode([User].self, from: data)
429
+ }
430
+
431
+ // Encode for POST
432
+ func createUser(_ user: User) async throws -> User {
433
+ var request = URLRequest(url: URL(string: "https://api.example.com/users")!)
434
+ request.httpMethod = "POST"
435
+ request.setValue("application/x-boom", forHTTPHeaderField: "Content-Type")
436
+ request.httpBody = try Boom.encode(user)
437
+
438
+ let (data, _) = try await URLSession.shared.data(for: request)
439
+ return try Boom.decode(User.self, from: data)
440
+ }
441
+
442
+ // Cache to disk (uses 60% less storage than JSON)
443
+ let encoded = try Boom.encode(users)
444
+ try encoded.write(to: cacheURL)
445
+ ```
446
+
447
+ ### Android (Java/Kotlin)
448
+
449
+ ```kotlin
450
+ import io.boomformat.Boom
451
+
452
+ // With Retrofit + custom converter
453
+ val retrofit = Retrofit.Builder()
454
+ .baseUrl("https://api.example.com/")
455
+ .addConverterFactory(BoomConverterFactory.create())
456
+ .build()
457
+
458
+ interface ApiService {
459
+ @GET("users")
460
+ @Headers("Accept: application/x-boom")
461
+ suspend fun getUsers(): List<User>
462
+
463
+ @POST("users")
464
+ @Headers("Content-Type: application/x-boom")
465
+ suspend fun createUser(@Body user: User): User
466
+ }
467
+
468
+ // Direct usage
469
+ val users = Boom.decode<List<User>>(response.bytes())
470
+ val encoded = Boom.encode(newUser)
471
+
472
+ // Room database with BOOM serialization (smaller DB files)
473
+ @TypeConverter
474
+ fun fromBoom(data: ByteArray): UserData = Boom.decode(data)
475
+
476
+ @TypeConverter
477
+ fun toBoom(userData: UserData): ByteArray = Boom.encode(userData)
478
+ ```
479
+
480
+ ### Why BOOM for Mobile?
481
+
482
+ | Benefit | Impact |
483
+ |---------|--------|
484
+ | **40-70% smaller payloads** | Faster downloads on 3G/4G/5G |
485
+ | **2-5x faster parsing** | Smoother UI, less jank |
486
+ | **Less data transfer** | Lower cellular bills, data caps |
487
+ | **Reduced battery drain** | Less radio usage, less CPU |
488
+ | **Offline storage** | 60% smaller cache files |
489
+ | **Native SDKs** | Swift, Java, C++ - no bridging overhead |
490
+
491
+ ## Browser Usage
492
+
493
+ ### Script Type
494
+
495
+ BOOM supports inline data via `<script type="text/boom">`:
496
+
497
+ ```html
498
+ <script type="text/boom" id="config">
499
+ {
500
+ apiUrl: "https://api.example.com"
501
+ features: {
502
+ darkMode: true
503
+ analytics: false
504
+ }
505
+ limits: [100 200 500]
506
+ }
507
+ </script>
508
+
509
+ <script type="module">
510
+ import { processBoomScripts, getBoomData } from 'boom-format';
511
+
512
+ // Process all boom scripts
513
+ processBoomScripts();
514
+
515
+ // Get specific data
516
+ const config = getBoomData('config');
517
+ console.log(config.apiUrl);
518
+ </script>
519
+ ```
520
+
521
+ ### Auto-initialisation
522
+
523
+ ```typescript
524
+ import { autoInit } from 'boom-format';
525
+
526
+ // Automatically process boom scripts when DOM is ready
527
+ autoInit();
528
+ ```
529
+
530
+ ### CDN Usage
531
+
532
+ ```html
533
+ <script type="module">
534
+ import * as boom from 'https://esm.sh/boom-format';
535
+
536
+ const data = boom.parseText('{name: "Tom"}');
537
+ </script>
538
+ ```
539
+
540
+ ## Text Format Syntax
541
+
542
+ ```boom
543
+ # Comments start with #
544
+
545
+ # Strings (quoted)
546
+ name: "Tom Taylor"
547
+
548
+ # Numbers (bare)
549
+ age: 42
550
+ price: 19.99
551
+ bignum: 9007199254740993n # BigInt
552
+
553
+ # Booleans & null
554
+ active: true
555
+ deleted: false
556
+ metadata: null
557
+
558
+ # Arrays (space or newline separated)
559
+ tags: ["web" "ai" "performance"]
560
+ matrix: [
561
+ [1 2 3]
562
+ [4 5 6]
563
+ ]
564
+
565
+ # Nested objects
566
+ user: {
567
+ name: "Tom"
568
+ address: {
569
+ city: "Liverpool"
570
+ country: "UK"
571
+ }
572
+ }
573
+
574
+ # Arrays of objects
575
+ users: [
576
+ { id: 1 name: "Alice" }
577
+ { id: 2 name: "Bob" }
578
+ ]
579
+
580
+ # Binary data (base64)
581
+ avatar: <binary:SGVsbG8gV29ybGQ=>
582
+ ```
583
+
584
+ ## Binary Format Specification
585
+
586
+ See [SPECIFICATION.md](./SPECIFICATION.md) for the full binary format specification.
587
+
588
+ ### Header
589
+
590
+ | Offset | Size | Description |
591
+ |--------|------|-------------|
592
+ | 0 | 4 | Magic: `BOOM` (0x42 0x4F 0x4F 0x4D) |
593
+ | 4 | 1 | Version: 0x01 |
594
+ | 5 | 1 | Flags (reserved) |
595
+ | 6 | ... | Root value |
596
+
597
+ ### Type Markers
598
+
599
+ | Byte | Type |
600
+ |------|------|
601
+ | 0x00 | null |
602
+ | 0x01 | false |
603
+ | 0x02 | true |
604
+ | 0x10-0x19 | integers (various sizes) |
605
+ | 0x20-0x21 | floats |
606
+ | 0x30 | string |
607
+ | 0x31 | binary |
608
+ | 0x40 | array |
609
+ | 0x50 | object |
610
+ | 0x60 | string reference (local interning) |
611
+ | 0x61 | dictionary reference (shared dictionary) |
612
+
613
+ ## Built-in Dictionary
614
+
615
+ BOOM includes a shared dictionary of **299 common strings** optimized for API responses, LLM streaming, and analytics data. Strings in the dictionary are encoded as 1-2 byte references instead of full UTF-8. The first 128 entries (indices 0-127) use single-byte varint encoding for maximum efficiency.
616
+
617
+ ```typescript
618
+ import { encode, decode, BOOM_DICTIONARY_V1, analyzeDictionary } from 'boom-format';
619
+
620
+ // Dictionary is used automatically
621
+ const data = {
622
+ id: 1,
623
+ status: 'active', // "id" and "status" are in dictionary
624
+ role: 'assistant', // "role" and "assistant" are in dictionary
625
+ content: 'Hello!' // "content" is in dictionary
626
+ };
627
+
628
+ const encoded = encode(data); // Keys encoded as 1-byte refs
629
+
630
+ // Analyze dictionary coverage
631
+ const analysis = analyzeDictionary(data);
632
+ console.log(analysis.stats.dictionaryHitRate); // e.g., 0.85 (85% hit rate)
633
+ console.log(analysis.missingStrings); // Strings not in dictionary
634
+ ```
635
+
636
+ ### Dictionary Contents (First 128 = 1-byte encoding)
637
+
638
+ The first 128 entries get optimal 1-byte encoding:
639
+
640
+ - **Core keys**: id, type, name, status, data, value, content, message, error
641
+ - **AI/LLM**: role, model, choices, delta, finish_reason, usage, prompt_tokens, completion_tokens
642
+ - **API patterns**: request, response, params, headers, body, method, url, path
643
+ - **Timestamps**: created_at, updated_at, timestamp, expires_at
644
+ - **Status values**: active, pending, completed, failed, enabled, disabled
645
+ - **HTTP**: GET, POST, PUT, DELETE, Content-Type, Authorization
646
+
647
+ ### Disable Dictionary
648
+
649
+ ```typescript
650
+ const encoded = encode(data, { useBuiltInDictionary: false });
651
+ ```
652
+
653
+ ### Strict Binary Mode (Production Security)
654
+
655
+ Reject non-BOOM input to prevent JSON injection attacks:
656
+
657
+ ```typescript
658
+ const decoded = decode(buffer, { strictBinaryMode: true });
659
+ // Throws if buffer doesn't start with BOOM magic bytes
660
+ ```
661
+
662
+ ## TypeScript Support
663
+
664
+ Full type definitions included:
665
+
666
+ ```typescript
667
+ import type { BoomValue, BoomObject, BoomArray, BoomOptions } from 'boom-format';
668
+
669
+ const data: BoomObject = {
670
+ name: 'Tom',
671
+ scores: [100, 95, 88] as BoomArray,
672
+ };
673
+ ```
674
+
675
+ ## Error Handling
676
+
677
+ ```typescript
678
+ import { encode, decode, BoomError } from 'boom-format';
679
+
680
+ try {
681
+ const value = decode(corruptedData);
682
+ } catch (error) {
683
+ if (error instanceof BoomError) {
684
+ console.error('Invalid BOOM data:', error.message);
685
+ }
686
+ }
687
+ ```
688
+
689
+ ## Benchmarks
690
+
691
+ Run benchmarks:
692
+
693
+ ```bash
694
+ npm run benchmark # Size/token benchmarks
695
+ npm run benchmark:compare # Full format comparison with speed tests
696
+ ```
697
+
698
+ ### Speed Benchmarks (Node.js v22)
699
+
700
+ BOOM is optimised for real-world data with repeated strings (API responses, logs, exports):
701
+
702
+ | Data Type | JSON Size | BOOM Size | Savings | Encode Speed | Decode Speed |
703
+ |-----------|-----------|-----------|---------|--------------|--------------|
704
+ | **Small** | 37 bytes | 35 bytes | **5.4%** | **2x faster** | **2x faster** |
705
+ | **Medium** | 9,727 bytes | 5,389 bytes | **44.6%** | **1.3x faster** | **1.1x faster** |
706
+ | **Tabular (500 rows)** | 52,226 bytes | 18,093 bytes | **65.4%** | **2x faster** | **2.5x faster** |
707
+ | **Large (float matrix)** | 192,966 bytes | 80,291 bytes | **58.4%** | **8x faster** | **19x faster** |
708
+
709
+ For typical API data, BOOM is **1.3-2x faster** than JSON for encoding and **1.1-2.5x faster** for decoding.
710
+ Float matrices benefit most from native binary encoding: **8-19x faster**.
711
+
712
+ ### Cross-Language Performance
713
+
714
+ BOOM is available in 13 implementations with consistent performance:
715
+
716
+ | Language | Encode Speed | Decode Speed | Size Savings |
717
+ |----------|-------------|--------------|--------------|
718
+ | **JavaScript** | **1.3-2x faster** | **1.1-2.5x faster** | 40-65% |
719
+ | **Go** | **2.0-2.6x faster** | **3.6-4.1x faster** | 40-70% |
720
+ | **Rust** | **2x+ faster** | **2x+ faster** | 40-70% |
721
+ | **C++** | **1.3-3.2x faster** | **1.5-1.6x faster** | 29-69% |
722
+ | **Java** | ~1x (Jackson optimized) | **2.8-5.3x faster** | 36-73% |
723
+ | **.NET** | **1.3-2.7x faster** | **3.4-4.9x faster** | 36-72% |
724
+ | **PHP** (C ext) | **1.2x faster** | **1.4x faster** | 40-70% |
725
+ | **Swift** | **2.2x faster** | **3.5x faster** | 40-70% |
726
+
727
+ **Key findings:**
728
+ - BOOM decode is **1.5-5x faster** than JSON across all languages
729
+ - BOOM encode is **1.2-3x faster** in most languages
730
+ - Float/binary data sees **8-19x** speedup
731
+ - Size savings of **36-73%** depending on data structure
732
+ - Tabular data with repeated strings shows the best improvements
733
+
734
+ ### Cross-Platform Compatibility (Production-Safe)
735
+
736
+ BOOM is **100% compatible** across all backend providers and mobile/frontend consumers. Every provider-consumer combination is automatically tested on every commit.
737
+
738
+ | Backend Provider | iOS (Swift) | Android (Java) | Web (JS) | Native (C++) |
739
+ |-----------------|-------------|----------------|----------|--------------|
740
+ | **Go** | ✅ | ✅ | ✅ | ✅ |
741
+ | **PHP** | ✅ | ✅ | ✅ | ✅ |
742
+ | **Rust** | ✅ | ✅ | ✅ | ✅ |
743
+ | **Java** | ✅ | ✅ | ✅ | ✅ |
744
+ | **.NET** | ✅ | ✅ | ✅ | ✅ |
745
+ | **Node.js** | ✅ | ✅ | ✅ | ✅ |
746
+
747
+ **Why this matters:**
748
+ - **Safe for production** - Any backend can serve any mobile app
749
+ - **CI-verified** - Automated tests on every commit via GitHub Actions
750
+ - **No surprises** - Binary format is byte-for-byte consistent
751
+ - **Mix and match** - Use different providers for different services
752
+
753
+ See [Interoperability Tests](https://boomformat.dev/interoperability.html) for live CI results.
754
+
755
+ #### Go Performance
756
+
757
+ ```
758
+ go test -bench=. -benchmem
759
+
760
+ Encode Small: BOOM 775ns vs JSON 1,619ns = 2.1x faster
761
+ Encode Medium: BOOM 131µs vs JSON 312µs = 2.4x faster
762
+ Decode Small: BOOM 787ns vs JSON 3,210ns = 4.1x faster
763
+ Decode Medium: BOOM 111µs vs JSON 352µs = 3.2x faster
764
+ Size savings: 48.3%
765
+ ```
766
+
767
+ #### Java Performance (vs Jackson)
768
+
769
+ ```
770
+ mvn exec:java
771
+
772
+ Decode Small: BOOM 1,083K ops/s vs Jackson 204K ops/s = 5.3x faster
773
+ Decode Medium: BOOM 20.4K ops/s vs Jackson 7.3K ops/s = 2.8x faster
774
+ Decode Tabular: BOOM 5.1K ops/s vs Jackson 1.2K ops/s = 4.4x faster
775
+ Size savings: 36% (medium), 73% (tabular)
776
+ ```
777
+
778
+ #### .NET Performance (vs System.Text.Json)
779
+
780
+ ```
781
+ dotnet run -c Release
782
+
783
+ Decode Small: BOOM 411ns vs JSON 1,572ns = 3.8x faster
784
+ Decode Medium: BOOM 72µs vs JSON 349µs = 4.9x faster
785
+ Decode Tabular: BOOM 578µs vs JSON 1,973µs = 3.4x faster
786
+ Encode Small: BOOM 447ns vs JSON 588ns = 1.3x faster
787
+ Encode Medium: BOOM 48µs vs JSON 101µs = 2.1x faster
788
+ Encode Tabular: BOOM 255µs vs JSON 700µs = 2.7x faster
789
+ Size savings: 36% (medium), 72% (tabular)
790
+ ```
791
+
792
+ #### PHP Performance (Native C Extension)
793
+
794
+ ```
795
+ php benchmark.php
796
+
797
+ Decode: BOOM Native 1.92x faster than json_decode
798
+ Size savings: 49%
799
+ ```
800
+
801
+ #### Rust Performance
802
+
803
+ Rust's `serde_json` is highly optimized. BOOM trades speed for size:
804
+
805
+ ```
806
+ cargo bench
807
+
808
+ Size savings: 66.3% on tabular data
809
+ Note: serde_json is faster for pure speed, but BOOM reduces network transfer significantly
810
+ ```
811
+
812
+ ### Payload Size Thresholds (Optional)
813
+
814
+ BOOM includes an **optional** threshold system for automatic format selection based on payload size. This is a tuning mechanism for users who want to optimize for their specific use case.
815
+
816
+ > **Note:** This feature is entirely optional. BOOM aims to be faster than JSON for all sizes, but the threshold system allows fine-tuning for edge cases where native JSON implementations may have slightly less overhead for very small payloads.
817
+
818
+ #### Default Thresholds (Benchmark-Based)
819
+
820
+ | Payload Size | Default Format | Reason |
821
+ |--------------|----------------|--------|
822
+ | < 1KB | JSON | Native JSON may have less overhead |
823
+ | 1KB - 100KB | BOOM Binary | Good balance of speed and size |
824
+ | > 100KB | BOOM Binary (forced) | Significant size/speed benefits |
825
+
826
+ #### Configuration
827
+
828
+ ```typescript
829
+ import { setThresholdConfig, selectFormat, estimateSize } from 'boom-format';
830
+
831
+ // Configure thresholds (optional - defaults work well for most cases)
832
+ setThresholdConfig({
833
+ minSize: 1024, // Below: may use JSON (default: 1KB)
834
+ preferSize: 10240, // Above: prefer BOOM (default: 10KB)
835
+ forceSize: 102400, // Above: always BOOM (default: 100KB)
836
+ autoDetect: true, // Enable auto format selection
837
+ });
838
+
839
+ // Auto-select format based on estimated size
840
+ const data = { users: [...] };
841
+ const { mode, reason } = selectFormat(estimateSize(data));
842
+ // mode: 'boom-binary' or 'json'
843
+ // reason: 'size-below-threshold', 'size-above-force', etc.
844
+
845
+ // Or use with boomFetch for automatic selection
846
+ const result = await boomFetch('/api/data', {
847
+ body: largePayload,
848
+ autoFormat: true, // Automatically selects format based on size
849
+ });
850
+ ```
851
+
852
+ #### HTTP Header Negotiation
853
+
854
+ Servers can announce their threshold policy, and clients can hint expected payload sizes:
855
+
856
+ ```
857
+ # Server response headers
858
+ X-Boom-Min-Size: 1024
859
+ X-Boom-Prefer-Size: 10240
860
+ X-Boom-Force-Size: 102400
861
+
862
+ # Client request header
863
+ X-Boom-Expected-Size: large # or 'small', or byte count like '50000'
864
+ ```
865
+
866
+ ```typescript
867
+ import { createThresholdHeaders, parseThresholdHeaders } from 'boom-format';
868
+
869
+ // Server: Create headers to announce policy
870
+ app.use((req, res, next) => {
871
+ const headers = createThresholdHeaders();
872
+ Object.entries(headers).forEach(([k, v]) => res.setHeader(k, v));
873
+ next();
874
+ });
875
+
876
+ // Client: Parse server's threshold policy
877
+ const serverConfig = parseThresholdHeaders(response.headers);
878
+ ```
879
+
880
+ #### When to Use Thresholds
881
+
882
+ - **Most users:** Don't need to configure thresholds - defaults work well
883
+ - **API developers:** May want to tune based on typical payload sizes
884
+ - **Performance-critical apps:** Can fine-tune based on their specific data patterns
885
+ - **Hybrid environments:** Useful when some clients don't support BOOM
886
+
887
+ ### BOOM vs JSON + HTTP Compression
888
+
889
+ Modern HTTP/2 and HTTP/3 use compression (gzip, brotli, deflate). BOOM still wins:
890
+
891
+ | Data Type | JSON | JSON+gzip | JSON+brotli | BOOM | BOOM+brotli |
892
+ |-----------|------|-----------|-------------|------|-------------|
893
+ | **Small** (3 keys) | 39 B | 59 B | 43 B | **37 B** | 41 B |
894
+ | **Medium** (100 rows) | 8,109 B | 1,064 B | 597 B | **4,623 B** | **624 B** |
895
+ | **Tabular** (500 rows) | 75,176 B | 523 B | 137 B | **39,587 B** | 191 B |
896
+ | **API Response** | 6,967 B | 719 B | 462 B | **3,071 B** | 554 B |
897
+
898
+ **Key findings:**
899
+
900
+ 1. **BOOM uncompressed is 40-70% smaller than JSON** - before any HTTP compression
901
+ 2. **For tabular data, BOOM is smaller than JSON+gzip** - string interning eliminates redundancy at source
902
+ 3. **BOOM + HTTP compression works** - BOOM can be further compressed via gzip/brotli
903
+ 4. **No CPU overhead difference** - both formats get HTTP-compressed anyway
904
+
905
+ **For HTTP/2 and HTTP/3:**
906
+ ```
907
+ # Server returns BOOM binary
908
+ Content-Type: application/x-boom
909
+ Content-Encoding: br # Brotli compression by HTTP layer
910
+
911
+ # Result: Smallest possible payload + fast binary parsing
912
+ ```
913
+
914
+ **Recommendation:**
915
+ - API servers: Return BOOM binary, let HTTP layer handle compression
916
+ - Mobile apps: Accept BOOM binary, benefit from smaller downloads + faster parsing
917
+ - Web apps: Accept BOOM binary, faster parsing than JSON even after decompression
918
+
919
+ Run the compression comparison:
920
+ ```bash
921
+ node benchmark/compression-comparison.cjs
922
+ ```
923
+
924
+ ### Why BOOM Wins for LLM Use Cases
925
+
926
+ | Metric | JSON | BOOM Binary | Winner |
927
+ |--------|------|-------------|--------|
928
+ | Decoding speed | Baseline | **240% faster** | **BOOM** |
929
+ | Encoding speed | Baseline | **125%** | **BOOM** |
930
+ | Payload size | 52KB | 18KB | **BOOM (65% smaller)** |
931
+ | Token count | ~13,000 | ~5,700 | **BOOM (56% fewer)** |
932
+ | Network transfer | Slower | **Faster** | **BOOM** |
933
+ | LLM processing | Slower | **Faster** | **BOOM** |
934
+ | API cost | $X | **$0.44X** | **BOOM (56% cheaper)** |
935
+
936
+ For the typical LLM workflow:
937
+ - Network latency (50-200ms) dominates
938
+ - LLM inference time (500-5000ms) is the bottleneck
939
+ - BOOM's size reduction speeds up both network AND inference
940
+ - BOOM decode being 2.4x faster helps when processing responses
941
+
942
+ ## Format Comparison
943
+
944
+ BOOM vs JSON, TRON, TOON, YAML, XML, CSV, and VSC - comprehensive benchmarks across different data structures.
945
+
946
+ ### Token Efficiency Rankings (LLM cost savings vs JSON)
947
+
948
+ | Rank | Format | Avg Token Reduction | Data Support |
949
+ |------|--------|---------------------|--------------|
950
+ | **1** | **BOOM binary** | **68.6%** | **All data types** |
951
+ | 2 | VSC | 64.5% | Flat tabular only |
952
+ | 3 | CSV | 63.8% | Flat tabular only |
953
+ | 4 | TRON | 55.2% | Uniform arrays only |
954
+ | 5 | TOON | 50.8% | Uniform arrays only |
955
+ | 6 | YAML | 20.6% | All data types |
956
+ | 7 | BOOM text | 3.9% | All data types |
957
+ | 8 | XML | -46.3% (more!) | All data types |
958
+
959
+ **Key insight:** BOOM binary beats CSV/VSC on token efficiency while supporting ALL data structures, including nested objects.
960
+
961
+ ### Size Efficiency (bytes saved vs JSON)
962
+
963
+ | Format | Simple Data | Employees (100) | Nested Orders | Deep Config | API Response |
964
+ |--------|-------------|-----------------|---------------|-------------|--------------|
965
+ | **BOOM binary** | **6%** | **63%** | **53%** | **24%** | **36%** |
966
+ | TRON | 12% | 48% | 58% | -12% | 24% |
967
+ | TOON | 16% | 51% | 64% | -18% | 27% |
968
+ | CSV/VSC* | - | 57% | 65% | - | - |
969
+ | YAML | 13% | -11% | -23% | -18% | -25% |
970
+ | XML | -67% | -87% | -124% | -106% | -157% |
971
+
972
+ *CSV/VSC only work for flat tabular data
973
+
974
+ ### Why BOOM Beats TRON & TOON
975
+
976
+ [TRON](https://github.com/nicois/tron) and [TOON](https://toonformat.dev) claim fewer tokens than JSON. Our benchmarks show:
977
+ - **BOOM binary: 80.6% fewer tokens than JSON**
978
+ - **TRON: 55.2% fewer tokens than JSON**
979
+ - **TOON: 50.8% fewer tokens than JSON**
980
+ - **BOOM uses 31.2% fewer tokens than TRON**
981
+ - **BOOM uses 37.8% fewer tokens than TOON**
982
+
983
+ | Metric | BOOM Binary | TRON | TOON | Winner |
984
+ |--------|-------------|------|------|--------|
985
+ | Token savings vs JSON | 80.6% | 55.2% | 50.8% | **BOOM** |
986
+ | Nested structures | Excellent | Poor | Poor | **BOOM** |
987
+ | Mixed data types | Full support | Limited | Limited | **BOOM** |
988
+ | Binary data | Native | None | None | **BOOM** |
989
+ | Schema required | No | No | No | Tie |
990
+ | Human readable | Via .boom.txt | Yes | Yes | TRON/TOON |
991
+
992
+ **TRON & TOON limitations:**
993
+ - Only efficient for uniform arrays of objects
994
+ - Nested structures lose efficiency
995
+ - No binary format option
996
+ - No string interning
997
+
998
+ **BOOM advantages:**
999
+ - Efficient for ALL data structures
1000
+ - Binary format for maximum compression
1001
+ - String interning for repeated values
1002
+ - Native BigInt and binary data support
1003
+ - Self-describing (no schema needed)
1004
+
1005
+ ### Real-World Example
1006
+
1007
+ ```javascript
1008
+ // 100-employee directory
1009
+ const data = {
1010
+ context: { task: 'Employee directory', department: 'Engineering' },
1011
+ employees: Array.from({ length: 100 }, (_, i) => ({
1012
+ id: i + 1,
1013
+ name: `Employee ${i + 1}`,
1014
+ email: `emp${i + 1}@company.com`,
1015
+ department: ['Engineering', 'Sales', 'Marketing', 'HR'][i % 4],
1016
+ salary: 50000 + (i * 500),
1017
+ active: i % 5 !== 0
1018
+ })),
1019
+ total: 100
1020
+ };
1021
+
1022
+ // Results:
1023
+ // JSON: 11,165 bytes | 5,993 tokens
1024
+ // TRON: 5,812 bytes | 2,687 tokens (48% smaller, 55% fewer tokens)
1025
+ // TOON: 5,499 bytes | 2,299 tokens (51% smaller, 62% fewer tokens)
1026
+ // BOOM binary: 4,134 bytes | 1,378 tokens (63% smaller, 77% fewer tokens)
1027
+ // CSV: 5,209 bytes | 2,261 tokens (flat array only)
1028
+ // VSC: 4,850 bytes | 2,224 tokens (flat array only)
1029
+ // XML: 20,837 bytes | 8,417 tokens (87% larger!)
1030
+ ```
1031
+
1032
+ **BOOM wins on both size AND tokens** - with tabular encoding, BOOM binary beats CSV/VSC for flat data too.
1033
+
1034
+ ### When to Use Each Format
1035
+
1036
+ | Format | Use When |
1037
+ |--------|----------|
1038
+ | **BOOM binary** | LLM API calls, AI agents, maximum efficiency |
1039
+ | **BOOM text** | Debugging, config files, human editing |
1040
+ | JSON | Interoperability with existing systems |
1041
+ | TRON | Uniform tabular data, human-readable priority |
1042
+ | TOON | Uniform tabular data, human-readable priority |
1043
+ | YAML | Human-edited config files |
1044
+ | CSV/VSC | Flat tabular data, spreadsheet export |
1045
+ | XML | Never for LLMs (2x the tokens of JSON) |
1046
+
1047
+ Run the full comparison benchmark:
1048
+ ```bash
1049
+ node benchmark/format-comparison.js
1050
+ ```
1051
+
1052
+ ## Contributing
1053
+
1054
+ 1. Fork the repository
1055
+ 2. Create a feature branch
1056
+ 3. Run tests: `npm test`
1057
+ 4. Submit a merge request
1058
+
1059
+ ## License
1060
+
1061
+ MIT © Tom Taylor
1062
+
1063
+ ## Links
1064
+
1065
+ - **Website**: [boomformat.dev](https://boomformat.dev)
1066
+ - **npm**: [npmjs.com/package/boom-format](https://www.npmjs.com/package/boom-format)
1067
+ - **Go**: [pkg.go.dev/github.com/t0mtaylor/boom-format/go](https://pkg.go.dev/github.com/t0mtaylor/boom-format/go)
1068
+ - **Rust**: [crates.io/crates/boom-format](https://crates.io/crates/boom-format)
1069
+ - **Java**: [Maven Central](https://central.sonatype.com/artifact/io.boom-format/boom)
1070
+ - **.NET**: [NuGet](https://www.nuget.org/packages/BoomFormat)
1071
+ - **PHP**: [Packagist](https://packagist.org/packages/boom-format/boom)
1072
+ - **Swift**: [Swift Package](https://github.com/t0mtaylor/boom-format)
1073
+ - **C++**: [Header-only](https://github.com/t0mtaylor/boom-format/tree/main/plugins/cpp)
1074
+
1075
+ ---
1076
+
1077
+ Made with ❤️ by [The Tom Taylor Company](https://tomtaylor.co.uk) • [𝕏 @tom_taylor](https://x.com/tom_taylor)
1078
+
1079
+ ![](https://st.rs.thetomtaylor.co.uk/matomo.php?idsite=28&rec=1)