Avro-js JavaScript Implementation
avro-js is a pure JavaScript implementation of the Apache Avro specification, providing efficient data serialization and deserialization. It is currently stable at version 1.12.1, with the Apache Avro project demonstrating an active release cadence, including regular minor and patch updates across its language SDKs. Key differentiators include its reported speed (often twice as fast as JSON with significantly smaller encodings), comprehensive Avro feature support (including recursive schemas, sort order, and schema evolution), and the ability to serialize arbitrary JavaScript objects through logical types. Notably, it boasts zero runtime dependencies and is designed to run both in Node.js environments and modern web browsers. While the core project evolves the Avro specification and multi-language SDKs, avro-js focuses solely on the JavaScript ecosystem.
Common errors
-
Error: Invalid value for union type: expected 'null' or 'LongList', got object
cause Attempting to serialize an object that uses an untagged record within a union type where the record type name is expected.fixWhen dealing with recursive or optional record types within a union, explicitly wrap the nested object with its Avro record name, e.g., `{ next: { LongList: { value: 2, next: null } } }` instead of `{ next: { value: 2, next: null } }`. -
ReferenceError: require is not defined
cause Using CommonJS `require()` syntax in a JavaScript module that is treated as an ES Module (e.g., in a Node.js project with `"type": "module"` or in a browser via modern bundling without CommonJS transpilation).fixFor modern JavaScript environments, use `import * as avro from 'avro-js';`. If running in Node.js ES Modules, ensure your `package.json` specifies `"type": "module"` and adjust imports accordingly. If `avro-js` is primarily CJS, use `import avro from 'avro-js';` with caution, as it implies a default export which may not exist, or `import * as avro from 'avro-js';`. -
ReferenceError: fs is not defined
cause Attempting to use `avro.parse('./path.avsc')` or `avro.createFileDecoder()` in a browser environment, which lack Node.js file system (`fs`) modules.fixEnsure that `avro-js` file-based operations are only executed in Node.js. For browser applications, load schemas as pre-fetched JSON strings or JavaScript objects and use `avro.parse(jsonString)` or `avro.parse(jsonObject)`. -
Error: Missing required field: 'fieldName'
cause An object being serialized is missing a field that is marked as required (i.e., not a union with 'null' and no default value) in the Avro schema.fixEnsure that the JavaScript object being passed for serialization contains all fields that are defined as required in the corresponding Avro schema. Provide a value for the missing field or update the schema to make the field optional or provide a default.
Warnings
- gotcha When defining recursive schemas, `avro-js` does not use duck-typing for nested records within unions. You must explicitly specify the record type name for recursive instances, e.g., `{ "RecordName": { ... } }` rather than just `{ ... }`.
- gotcha File system operations, such as `avro.parse('./path/to/schema.avsc')` for loading schema files or `avro.createFileDecoder()` for reading Avro container files, are strictly for Node.js environments and are not supported in web browsers.
- gotcha Avro `long` types correspond to 64-bit signed integers. JavaScript's native `Number` type uses 64-bit floating-point format and can only safely represent integers up to `2^53 - 1`. Handling `long` values outside this range can lead to precision loss without explicit configuration.
- gotcha While Avro schemas are JSON-based, strict adherence to the Avro specification is required for schema parsing and data validation. Common JSON syntax errors (e.g., trailing commas, unquoted property names) or Avro-specific schema definition errors (e.g., invalid field types, missing required attributes) can lead to parsing failures.
Install
-
npm install avro-js -
yarn add avro-js -
pnpm add avro-js
Imports
- avro
import avro from 'avro-js';
import * as avro from 'avro-js';
- avro.parse
import { parse } from 'avro-js'; const type = parse(schema);import * as avro from 'avro-js'; const type = avro.parse(schema);
- avro.createFileDecoder
import { createFileDecoder } from 'avro-js';import * as avro from 'avro-js'; avro.createFileDecoder('./records.avro')
Quickstart
import * as avro from 'avro-js';
// 1. Define an Avro schema for a 'Pet' record
const petType = avro.parse({
name: 'Pet',
type: 'record',
fields: [
{name: 'kind', type: {name: 'Kind', type: 'enum', symbols: ['CAT', 'DOG', 'FISH']}},
{name: 'name', type: 'string'},
{name: 'age', type: 'int', default: 0}
]
});
// 2. Create a JavaScript object conforming to the schema
const myPet = {kind: 'CAT', name: 'Albert', age: 5};
// 3. Serialize the object to an Avro binary buffer
const buffer = petType.toBuffer(myPet);
console.log('Serialized Buffer:', buffer.toString('hex'));
// 4. Deserialize the buffer back into a JavaScript object
const deserializedPet = petType.fromBuffer(buffer);
console.log('Deserialized Object:', deserializedPet);
// 5. Generate a random instance of the schema
const randomIdType = avro.parse('{"type": "fixed", "name": "Id", "size": 4}');
const randomId = randomIdType.random();
console.log('Random ID (Buffer):', randomId.toString('hex'));
// 6. Check if an object is valid against a schema
const isValid = petType.isValid({kind: 'DOG', name: 'Buddy'});
console.log('Is valid pet object:', isValid);
const isInvalid = petType.isValid({kind: 'FISH', unknownField: 'extra'});
console.log('Is invalid pet object (extra field):', isInvalid);