@ipld/schema
JavaScript IPLD Schema parser, validator, and code generator.
What are IPLD Schemas?
IPLD Schemas define a type system for content-addressed data. Think of them like TypeScript or Protocol Buffers, but designed for immutable, linked data structures. They help you:
- 🛡️ Validate that your data matches an expected structure
- 🔄 Transform between compact binary formats and developer-friendly JSON
- 🏗️ Generate type-safe code in multiple languages (Go, Rust, TypeScript)
- 🔗 Link between data structures using content identifiers (CIDs)
Learn more at https://ipld.io/docs/schemas/
Features
- Parse and validate IPLD Schema DSL (Domain Specific Language)
- Runtime validation with automatic format conversion
- Code generation for Go, Rust, and TypeScript
- Advanced type features: optional fields, defaults, renames, type aliases
- Multiple data representations for space-efficient storage
- CLI tools for validation and code generation
Installation
npm install @ipld/schema
For CLI usage:
npm install -g @ipld/schema
Quick Start
Basic Schema Definition
IPLD Schemas use a simple, readable syntax:
import { fromDSL } from '@ipld/schema/from-dsl.js'
import { create } from '@ipld/schema/typed.js'
const schema = fromDSL(`
# A simple user profile schema
type UserProfile struct {
username String
email String
age Int
isActive Bool
}
`)
const validator = create(schema, 'UserProfile')
const userData = {
username: 'alice',
email: 'alice@example.com',
age: 25,
isActive: true
}
const validatedData = validator.toTyped(userData)
if (validatedData === undefined) {
console.error('Invalid data!')
} else {
console.log('Valid user profile:', validatedData)
}
Schema Language Basics
Basic Types
type MyString String # UTF-8 string
type MyInt Int # Signed integer
type MyFloat Float # Floating point
type MyBool Bool # Boolean
type MyBytes Bytes # Binary data
type MyLink &Any # IPLD Link (CID)
Structs (Objects)
type Person struct {
name String
age Int
email String optional # Optional field
nickname String (implicit "") # Default value
}
Lists and Maps
# List of strings
type Names [String]
# Map from string to integers
type Scores {String: Int}
# Nested structures
type Team struct {
name String
members [Person]
metadata {String: String}
}
Enums
type Status enum {
| Active
| Inactive
| Pending
}
# With custom string values
type Color enum {
| Red ("red")
| Green ("green")
| Blue ("blue")
} representation string
Type Aliases
type UserID = String
type Timestamp = Int
type EmailAddress = String
Data Representations
IPLD Schemas separate the logical structure (what developers work with) from the storage format (how it's encoded). This allows for space-efficient storage while maintaining developer-friendly APIs.
Example: Tuple Representation
import { fromDSL } from '@ipld/schema/from-dsl.js'
import { create } from '@ipld/schema/typed.js'
const schema = fromDSL(`
# Store as array instead of object to save space
type Point struct {
x Float
y Float
} representation tuple
`)
const validator = create(schema, 'Point')
const point = { x: 10.5, y: 20.3 }
const stored = validator.toRepresentation(point)
console.log(stored)
const restored = validator.toTyped(stored)
console.log(restored)
Code Generation
Generate type-safe code from your schemas:
Go
import { fromDSL } from '@ipld/schema/from-dsl.js'
import { generateGo } from '@ipld/schema/gen/go.js'
const schema = fromDSL(`
type Person struct {
name String
age Int optional
}
`)
const goCode = generateGo(schema, { packageName: 'person' })
Rust
import { generateRust } from '@ipld/schema/gen/rust.js'
const rustCode = generateRust(schema)
TypeScript
import { generateTypeScript } from '@ipld/schema/gen/typescript.js'
const tsCode = generateTypeScript(schema)
Advanced Features
Field Renames
Control JSON field names separately from your schema field names:
type ServerConfig struct {
serverPort Int (rename "server_port")
debugMode Bool (rename "debug_mode")
apiKey String (rename "api_key")
}
Annotations
Add language-specific type information:
# Use big integers in Go
# @gotype(big.Int)
type Balance Int
type Transaction struct {
# Custom serialization in Rust
# @rustserde(with = "chrono::serde::ts_seconds")
timestamp Int
# Multiple annotations
# @gotag(`json:"tx_id" db:"transaction_id"`)
id String
}
Custom Transforms
Handle special encoding requirements:
const customTransforms = {
Base64String: {
toTyped: (str) => {
try {
return Uint8Array.from(atob(str), c => c.charCodeAt(0))
} catch {
return undefined
}
},
toRepresentation: (bytes) => {
return btoa(String.fromCharCode(...bytes))
}
}
}
const validator = create(schema, 'MyType', { customTransforms })
Command Line Interface
The ipld-schema command provides tools for working with schemas:
Validation
ipld-schema validate schema.ipldsch
ipld-schema validate README.md
Conversion
ipld-schema to-json schema.ipldsch
ipld-schema to-schema schema.ipldsch
Code Generation
ipld-schema to-js schema.ipldsch
ipld-schema to-tsdefs schema.ipldsch
API Reference
Parsing Schemas
fromDSL(dsl: string) - Parse schema DSL into an AST
toDSL(schema: Schema) - Convert AST back to DSL
Validation
create(schema: Schema, type: string, options?) - Create a validator
- Returns
{ toTyped, toRepresentation }
toTyped(data) - Validate and convert from storage format
toRepresentation(data) - Validate and convert to storage format
Code Generation
generateGo(schema, options) - Generate Go code
generateRust(schema, options) - Generate Rust code
generateTypeScript(schema, options) - Generate TypeScript code
License & Copyright
Copyright 2019-2025 Rod Vagg
Licensed under either of
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.