---
title: "effect-orm"
description: "Type-safe ClickHouse, Postgres, SQLite and MySQL queries, result decoding, and reproducible benchmarks for Effect and TypeScript."
---

> Documentation Index
> Fetch the complete documentation index at: https://effect-orm.maple.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# effect-orm

`@maple-dev/effect-orm` builds SQL from typed TypeScript. Describe a table once, and the query builder infers column types, output row shapes and join accessors from it. A query compiles to a SQL string plus a decoder for its own rows. You bring the database client.

> **Alpha**
>
> The API is still changing and minor releases may break it. Pin an exact version and read the [changelog](https://github.com/MapleTechLabs/effect-orm/blob/main/CHANGELOG.md) before upgrading.

## Install

```sh
npm i @maple-dev/effect-orm effect@^4.0.6
yarn add @maple-dev/effect-orm effect@^4.0.6
pnpm add @maple-dev/effect-orm effect@^4.0.6
bun add @maple-dev/effect-orm effect@^4.0.6
```

`effect` is a peer dependency. Effect 3 and the Effect 4 prereleases are not supported.

## A first query

Each database has one import that holds the whole query builder plus that database's column types, functions, table definitions and `compile`:

```ts
import * as CH from "@maple-dev/effect-orm/clickhouse"

const Events = CH.table("events", {
	columns: {
		OrgId: CH.string,
		Name: CH.string,
		Timestamp: CH.dateTime,
		DurationMs: CH.uint64,
	},
	engine: CH.engine.mergeTree(),
	orderBy: ["OrgId", "Timestamp"],
})

const query = CH.from(Events)
	.select(($) => ({
		name: $.Name,
		p95: CH.quantile(0.95)($.DurationMs),
		count: CH.count(),
	}))
	.where(($) => [$.OrgId.eq(CH.param.string("orgId"))])
	.groupBy("name")
	.orderBy(["count", "desc"])
	.limit(50)

const compiled = CH.compileUnsafe(query, { orgId: "org_123" })
compiled.sql // SELECT events.Name AS name, quantile(0.95)(events.DurationMs) AS p95, ...
```

## Why effect-orm

- **Schema-first** — A column type is an Effect `Schema`, so a query compiles to its own row schema. Wire quirks, such as 64-bit integers arriving quoted, are modelled once in the types.
- **Type-safe** — Column types, output row shapes and join accessors are inferred from the table. No stringly-typed columns.
- **Immutable and composable** — Every builder method returns a new query, so you can share and extend base queries.
- **Four databases** — ClickHouse, Postgres, SQLite and Cloudflare D1, MySQL and MariaDB. Each has its own column types, functions and DDL.

## Pick your database

Every database has its own section with the same guides, written with its own examples. The tabs at the top switch between them and keep you on the page you are reading.

- **ClickHouse** — Analytics queries, engines and `SETTINGS`, mutations, and Tinybird.
- **Postgres** — Postgres column types and functions, `RETURNING`, transactions and migrations.
- **SQLite** — SQLite and Cloudflare D1: codecs, functions, table DDL and drivers.
- **MySQL** — MySQL and MariaDB: codecs, functions, collations and `@effect/sql-mysql2`.

[Benchmarks](https://effect-orm.maple.dev/benchmarks/benchmarking/) and the [export reference](https://effect-orm.maple.dev/reference/reference/) are shared by every database.

Source: https://effect-orm.maple.dev/index.mdx
