Skip to main content
@effect/sql is a SQL toolkit for Effect that provides type-safe database access, schema validation, and integrations for PostgreSQL, MySQL, SQLite, MSSQL, and more.

Installation

npm install @effect/sql

Database Drivers

Install the appropriate driver for your database:

PostgreSQL

npm install @effect/sql-pg

MySQL

npm install @effect/sql-mysql2

SQLite

npm install @effect/sql-sqlite-node

MSSQL

npm install @effect/sql-mssql

ClickHouse

npm install @effect/sql-clickhouse

LibSQL

npm install @effect/sql-libsql

Quick Start

import { Effect, pipe } from "effect"
import { PgClient } from "@effect/sql-pg"
import { SqlClient } from "@effect/sql"

const SqlLive = PgClient.layer({
  database: "effect_pg_dev"
})

const program = Effect.gen(function* () {
  const sql = yield* SqlClient.SqlClient

  const people = yield* sql<{
    readonly id: number
    readonly name: string
  }>`SELECT id, name FROM people`

  yield* Effect.log(`Got ${people.length} results!`)
})

pipe(program, Effect.provide(SqlLive), Effect.runPromise)

Query Building

Safe Interpolation

Parameters are automatically escaped:
const limit = 10
const statement = sql`SELECT * FROM people LIMIT ${limit}`
// SELECT * FROM people LIMIT ?

Identifiers

Quote table and column names safely:
const table = "people"
const statement = sql`SELECT * FROM ${sql(table)} LIMIT 10`
// SELECT * FROM "people" LIMIT 10

Where Clauses

Combine conditions with AND and OR:
const names = ["Alice", "Bob", "Charlie"]
const cursor = new Date()

// AND
const query = sql`SELECT * FROM people WHERE ${sql.and([
  sql.in("name", names),
  sql`created_at < ${cursor}`
])}`

// OR
const query = sql`SELECT * FROM people WHERE ${sql.or([
  sql.in("name", names),
  sql`created_at < ${cursor}`
])}`

Schema Integration

Use Effect schemas for type-safe queries:
import { Effect, Schema } from "effect"
import { SqlClient, SqlSchema } from "@effect/sql"

class Person extends Schema.Class<Person>("Person")({
  id: Schema.Number,
  name: Schema.String,
  createdAt: Schema.DateFromSelf,
  updatedAt: Schema.DateFromSelf
}) {}

const program = Effect.gen(function* () {
  const sql = yield* SqlClient.SqlClient

  const people = yield* sql`SELECT * FROM people`.pipe(
    SqlSchema.findAll(Person)
  )

  return people
})

Resolvers

Build efficient data loaders with automatic batching:
import { Effect, Schema } from "effect"
import { SqlResolver, SqlClient } from "@effect/sql"

class Person extends Schema.Class<Person>("Person")({
  id: Schema.Number,
  name: Schema.String
}) {}

const makePersonService = Effect.gen(function* () {
  const sql = yield* SqlClient.SqlClient

  const GetById = yield* SqlResolver.findById("GetPersonById", {
    Id: Schema.Number,
    Result: Person,
    ResultId: (_) => _.id,
    execute: (ids) => sql`SELECT * FROM people WHERE ${sql.in("id", ids)}`
  })

  const getById = (id: number) =>
    Effect.withRequestCaching("on")(GetById.execute(id))

  return { getById }
})

Migrations

Manage schema migrations with TypeScript:
// src/migrations/0001_add_users.ts
import { Effect } from "effect"
import { SqlClient } from "@effect/sql"

export default Effect.flatMap(
  SqlClient.SqlClient,
  (sql) => sql`
    CREATE TABLE users (
      id serial PRIMARY KEY,
      name varchar(255) NOT NULL,
      created_at TIMESTAMP NOT NULL DEFAULT NOW()
    )
  `
)
Run migrations:
import { Effect, Layer } from "effect"
import { NodeContext, NodeRuntime } from "@effect/platform-node"
import { PgClient, PgMigrator } from "@effect/sql-pg"
import { fileURLToPath } from "node:url"

const SqlLive = PgClient.layer({
  database: "example_database"
})

const MigratorLive = PgMigrator.layer({
  loader: PgMigrator.fromFileSystem(
    fileURLToPath(new URL("migrations", import.meta.url))
  ),
  schemaDirectory: "src/migrations"
}).pipe(Layer.provide(SqlLive))

const program = Effect.gen(function* () {
  // Your application code
})

const EnvLive = Layer.mergeAll(SqlLive, MigratorLive).pipe(
  Layer.provide(NodeContext.layer)
)

pipe(program, Effect.provide(EnvLive), NodeRuntime.runMain)

ORM Integrations

Drizzle

npm install @effect/sql-drizzle

Kysely

npm install @effect/sql-kysely

Database Support

DatabasePackageDescription
PostgreSQL@effect/sql-pgFull-featured PostgreSQL client
MySQL@effect/sql-mysql2MySQL client using mysql2 driver
SQLite (Node)@effect/sql-sqlite-nodeSQLite for Node.js
SQLite (Bun)@effect/sql-sqlite-bunSQLite for Bun runtime
SQLite (Wasm)@effect/sql-sqlite-wasmSQLite in WebAssembly
MSSQL@effect/sql-mssqlMicrosoft SQL Server
ClickHouse@effect/sql-clickhouseClickHouse analytics database
LibSQL@effect/sql-libsqlTurso/LibSQL client
Cloudflare D1@effect/sql-d1Cloudflare D1 database

API Reference

Complete API documentation

@effect/platform

Platform abstractions

Build docs developers (and LLMs) love