Docs
Better auth

2. Drizzle

Cài đặt drizzle

Cài đặt drizzle

pnpm add drizzle-orm

Cài đặt kit

pnpm add -D drizzle-kit

Cài đặt neon DB driver

pnpm add @neondatabase/serverless

cài đặt môi trường

pnpm add dotenv

Cài đặt Neon

  1. Đăng ký tài khoản neon
  2. Lấy URL và cập nhật .env
postgres://username:password@ep-cool-darkness-123456.us-east-2.aws.neon.tech/neondb
  • Bổ sung vào file .env
DATABASE_URL=NEON_DATABASE_CONNECTION_STRING
  1. Tạo file src/db/drizzle.ts
src/db/drizzle.ts
import { config } from "dotenv";
import { drizzle } from 'drizzle-orm/neon-http';

config({ path: ".env" }); // or .env.local

export const db = drizzle(process.env.DATABASE_URL!);
  1. Tạo schema
src/db/schema.ts
import { integer, text, boolean, pgTable } from "drizzle-orm/pg-core";

export const todo = pgTable("todo", {
  id: integer("id").primaryKey(),
  text: text("text").notNull(),
  done: boolean("done").default(false).notNull(),
});
  1. Tạo file cấu hình

nằm ngang hàng file .env

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

config({ path: '.env' });

export default defineConfig({
  schema: "./src/db/schema.ts",
  out: "./migrations",
  dialect: "postgresql",
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
});
  1. Chạy khởi tạo
terminal
npx @better-auth/cli generate

chọn yes để khởi tạo schema

√ Do you want to generate the schema to ./auth-schema.ts? ... yes 2025-08-10T10:02:15.493Z SUCCESS [Better Auth]: 🚀 Schema was generated successfully!

  1. Thay thế nội dung file schema

Cập nhật lại file db/schema và xoá file đã tạo ở trên

db/schema.ts
import {
  pgTable,
  text,
  timestamp,
  boolean,
  integer,
} from "drizzle-orm/pg-core";

export const user = pgTable("user", {
  id: text("id").primaryKey(),
  name: text("name").notNull(),
  email: text("email").notNull().unique(),
  emailVerified: boolean("email_verified")
    .$defaultFn(() => false)
    .notNull(),
  image: text("image"),
  createdAt: timestamp("created_at")
    .$defaultFn(() => /* @__PURE__ */ new Date())
    .notNull(),
  updatedAt: timestamp("updated_at")
    .$defaultFn(() => /* @__PURE__ */ new Date())
    .notNull(),
});

export const session = pgTable("session", {
  id: text("id").primaryKey(),
  expiresAt: timestamp("expires_at").notNull(),
  token: text("token").notNull().unique(),
  createdAt: timestamp("created_at").notNull(),
  updatedAt: timestamp("updated_at").notNull(),
  ipAddress: text("ip_address"),
  userAgent: text("user_agent"),
  userId: text("user_id")
    .notNull()
    .references(() => user.id, { onDelete: "cascade" }),
});

export const account = pgTable("account", {
  id: text("id").primaryKey(),
  accountId: text("account_id").notNull(),
  providerId: text("provider_id").notNull(),
  userId: text("user_id")
    .notNull()
    .references(() => user.id, { onDelete: "cascade" }),
  accessToken: text("access_token"),
  refreshToken: text("refresh_token"),
  idToken: text("id_token"),
  accessTokenExpiresAt: timestamp("access_token_expires_at"),
  refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),
  scope: text("scope"),
  password: text("password"),
  createdAt: timestamp("created_at").notNull(),
  updatedAt: timestamp("updated_at").notNull(),
});

export const verification = pgTable("verification", {
  id: text("id").primaryKey(),
  identifier: text("identifier").notNull(),
  value: text("value").notNull(),
  expiresAt: timestamp("expires_at").notNull(),
  createdAt: timestamp("created_at").$defaultFn(
    () => /* @__PURE__ */ new Date(),
  ),
  updatedAt: timestamp("updated_at").$defaultFn(
    () => /* @__PURE__ */ new Date(),
  ),
});
  1. Tạo bảng table trên neon
terminal
npx drizzle-kit push

Vào neon và kiểm tra xem 4 bảng mới tạo ra