---
title: "Entity Relations"
description: "Entity Relations form the core of the relational query engine in Drizzle ORM. They act as the abstraction layer that maps TypeScript schema definitions to database-level operations, enabling comple..."
last_updated: "2026-07-02T09:35:19.071885+00:00"
canonical_url: "https://www.doc0.app/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/database-schema/entity-relations"
---

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [drizzle-orm/src/pg-core/dialect.ts](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/pg-core/dialect.ts)
- [drizzle-orm/src/gel-core/dialect.ts](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/gel-core/dialect.ts)
- [drizzle-kit/src/introspect-pg.ts](https://github.com/blade47/drizzle-kit/blob/main/drizzle-kit/src/introspect-pg.ts)
- [drizzle-orm/src/mysql-core/dialect.ts](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/mysql-core/dialect.ts)
</details>

Entity Relations form the core of the relational query engine in Drizzle ORM. They act as the abstraction layer that maps TypeScript schema definitions to database-level operations, enabling complex graph-like queries across multiple tables while maintaining type safety. By decoupling the query definition from the underlying SQL dialect, the subsystem allows developers to express deeply nested relationships without manually writing verbose `JOIN` or aggregate logic.

The architecture solves the "N+1" problem by translating high-level relational configuration—such as `One` and `Many` definitions—into optimized, dialect-specific SQL. It uses an internal configuration model to understand table structures, primary keys, and foreign key constraints, which it then uses to dynamically generate subqueries, lateral joins, or aggregate functions as required by the backend dialect (Postgres, MySQL, or Gel).

The design prioritizes flexibility and performance by performing a multi-pass transformation during query building. It handles complex cases like cyclic references and lateral subqueries by normalizing relations before dispatching them to the query builder. This design enables seamless interaction with the query builders, where relations are resolved into SQL execution plans at runtime.

## Core Relational Configuration

The subsystem relies on a relational config structure to understand how entities connect. This structure, typically extracted via `extractTablesRelationalConfig`, maps database table objects into a graph of `One` and `Many` relations. This metadata allows the dialect to determine, for example, if a `Many` relation necessitates a `JSON_AGG` or similar aggregation to satisfy a nested result set.

Sources: [drizzle-kit/src/introspect-pg.ts:210-210](https://github.com/blade47/drizzle-orm/blob/main/drizzle-kit/src/introspect-pg.ts#L210-L210), [drizzle-orm/src/relations.ts](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/relations.ts)

## Normalization Mechanism

Normalization is the process of flattening and standardizing relation definitions. The `normalizeRelation` utility function transforms raw metadata into a predictable format (with `fields` and `references` arrays), ensuring the query builder doesn't need to handle dialect-specific implementation details of a relationship during the building phase. This provides a uniform contract for joining tables regardless of their origin.

Sources: [drizzle-orm/src/pg-core/dialect.ts:1223-1223](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/pg-core/dialect.ts#L1223-L1223), [drizzle-orm/src/gel-core/dialect.ts:1292-1292](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/gel-core/dialect.ts#L1292-L1292)

## Building Relational Queries

The core engine responsible for turning relational config into SQL resides in methods like `buildRelationalQueryWithoutPK` or `buildRelationalQuery`. These functions act as a recursive traversal engine. When a developer executes a relational query, the builder walks the relationship graph, dynamically constructing aliases and `LEFT JOIN` operations.

- The process begins by selecting columns and optional "extras" defined in the query configuration.
- It then iterates over requested relations, calculating join conditions based on normalized foreign key metadata.
- If a `Many` relation is encountered, the builder may inject subqueries or lateral joins to maintain row integrity while aggregating related records.

Sources: [drizzle-orm/src/pg-core/dialect.ts:1150-1444](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/pg-core/dialect.ts#L1150-L1444), [drizzle-orm/src/mysql-core/dialect.ts:658-1336](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/mysql-core/dialect.ts#L658-L1336)

## Query Builder Selection Strategy

When the builder decides how to fetch related data, it evaluates the nature of the relation. `Many` relations (which imply 1:N or M:N) are typically treated with subquery aggregation, whereas `One` relations may be joined directly. A key architectural guard exists here: the code explicitly distinguishes between queries with primary keys and those without, selecting different strategies to ensure the database can resolve rows uniquely.

> [!TIP]
> When building relational queries, `isLateralJoin` logic determines if a subquery needs to be correlated with the outer query. This is a critical performance path for handling complex joins.

Sources: [drizzle-orm/src/pg-core/dialect.ts:858-859](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/pg-core/dialect.ts#L858-L859), [drizzle-orm/src/mysql-core/dialect.ts:1208-1212](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/mysql-core/dialect.ts#L1208-L1212)

## Dialect-Specific Aggregation

The dialect-specific implementation files provide the final SQL generation logic. Because PostgreSQL, MySQL, and Gel handle JSON aggregation differently (e.g., `json_agg` vs `json_arrayagg`), the dialect methods `buildRelationalQueryWithoutPK` or `buildRelationalQuery` encapsulate these differences. This isolates the relational engine from the database driver, allowing the same high-level query syntax to function across different database backends.

Sources: [drizzle-orm/src/pg-core/dialect.ts:1369-1371](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/pg-core/dialect.ts#L1369-L1371), [drizzle-orm/src/mysql-core/dialect.ts:1249-1250](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/mysql-core/dialect.ts#L1249-L1250)

## Introspection and Schema Generation

The subsystem also provides utilities for reconstructing these relationships from existing databases. The `introspect-pg` module scans schema definitions, foreign key constraints, and table names to output TypeScript code that defines the `relations()` configuration. This bridges the gap between raw database structure and the relational engine’s requirements.

Sources: [drizzle-kit/src/introspect-pg.ts:210-272](https://github.com/blade47/drizzle-orm/blob/main/drizzle-kit/src/introspect-pg.ts#L210-L272)

## Key Design Trade-offs

| Design Choice | Benefit | Cost |
| :--- | :--- | :--- |
| **Recursive Subqueries** | Deeply nested relations support | Potential SQL performance degradation on massive tables |
| **Normalization** | Clean code paths for query generation | Overhead during query building initialization |
| **Dialect Isolation** | Backend portability | Increased boilerplate in individual dialect files |

Sources: [drizzle-orm/src/pg-core/dialect.ts:1150-1444](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/pg-core/dialect.ts#L1150-L1444), [drizzle-orm/src/mysql-core/dialect.ts:658-1336](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/mysql-core/dialect.ts#L658-L1336)

## Related

- [Schema Declarations](https://www.doc0.app/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/database-schema/schema-declarations)
- [Select Queries](https://www.doc0.app/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/query-engine/select-queries)


## Sitemap

See the full [sitemap](https://www.doc0.app/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/llms.txt) for all pages in this wiki.
