Drizzle with Vercel Edge Functions

This tutorial demonstrates how to use Drizzle ORM with Vercel Functions in Edge runtime.

This guide assumes familiarity with:
  • You should have the latest version of Vercel CLI installed.
npm
yarn
pnpm
bun
npm i -g vercel
  • You should have an existing Next.js project or create a new one using the following command:
npx create-next-app@latest --typescript
  • You should have installed Drizzle ORM and Drizzle kit. You can do this by running the following command:
npm
yarn
pnpm
bun
npm i drizzle-orm
npm i -D drizzle-kit

Edge-compatible driver

When using Drizzle ORM with Vercel Edge functions you have to use edge-compatible drivers because the functions run in Edge runtime not in Node.js runtime, so there are some limitations of standard Node.js APIs.

You can choose on of these drivers according to your database dialect:

  • Neon serverless driver allows you access any PostgreSQL client and query data from serverless and edge environments over HTTP or WebSockets in place of TCP. We recommend using this driver for non-Vercel Postgres client because Vercel Postgres driver implements specific connection string checks that may not be compatible with other PostgreSQL clients.
  • Vercel Postgres driver is built on top of the Neon serverless driver and allows you access any PostgreSQL client. We recommend using this driver for Vercel Postgres client.
  • PlanetScale serverless driver allows you access any MySQL client and execute queries over an HTTP connection, which is generally not blocked by cloud providers.
  • libSQL client allows you to access Turso database.

Any PostgreSQL client

In this tutorial we use Supabase PostgreSQL to demonstrate that any PostgreSQL client can be used with the Neon serverless driver and Vercel Edge functions.

Setup Drizzle config file

Drizzle config - a configuration file that is used by Drizzle Kit and contains all the information about your database connection, migration folder and schema files.

Create a drizzle.config.ts file in the root of your project and add the following content:

drizzle.config.ts
import { Config } from "drizzle-kit";

export default defineConfig({
  schema: "./app/db/schema.ts",
  dialect: "postgresql",
  dbCredentials: {
    url: process.env.POSTGRES_URL!,
  },
});

Configure your database connection string in the .env file:

.env
POSTGRES_URL="postgres://[user].xyejfgcvritnursacipt:[password]@aws-0-[region].pooler.supabase.com:6543/[db-name]"

Create a table

Create a schema.ts file in the app/db directory and declare a table schema:

app/db/schema.ts
import { pgTable, serial, text } from "drizzle-orm/pg-core";

export const usersTable = pgTable('users_table', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  age: text('age').notNull(),
  email: text('email').notNull().unique(),
})

Push your changes to the database

Run the drizzle-kit push command to push your changes to the database:

npx drizzle-kit push

Learn more about push command here. Alternatively, apply your changes through the migration process.

Connect Drizzle ORM to your database

Install the @neondatabase/serverless driver:

npm
yarn
pnpm
bun
npm i @neondatabase/serverless

Create a db.ts file in the app/db directory and set up your database configuration:

app/db/db.ts
import { Pool } from '@neondatabase/serverless';
import { drizzle } from 'drizzle-orm/neon-serverless';

const pool = new Pool({ connectionString: process.env.POSTGRES_URL! });

export const db = drizzle(pool)

Create an API route

Create /api/hello/route.ts in app directory. To learn more about how to write a function, see the Functions API Reference and Vercel Functions Quickstart.

app/api/hello/route.ts
import { db } from "@/app/db/db";
import { usersTable } from "@/app/db/schema";
import { NextResponse } from "next/server";

export const dynamic = 'force-dynamic'; // static by default, unless reading the request
export const runtime = 'edge' // specify the runtime to be edge

export async function GET(request: Request) {
  const users = await db.select().from(usersTable)

  return NextResponse.json({ users, message: 'success' });
}

Test your code locally

Run the next dev command to start your local development server:

npx next dev

Navigate to the route you created (e.g. /api/hello) in your browser:

{
  "users": [],
  "message": "success"
}

Deploy your project

Create a new project in the dashboard or run the vercel command to deploy your project:

vercel

Add POSTGRES_URL environment variable:

vercel env add POSTGRES_URL

Redeploy your project to update your environment variables:

vercel

Finally, you can use URL of the deployed project and navigate to the route you created (e.g. /api/hello) to access your edge function.

Vercel Postgres client

You can check quickstart guide for Drizzle with Vercel Postgres client in the documentation.

Setup Drizzle config file

Drizzle config - a configuration file that is used by Drizzle Kit and contains all the information about your database connection, migration folder and schema files.

Create a drizzle.config.ts file in the root of your project and add the following content:

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

export default defineConfig({
  schema: "./app/db/schema.ts",
  dialect: "postgresql",
  dbCredentials: {
    url: process.env.POSTGRES_URL!,
  },
});

Configure your database connection string in the .env file:

.env
POSTGRES_URL="postgres://[user]:[password]@[host]-[region].aws.neon.tech:5432/[db-name]?sslmode=[ssl-mode]"

Create a table

Create a schema.ts file in the app/db directory and declare a table schema:

app/db/schema.ts
import { pgTable, serial, text } from "drizzle-orm/pg-core";

export const usersTable = pgTable('users_table', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  age: text('age').notNull(),
  email: text('email').notNull().unique(),
})

Push your changes to the database

Run the drizzle-kit push command to push your changes to the database:

npx drizzle-kit push

Learn more about push command here. Alternatively, apply your changes through the migration process.

Connect Drizzle ORM to your database

Install the @vercel/postgres driver:

npm
yarn
pnpm
bun
npm i @vercel/postgres

Create a db.ts file in the app/db directory and set up your database configuration:

app/db/db.ts
import { sql } from '@vercel/postgres';
import { drizzle } from 'drizzle-orm/vercel-postgres';

export const db = drizzle(sql)

Create an API route

Create /api/hello/route.ts in app directory. To learn more about how to write a function, see the Functions API Reference and Vercel Functions Quickstart.

app/api/hello/route.ts
import { db } from "@/app/db/db";
import { usersTable } from "@/app/db/schema";
import { NextResponse } from "next/server";

export const dynamic = 'force-dynamic'; // static by default, unless reading the request
export const runtime = 'edge' // specify the runtime to be edge

export async function GET(request: Request) {
  const users = await db.select().from(usersTable)

  return NextResponse.json({ users, message: 'success' });
}

Test your code locally

Run the next dev command to start your local development server:

npx next dev

Navigate to the route you created (e.g. /api/hello) in your browser:

{
  "users": [],
  "message": "success"
}

Deploy your project

Create a new project in the dashboard or run the vercel command to deploy your project:

vercel

Add POSTGRES_URL environment variable:

vercel env add POSTGRES_URL

Redeploy your project to update your environment variables:

vercel

Finally, you can use URL of the deployed project and navigate to the route you created (e.g. /api/hello) to access your edge function.

Any MySQL client

In this tutorial we use PlanetScale MySQL.

Setup Drizzle config file

Drizzle config - a configuration file that is used by Drizzle Kit and contains all the information about your database connection, migration folder and schema files.

Create a drizzle.config.ts file in the root of your project and add the following content:

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

export default defineConfig({
  schema: "./app/db/schema.ts",
  dialect: "mysql",
  dbCredentials: {
    url: process.env.MYSQL_URL!,
  },
});

Configure your database connection string in the .env file:

.env
MYSQL_URL="mysql://[user]:[password]@[host].[region].psdb.cloud/[db-name]?ssl={'rejectUnauthorized':[ssl-rejectUnauthorized]}"

Create a table

Create a schema.ts file in the app/db directory and declare a table schema:

app/db/schema.ts
import { mysqlTable, serial, text } from "drizzle-orm/mysql-core";

export const usersTable = mysqlTable('users_table', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  age: text('age').notNull(),
  email: text('email').notNull().unique(),
})

Push your changes to the database

Run the drizzle-kit push command to push your changes to the database:

npx drizzle-kit push

Learn more about push command here. Alternatively, apply your changes through the migration process.

Connect Drizzle ORM to your database

Install the @planetscale/database driver:

npm
yarn
pnpm
bun
npm i @planetscale/database

Create a db.ts file in the app/db directory and set up your database configuration:

app/db/db.ts
import { drizzle } from "drizzle-orm/planetscale-serverless";
import { Client } from "@planetscale/database";

const client = new Client({
  url: process.env.MYSQL_URL!,
})

export const db = drizzle(client)

Create an API route

Create /api/hello/route.ts in app directory. To learn more about how to write a function, see the Functions API Reference and Vercel Functions Quickstart.

app/api/hello/route.ts
import { db } from "@/app/db/db";
import { usersTable } from "@/app/db/schema";
import { NextResponse } from "next/server";

export const dynamic = 'force-dynamic'; // static by default, unless reading the request
export const runtime = 'edge' // specify the runtime to be edge

export async function GET(request: Request) {
  const users = await db.select().from(usersTable)

  return NextResponse.json({ users, message: 'success' });
}

Test your code locally

Run the next dev command to start your local development server:

npx next dev

Navigate to the route you created (e.g. /api/hello) in your browser:

{
  "users": [],
  "message": "success"
}

Deploy your project

Create a new project in the dashboard or run the vercel command to deploy your project:

vercel

Add MYSQL_URL environment variable:

vercel env add MYSQL_URL

Redeploy your project to update your environment variables:

vercel

Finally, you can use URL of the deployed project and navigate to the route you created (e.g. /api/hello) to access your edge function.

Turso

You can check quickstart guide or tutorial for Drizzle with Turso in the documentation.

Setup Drizzle config file

Drizzle config - a configuration file that is used by Drizzle Kit and contains all the information about your database connection, migration folder and schema files.

Create a drizzle.config.ts file in the root of your project and add the following content:

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

export default defineConfig({
  schema: "./app/db/schema.ts",
  dialect: "sqlite",
  driver: "turso",
  dbCredentials: {
    url: process.env.TURSO_CONNECTION_URL!,
    authToken: process.env.TURSO_AUTH_TOKEN!,
  },
});

Configure your database connection string in the .env file:

.env
TURSO_CONNECTION_URL="libsql://[db-name].turso.io"
TURSO_AUTH_TOKEN="[auth-token]"

Create a table

Create a schema.ts file in the app/db directory and declare a table schema:

app/db/schema.ts
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";

export const usersTable = sqliteTable('users_table', {
  id: integer('id').primaryKey(),
  name: text('name').notNull(),
  age: text('age').notNull(),
  email: text('email').notNull().unique(),
})

Push your changes to the database

Install the @libsql/client driver:

npm
yarn
pnpm
bun
npm i @libsql/client

Run the drizzle-kit push command to push your changes to the database:

npx drizzle-kit push

Learn more about push command here. Alternatively, apply your changes through the migration process.

Connect Drizzle ORM to your database

Create a db.ts file in the app/db directory and set up your database configuration:

app/db/db.ts
import { drizzle } from 'drizzle-orm/libsql';
import { createClient } from '@libsql/client';

const client = createClient({
  url: process.env.TURSO_CONNECTION_URL!,
  authToken: process.env.TURSO_AUTH_TOKEN!,
});

export const db = drizzle(client)

Create an API route

Create /api/hello/route.ts in app directory. To learn more about how to write a function, see the Functions API Reference and Vercel Functions Quickstart.

app/api/hello/route.ts
import { db } from "@/app/db/db";
import { usersTable } from "@/app/db/schema";
import { NextResponse } from "next/server";

export const dynamic = 'force-dynamic'; // static by default, unless reading the request
export const runtime = 'edge' // specify the runtime to be edge

export async function GET(request: Request) {
  const users = await db.select().from(usersTable)

  return NextResponse.json({ users, message: 'success' });
}

Test your code locally

Run the next dev command to start your local development server:

npx next dev

Navigate to the route you created (e.g. /api/hello) in your browser:

{
  "users": [],
  "message": "success"
}

Deploy your project

Create a new project in the dashboard or run the vercel command to deploy your project:

vercel

Add TURSO_CONNECTION_URL and TURSO_AUTH_TOKEN environment variables:

vercel env add TURSO_CONNECTION_URL
vercel env add TURSO_AUTH_TOKEN

Redeploy your project to update your environment variables:

vercel

Finally, you can use URL of the deployed project and navigate to the route you created (e.g. /api/hello) to access your edge function.