# Introduction

> Minimal, type-safe repository helpers for Drizzle ORM - keep the type-safety, drop the repetitive query glue.

URL: https://better-drizzle.com/docs

**better-drizzle** wraps an existing Drizzle client and gives every table a small, consistent API for reads, writes, pagination, nested filters, relation loading, and optional hooks.

It is not a new ORM, and it does not try to hide Drizzle. You still define your schema, choose your driver, and reach for raw SQL whenever you want. better-drizzle just removes the query glue you would otherwise rewrite in every service.

> **Drizzle ORM 1.x only:** better-drizzle supports **only Drizzle ORM 1.x** (`drizzle-orm`
> `>=1.0.0-rc.4 <1.0.0-rc.5`; later release candidates are not supported yet) with its `defineRelations(...)`
> relations API. `drizzle-orm` 0.x is **not supported** by the current
> release - projects on 0.x must stay on better-drizzle `0.2.x`. See
> [upgrading](/docs/guides/upgrading-0-3).

```ts
import { better } from 'better-drizzle';
import { Database } from 'bun:sqlite';
import { drizzle } from 'drizzle-orm/bun-sqlite';
import { relations } from './relations'; // defineRelations(schema, ...)

const db = drizzle({ client: new Database('app.db'), relations });
const client = better(db);

await client.users.upsertMany({
	data: [
		{ email: 'alice@example.com', name: 'Alice', active: true },
		{ email: 'bob@example.com', name: 'Bob', active: false },
	],
	target: ['email'],
	update: ['name', 'active'],
});

const posts = await client.posts.findMany({
	where: {
		published: true,
		author: { is: { active: true } },
	},
	select: {
		id: true,
		title: true,
		author: { select: { id: true, name: true } },
	},
	orderBy: [{ id: 'desc' }],
	take: 20,
});
```

> **Type-safety, all the way down:** Every delegate is generated from your Drizzle tables and relations. Filters, projections,
> relation includes, and return payloads are all inferred - `posts` above is
> typed as the post row plus its `author`, no casts required.

## Why it exists

Drizzle is excellent when you want explicit, SQL-first control. It gets repetitive when every service re-writes the same patterns:

* point lookups by id or unique field
* relation includes and projections
* pagination payloads with `count` / `hasNext` / `hasPrevious`
* existence checks and counts
* consistent CRUD return shapes
* nested `where` filters across relations

better-drizzle packages those patterns into a repository-style API - without replacing Drizzle itself.

## What you get

- [A delegate per table](/docs/getting-started): `client.users`, `client.posts`, … each with `findMany`, `findFirst`,
`create`, `update`, `delete`, `paginate`, `cursor`, `count`, `exists`, `upsert`,
and `upsertMany`.

- [Typed nested filters](/docs/querying/relations): Filter by related rows with `some` / `every` / `none` / `is`, fully typed
against your relations.

- [One pagination shape](/docs/querying/pagination): Offset pages and cursor pages each return `{ data, pagination }`, with
metadata tailored to the strategy.

- [First-class plugins](/docs/plugins/overview): Timestamps, soft delete, and your own - with transforms, hooks, and typed
operation args.

- [Hooks & transactions](/docs/advanced/transactions): Lifecycle hooks for cross-cutting concerns; transactions with nested
savepoints, retries, and `afterCommit`.

- [Close to the metal](/docs/performance/benchmarks): Fast paths for common reads and writes, and a batched relation loader
that beats the equivalent raw Drizzle code by \~9× at parity. Everything
else stays within \~10%.

## How the layers fit

1. You define tables and `defineRelations(...)` with **Drizzle**.
2. You create a normal **Drizzle client** with your driver of choice and pass it `relations`.
3. You wrap it once with &#x2A;*`better(db)`**.
4. You call typed delegates from your services - and drop down to raw SQL whenever it reads better.

## Next steps

- [Get started](/docs/getting-started): Install, define a schema, and run your first queries.

- [Why better-drizzle?](/docs/why): What you gain over raw Drizzle, and the few cases where raw Drizzle still wins.

- [Changelog](/changelog): Everything that changed in 0.3.0 since 0.2.0.
