tl-kysely-patterns
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinese<!-- Copyright (c) 2026 Todd Levy. Licensed under MIT. SPDX-License-Identifier: MIT -->
<!-- Copyright (c) 2026 Todd Levy. Licensed under MIT. SPDX-License-Identifier: MIT -->
Kysely: Type-Safe SQL Patterns
Kysely:类型安全的SQL模式
Kysely (pronounced "Key-Seh-Lee") is a type-safe TypeScript SQL query builder. It generates plain SQL with zero runtime ORM overhead. Every query is validated at compile time with full autocompletion.
Kysely is not an ORM -- no relations, no lazy loading, no magic. Just SQL with types.
Kysely(发音为"Key-Seh-Lee")是一个类型安全的TypeScript SQL查询构建器。它生成纯SQL,无任何ORM运行时开销。每个查询都会在编译时进行验证,并支持完整的自动补全。
Kysely 不是ORM——没有关联关系、没有懒加载、没有魔法特性。它只是带类型校验的SQL工具。
When to Use
使用场景
- "write a Kysely query"
- "create database migration"
- "add a new table"
- "query with joins / subqueries / CTEs"
- "JSONB or array column operations"
- Working with an existing Kysely + PostgreSQL codebase
- Debugging Kysely type inference issues
- "编写Kysely查询"
- "创建数据库迁移"
- "添加新表"
- "使用连接/子查询/CTE进行查询"
- "JSONB或数组列操作"
- 处理现有的Kysely + PostgreSQL代码库
- 调试Kysely类型推断问题
Outcomes
预期成果
- Artifact: Type-safe queries using ExpressionBuilder patterns
- Artifact: Migration files via kysely-ctl
- Decision: When to use query builder vs template tag
sql
- 产出物:使用ExpressionBuilder模式的类型安全查询
- 产出物:通过kysely-ctl生成的迁移文件
- 决策:何时使用查询构建器 vs 模板标签
sql
Core Philosophy
核心理念
Prefer Kysely's query builder for everything it can express. Fall back to template tag only when the builder lacks support.
sql| Use Case | Approach |
|---|---|
| Schema definitions | Kysely migrations ( |
| Simple CRUD | Query builder ( |
| JOINs (any complexity) | Query builder (callback format for complex joins) |
| Aggregations / GROUP BY | Query builder with |
| CTEs | Query builder ( |
| Relations / nested JSON | |
| Conditional queries | |
| Reusable fragments | |
| Dynamic columns/tables | |
| Dynamic SQL fragments | |
| Dialect-specific syntax | |
| Unsupported operators | |
Need a query?
Can Kysely's builder express it?
YES -> Use the query builder (type-safe, composable)
NO -> Use sql`` template tag (always type your output: sql<Type>`...`)优先使用Kysely查询构建器实现所有可表达的逻辑。仅当构建器不支持时,才回退到模板标签。
sql| 使用场景 | 实现方式 |
|---|---|
| Schema定义 | Kysely迁移( |
| 简单CRUD | 查询构建器( |
| JOIN(任意复杂度) | 查询构建器(复杂连接使用回调格式) |
| 聚合 / GROUP BY | 带 |
| CTE | 查询构建器( |
| 关联关系 / 嵌套JSON | |
| 条件查询 | |
| 可复用片段 | |
| 动态列/表 | |
| 动态SQL片段 | |
| 方言特定语法 | |
| 不支持的运算符 | |
需要编写查询?
Kysely构建器能否实现?
是 -> 使用查询构建器(类型安全、可组合)
否 -> 使用sql``模板标签(务必为输出指定类型:sql<Type>`...`)ExpressionBuilder (eb) Cheat Sheet
ExpressionBuilder (eb) 速查表
The callback parameter is the foundation of type-safe query building:
eb| Method | Purpose | Example |
|---|---|---|
| Column reference | |
| Parameterized value ($1) | |
| SQL literal (numbers, bools, null only) | |
| Typed function call | |
| COUNT aggregate | |
| Other aggregates | |
| COALESCE | |
| CASE expression | see query-patterns.md |
| Combine conditions | |
| EXISTS check | |
| Negate expression | |
| SQL CAST | |
| Binary expression | |
For full query examples, see references/query-patterns.md.
eb| 方法 | 用途 | 示例 |
|---|---|---|
| 列引用 | |
| 参数化值($1) | |
| SQL字面量(仅支持数字、布尔值、null) | |
| 带类型的函数调用 | |
| COUNT聚合函数 | |
| 其他聚合函数 | |
| COALESCE函数 | |
| CASE表达式 | 查看 query-patterns.md |
| 组合条件 | |
| EXISTS检查 | |
| 表达式取反 | |
| SQL CAST转换 | |
| 二元表达式 | |
完整查询示例请查看 references/query-patterns.md。
Database Types
数据库类型
typescript
import { Generated, Insertable, Selectable, Updateable } from "kysely"
interface Database {
users: UsersTable
posts: PostsTable
}
interface UsersTable {
id: Generated<number>
email: string
name: string
created_at: Generated<Date>
}
// Helper types make Generated fields optional for inserts/updates
type NewUser = Insertable<UsersTable>
type UserUpdate = Updateable<UsersTable>
type User = Selectable<UsersTable>Use to generate these types from your database. See references/migrations.md.
kysely-codegentypescript
import { Generated, Insertable, Selectable, Updateable } from "kysely"
interface Database {
users: UsersTable
posts: PostsTable
}
interface UsersTable {
id: Generated<number>
email: string
name: string
created_at: Generated<Date>
}
// 辅助类型让Generated字段在插入/更新时可选
type NewUser = Insertable<UsersTable>
type UserUpdate = Updateable<UsersTable>
type User = Selectable<UsersTable>使用从数据库生成这些类型。查看 references/migrations.md。
kysely-codegenPitfalls
常见陷阱
These are the most common mistakes when writing Kysely code.
以下是编写Kysely代码时最容易犯的错误。
1. eb.val() vs eb.lit() confusion
1. eb.val() 与 eb.lit() 混淆
eb.val()eb.lit()sql\typescript
eb.val("safe input") // $1 -- parameterized, safe
eb.lit(42) // 42 -- literal in SQL
eb.lit("text") // THROWS "unsafe immediate value"
eb.cast(eb.val("text"), "text") // $1::text -- workaround for typed string paramseb.val()eb.lit()sql\typescript
eb.val("safe input") // $1 -- 参数化,安全
eb.lit(42) // 42 -- SQL中的字面量
eb.lit("text") // 抛出 "unsafe immediate value" 错误
eb.cast(eb.val("text"), "text") // $1::text -- 带类型字符串参数的解决方案2. Forgetting .execute()
2. 忘记调用.execute()
Queries are lazy builders. Without an execute method, nothing runs.
typescript
db.selectFrom("user").selectAll() // does nothing
await db.selectFrom("user").selectAll().execute() // runs the query查询是延迟构建的。如果不调用执行方法,不会执行任何操作。
typescript
db.selectFrom("user").selectAll() // 无任何操作
await db.selectFrom("user").selectAll().execute() // 执行查询3. .where() vs .whereRef() for column comparisons
3. 列比较时使用.where() 而非 .whereRef()
.where("a", "=", "b")a"b".whereRef()typescript
.where("table.col", "=", "other.col") // compares to string literal
.whereRef("table.col", "=", "other.col") // compares two columns.where("a", "=", "b")a"b".whereRef()typescript
.where("table.col", "=", "other.col") // 与字符串字面量比较
.whereRef("table.col", "=", "other.col") // 比较两个列4. Always type sql`` template literals
4. 务必为sql``模板字面量指定类型
sqlunknowntypescript
sql`now()` // Expression<unknown> -- bad
sql<Date>`now()` // Expression<Date> -- goodsqlunknowntypescript
sql`now()` // Expression<unknown> -- 不推荐
sql<Date>`now()` // Expression<Date> -- 推荐5. selectAll() breaks nested json helper type inference (#1059)
5. selectAll() 破坏嵌套json辅助函数的类型推断(#1059)
Bare inside json helper subqueries merges outer table columns into the type. Use table-qualified instead. See references/relations-helpers.md.
.selectAll().selectAll("table_name")在json辅助函数的子查询中直接使用会将外部表列合并到类型中。请改用带表限定的。查看 references/relations-helpers.md。
.selectAll().selectAll("table_name")6. DATE columns cause timezone drift
6. DATE列导致时区偏移
The driver converts DATE to JS , causing timezone issues. Parse DATE as string instead. See references/migrations.md.
pgDatepgDate7. "Type instantiation is excessively deep"
7. "Type instantiation is excessively deep"
Complex queries with many CTEs can exceed TypeScript's type depth. Use on intermediate CTEs. See references/relations-helpers.md.
$assertType<T>()包含多个CTE的复杂查询可能超出TypeScript的类型深度限制。在中间CTE上使用。查看 references/relations-helpers.md。
$assertType<T>()8. PostgreSQL does NOT auto-index foreign keys
8. PostgreSQL不会自动为外键创建索引
Always create indexes on FK columns manually in migrations. See references/migrations.md.
务必在迁移中手动为FK列创建索引。查看 references/migrations.md。
9. CamelCasePlugin causes drift with raw SQL
9. CamelCasePlugin 导致原生SQL命名偏移
CamelCasePluginsqlCamelCasePluginsql10. JSONB inserts need JSON.stringify only in sql templates (#209)
10. JSONB插入仅在sql模板中需要JSON.stringify(#209)
The driver auto-serializes objects for / JSONB params (pg types). You only need explicit inside template expressions or with non-pg drivers. See references/jsonb-arrays.md.
pg.values().set()JSON.stringifysqlpg.values().set()sqlJSON.stringifyEach query may use a different pooled connection. , session variables, and RLS context do not persist across queries. Use or to pin multiple statements to one connection. See references/advanced-patterns.md.
SETdb.transaction()db.connection()每个查询可能使用连接池中的不同连接。、会话变量和RLS上下文不会在查询间持久化。使用或将多个语句绑定到同一个连接。查看 references/advanced-patterns.md。
SETdb.transaction()db.connection().where('col', 'is not', null)null$narrowType.where('col', 'is not', null)null$narrowTypeMigrations added on parallel branches may fail strict ordering when merged. Set on the . See references/migrations.md.
allowUnorderedMigrations: trueMigrator并行分支上添加的迁移在合并时可能因严格排序失败。在上设置。查看 references/migrations.md。
MigratorallowUnorderedMigrations: trueDatejsonArrayFromjsonObjectFromjson_aggDatejsonArrayFromjsonObjectFromjson_aggDateDateOfficial Resources
官方资源
| Resource | URL |
|---|---|
| LLM-friendly docs (full) | |
| API documentation | |
| Playground | |
| GitHub | |
| Awesome Kysely (ecosystem) | |
When using Cursor , reference for the most complete context.
@Docshttps://kysely.dev/llms-full.txt| 资源 | 链接 |
|---|---|
| 适配LLM的完整文档 | |
| API文档 | |
| 在线 playground | |
| GitHub仓库 | |
| Awesome Kysely(生态) | |
使用Cursor 时,引用可获取最完整的上下文。
@Docshttps://kysely.dev/llms-full.txtReference Files
参考文件
Consult these for detailed code patterns:
| Reference | When to Use |
|---|---|
| query-patterns.md | SELECT, WHERE, JOINs, aggregations, ORDER BY, mutations, $if, subqueries, transactions |
| jsonb-arrays.md | JSONB columns, array columns, JSONPath, querying JSON/array data |
| relations-helpers.md | jsonArrayFrom, jsonObjectFrom, reusable Expression<T> helpers, CTEs, compile/InferResult |
| migrations.md | kysely-ctl setup, migration files, column types, type generation, plugins, Neon dialect, DATE fix |
| advanced-patterns.md | Dynamic columns, withSchema, connection pinning, RLS, $narrowType, streaming, MERGE, views, FTS, testing |
| ecosystem.md | Pagination, auth adapters, Fastify plugin, community dialects |
如需详细代码模式,请查阅以下文件:
| 参考文件 | 使用场景 |
|---|---|
| query-patterns.md | SELECT、WHERE、JOIN、聚合、ORDER BY、数据变更、$if、子查询、事务 |
| jsonb-arrays.md | JSONB列、数组列、JSONPath、JSON/数组数据查询 |
| relations-helpers.md | jsonArrayFrom、jsonObjectFrom、可复用Expression<T>辅助函数、CTE、compile/InferResult |
| migrations.md | kysely-ctl配置、迁移文件、列类型、类型生成、插件、Neon方言、DATE问题修复 |
| advanced-patterns.md | 动态列、withSchema、连接绑定、RLS、$narrowType、流式查询、MERGE、视图、FTS、测试 |
| ecosystem.md | 分页、认证适配器、Fastify插件、社区方言 |