Skip to Content
IntegrationDrizzle ORM

Drizzle ORM

Drizzle ORM  is a TypeScript ORM with type-safe schema definitions. gqlkit integrates seamlessly with Drizzle by using InferSelectModel and InferInsertModel to derive GraphQL types from your table definitions.

Installation

npm install drizzle-orm postgres
pnpm add drizzle-orm postgres
yarn add drizzle-orm postgres

Defining Tables

Define your database tables with Drizzle:

// src/db/schema.ts import { pgEnum, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core"; export const userStatusEnum = pgEnum("user_status", [ "active", "inactive", "suspended", ]); export const users = pgTable("users", { id: uuid().primaryKey().defaultRandom(), name: text().notNull(), email: text().notNull().unique(), status: userStatusEnum().notNull().default("active"), createdAt: timestamp().notNull().defaultNow(), }); export const posts = pgTable("posts", { id: uuid().primaryKey().defaultRandom(), title: text().notNull(), content: text(), priority: text({ enum: ["low", "medium", "high"] }).notNull().default("medium"), authorId: uuid() .notNull() .references(() => users.id), createdAt: timestamp().notNull().defaultNow(), });

Both pgEnum() and text({ enum: [...] }) are supported for defining enum columns. gqlkit automatically generates corresponding GraphQL enum types from these definitions.

Defining Custom Scalars

Define custom scalar types using GqlScalar for fields like timestamps:

// src/gqlkit/schema/scalars.ts import type { GqlScalar } from "@gqlkit-ts/runtime"; export type DateTime = GqlScalar<"DateTime", Date>;

Exporting GraphQL Types

Use Drizzle’s type inference utilities to export GraphQL types from your table definitions:

// src/gqlkit/schema/user.ts import type { InferSelectModel } from "drizzle-orm"; import { users as usersTable } from "../../db/schema.js"; // Export as GraphQL object type export type User = InferSelectModel<typeof usersTable>;

This generates the following GraphQL schema:

enum UserStatus { ACTIVE INACTIVE SUSPENDED } type User { id: String! name: String! email: String! status: UserStatus! createdAt: DateTime! }

Defining Resolvers

Define resolvers that use the derived types:

// src/gqlkit/schema/user.ts import type { NoArgs } from "@gqlkit-ts/runtime"; import type { InferInsertModel, InferSelectModel } from "drizzle-orm"; import { eq } from "drizzle-orm"; import { posts as postsTable, users as usersTable } from "../../db/schema.js"; import { defineField, defineMutation, defineQuery } from "../gqlkit.js"; import type { Post } from "./post.js"; export type User = InferSelectModel<typeof usersTable>; export const allUsers = defineQuery<NoArgs, User[]>( async (_root, _args, ctx) => { return ctx.db.select().from(usersTable); }, ); export const user = defineQuery<{ id: string }, User | null>( async (_root, args, ctx) => { const result = await ctx.db .select() .from(usersTable) .where(eq(usersTable.id, args.id)); return result[0] ?? null; }, ); export const createUser = defineMutation< { input: Omit<InferInsertModel<typeof usersTable>, "id" | "createdAt"> }, User >(async (_root, args, ctx) => { const result = await ctx.db.insert(usersTable).values(args.input).returning(); return result[0]!; }); export const posts = defineField<User, NoArgs, Post[]>( async (parent, _args, ctx) => { return ctx.db .select() .from(postsTable) .where(eq(postsTable.authorId, parent.id)); }, );

Context with Database

Set up the context type to include your database instance. For basic setup, see Set Up Context and Resolver Factories.

// src/db/db.ts import { drizzle } from "drizzle-orm/postgres-js"; import postgres from "postgres"; import * as schema from "./schema.js"; const client = postgres(process.env.DATABASE_URL!); export const db = drizzle(client, { schema, casing: "snake_case" }); export type Database = typeof db;
// src/gqlkit/context.ts import type { Database } from "../db/db.js"; export type Context = { db: Database; };

Complete Example

See the examples/with-drizzle  directory for a complete working example with:

  • PostgreSQL tables with DateTime scalar
  • Enum types using both pgEnum() and text({ enum: [...] })
  • User and Post types with relationships
  • Query, Mutation, and Field resolvers

Further Reading

Last updated on