---
title: "Views and Aggregates"
description: "Database views act as virtual tables; in a migration-based workflow, Drizzle Kit manages their definitions and structural configuration to ensure that changes to underlying SQL can be accurately de..."
last_updated: "2026-08-13T14:49:35.965624+00:00"
canonical_url: "https://www.doc0.app/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/query-engine/views-and-aggregates"
---

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

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

- [drizzle-kit/src/snapshotsDiffer.ts](https://github.com/blade47/drizzle-orm/blob/main/drizzle-kit/src/snapshotsDiffer.ts)
- [drizzle-kit/src/serializer/pgSerializer.ts](https://github.com/blade47/drizzle-orm/blob/main/drizzle-kit/src/serializer/pgSerializer.ts)
</details>

Database views act as virtual tables; in a migration-based workflow, Drizzle Kit manages their definitions and structural configuration to ensure that changes to underlying SQL can be accurately detected and rendered into actionable migration files. The system handles the view definition, schema, and specific configuration options—such as `MATERIALIZED` status or `WITH` parameters—to bridge the gap between a database's current state (introspected) and the developer's desired state.

The role of this component is to manage schema drift by capturing the view's definition string and metadata, performing a comparison against the existing snapshot, and generating the necessary `DROP`/`CREATE` or `ALTER` statements. The design relies on serialization logic that converts database-native view configuration into a JSON format suitable for diffing, followed by a reconciliation pass that resolves potential name or schema collisions during migration.

This subsystem integrates with the logic found in `drizzle-kit/src/snapshotsDiffer.ts`, which orchestrates the diffing pipeline. When views change, the differ uses resolver functions to identify if a view was renamed, moved between schemas, or fundamentally redefined. Because views often depend on underlying table structures, this component ensures that migration statements are ordered correctly—prioritizing view modifications after table structural changes are stabilized—to prevent invalid SQL execution.

## View Serialization Mechanism

The serialization of views is handled during introspection to generate the internal snapshot representation. The mechanism processes views and materialized views by invoking `getViewConfig` or `getMaterializedViewConfig` from `drizzle-orm/pg-core`. It transforms database-native configurations into a consistent structure that tracks the definition string, schema, and materialization options.

For each view, the serializer performs the following steps:
1.  **Identity Resolution:** Extracts the view name and schema to form a unique key for the `resultViews` collection.
2.  **Field Processing:** Iterates over the selected fields of the view to reconstruct the structure, mirroring the logic used for standard tables. This allows the system to track view structure similarly to base tables.
3.  **Metadata Capture:** Stores the SQL query definition, materialization status, and properties (e.g., `WITH`, `TABLESPACE`, `USING`) in the final schema snapshot.

Sources: [drizzle-kit/src/serializer/pgSerializer.ts:L706-L870](https://github.com/blade47/drizzle-orm/blob/main/drizzle-kit/src/serializer/pgSerializer.ts#L706-L870)

## Diffing Pipeline for Views

The diffing engine, specifically `applyPgSnapshotsDiff`, manages view changes by comparing the view record from the source snapshot to the target JSON state. The mechanism follows an order-of-operations flow that avoids race conditions:

1.  **State Reconstruction:** The system clones the existing schema snapshot and patches it with view renames or moves to align the keys with the new snapshot state.
2.  **Change Detection:** `applyJsonDiff` compares the patched snapshot and the target state to isolate modified attributes.
3.  **Statement Generation:** The engine iterates through the collection of views. If `alteredDefinition` is flagged, the view is dropped and recreated. If only metadata (e.g., `tablespace` or `WITH` options) changes, the engine queues targeted `alter` statements using specific `prepare` functions.

This separation ensures that structural changes to view content (which cannot be easily altered in SQL) trigger a destructive/re-constructive cycle, while property updates are handled via non-destructive SQL commands.

Sources: [drizzle-kit/src/snapshotsDiffer.ts:L1136-L1176](https://github.com/blade47/drizzle-orm/blob/main/drizzle-kit/src/snapshotsDiffer.ts#L1136-L1176), [drizzle-kit/src/snapshotsDiffer.ts:L1844-L1946](https://github.com/blade47/drizzle-orm/blob/main/drizzle-kit/src/snapshotsDiffer.ts#L1844-L1946)

## Control Flow for View Alterations

The logic for deciding how to alter a view is governed by guards based on the view snapshot state. The following flowchart illustrates the decision hierarchy implemented in the differ:

```mermaid
flowchart TD
    A["Begin Altered View"] --> B{"Is definition changed?<br>Action != push"}
    B -->|Yes| C[Drop View]
    C --> D[Create View]
    B -->|No| E{"Altered Options/Metadata"}
    E -->|Add Option| F[preparePgAlterViewAddWithOptionJson]
    E -->|Alter Tablespace| G[preparePgAlterViewAlterTablespaceJson]
    E -->|Alter Using| H[preparePgAlterViewAlterUsingJson]
```

The "load-bearing line" here is `if (alteredView.alteredExisting || (alteredView.alteredDefinition && action !== 'push'))`, which acts as an invariant guard. This ensures that any modification to the core SQL definition of a view forces a drop/recreate, preventing the engine from attempting invalid `ALTER VIEW` operations on the definition itself.

Sources: [drizzle-kit/src/snapshotsDiffer.ts:L1851-L1868](https://github.com/blade47/drizzle-orm/blob/main/drizzle-kit/src/snapshotsDiffer.ts#L1851-L1868)

## View and Schema Migration Invariants

> [!CAUTION]
> During view migrations, the engine assumes that views exist in the schema provided in the snapshot. If a view is renamed or moved between schemas, the engine MUST resolve these via `renamedViews` and `movedViews` maps before running `applyJsonDiff`. Failure to populate these maps results in the system treating the renamed view as a "Delete" and "Create" operation pair, which risks data loss if the view were a `MATERIALIZED` view containing data.

The system uses a key-based lookup where the dictionary key is `${schema}.${viewName}`. This is the primary index for lookup. Invariants are maintained by strictly updating the string keys during the patching phase.

Sources: [drizzle-kit/src/snapshotsDiffer.ts:L1148-L1174](https://github.com/blade47/drizzle-orm/blob/main/drizzle-kit/src/snapshotsDiffer.ts#L1148-L1174)

## Configuration Fields for View Changes

The logic uses Zod schemas to define the permissible alterations for views. The structure is used to validate and parse the output of the diff process:

| Field | Type | Purpose |
| :--- | :--- | :--- |
| `name` | `string` | The current identifier of the view |
| `alteredDefinition` | `object` | Holds `__old` and `__new` definition strings |
| `alteredSchema` | `object` | Schema migration tracking |
| `addedWithOption` | `object` | Track new `WITH` options |
| `deletedWithOption` | `object` | Track removed `WITH` options |
| `alteredTablespace` | `object` | Track change in view storage location |
| `alteredUsing` | `object` | Track change in the `USING` clause |

Sources: [drizzle-kit/src/snapshotsDiffer.ts:L340-L373](https://github.com/blade47/drizzle-orm/blob/main/drizzle-kit/src/snapshotsDiffer.ts#L340-L373)

## Statement Generation Pipeline

The generation of SQL statements is the final stage of the view migration process. The `jsonStatements` array is ordered to ensure that drop statements for views precede any table modifications, and creation statements follow them.

1.  **Drop Statements:** `jsonStatements.push(...dropViews)` executes after constraints are processed to ensure dependent objects are cleaned up.
2.  **Rename/Alter:** `renameViews` and `alterViews` are injected before the creation of new objects to maintain object existence during the transaction.
3.  **Creation:** `jsonStatements.push(...createViews)` happens at the end of the batch to ensure all underlying schema requirements are satisfied.

This sequence is critical because views are often dependent on tables. Recreating tables while views are active without dropping the views first would violate database schema constraints.

Sources: [drizzle-kit/src/snapshotsDiffer.ts:L1969-L2008](https://github.com/blade47/drizzle-orm/blob/main/drizzle-kit/src/snapshotsDiffer.ts#L1969-L2008)

## Related

- [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.
