---
title: "Schema Declarations"
description: "Schema declarations in Drizzle define the structure of your database, acting as the single source of truth for the ORM. They bridge the gap between physical database tables and the TypeScript types..."
last_updated: "2026-07-02T09:35:19.075347+00:00"
canonical_url: "https://www.doc0.dev/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/database-schema/schema-declarations"
---

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

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

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

Schema declarations in Drizzle define the structure of your database, acting as the single source of truth for the ORM. They bridge the gap between physical database tables and the TypeScript types required for type-safe query building. By utilizing declarative constructs like `pgTable`, `mysqlTable`, and `sqliteTable`, developers specify column names, data types, constraints, and relationships that allow the library to introspect and communicate with the underlying database engine effectively.

This subsystem provides both a runtime representation (used by drivers to construct SQL) and a compile-time type inference engine. The declarations handle mapping database-specific types (e.g., `serial`, `uuid`, `jsonb`) to their TypeScript equivalents, managing default values, and defining complex constraints like primary keys, foreign keys, and indexes.

In the context of `drizzle-kit`, these declarations are further utilized by introspection tools to reverse-engineer existing database schemas into code. The system converts raw schema metadata into high-fidelity TypeScript code, ensuring that the generated output maintains naming conventions, relationship mappings, and structural constraints that the Drizzle core understands.

## Declarative Table Construction

At the core of schema declarations are the table definition functions, which accept a table name and an object mapping column names to their definitions. Each column definition function (e.g., `text()`, `integer()`) acts as a builder, allowing for method chaining to apply modifiers such as `.notNull()`, `.primaryKey()`, or `.default()`.

The construction process is designed for composability. By separating the column name, the database name, and the constraint modifiers, Drizzle ensures that runtime execution paths can accurately map internal definitions to SQL syntax while type-checkers verify that query results align with the schema.

```typescript
// Example of a table declaration using pgTable
import { pgTable, serial, text, integer } from 'drizzle-orm/pg-core';

export const users = pgTable('users_table', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  age: integer('age'),
});
```
Sources: [drizzle-orm/type-tests/pg/tables.ts:87-105](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/type-tests/pg/tables.ts#L87-L105)

## Introspection and Serialization Mechanisms

The `drizzle-kit` introspectors (e.g., `introspect-pg.ts`, `introspect-mysql.ts`) operate by traversing database-specific internal schemas and serializing them into executable TypeScript code. The mechanism begins by collecting tables, enums, sequences, and views, then iteratively generating import statements and table declarations.

The core flow for `schemaToTypeScript` involves:
1. Identifying mandatory imports (e.g., `pgTable`, `index`, `foreignKey`).
2. Generating enum and sequence statements.
3. Iterating through tables to generate column statements via `createTableColumns`.
4. Appending constraint statements (indexes, primary keys, unique constraints, policies) using `createTableIndexes`, `createTablePKs`, etc.

```mermaid
flowchart TD
    A["schemaToTypeScript"] --> B["Collect FKs and metadata"]
    B --> C["Generate imports (list filtering)"]
    C --> D["Generate Enums/Sequences"]
    D --> E["Generate Tables (via createTableColumns)"]
    E --> F["Generate Constraints (via index/FK/PK helpers)"]
    F --> G["Final file string assembly"]
```
Sources: [drizzle-kit/src/introspect-pg.ts:309-636](https://github.com/blade47/drizzle-orm/blob/main/drizzle-kit/src/introspect-pg.ts#L309-L636)

## Column Mapping and Default Value Resolution

Mapping database types to Drizzle columns involves resolving type-specific metadata and defaults. The `mapDefault` function handles the resolution of default values by checking the type and the internal configuration of the column.

> [!NOTE]
> When `internals.tables[tableName].columns[name].isDefaultAnExpression` is `true`, the system treats the default as an SQL expression, wrapping it in `sql\` \`` to ensure it is not treated as a string literal.

The mechanism includes guard logic to prevent incorrect type-casting:
- `isArray` check: If a column is an array, `buildArrayDefault` is called.
- Enum checks: Verifies if the type exists in the enum set before applying a standard default mapping.
- Type-specific handlers: Specialized branches exist for `uuid` (using `.defaultRandom()`), `timestamp` (using `.defaultNow()`), and others.

Sources: [drizzle-kit/src/introspect-pg.ts:673-836](https://github.com/blade47/drizzle-orm/blob/main/drizzle-kit/src/introspect-pg.ts#L673-L836)

## Foreign Key and Relationship Handling

Foreign keys are registered by iterating through a table's `foreignKeys` collection. The introspector tracks existing relationships to detect cyclic dependencies, which helps in correctly ordering or annotating references.

The mechanism for creating foreign key references ensures that if a table references itself, the generator correctly uses `table` as the reference target instead of the generated variable name.

> [!WARNING]
> The current introspector implementation has specific limitations regarding naming; custom references in `.references()` are sometimes switched off in the generator to avoid potential naming collisions or complexity with generated identifiers.

Sources: [drizzle-kit/src/introspect-pg.ts:1343-1369](https://github.com/blade47/drizzle-orm/blob/main/drizzle-kit/src/introspect-pg.ts#L1343-L1369)

## Index and Constraint Generation

Indexes, primary keys, and unique constraints are defined as a factory function parameter after the column mapping. This is critical for supporting composite constraints that span multiple columns. The `createTableIndexes` function takes a list of indexes and processes their metadata to produce valid index statements.

The selection logic for index naming is determined by `indexName`: if an index name matches the default format (e.g., `tablename_column1_column2_index`), it remains implicit, otherwise, it is explicitly escaped as a string.

Sources: [drizzle-kit/src/introspect-pg.ts:1201-1257](https://github.com/blade47/drizzle-orm/blob/main/drizzle-kit/src/introspect-pg.ts#L1201-L1257)

## Design Choices and Trade-offs

| Design Choice | Benefit | Cost |
| :--- | :--- | :--- |
| Declarative Column Builder | Allows for clean, readable schema definitions | Increased complexity in the type-generation layer |
| Lazy Relation Resolution | Enables circular references between tables | Requires a two-pass approach or helper functions |
| Casing Normalization | Consistent naming throughout the application | Potential for conflicts with database-reserved words |

Sources: [drizzle-kit/src/introspect-pg.ts:168-177](https://github.com/blade47/drizzle-orm/blob/main/drizzle-kit/src/introspect-pg.ts#L168-L177)

## Call-Chain Execution: Introspecting a Table

The process of generating a table's TypeScript representation follows a specific hierarchy:

1. `schemaToTypeScript` invokes `Object.values(schema.tables).map(...)`.
2. Inside the map, `createTableColumns` is called for the column definitions.
3. `column()` is triggered for every column iteration, returning the column statement string.
4. If constraints are present, `createTableIndexes` or `createTableFKs` are called to append the constraint array factory function.
5. `statement += ');'` finalizes the table definition.

This sequential ordering ensures that the output file structure is consistent, grouping definitions, constraints, and final initialization code.

Sources: [drizzle-kit/src/introspect-pg.ts:508-565](https://github.com/blade47/drizzle-orm/blob/main/drizzle-kit/src/introspect-pg.ts#L508-L565)

## Related

- [Column Types](https://www.doc0.dev/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/database-schema/column-types)
- [Indexes and Constraints](https://www.doc0.dev/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/database-schema/indexes-and-constraints)


## Sitemap

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