doba

Introduction

Schema registry with flexible transformations. Type-safe migrations between any schemas, errors as values.

Introduction

doba is a TypeScript schema registry that lets you define multiple representations of the same data and transform between them with full type safety.

Standard Schema

doba works with any Standard Schema compliant library: Zod, Valibot, ArkType, and more. No lock-in.

Why doba?

Most applications deal with the same data in multiple shapes:

  • Database: full record with sensitive fields
  • Frontend: stripped for the client
  • AI/LLM: flattened for context windows
  • Export: formatted for data portability
  • Legacy: old versions that still need support

doba lets you put all these variants in one registry with migrations between them. It finds the shortest path automatically, validates at each step, and returns typed results with metadata.

Database UserFrontend User
id
string
email
string
-passwordHash
string
createdAt
string
role
enum

Key features

Quick example

import { createRegistry } from 'dobajs'
import { z } from 'zod'

const registry = createRegistry({
  schemas: {
    database: z.object({ id: z.string(), email: z.string(), passwordHash: z.string() }),
    frontend: z.object({ id: z.string(), email: z.string() }),
  },
  migrations: {
    'database->frontend': (user) => ({ id: user.id, email: user.email }),
  },
})
import { createRegistry } from 'dobajs'
import * as v from 'valibot'

const registry = createRegistry({
  schemas: {
    database: v.object({ id: v.string(), email: v.string(), passwordHash: v.string() }),
    frontend: v.object({ id: v.string(), email: v.string() }),
  },
  migrations: {
    'database->frontend': (user) => ({ id: user.id, email: user.email }),
  },
})
import { createRegistry } from 'dobajs'
import { type } from 'arktype'

const registry = createRegistry({
  schemas: {
    database: type({ id: 'string', email: 'string', passwordHash: 'string' }),
    frontend: type({ id: 'string', email: 'string' }),
  },
  migrations: {
    'database->frontend': (user) => ({ id: user.id, email: user.email }),
  },
})

On this page