Documentation
API reference
ponder.schema.ts

Schema API

The ponder.schema.ts file defines your database tables and their relationships. Tables defined in this file are used to store indexed blockchain data and are automatically exposed via the GraphQL API.

File requirements

The ponder.schema.ts must use named exports for tables, enums, and relations, and these objects must be created using the corresponding functions exported by @ponder/core.

ponder.schema.ts
import { onchainTable } from "@ponder/core";
 
export const pets = onchainTable("pets", (t) => ({
  name: t.text().primaryKey(),
  age: t.integer().notNull(),
}));

onchainTable

The onchainTable function accepts three positional arguments.

ArgumentTypeDescription
namestringThe SQL table name. Use snake_case.
columns(t: TableBuilder) => Record<string, Column>A function that returns column definitions.
constraints?(table: Table) => Record<string, Constraint>Optional function that returns table constraints like composite primary keys and indexes.
ponder.schema.ts
import { onchainTable } from "@ponder/core";
 
export const transferEvents = onchainTable(
  "transfer_event", // SQL table name
  (t) => ({ // Column definitions
    id: t.text().primaryKey(),
    from: t.hex().notNull(),
    to: t.hex().notNull(),
    value: t.bigint().notNull(),
  }),
  (table) => ({  // Constraints & indexes
    fromIdx: index().on(table.from),
  })
);

Column types

The schema definition API supports most PostgreSQL data types. Here's a quick reference for the most commonly used data types. For a complete list, see the Drizzle documentation.

NameDescriptionTypeScript typeSQL data type
textUTF‐8 character sequencestringTEXT
integerSigned 4‐byte integernumberINTEGER
realSigned 4-byte floating‐point valuenumberREAL
booleantrue or falsebooleanBOOLEAN
timestampDate and time value (no time zone)DateTIMESTAMP
jsonJSON objectany or customJSON
bigintLarge integer (holds uint256 and int256)bigintNUMERIC(78,0)
hexUTF‐8 character sequence with 0x prefix0x${string}TEXT

Column modifiers

Column modifiers can be chained after column type definitions.

ModifierDescription
.primaryKey()Marks column as the table's primary key
.notNull()Marks column as NOT NULL
.array()Marks column as an array type
.default(value)Sets a default value for column
.$default(() => value)Sets a dynamic default via function
.$type<T>()Annotates column with a custom TypeScript type

Constraints

Primary key

Every table must have exactly one primary key defined using either the .primaryKey() column modifier or the primaryKey() function in the table constraints argument.

ponder.schema.ts
import { onchainTable, primaryKey } from "@ponder/core";
 
// Single column primary key
export const tokens = onchainTable("tokens", (t) => ({
  id: t.bigint().primaryKey(),
}));
 
// Composite primary key
export const poolStates = onchainTable(
  "pool_states",
  (t) => ({
    poolId: t.bigint().notNull(),
    address: t.hex().notNull(),
  }),
  (table) => ({
    pk: primaryKey({ columns: [table.poolId, table.address] }),
  })
);

Indexes

Create indexes using the index() function in the constraints & indexes argument. The indexing engine creates indexes after historical indexing completes, just before the app becomes healthy.

ponder.schema.ts
import { onchainTable, index } from "@ponder/core";
 
export const persons = onchainTable(
  "persons",
  (t) => ({
    id: t.text().primaryKey(),
    name: t.text(),
  }),
  (table) => ({
    nameIdx: index().on(table.name),
  })
);

onchainEnum

The onchainEnum function accepts two positional arguments. It returns a function that can be used as a column type.

ArgumentTypeDescription
namestringThe SQL enum name. Use snake_case.
valuesstring[]An array of strings representing the allowed values for the enum.
ponder.schema.ts
import { onchainEnum, onchainTable } from "@ponder/core";
 
export const color = onchainEnum("color", ["ORANGE", "BLACK"]);
 
export const cats = onchainTable("cats", (t) => ({
  name: t.text().primaryKey(),
  color: color().notNull(),
}));

Like any other column types, you can use modifiers like .notNull(), .default(), and .array() with enum columns.

ponder.schema.ts
// ...
 
export const dogs = onchainTable("cats", (t) => ({
  name: t.text().primaryKey(),
  color: color().array().default([]),
}));

relations

Use the relations function to define relationships between tables.

ponder.schema.ts
import { onchainTable, relations } from "@ponder/core";
 
export const users = onchainTable("users", (t) => ({
  id: t.text().primaryKey(),
}));
 
export const usersRelations = relations(users, ({ one }) => ({
  profile: one(profiles, {
    fields: [users.id],
    references: [profiles.userId],
  }),
}));

Relationship types

TypeMethodDescription
One-to-oneone()References single related record
One-to-manymany()References array of related records
Many-to-manyCombinationUses join table with two one-to-many relations

Read more in the relationships guide and the Drizzle relations documentation.