You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A utility for high-performance data transport from JSI C++ to JavaScript.
5
+
High-performance columnar `ArrayBuffer` transport from JSI C++ to JavaScript.
6
6
7
-
JSI native modules typically return data as an array of objects — one JS object per row, with a key for every field. This works fine for small amounts of data, but becomes slow at scale: the JS engine has to allocate thousands of objects, box every value, and put pressure on the GC.
7
+
JSI modules often return large datasets as arrays of objects. That is easy to use, but expensive at scale: every row becomes a JS object, every value is boxed, and the result puts pressure on the GC.
8
8
9
-
`react-native-columnar` replaces the array of objects with a single binary `ArrayBuffer` in columnar layout. The C++ side writes all values directly into a pre-allocated buffer, passes it to JS via JSI with zero copies, and the JS side reads it through typed array views (`Int32Array`, `Float64Array`, etc.) over the same memory — no allocation, no parsing, no overhead.
9
+
`react-native-columnar` writes fixed-width native values into one binary columnar buffer and exposes it to JS as typed array views (`Int32Array`, `Float64Array`, etc.). No per-row objects, no parsing, and no payload copy.
10
+
11
+
---
12
+
13
+
## Best use cases
14
+
15
+
- SQLite result sets
16
+
- Frame processor outputs
17
+
- Sensor streams
18
+
- Analytics events
19
+
- Game / physics data
20
+
- Large JSI payloads
21
+
- Realtime charts
22
+
23
+
---
24
+
25
+
## Benchmark
26
+
27
+
**Test:** 10 000 iterations — each call transfers N rows (5 columns) from C++ to JS and reads one row.
28
+
29
+
```
30
+
Schema: id (int32) | status (uint8) | isActive (uint8) | createdAt (double) | updatedAt (double)
**Array of objects** — each call allocates a JS array of objects with 5 keys each, boxes every value, and puts pressure on the GC — multiplied across 10 000 iterations.
42
+
43
+
**react-native-columnar** — one binary buffer is allocated in C++, all rows are written in a single loop, and the buffer pointer is handed to the JS engine as an `ArrayBuffer`. The JS side creates five typed array views (`Int32Array`, `Uint8Array`, `Float64Array`) over the same memory — **zero copies, zero parsing, no per-row object allocation**.
44
+
45
+
> Measured on iPhone 16 Pro. Results will vary by device and data shape.
46
+
47
+
---
48
+
49
+
## Requirements
50
+
51
+
- React Native with JSI native modules
52
+
- C++20 or newer (`std::span` is used by the C++ helper)
53
+
- iOS via CocoaPods or Android via CMake
54
+
- Fixed-width numeric data (`int8_t`, `uint32_t`, `double`, etc.)
**Array of objects** — each call allocates a JS array of objects with 5 keys each, boxes every value, and puts pressure on the GC — multiplied across 10 000 iterations.
278
+
The C++ helper uses `std::span`, so your native target must compile with C++20 or
279
+
newer. If your build fails with errors around `std::span`, enable C++20 for the
280
+
target that includes `react-native-columnar.h`.
199
281
200
-
**react-native-columnar** — one binary buffer is allocated in C++, all rows are written in a single loop, and the buffer pointer is handed to the JS engine as an `ArrayBuffer`. The JS side creates five typed array views (`Int32Array`, `Uint8Array`, `Float64Array`) over the same memory — **zero copies, zero parsing, zero object allocation**.
282
+
### `RangeError` while creating typed arrays
201
283
202
-
> Measured on iPhone 16 Pro. Results will vary by device and data shape.
284
+
This usually means the JavaScript schema does not match the native schema, or the
285
+
buffer was not created by `ColumnarWriterBuilder`.
286
+
287
+
Check that:
288
+
289
+
- The JS `ColumnType` list has the same order as the C++ schema.
290
+
- Each JS type matches the exact C++ type size (`int32_t` → `ColumnType.Int32`,
291
+
`double` → `ColumnType.Float64`, etc.).
292
+
- The buffer is the `ArrayBuffer` returned by `writer.toArrayBuffer(rt)`.
293
+
294
+
### Values look shifted or incorrect
295
+
296
+
The reader and writer must agree on both column order and type width. A single
297
+
wrong type can shift all following columns. Start by comparing the C++ schema with
0 commit comments