📖 目录

  1. 🏗️ 全局架构逻辑图 (新增)
  2. 前置准备:依赖安装
  3. 核心配置:drizzle.config.ts (必填项检查)
  4. 环境与安全:.env 与 .gitignore
  5. TypeScript 增强:tsconfig.json 路径别名
  6. 定义模型:db/schema.ts (类型生成的源头)
  7. ✨ 核心实战:类型推导与数据插入 (含流程图)
  8. 完整工作流验证
  9. 常见问题与避坑指南

1. 🏗️ 全局架构 (新增)

在写代码之前,我们先看一张图,理解 Drizzle ORM 是如何连接 代码配置数据库 的。

💡 图解关键点:

  1. 左侧 (定义层)schema.ts 是唯一的真理来源(Single Source of Truth)。它不仅定义表,还通过 $inferInsert 自动生成NewUser 类型。
  2. 中间 (配置层)drizzle.config.ts 负责桥接,它读取 .env 找到数据库,并告诉工具去哪里找 schema.ts
  3. 右侧 (执行层):CLI 工具根据配置生成 SQL 并更新数据库;而你的业务代码则利用生成的 NewUser 类型,确保传给数据库的数据是安全的。

2. 前置准备:依赖安装

确保安装了运行时库、开发工具库以及类型定义。

# 1. 核心运行时库
npm install drizzle-orm postgres

# 2. 开发工具库 (生成迁移用)
npm install -D drizzle-kit dotenv

# 3. TypeScript 类型定义
npm install -D @types/node

3. 核心配置:drizzle.config.ts (必填项检查)

此文件位于项目根目录。必须包含 dotenv 加载和环境变量校验。

import { defineConfig } from "drizzle-kit";
import * as dotenv from "dotenv";

// 【必填】加载 .env
dotenv.config({ path: ".env" });

if (!process.env.DATABASE_URL) {
  throw new Error("❌ 错误: .env 中缺少 DATABASE_URL");
}

export default defineConfig({
  dialect: "postgresql",
  dbCredentials: {
    url: process.env.DATABASE_URL!, // 非空断言
  },
  schema: "./db/schema.ts", // ⚠️ 必须对应实际路径
  out: "./drizzle",         // 迁移文件输出目录
  verbose: true,
  strict: true,
});

4. 环境与安全:.env 与 .gitignore

.env 文件

DATABASE_URL="postgresql://postgres:你的密码@localhost:5432/my_nextjs_db?schema=public"

.gitignore 文件

确保包含:

.env
.node_modules
.next

5. TypeScript 增强:tsconfig.json 路径别名

为了让导入更优雅(如 @/db/schema),配置 paths

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./*"],
      "@/db": ["./db"],
      "@/db/*": ["./db/*"]
    }
  }
}

6. 定义模型:db/schema.ts (类型生成的源头)

这是所有 TypeScript 类型的来源

文件路径: db/schema.ts

import { pgTable, text, serial, timestamp } from "drizzle-orm/pg-core";

export const users = pgTable("users", {
  id: serial("id").primaryKey(),       // 自增主键
  name: text("name").notNull(),        // 必填
  email: text("email").unique(),       // 唯一
  createdAt: timestamp("created_at").defaultNow(), // 默认当前时间
});

// 💡 显式导出类型
// 1. 查询返回的类型 (全量字段)
export type User = typeof users.$inferSelect;

// 2. 插入数据的类型 (自动排除自增和默认值字段)
export type NewUser = typeof users.$inferInsert;

7. ✨ 核心实战:类型推导与数据插入 (含流程图)

这一步展示了 NewUser 类型如何在代码中发挥作用。

🔄 类型推导微观流程

PostgreSQL 你的业务代码 (API) TypeScript 编译器 db/schema.ts PostgreSQL 你的业务代码 (API) TypeScript 编译器 db/schema.ts 推断结果: id? (可选) name (必填) email? (可选) createdAt? (可选) 定义 id (serial), name (notNull), createdAt (default) 运行 $inferInsert 推断逻辑 const user: NewUser = { ... } ✅ 检查通过 (若只传 name, email) ❌ 报错 (若漏传 name 或 多传 id) db.insert(users).values(user) 成功写入 (id 和 createdAt 由数据库生成)

💻 代码实战

创建一个测试文件(例如 test-insert.ts):

import { type NewUser } from "@/db/schema"; 

// ✅ 正确示范:只需关注业务必填字段
const newUser: NewUser = {
  name: "Alice",
  email: "alice@example.com",
  // TS 智能提示:id 和 createdAt 不需要传,因为它们有默认值/自增
};

// ❌ 错误示范 1:漏传必填字段 (TS 会红线报错)
// const badUser1: NewUser = { email: "bob@example.com" }; 
// 报错信息: Property 'name' is missing...

// ❌ 错误示范 2:传了不该传的字段 (TS 会红线报错)
// const badUser2: NewUser = { ..., id: 123 }; 
// 报错信息: Object literal may only specify known properties, and 'id' does not exist...

console.log("✅ 类型检查通过!数据准备就绪:", newUser);

// --- 实际插入逻辑 ---
// import { db } from "@/db"; 
// import { users } from "@/db/schema";
// await db.insert(users).values(newUser);

💡 为什么这很重要?

  • 编译期拦截:在代码运行前,TypeScript 就已经帮你挡掉了 90% 的数据库字段错误。
  • 智能提示:输入 newUser. 时,IDE 只会显示 nameemail,界面清爽,不再被 idupdatedAt 等系统字段干扰。
  • 重构友好:如果数据库改了(比如 email 变为必填),所有使用该类型的地方都会立即报错提示你修改。

8. 完整工作流验证

结合图表逻辑,跑通全流程:

  1. 生成迁移 (读取 Config & Schema -> 生成 SQL):
    npx drizzle-kit generate
    
  2. 执行迁移 (执行 SQL -> 更新 DB):
    npx drizzle-kit migrate
    
    失效时可以用
$env:PGPASSWORD='密码'; & "C:\Program Files\PostgreSQL\17\bin\psql.exe" -h localhost -p 5432 -U postgres -d my_first_nextjs_db -f "./db/migrations/第一步生成的sql文件"
  1. 类型检查 (验证代码是否符合 Schema 类型):
    npx tsc --noEmit
    
    ✅ 无报错 = 类型安全通关
  2. 运行测试:
    npx tsx test-insert.ts
    

9. 常见问题与避坑指南

问题 原因 解决方案
Cannot find module '@/db/schema' TS 路径未生效 检查 tsconfig.json,重启 VS Code TS 服务。
Property 'id' is missing 误用了 $inferSelect 插入用 $inferInsert (NewUser),查询用 $inferSelect (User)。
process.env.DATABASE_URL is undefined config 文件没加载 env 确保 drizzle.config.ts 顶部有 dotenv.config()
TS 提示 id 不是可选的 Schema 定义问题 检查 id 是否加了 .primaryKey(),Drizzle 依赖此标记来推断可选性。

10. 核心概念解析

在开始动手之前,我们需要明确今天涉及的四个关键角色及其关系:

组件 角色比喻 作用
PostgreSQL Server 仓库管理员 真正存储数据的地方。它是一个后台服务,负责接收指令、保存数据、保证数据安全。
pgAdmin 4 仓库可视化大屏 图形化管理工具。让你不用敲黑底白字的命令,通过点击鼠标就能查看表结构、浏览数据、执行 SQL。
Drizzle ORM 翻译官/中介 位于你的 Next.js 代码和数据库之间。你写的是 TypeScript/JavaScript 代码,Drizzle 把它“翻译”成数据库能听懂的 SQL 语句。
.env 文件 门禁卡/钥匙 存储敏感信息(如数据库密码、连接地址)。绝对不能上传到 GitHub,是连接代码与数据库的唯一凭证。

11. 环境准备与安装流程 (Windows 版

2. 环境准备与安装流程 (Windows 版)

2.1 下载官方安装包

我们采用“一站式”安装策略,一个安装包同时解决数据库和管理工具。

  • 下载地址PostgreSQL Windows Installer
  • 选择版本:推荐下载最新的稳定版(如 PostgreSQL 17 或 16),架构选择 Windows x86-64

2.2 安装向导关键步骤详解

双击 .exe 文件后,请严格遵循以下设置:

  1. 安装目录:保持默认 (C:\Program Files\PostgreSQL\xx)。
  2. 组件选择 (Select Components) ⚠️ 关键点
    • PostgreSQL Server (必选)
    • pgAdmin 4 (必选,用于可视化操作)
    • Command Line Tools (必选,用于命令行调试)
    • Stack Builder (安装完成后弹出的额外窗口,直接关闭或选 No,无需安装)
  3. 设置超级用户密码 (Superuser Password) 🔑 最重要
    • 用户名默认为 postgres
    • 密码:设置一个你记得住的密码(开发环境可用 123456,生产环境必须复杂)。
    • 注意:这个密码将用于 .env 配置和 pgAdmin 登录。
  4. 端口 (Port):保持默认 5432
  5. 区域 (Locale):保持默认 Default locale

🎉 总结

通过这张架构逻辑图类型推导流程,我们清晰地看到了:

  1. 单一事实来源schema.ts 定义了结构,也定义了类型。
  2. 自动化魔法$inferInsert 自动过滤掉系统字段,让你只关心业务数据。
  3. 全链路安全:从配置文件的路径检查,到 TypeScript 的编译时校验,再到数据库的最终写入,每一层都有保护。

现在,你不仅拥有了一个可运行的环境,更掌握了一套类型驱动开发 (Type-Driven Development) 的最佳实践。去构建你的应用吧!🚀

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐