Package Exports
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (iceberg-js) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
iceberg-js
A small, framework-agnostic JavaScript/TypeScript client for the Apache Iceberg REST Catalog.
Features
- Generic: Works with any Iceberg REST Catalog implementation, not tied to any specific vendor
- Minimal: Thin HTTP wrapper over the official REST API, no engine-specific logic
- Type-safe: First-class TypeScript support with strongly-typed request/response models
- Fetch-based: Uses native
fetchAPI with support for custom implementations - Universal: Targets Node 20+ and modern browsers (ES2020)
- Catalog-only: Focused on catalog operations (no data reading/Parquet support in v0.1.0)
Documentation
📚 Full API documentation: supabase.github.io/iceberg-js
Installation
npm install iceberg-jsQuick Start
import { IcebergRestCatalog } from 'iceberg-js'
const catalog = new IcebergRestCatalog({
baseUrl: 'https://my-catalog.example.com/iceberg/v1',
auth: {
type: 'bearer',
token: process.env.ICEBERG_TOKEN,
},
})
// Create a namespace
await catalog.createNamespace({ namespace: ['analytics'] })
// Create a table
await catalog.createTable(
{ namespace: ['analytics'] },
{
name: 'events',
schema: {
type: 'struct',
fields: [
{ id: 1, name: 'id', type: 'long', required: true },
{ id: 2, name: 'timestamp', type: 'timestamp', required: true },
{ id: 3, name: 'user_id', type: 'string', required: false },
],
'schema-id': 0,
'identifier-field-ids': [1],
},
'partition-spec': {
'spec-id': 0,
fields: [],
},
'write-order': {
'order-id': 0,
fields: [],
},
properties: {
'write.format.default': 'parquet',
},
}
)API Reference
Constructor
new IcebergRestCatalog(options)
Creates a new catalog client instance.
Options:
baseUrl(string, required): Base URL of the REST catalogauth(AuthConfig, optional): Authentication configurationcatalogName(string, optional): Catalog name for multi-catalog servers. When specified, requests are sent to{baseUrl}/v1/{catalogName}/.... For example, withbaseUrl: 'https://host.com'andcatalogName: 'prod', requests go tohttps://host.com/v1/prod/namespacesfetch(typeof fetch, optional): Custom fetch implementationaccessDelegation(AccessDelegation[], optional): Access delegation mechanisms to request from the server
Authentication types:
// No authentication
{ type: 'none' }
// Bearer token
{ type: 'bearer', token: 'your-token' }
// Custom header
{ type: 'header', name: 'X-Custom-Auth', value: 'secret' }
// Custom function
{ type: 'custom', getHeaders: async () => ({ 'Authorization': 'Bearer ...' }) }Access Delegation:
Access delegation allows the catalog server to provide temporary credentials or sign requests on your behalf:
import { IcebergRestCatalog } from 'iceberg-js'
const catalog = new IcebergRestCatalog({
baseUrl: 'https://catalog.example.com/iceberg/v1',
auth: { type: 'bearer', token: 'your-token' },
// Request vended credentials for data access
accessDelegation: ['vended-credentials'],
})
// The server may return temporary credentials in the table metadata
const metadata = await catalog.loadTable({ namespace: ['analytics'], name: 'events' })
// Use credentials from metadata.config to access table data filesSupported delegation mechanisms:
vended-credentials: Server provides temporary credentials (e.g., AWS STS tokens) for accessing table dataremote-signing: Server signs data access requests on behalf of the client
Namespace Operations
listNamespaces(parent?: NamespaceIdentifier): Promise<NamespaceIdentifier[]>
List all namespaces, optionally under a parent namespace.
const namespaces = await catalog.listNamespaces()
// [{ namespace: ['default'] }, { namespace: ['analytics'] }]
const children = await catalog.listNamespaces({ namespace: ['analytics'] })
// [{ namespace: ['analytics', 'prod'] }]createNamespace(id: NamespaceIdentifier, metadata?: NamespaceMetadata): Promise<void>
Create a new namespace with optional properties.
await catalog.createNamespace({ namespace: ['analytics'] }, { properties: { owner: 'data-team' } })dropNamespace(id: NamespaceIdentifier): Promise<void>
Drop a namespace. The namespace must be empty.
await catalog.dropNamespace({ namespace: ['analytics'] })loadNamespaceMetadata(id: NamespaceIdentifier): Promise<NamespaceMetadata>
Load namespace metadata and properties.
const metadata = await catalog.loadNamespaceMetadata({ namespace: ['analytics'] })
// { properties: { owner: 'data-team', ... } }Table Operations
listTables(namespace: NamespaceIdentifier): Promise<TableIdentifier[]>
List all tables in a namespace.
const tables = await catalog.listTables({ namespace: ['analytics'] })
// [{ namespace: ['analytics'], name: 'events' }]createTable(namespace: NamespaceIdentifier, request: CreateTableRequest): Promise<TableMetadata>
Create a new table.
const metadata = await catalog.createTable(
{ namespace: ['analytics'] },
{
name: 'events',
schema: {
type: 'struct',
fields: [
{ id: 1, name: 'id', type: 'long', required: true },
{ id: 2, name: 'timestamp', type: 'timestamp', required: true },
],
'schema-id': 0,
},
'partition-spec': {
'spec-id': 0,
fields: [
{
source_id: 2,
field_id: 1000,
name: 'ts_day',
transform: 'day',
},
],
},
}
)loadTable(id: TableIdentifier): Promise<TableMetadata>
Load table metadata.
const metadata = await catalog.loadTable({
namespace: ['analytics'],
name: 'events',
})updateTable(id: TableIdentifier, request: UpdateTableRequest): Promise<TableMetadata>
Update table metadata (schema, partition spec, or properties).
const updated = await catalog.updateTable(
{ namespace: ['analytics'], name: 'events' },
{
properties: { 'read.split.target-size': '134217728' },
}
)dropTable(id: TableIdentifier): Promise<void>
Drop a table from the catalog.
await catalog.dropTable({ namespace: ['analytics'], name: 'events' })Error Handling
All API errors throw an IcebergError with details from the server:
import { IcebergError } from 'iceberg-js'
try {
await catalog.loadTable({ namespace: ['test'], name: 'missing' })
} catch (error) {
if (error instanceof IcebergError) {
console.log(error.status) // 404
console.log(error.icebergType) // 'NoSuchTableException'
console.log(error.message) // 'Table does not exist'
}
}TypeScript Types
The library exports all relevant types:
import type {
NamespaceIdentifier,
TableIdentifier,
TableSchema,
TableField,
IcebergType,
PartitionSpec,
SortOrder,
CreateTableRequest,
TableMetadata,
AuthConfig,
AccessDelegation,
} from 'iceberg-js'Supported Iceberg Types
The following Iceberg primitive types are supported:
boolean,int,long,float,doublestring,uuid,binarydate,time,timestamp,timestamptzdecimal(precision, scale),fixed(length)
Compatibility
This package is built to work in all Node.js and JavaScript environments:
| Environment | Module System | Import Method | Status |
|---|---|---|---|
| Node.js ESM | "type": "module" |
import { ... } from 'iceberg-js' |
✅ Fully supported |
| Node.js CommonJS | Default | const { ... } = require('iceberg-js') |
✅ Fully supported |
| TypeScript ESM | module: "ESNext" |
import { ... } from 'iceberg-js' |
✅ Full type support |
| TypeScript CommonJS | module: "CommonJS" |
import { ... } from 'iceberg-js' |
✅ Full type support |
| Bundlers | Any | Webpack, Vite, esbuild, Rollup, etc. | ✅ Auto-detected |
| Browsers | ESM | <script type="module"> |
✅ Modern browsers |
| Deno | ESM | import from npm: |
✅ With npm specifier |
Package exports:
- ESM:
dist/index.mjswithdist/index.d.ts - CommonJS:
dist/index.cjswithdist/index.d.cts - Proper
exportsfield for Node.js 12+ module resolution
All scenarios are tested in CI on Node.js 20 and 22.
Browser Usage
The library works in modern browsers that support native fetch:
import { IcebergRestCatalog } from 'iceberg-js'
const catalog = new IcebergRestCatalog({
baseUrl: 'https://public-catalog.example.com/iceberg/v1',
auth: { type: 'none' },
})
const namespaces = await catalog.listNamespaces()Node.js Usage
Node.js 20+ includes native fetch support. For older versions, provide a custom fetch implementation:
import { IcebergRestCatalog } from 'iceberg-js'
import fetch from 'node-fetch'
const catalog = new IcebergRestCatalog({
baseUrl: 'https://catalog.example.com/iceberg/v1',
auth: { type: 'bearer', token: 'token' },
fetch: fetch as any,
})Limitations (v0.1.0)
This is a catalog client only. The following are not supported:
- Reading table data (scanning Parquet files)
- Writing data to tables
- Advanced table operations (commits, snapshots, time travel)
- Views support
- Multi-table transactions
Development
# Install dependencies
pnpm install
# Build the library
pnpm run build
# Run unit tests
pnpm test
# Run integration tests (requires Docker)
pnpm test:integration
# Run integration tests with cleanup (for CI)
pnpm test:integration:ci
# Run compatibility tests (all module systems)
pnpm test:compatibility
# Format code
pnpm run format
# Lint and test
pnpm run checkTesting with Docker
Integration tests run against a local Iceberg REST Catalog in Docker. See TESTING-DOCKER.md for details.
# Start Docker services and run integration tests
pnpm test:integration
# Or manually
docker compose up -d
npx tsx test/integration/test-local-catalog.ts
docker compose down -vCompatibility Testing
The test:compatibility script verifies the package works correctly in all JavaScript/TypeScript environments:
- Pure JavaScript ESM - Projects with
"type": "module" - Pure JavaScript CommonJS - Traditional Node.js projects
- TypeScript ESM - TypeScript with
module: "ESNext" - TypeScript CommonJS - TypeScript with
module: "CommonJS"
These tests ensure proper module resolution, type definitions, and runtime behavior across all supported environments. See test/compatibility/README.md for more details.
License
MIT
Releases
This project uses release-please for automated releases. Here's how it works:
Commit with conventional commits: Use Conventional Commits format for your commits:
feat:for new features (minor version bump)fix:for bug fixes (patch version bump)feat!:orBREAKING CHANGE:for breaking changes (major version bump)chore:,docs:,test:, etc. for non-release commits
Release PR is created automatically: When you push to
main, release-please creates/updates a release PR with:- Version bump in
package.json - Updated
CHANGELOG.md - Release notes
- Version bump in
Merge the release PR: When you're ready to release, merge the PR. This will:
- Create a GitHub release and git tag
- Automatically publish to npm with provenance (using trusted publishing, no secrets needed)
Example commits:
git commit -m "feat: add support for view operations"
git commit -m "fix: handle empty namespace list correctly"
git commit -m "feat!: change auth config structure"Contributing
Contributions are welcome! This library aims to be a minimal, generic client for the Iceberg REST Catalog API.