Search
ctrl+/
Ask AI
ctrl+.
Light
Dark
System
Sign in
Environment:

Drizzle ORM in Next.js

Gel integrates seamlessly with Drizzle ORM, providing a type-safe and intuitive way to interact with your database in TypeScript applications.

To integrate Drizzle with your Gel project, you'll need to install the necessary dependencies:

Copy
$ 
npm install drizzle-orm
Copy
$ 
npm install -D drizzle-kit

Next, create a Drizzle configuration file in your project root to tell Drizzle how to work with your Gel database:

drizzle.config.ts
Copy
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
  dialect: 'gel',
});

Before using Drizzle with your Gel database, you'll need to let Drizzle introspect your schema. This step generates TypeScript files that Drizzle can use to interact with your database.

Copy
$ 
npx drizzle-kit pull

This command will create a schema file based on your Gel database. The file will typically look something like this:

drizzle/schema.ts
Copy
import { gelTable, uniqueIndex, uuid, smallint, text, timestamp, relations } from "drizzle-orm/gel-core"
import { sql } from "drizzle-orm"

export const books = gelTable("Book", {
  id: uuid().default(sql`uuid_generate_v4()`).primaryKey().notNull(),
  title: text().notNull(),
  author: text(),
  year: smallint(),
  genre: text(),
  read_date: timestamp(),
}, (table) => [
  uniqueIndex("books_pkey").using("btree", table.id.asc().nullsLast().op("uuid_ops")),
]);

export const notes = gelTable("Note", {
  id: uuid().default(sql`uuid_generate_v4()`).primaryKey().notNull(),
  text: text().notNull(),
  created_at: timestamp().default(sql`datetime_current()`),
  book_id: uuid().notNull(),
}, (table) => [
  uniqueIndex("notes_pkey").using("btree", table.id.asc().nullsLast().op("uuid_ops")),
]);
Show more

To keep your Drizzle schema in sync with your Gel schema, add a hook to your gel.toml file. This hook will automatically run drizzle-kit pull after each migration:

gel.toml
Copy
[hooks]
after_migration_apply = [
  "npx drizzle-kit pull"
]

With this hook in place, your Drizzle schema will automatically update whenever you apply Gel migrations.

Now, let's create a database client that you can use throughout your application:

src/db/index.ts
Copy
import { drizzle } from 'drizzle-orm/gel';
import { createClient } from 'gel-js';
import * as schema from '@/drizzle/schema';
import * as relations from '@/drizzle/relations';

// Import our schema
import * as schema from './schema';

// Initialize Gel client
const gelClient = createClient();

// Create Drizzle instance
export const db = drizzle({
  client: gelClient,
  schema: {
    ...schema,
    ...relations
  },
});

// Helper types for use in our application
export type Book = typeof schema.book.$inferSelect;
export type NewBook = typeof schema.book.$inferInsert;

export type Note = typeof schema.note.$inferSelect;
export type NewNote = typeof schema.note.$inferInsert;

For more detailed information on querying and other operations, refer to the Drizzle documentation. Below are some examples of common database operations you can perform with Drizzle.

Drizzle provides a clean, type-safe API for database operations. Here are some examples of common operations:

Selecting data:

Copy
// Get all books with their notes
const allBooks = await db.query.book.findMany({
  with: {
    notes: true,
  },
});

// Get a specific book
const book = await db.query.book.findFirst({
  where: eq(books.id, id),
  with: { notes: true },
});

Inserting data:

Copy
// Insert a new book
const newBook = await db.insert(book).values({
  title: 'The Great Gatsby',
  author: 'F. Scott Fitzgerald',
  year: 1925,
  genre: 'Novel',
}).returning();

// Insert a note for a book
const newNote = await db.insert(note).values({
  text: 'A classic novel about the American Dream',
  book_id: newBook.bookId,
}).returning();

Bulk inserting data:

Copy
// Insert multiple books at once
const newBooks = await db.insert(book).values([
  {
    title: '1984',
    author: 'George Orwell',
    year: 1949,
    genre: 'Dystopian',
  },
  {
    title: 'To Kill a Mockingbird',
    author: 'Harper Lee',
    year: 1960,
    genre: 'Fiction',
  },
  {
    title: 'Pride and Prejudice',
    author: 'Jane Austen',
    year: 1813,
    genre: 'Romance',
  },
]).returning();

Updating data:

Copy
// Update a book
const updatedBook = await db.update(book)
  .set({
    title: 'Updated Title',
    author: 'Updated Author',
  })
  .where(eq(books.id, bookId))
  .returning();

Deleting data:

Copy
// Delete a note
await db.delete(notes).where(eq(notes.id, noteId));

In a Next.js application, you can use your Drizzle client in API routes and server components. Here's an example of an API route that gets all books:

src/app/api/books/route.ts
Copy
import { NextResponse } from 'next/server';
import { db } from '@/db';

export async function GET() {
  try {
    const allBooks = await db.query.book.findMany({
      with: { notes: true },
    });

    return NextResponse.json(allBooks);
  } catch (error) {
    console.error('Error fetching books:', error);
    return NextResponse.json(
      { error: 'Failed to fetch books' },
      { status: 500 }
    );
  }
}

And here's an example of using Drizzle in a server component:

src/app/books/page.tsx
Copy
import { db } from '@/db';
import BookCard from '@/components/BookCard';

export default async function BooksPage() {
  const books = await db.query.book.findMany({
    with: { notes: true },
  });

  return (
    <div>
      {books.map((book) => (
        <BookCard key={book.id} book={book} />
      ))}
    </div>
  );
}

You are now ready to use Gel with Drizzle in your applications. This integration gives you the best of both worlds: Gel's powerful features and Drizzle's type-safe, intuitive API.

For a complete example of using Gel with Drizzle in a Next.js application, check out our Book Notes app example.

You can also find a detailed tutorial on building a Book Notes app with Gel, Drizzle, and Next.js in our documentation.