
Security News
The Nightmare Before Deployment
Season’s greetings from Socket, and here’s to a calm end of year: clean dependencies, boring pipelines, no surprises.
A small, framework-agnostic JavaScript/TypeScript client for the Apache Iceberg REST Catalog
A small, framework-agnostic JavaScript/TypeScript client for the Apache Iceberg REST Catalog.
fetch API with support for custom implementations📚 Full API documentation: supabase.github.io/iceberg-js
npm install iceberg-js
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',
},
}
)
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, with baseUrl: 'https://host.com' and catalogName: 'prod', requests go to https://host.com/v1/prod/namespacesfetch (typeof fetch, optional): Custom fetch implementationaccessDelegation (AccessDelegation[], optional): Access delegation mechanisms to request from the serverAuthentication 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 files
Supported 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 clientlistNamespaces(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', ... } }
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' })
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'
}
}
The library exports all relevant types:
import type {
NamespaceIdentifier,
TableIdentifier,
TableSchema,
TableField,
IcebergType,
PartitionSpec,
SortOrder,
CreateTableRequest,
TableMetadata,
AuthConfig,
AccessDelegation,
} from 'iceberg-js'
The following Iceberg primitive types are supported:
boolean, int, long, float, doublestring, uuid, binarydate, time, timestamp, timestamptzdecimal(precision, scale), fixed(length)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:
dist/index.mjs with dist/index.d.tsdist/index.cjs with dist/index.d.ctsexports field for Node.js 12+ module resolutionAll scenarios are tested in CI on Node.js 20 and 22.
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 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,
})
This is a catalog client only. The following are not supported:
# 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 check
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 -v
The test:compatibility script verifies the package works correctly in all JavaScript/TypeScript environments:
"type": "module"module: "ESNext"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.
MIT
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!: or BREAKING CHANGE: for breaking changes (major version bump)chore:, docs:, test:, etc. for non-release commitsRelease PR is created automatically: When you push to main, release-please creates/updates a release PR with:
package.jsonCHANGELOG.mdMerge the release PR: When you're ready to release, merge the PR. This will:
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"
Contributions are welcome! This library aims to be a minimal, generic client for the Iceberg REST Catalog API.
FAQs
A small, framework-agnostic JavaScript/TypeScript client for the Apache Iceberg REST Catalog
We found that iceberg-js demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Season’s greetings from Socket, and here’s to a calm end of year: clean dependencies, boring pipelines, no surprises.

Research
/Security News
Impostor NuGet package Tracer.Fody.NLog typosquats Tracer.Fody and its author, using homoglyph tricks, and exfiltrates Stratis wallet JSON/passwords to a Russian IP address.

Security News
Deno 2.6 introduces deno audit with a new --socket flag that plugs directly into Socket to bring supply chain security checks into the Deno CLI.