PageSourceSearch

https://kysely.dev/assets/js/3873a5a7.cb4b2e31.js

js kysely.dev collected 2026-10-02 02:58:29 UTC 6,955 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkkysely_site=globalThis.webpackChunkkysely_site||[]).push([[6598],{1190(e,n,i){i.r(n),i.d(n,{assets:()=>o,contentTitle:()=>c,default:()=>u,frontMatter:()=>l,metadata:()=>s,toc:()=>a});const s=JSON.parse('{"id":"recipes/splitting-query-building-and-execution","title":"Splitting query building and execution","description":"Compile Kysely queries without a database connection using DummyDriver, infer result types, and execute compiled queries separately.","source":"@site/docs/recipes/0004-splitting-query-building-and-execution.md","sourceDirName":"recipes","slug":"/recipes/splitting-query-building-and-execution","permalink":"/docs/recipes/splitting-query-building-and-execution","draft":false,"unlisted":false,"editUrl":"https://github.com/kysely-org/kysely/tree/master/site/docs/recipes/0004-splitting-query-building-and-execution.md","tags":[],"version":"current","sidebarPosition":4,"frontMatter":{"description":"Compile Kysely queries without a database connection using DummyDriver, infer result types, and execute compiled queries separately."},"sidebar":"tutorialSidebar","previous":{"title":"Raw SQL","permalink":"/docs/recipes/raw-sql"},"next":{"title":"Conditional selects","permalink":"/docs/recipes/conditional-selects"}}');var r=i(1058),t=i(4801);const l={description:"Compile Kysely queries without a database connection using DummyDriver, infer result types, and execute compiled queries separately."},c="Splitting query building and execution",o={},a=[{value:"&quot;Cold&quot; Kysely instances",id:"cold-kysely-instances",level:2},{value:"Compile a query",id:"compile-a-query",level:2},{value:"Infer result type",id:"infer-result-type",level:2},{value:"Execute compiled queries",id:"execute-compiled-queries",level:2}];function d(e){const n={blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",pre:"pre",...(0,t.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"splitting-query-building-and-execution",children:"Splitting query building and execution"})}),"\n",(0,r.jsx)(n.p,{children:"Kysely is primarily a type-safe sql query builder."}),"\n",(0,r.jsx)(n.p,{children:'It also does query execution, migrations, etc. in order to align with Knex\'s "batteries\nincluded" approach.'}),"\n",(0,r.jsx)(n.h2,{id:"cold-kysely-instances",children:'"Cold" Kysely instances'}),"\n",(0,r.jsxs)(n.p,{children:["In order to use Kysely purely as a query builder without database driver dependencies,\nyou can instantiate it with the built-in ",(0,r.jsx)(n.code,{children:"DummyDriver"})," class:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",children:"import {\n  Generated,\n  DummyDriver,\n  Kysely,\n  PostgresAdapter,\n  PostgresIntrospector,\n  PostgresQueryCompiler,\n} from 'kysely'\n\ninterface Person {\n  id: Generated<number>\n  first_name: string\n  last_name: string | null\n}\n\ninterface Database {\n  person: Person\n}\n\nconst db = new Kysely<Database>({\n  dialect: {\n    createAdapter: () => new PostgresAdapter(),\n    createDriver: () => new DummyDriver(),\n    createIntrospector: (db) => new PostgresIntrospector(db),\n    createQueryCompiler: () => new PostgresQueryCompiler(),\n  },\n})\n"})}),"\n",(0,r.jsx)(n.p,{children:'This Kysely instance will compile to PostgreSQL sql dialect. You can brew "dummy"\ndialects to compile to all kinds of sql dialects (e.g. MySQL). Trying to execute\nqueries using "cold" kysely instances will return empty results without communicating\nwith a database.'}),"\n",(0,r.jsxs)(n.blockquote,{children:["\n",(0,r.jsx)(n.p,{children:'"Cold" Kysely instances are not required for the following sections. You can\nuse "hot" kysely instances, with real drivers, if you want to.'}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"compile-a-query",children:"Compile a query"}),"\n",(0,r.jsxs)(n.p,{children:["To compile a query, simply call ",(0,r.jsx)(n.code,{children:".compile()"})," at the end of the query building chain:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",children:"const compiledQuery = db\n  .selectFrom('person')\n  .select('first_name')\n  .where('id', '=', id)\n  .compile()\n\nconsole.log(compiledQuery) // { sql: 'select \"first_name\" from \"person\" where \"id\" = $1', parameters: [1], query: { ... } }\n"})}),"\n",(0,r.jsxs)(n.p,{children:["The result of ",(0,r.jsx)(n.code,{children:".compile()"})," is a ",(0,r.jsx)(n.code,{children:"CompiledQuery"})," object. It contains the query string\n(in ",(0,r.jsx)(n.code,{children:"sql"})," field), parameters and the original Kysely-specific syntax tree used\nfor compilation."]}),"\n",(0,r.jsx)(n.p,{children:"This output alone can be used with any database driver that understands the sql\ndialect used (PostgreSQL in this example)."}),"\n",(0,r.jsx)(n.p,{children:"Raw queries can be compiled as well:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",children:"import { Selectable, sql } from 'kysely'\n\nconst compiledQuery = sql<Selectable<Person>>`select * from person where id = ${id}`.compile(db)\n\nconsole.log(compiledQuery) // { sql: 'select * from person where id = $1', parameters: [1], query: { ... } }\n"})}),"\n",(0,r.jsx)(n.h2,{id:"infer-result-type",children:"Infer result type"}),"\n",(0,r.jsx)(n.p,{children:"Kysely supports inferring a (compiled) query's result type even when detached from\nquery building chains. This allows splitting query building, compilation and execution\ncode without losing type-safety."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",children:"import { InferResult } from 'kysely'\n\nconst query = db\n  .selectFrom('person')\n  .select('first_name')\n  .where('id', '=', id)\n\ntype QueryReturnType = InferResult<typeof query> // { first_name: string }[]\n\nconst compiledQuery = query.compile()\n\ntype CompiledQueryReturnType = InferResult<typeof compiledQuery> // { first_name: string }[]\n"})}),"\n",(0,r.jsx)(n.h2,{id:"execute-compiled-queries",children:"Execute compiled queries"}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"CompiledQuery"})," object returned by ",(0,r.jsx)(n.code,{children:".compile()"}),' can be executed\nvia "hot" Kysely instances (real drivers in use):']}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",children:"const compiledQuery = db\n  .selectFrom('person')\n  .select('first_name')\n  .where('id', '=', id)\n  .compile()\n\nconst results = await db.executeQuery(compiledQuery)\n"})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"QueryResult"})," object returned by ",(0,r.jsx)(n.code,{children:".executeQuery()"})," contains the query results'\nrows, insertId and number of affected rows (if applicable)."]})]})}function u(e={}){const{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.