| name | Apache Arrow JS |
| description | This skill should be used when working with Apache Arrow in JavaScript/TypeScript — Table, Vector, Schema, IPC serialization, columnar data, RecordBatch, Flight SQL, Flechette, Arquero, Mosaic, DuckDB-WASM, or imports from 'apache-arrow', '@uwdata/flechette', '@uwdata/vgplot', 'arquero'. Covers zero-copy patterns, typed arrays, builder API, Arrow Flight, and the Arrow JS ecosystem. |
| user-invocable | true |
| context | current |
Apache Arrow JS (v21+)
Columnar in-memory data format for high-performance analytics in JavaScript/TypeScript.
Core Concepts
Arrow stores data in columns (Vectors), not rows. A Table is a collection of named Vectors sharing a Schema. Data is stored as flat TypedArrays — no per-row object allocation, zero-copy slicing, and direct GPU/WASM interop.
Table (Schema + RecordBatches)
├── Vector<Int32> "id" → Int32Array
├── Vector<Utf8> "name" → Uint8Array (UTF-8 bytes) + offsets
└── Vector<Float32> "score" → Float32Array
Creating Tables
From JS arrays (copies data, infers types)
import { tableFromArrays } from "apache-arrow"
const table = tableFromArrays({
id: [1, 2, 3],
name: ["Alice", "Bob", "Carol"],
score: new Float32Array([0.9, 0.7, 0.85]),
})
From typed arrays (zero-copy)
import { makeTable } from "apache-arrow"
const table = makeTable({
x: new Float32Array([10, 20, 30]),
y: new Float32Array([40, 50, 60]),
})
From JSON objects
import { tableFromJSON } from "apache-arrow"
const table = tableFromJSON([
{ a: "foo", b: 42 },
{ a: "bar", b: 12 },
])
From IPC binary (deserialization)
import { tableFromIPC } from "apache-arrow"
const table = tableFromIPC(bytes)
const table = await tableFromIPC(fetch("/data.arrow"))
const table = tableFromIPC([schemaBytes, recordBytes])
With explicit Schema
import { Table, Schema, Field, Float32, Utf8, tableFromArrays } from "apache-arrow"
const schema = new Schema([
new Field("x", new Float32()),
new Field("label", new Utf8()),
])
const schemaWithMeta = new Schema(fields, new Map([
["image_base64", base64String],
["page_id", "page-001"],
]))
Serializing Tables
import { tableToIPC } from "apache-arrow"
const bytes: Uint8Array = tableToIPC(table, "stream")
const bytes: Uint8Array = tableToIPC(table, "file")
Reading Tables
Column access
const col = table.getChild("name")
const col2 = table.getChildAt(0)
const arr = col.toArray()
Row access
const row = table.get(0)
const row2 = table.at(-1)
console.log(row.name, row.score)
for (const row of table) {
console.log(row.id, row.name)
}
Table properties
table.numRows
table.numCols
table.schema
table.batches
table.nullCount
Slicing & selecting (zero-copy)
const subset = table.slice(10, 20)
const projected = table.select(["name", "score"])
const combined = table.concat(otherTable)
const merged = table.assign(extraColumns)
Modifying columns
const updated = table.setChild("name", newNameVector)
const replaced = table.setChildAt(0, newVector)
Vectors
Creating Vectors
import { makeVector, vectorFromArray } from "apache-arrow"
const v = makeVector(new Float32Array([1, 2, 3]))
const nums = vectorFromArray([1, 2, 3])
const ints = vectorFromArray([1, 2, 3], new Int8)
const strs = vectorFromArray(["a", "b", "c"])
const bools = vectorFromArray([true, false])
const dates = vectorFromArray([new Date()])
const structs = vectorFromArray([{x: 1}, {x: 2}])
Vector API
vector.get(0)
vector.at(-1)
vector.set(0, value)
vector.isValid(0)
vector.length
vector.nullCount
vector.type
vector.toArray()
vector.slice(0, 10)
vector.indexOf(value)
vector.includes(value)
const memo = vector.memoize()
const original = memo.unmemoize()
Dictionary Vectors (string encoding)
import { makeVector, vectorFromArray, Dictionary, Utf8, Uint8 } from "apache-arrow"
const dict = vectorFromArray(["foo", "bar", "foo", "baz"])
const keys = vectorFromArray(["foo", "bar", "baz"], new Utf8)
const dictVec = makeVector({
data: [0, 1, 2, 0, 1],
dictionary: keys,
type: new Dictionary(new Utf8, new Uint8),
})
Builder API
For constructing Vectors incrementally:
import { makeBuilder, Utf8 } from "apache-arrow"
const builder = makeBuilder({
type: new Utf8(),
nullValues: [null, "n/a"],
})
builder.append("hello")
builder.append("n/a")
builder.append("world")
builder.append(null)
const vector = builder.finish().toVector()
Chunked building with iterables
import { builderThroughIterable, Float64 } from "apache-arrow"
const through = builderThroughIterable({
type: new Float64(),
highWaterMark: 1000,
queueingStrategy: "count",
})
for (const vector of through(valueIterator)) {
}
Schema & Metadata
import { Schema, Field, Float32, Utf8 } from "apache-arrow"
const schema = new Schema(
[new Field("x", new Float32()), new Field("label", new Utf8())],
new Map([["version", "1"], ["author", "system"]])
)
const meta = table.schema.metadata
const version = meta.get("version")
const newSchema = new Schema(newFields, existingTable.schema.metadata)
const newTable = new Table(newSchema, newBatches)
RecordBatch Reader/Writer
Reading IPC streams
import { RecordBatchReader } from "apache-arrow"
const reader = await RecordBatchReader.from(uint8Array)
const reader = await RecordBatchReader.from(fetch("/data.arrow"))
const reader = await RecordBatchReader.from(readableStream)
for (const batch of reader) {
console.log(batch.numRows, batch.schema)
}
Writing IPC streams
import { RecordBatchWriter } from "apache-arrow"
const writer = new RecordBatchWriter()
writer.write(table)
writer.finish()
const bytes = writer.toUint8Array(true)
const stream = writer.toDOMStream()
Data Types Reference
| Arrow Type | JS Type | TypedArray |
|---|
Int8/16/32 | number | Int8/16/32Array |
Uint8/16/32 | number | Uint8/16/32Array |
Int64/Uint64 | bigint | BigInt64/BigUint64Array |
Float16/32/64 | number | Uint16/Float32/Float64Array |
Bool | boolean | Uint8Array (bit-packed) |
Utf8 | string | Uint8Array + offsets |
Binary | Uint8Array | Uint8Array + offsets |
List<T> | T[] | nested Vector |
Struct<{...}> | StructRowProxy | nested Vectors |
Dictionary<V,K> | V["TValue"] | key array + dictionary Vector |
Timestamp* | number | Int32Array (pair) |
Date* | number | Int32Array |
Null | null | (no buffer) |
Type guards
import { DataType } from "apache-arrow"
DataType.isFloat(field.type)
DataType.isInt(field.type)
DataType.isUtf8(field.type)
DataType.isList(field.type)
DataType.isStruct(field.type)
DataType.isDictionary(field.type)
Performance Patterns
Zero-copy column access
const xArr = table.getChild("x")!.toArray() as Float32Array
for (const row of table) { }
Avoid per-row allocation
const results = []
for (let i = 0; i < table.numRows; i++) {
results.push(table.get(i))
}
const xArr = table.getChild("x")!.toArray() as Float32Array
const yArr = table.getChild("y")!.toArray() as Float32Array
for (let i = 0; i < table.numRows; i++) {
process(xArr[i], yArr[i])
}
Memoize string decoding
const col = table.getChild("text")!
const memo = col.memoize()
for (let i = 0; i < memo.length; i++) {
memo.get(i)
}
Rebuild table without full copy
const cols: Record<string, unknown[]> = {}
for (const field of table.schema.fields) {
const col = table.getChild(field.name)!
const arr = new Array(table.numRows)
for (let i = 0; i < table.numRows; i++) arr[i] = col.get(i)
cols[field.name] = arr
}
const rebuilt = tableFromArrays(cols)
const withMeta = new Table(
new Schema(rebuilt.schema.fields, originalTable.schema.metadata),
rebuilt.batches,
)
Reference Documents
./references/zero-copy.md — What is/isn't zero-copy, performance decision tree, golden rules
./references/reading-writing.md — Column access, row access, rebuilding tables, add/delete/update rows, streaming
./references/types.md — Type hierarchy, constructors, type guards, Field/Schema, vectorFromArray inference
./references/anti-patterns.md — 10 common mistakes (row iteration, metadata loss, List gotchas, etc.)
./references/ipc-patterns.md — IPC streaming, chunked loading, HTTP transfer, delta updates
./references/flight-sql.md — Flight SQL client, gRPC, query execution
./references/flechette.md — Flechette: faster/smaller Arrow alternative, useProxy, toColumns, compression
./references/arquero.md — Arquero: dplyr-style data wrangling on Arrow (derive, filter, join, rollup)
./references/mosaic.md — Mosaic: scalable interactive viz framework (Coordinator, vgplot, SQL, cross-filtering)
./references/duckdb-wasm.md — DuckDB-WASM + Arrow in SvelteKit (SQL on Arrow in browser)