TypebaseTypebase
Database

Relations

Define how your tables connect to each other and work with generated types.

Last updated on

Relations tell Typebase how your tables connect to each other so you can query across them. For example, instead of manually looking up a user's posts by their authorId, you can ask for a user and get their posts included automatically.

Every table exported from schema.ts must be registered in typebase/db/relations.ts, even if it has no relations to other tables. Typebase uses this file to enable the relational query API (e.g. db.query.users.findFirst()).

Defining relations

Here's what the default relations file looks like with the todos table generated by npx typebase-io-cli init:

typebase/db/relations.ts
import { q } from 'typebase-io/db';

import * as schema from './schema.ts';

export const relations = q.defineRelations(schema, (r) => ({
  todos: {},
}));

Adding relations

When you add more tables, register each one in the relations callback. If two tables are related, define the relationship using r.one() and r.many(). In the example below, a user can have many todos (r.many.todos()), and each todo belongs to one user (r.one.users()):

typebase/db/relations.ts
import { q } from 'typebase-io/db';

import * as schema from './schema.ts';

export const relations = q.defineRelations(schema, (r) => ({
  todos: {
    user: r.one.users({
      from: r.todos.userId,
      to: r.users.id,
    }),
  },
  users: {
    todos: r.many.todos(),
  },
}));

Even if a table is standalone with no relations to other tables, it still needs an empty entry:

typebase/db/relations.ts
export const relations = q.defineRelations(schema, (r) => ({
  todos: {
    user: r.one.users({
      from: r.todos.userId,
      to: r.users.id,
    }),
  },
  users: {
    todos: r.many.todos(),
  },
  // No relations, but still needs to be registered
  logs: {},
}));

For more details on Drizzle relations, see the Drizzle relations documentation.

On this page