DataFn
Client

Client Setup

Create and configure a DataFn client instance.

Creating a Client

Use createDatafnClient() to initialize a DataFn client. The client validates your schema at creation time and sets up table handles, event bus, sync engine, and KV store.

import { createDatafnClient } from "@datafn/client";
import { IndexedDbStorageAdapter } from "@datafn/client";
import { defineSchema } from "@datafn/core";

const schema = defineSchema({
  resources: [
    {
      name: "todos",
      version: 1,
      idPrefix: "td",
      fields: [
        { name: "title", type: "string", required: true },
        { name: "completed", type: "boolean", required: true },
      ],
    },
  ],
});

const client = createDatafnClient({
  schema,
  clientId: "device-abc-123",
  storage: new IndexedDbStorageAdapter("my-app-db"),
  sync: {
    remote: "https://api.example.com/datafn",
    ws: true,
    offlinability: true,
    mode: "sync",
    hydration: {
      bootResources: ["todos"],
      clonePageSize: 500,
    },
  },
});

Configuration Reference

Top-Level Options

OptionTypeDescription
schemaDatafnSchemaRequired. Your application schema created with defineSchema().
clientIdstringRequired. Stable device/client identifier used for idempotency and offline changelogs.
storageDatafnStorageAdapter | DatafnStorageFactoryLocal persistence adapter. Pass an instance directly or a factory function (ctx: AuthContext) => DatafnStorageAdapter for multi-user isolation.
authContextAuthContext | AuthContextProviderAuthentication context for multi-tenant data isolation. Required when storage is a factory function. Can be a plain object or a provider that implements getContext().
syncDatafnSyncConfigSync and connectivity configuration. See below.
pluginsDatafnPlugin[]Client-side plugins for hook execution (beforeQuery, afterMutation, etc.).
generateId(params: { resource: string; idPrefix?: string }) => stringCustom ID generator for insert operations. Defaults to crypto.randomUUID() with resource prefix.

Sync Configuration

The sync object controls how the client communicates with the server and handles offline scenarios.

sync: {
  // Connection
  remote: "https://api.example.com/datafn",
  ws: true,
  wsUrl: "wss://api.example.com/datafn/ws",   // optional, derived from remote

  // Mode
  mode: "sync",            // "sync" (default) or "local-only"
  offlinability: true,     // enable offline mutation queue

  // Push tuning
  pushInterval: 5000,      // ms between push cycles
  pushBatchSize: 100,      // mutations per push batch
  pushMaxRetries: 3,       // max retries per push round

  // Hydration
  hydration: {
    bootResources: ["todos", "users"],     // must clone before app is ready
    backgroundResources: ["analytics"],     // clone in background after boot
    clonePageSize: 500,                     // page size for paginated clone
  },

  // WebSocket reconnection
  wsReconnect: {
    enabled: true,
    baseDelayMs: 1000,
    maxDelayMs: 60000,
    multiplier: 2,
    jitterMs: 500,
  },

  // Cross-tab coordination
  crossTab: true,
}
OptionDefaultDescription
remote--Server URL. Required in "sync" mode unless remoteAdapter is provided.
remoteAdapter--Injected remote adapter, used instead of the built-in HTTP transport.
wsfalseEnable WebSocket for real-time server push.
wsUrlderivedWebSocket URL. Auto-derived from remote when ws is enabled.
mode"sync""sync" requires a remote. "local-only" marks all tables as ready immediately with no server.
offlinabilityfalseQueue mutations locally when offline and push when reconnected. Requires storage.
pushInterval--Milliseconds between automatic push cycles.
pushBatchSize100Max mutations sent per push batch.
pushMaxRetries3Max retry attempts per push round.
hydration--Controls initial data clone strategy. See below.
wsReconnectenabledExponential backoff config for WebSocket reconnection.
crossTabfalseRelay mutation events to other same-origin browser tabs via BroadcastChannel.

Hydration

Hydration controls how the client populates local storage from the server on first load.

  • bootResources -- Resources that must finish cloning before the app is considered hydrated. The client blocks on these during sync.start().
  • backgroundResources -- Resources that clone in the background after boot resources are ready.
  • clonePageSize -- Page size for paginated clone requests. Can be a single number or a per-resource map: { todos: 500, users: 200 }.

Storage Adapters

DataFn ships two built-in storage adapters:

import { MemoryStorageAdapter, IndexedDbStorageAdapter } from "@datafn/client";

// In-memory (useful for tests)
const memory = new MemoryStorageAdapter();

// IndexedDB (browser persistence)
const idb = new IndexedDbStorageAdapter("my-app-db");

For multi-user isolation, pass a factory function:

const client = createDatafnClient({
  schema,
  clientId: "device-abc",
  storage: (ctx) =>
    IndexedDbStorageAdapter.createForUser("my-app", ctx.userId, ctx.tenantId),
  authContext: { userId: "user-123", tenantId: "tenant-456" },
  sync: { remote: "https://api.example.com/datafn" },
});

Destroying the Client

Call destroy() to tear down the client. This stops the sync engine, closes WebSocket connections, unsubscribes all event listeners, and releases resources.

await client.destroy();

Call clear() to wipe all local data (IndexedDB stores, cursors, changelog, hydration state) without destroying the client:

await client.clear();