Custom Tables

Store app-specific structured data in ezAuth. Create typed tables, insert rows, and query with filtering and sorting.

Overview

Custom tables let you store structured data alongside your users without running a separate database. Each application can create tables with typed columns, and rows can optionally be scoped to individual users.

Use cases: user profiles, settings, contacts, form submissions, feature flags, app configuration.

Concepts

Column Types

TypeDescriptionExample
textString value"Alice"
intInteger30
floatFloating-point number3.14
boolBooleantrue
dateDate/datetime string"2025-01-15"
jsonArbitrary JSON{"key": "value"}

Create a Table

const table = await ez.tables.create({
  name: 'contacts',
  columns: [
    { name: 'name', type: 'text', required: true },
    { name: 'age', type: 'int' },
    { name: 'active', type: 'bool', defaultValue: true },
  ],
})

Add / Update / Remove Columns

// Add a column to an existing table
const col = await ez.tables.columns.add(table.id, {
  name: 'email',
  type: 'text',
  required: false,
  position: 2,
})

// Update a column
await ez.tables.columns.update(table.id, col.id, {
  name: 'email_address',
  required: true,
})

// Delete a column
await ez.tables.columns.delete(table.id, col.id)

Insert Rows

const row = await ez.tables.rows.insert(table.id, {
  data: { name: 'Alice', age: 30, active: true },
})
// row.id, row.data, row.created_at, row.updated_at

User-Scoped Rows

Pass user_id to tie a row to a specific user. When authenticated users access the table, they only see their own rows.

// Backend: insert a row for a specific user
await ez.tables.rows.insert(table.id, {
  data: { name: 'Alice' },
  userId: 'user-uuid',
})

Query Rows

Query rows with filtering, sorting, and cursor-based pagination:

const result = await ez.tables.rows.query(table.id, {
  filter: { field: 'age', op: 'gte', value: 18 },
  sort: { field: 'name', dir: 'asc' },
  limit: 50,
})
// result.rows — array of row objects
// result.next_cursor — pass to next query for pagination

Filter Operators

OperatorDescriptionExample
eqEqual{"field": "name", "op": "eq", "value": "Alice"}
neqNot equal{"field": "active", "op": "neq", "value": false}
gtGreater than{"field": "age", "op": "gt", "value": 21}
gteGreater than or equal{"field": "age", "op": "gte", "value": 18}
ltLess than{"field": "age", "op": "lt", "value": 65}
lteLess than or equal{"field": "age", "op": "lte", "value": 100}

Sort

FieldDescription
fieldColumn name to sort by
dir"asc" or "desc"

Update & Delete Rows

// Partial update
await ez.tables.rows.update(table.id, row.id, {
  data: { age: 31 },
})

// Delete
await ez.tables.rows.delete(table.id, row.id)

Storage Limits

Custom tables have a configurable storage limit per application (default: 100 MB).

const usage = await ez.storage.get()
console.log(`${usage.used_bytes} / ${usage.limit_bytes} bytes`)

Configure via CUSTOM_TABLES_STORAGE_LIMIT_BYTES environment variable.