---
title: "Drizzle Valibot Integration"
description: "Drizzle Valibot Integration translates Drizzle ORM table definitions, database views, and column specifications into corresponding Valibot runtime validation schemas. It provides factory functions ..."
last_updated: "2026-10-12T08:14:00.811777+00:00"
canonical_url: "https://www.doc0.dev/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/ecosystem-packages/drizzle-valibot-integration"
---

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

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

- [drizzle-valibot/src/column.types.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/column.types.ts)
- [drizzle-orm/type-tests/mysql/tables.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/type-tests/mysql/tables.ts)
- [drizzle-valibot/src/column.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/column.ts)
- [drizzle-orm/type-tests/singlestore/tables.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/type-tests/singlestore/tables.ts)
- [drizzle-kit/src/snapshotsDiffer.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/snapshotsDiffer.ts)
- [drizzle-valibot/src/schema.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/schema.ts)
- [drizzle-kit/src/serializer/gelSchema.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/gelSchema.ts)
- [drizzle-kit/src/serializer/pgSchema.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/pgSchema.ts)
- [drizzle-kit/src/introspect-pg.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-pg.ts)
- [drizzle-orm/type-tests/mysql/1000columns.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/type-tests/mysql/1000columns.ts)
- [drizzle-kit/src/introspect-mysql.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-mysql.ts)
- [drizzle-kit/src/introspect-gel.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-gel.ts)
- [drizzle-typebox/src/schema.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-typebox/src/schema.ts)
- [drizzle-valibot/src/schema.types.internal.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/schema.types.internal.ts)
- [drizzle-kit/src/serializer/mysqlSchema.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/mysqlSchema.ts)
- [drizzle-kit/src/introspect-singlestore.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-singlestore.ts)
- [drizzle-zod/src/schema.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-zod/src/schema.ts)
- [drizzle-valibot/src/index.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/index.ts)
- [drizzle-typebox/src/column.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-typebox/src/column.ts)
- [drizzle-seed/src/index.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-seed/src/index.ts)
- [drizzle-kit/src/serializer/studio.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/studio.ts)
- [drizzle-kit/src/serializer/sqliteSchema.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/sqliteSchema.ts)
- [drizzle-valibot/package.json](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/package.json)
- [drizzle-kit/src/serializer/singlestoreSchema.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/singlestoreSchema.ts)
- [drizzle-valibot/src/utils.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/utils.ts)
- [drizzle-kit/src/serializer/singlestoreSerializer.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/singlestoreSerializer.ts)
- [drizzle-kit/src/schemaValidator.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/schemaValidator.ts)
- [drizzle-typebox/src/schema.types.internal.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-typebox/src/schema.types.internal.ts)
</details>

## Overview

Drizzle Valibot Integration translates Drizzle ORM table definitions, database views, and column specifications into corresponding Valibot runtime validation schemas. It provides factory functions such as `createSelectSchema`, `createInsertSchema`, and `createUpdateSchema` that inspect column nullability, default values, and generation rules to build precise object schemas for querying, inserting, and updating data.
Sources: [drizzle-valibot/src/schema.ts:58-94](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/schema.ts#L58-L94)

The integration handles column mapping across various SQL dialects, converting primitive types, arrays, JSON objects, enums, and custom types into their Valibot validator equivalents with proper type safety and constraints.
Sources: [drizzle-valibot/src/column.ts:73-126](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/column.ts#L73-L126), [drizzle-valibot/src/column.types.ts:42-88](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/column.types.ts#L42-L88)

Developers can also supply custom refinements to override or extend individual field validators while maintaining compile-time type inference across operations.
Sources: [drizzle-valibot/src/schema.ts:28-36](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/schema.ts#L28-L36), [drizzle-valibot/src/schema.types.internal.ts:14-29](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/schema.types.internal.ts#L14-L29)

## Public API surface

### Entry-Point Exports and Module Structure

The `drizzle-valibot` package exposes its public API through a main entry point defined in `drizzle-valibot/src/index.ts`. The primary exports include explicit column utility schemas (`bufferSchema`, `jsonSchema`, `literalSchema`) alongside star exports for column types, schema factories, internal schema types, and general utility functions.

```typescript
export { bufferSchema, jsonSchema, literalSchema } from './column.ts';
export * from './column.types.ts';
export * from './schema.ts';
export * from './schema.types.internal.ts';
export * from './schema.types.ts';
export * from './utils.ts';
```
Sources: [drizzle-valibot/src/index.ts:1-6](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/index.ts#L1-L6)

> [!NOTE]
> The entry-point exports are bundled to support both ESM and CommonJS module resolution paths via conditional exports in package configuration.

### Package Configuration and Exports Map

The module distribution is governed by `drizzle-valibot/package.json`, which specifies dual CJS and ESM output paths, type definitions, peer dependencies on `drizzle-orm` (`>=0.36.0`) and `valibot` (`>=1.0.0-beta.7`), and provenance publishing configuration.

| Field | Target / Value | Purpose |
| :--- | :--- | :--- |
| `main` | `./index.cjs` | CommonJS entry point |
| `module` | `./index.mjs` | ECMAScript module entry point |
| `types` | `./index.d.ts` | TypeScript type definitions |
| `peerDependencies` | `drizzle-orm`, `valibot` | Required host library versions |
| `publishConfig` | `provenance: true` | Cryptographic provenance for npm publishing |

Sources: [drizzle-valibot/package.json:14-33](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/package.json#L14-L33)

## Schema generation architecture

### Entity Dispatch and Column Resolution

The runtime schema generation process begins by resolving the input entity—whether a table, view, or PostgreSQL enum—into its constituent column definitions or selected fields. The helper function `getColumns` inspects the entity using `isTable`, returning columns via `getTableColumns` if it represents a table or `getViewSelectedFields` if it represents a view. For PostgreSQL enums identified via `isPgEnum`, `createSelectSchema` bypasses column iteration entirely, mapping the enum's string values directly to a Valibot enum validator using `mapEnumValues`.

```typescript
function getColumns(tableLike: Table | View) {
	return isTable(tableLike) ? getTableColumns(tableLike) : getViewSelectedFields(tableLike);
}
```
Sources: [drizzle-valibot/src/schema.ts:10-12](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/schema.ts#L10-L12)

```typescript
export const createSelectSchema: CreateSelectSchema = (
	entity: Table | View | PgEnum<[string, ...string[]]>,
	refine?: Record<string, any>,
) => {
	if (isPgEnum(entity)) {
		return v.enum(mapEnumValues(entity.enumValues));
	}
	const columns = getColumns(entity);
	return handleColumns(columns, refine ?? {}, {
		never: () => false,
		optional: () => false,
		nullable: (column) => !column.notNull,
	}) as any;
};
```
Sources: [drizzle-valibot/src/schema.ts:58-71](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/schema.ts#L58-L71)

### Operation-Specific Condition Strategies

The core schema builder function `handleColumns` iterates over column records while accepting a `Conditions` interface that dictates how individual column properties translate into Valibot wrappers for select, insert, and update operations. Each factory injects a specific condition strategy:

| Factory Function | `never` Condition | `optional` Condition | `nullable` Condition |
| :--- | :--- | :--- | :--- |
| `createSelectSchema` | `() => false` | `() => false` | `(column) => !column.notNull` |
| `createInsertSchema` | `(column) => column?.generated?.type === 'always' || column?.generatedIdentity?.type === 'always'` | `(column) => !column.notNull || (column.notNull && column.hasDefault)` | `(column) => !column.notNull` |
| `createUpdateSchema` | `(column) => column?.generated?.type === 'always' || column?.generatedIdentity?.type === 'always'` | `() => true` | `(column) => !column.notNull` |

Sources: [drizzle-valibot/src/schema.ts:66-70](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/schema.ts#L66-L70), [drizzle-valibot/src/schema.ts:78-82](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/schema.ts#L78-L82), [drizzle-valibot/src/schema.ts:90-94](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/schema.ts#L90-L94)

> [!NOTE]
> Columns with database-generated values (`generated?.type === 'always'` or `generatedIdentity?.type === 'always'`) return true for the `never` condition during insert and update operations, causing them to be entirely omitted from the resulting Valibot object schema.

```typescript
export const createInsertSchema: CreateInsertSchema = (
	entity: Table,
	refine?: Record<string, any>,
) => {
	const columns = getColumns(entity);
	return handleColumns(columns, refine ?? {}, {
		never: (column) => column?.generated?.type === 'always' || column?.generatedIdentity?.type === 'always',
		optional: (column) => !column.notNull || (column.notNull && column.hasDefault),
		nullable: (column) => !column.notNull,
	}) as any;
};
```
Sources: [drizzle-valibot/src/schema.ts:73-83](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/schema.ts#L73-L83)

```typescript
export const createUpdateSchema: CreateUpdateSchema = (
	entity: Table,
	refine?: Record<string, any>,
) => {
	const columns = getColumns(entity);
	return handleColumns(columns, refine ?? {}, {
		never: (column) => column?.generated?.type === 'always' || column?.generatedIdentity?.type === 'always',
		optional: () => true,
		nullable: (column) => !column.notNull,
	}) as any;
};
```
Sources: [drizzle-valibot/src/schema.ts:85-95](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/schema.ts#L85-L95)

### Recursive Handling of Nested Relations and Refinements

When `handleColumns` encounters nested object properties, aliased SQL expressions, or relational selections rather than raw column instances, it recursively evaluates sub-schemas. If a static refinement value is provided for a key, it bypasses column conversion and assigns the replacement schema directly. Otherwise, it generates the base schema via `columnToSchema`, applies any functional refinement, evaluates exclusion via `conditions.never`, and wraps the resulting validator with `v.nullable` or `v.optional` based on the active condition strategy.

```typescript
function handleColumns(
	columns: Record<string, any>,
	refinements: Record<string, any>,
	conditions: Conditions,
): v.GenericSchema {
	const columnSchemas: Record<string, v.GenericSchema> = {};

	for (const [key, selected] of Object.entries(columns)) {
		if (!is(selected, Column) && !is(selected, SQL) && !is(selected, SQL.Aliased) && typeof selected === 'object') {
			const columns = isTable(selected) || isView(selected) ? getColumns(selected) : selected;
			columnSchemas[key] = handleColumns(columns, refinements[key] ?? {}, conditions);
			continue;
		}

		const refinement = refinements[key];
		if (refinement !== undefined && typeof refinement !== 'function') {
			columnSchemas[key] = refinement;
			continue;
		}

		const column = is(selected, Column) ? selected : undefined;
		const schema = column ? columnToSchema(column) : v.any();
		const refined = typeof refinement === 'function' ? refinement(schema) : schema;

		if (conditions.never(column)) {
			continue;
		} else {
			columnSchemas[key] = refined;
		}

		if (column) {
			if (conditions.nullable(column)) {
				columnSchemas[key] = v.nullable(columnSchemas[key]!);
			}

			if (conditions.optional(column)) {
				columnSchemas[key] = v.optional(columnSchemas[key]!);
			}
		}
	}

	return v.object(columnSchemas) as any;
}
```
Sources: [drizzle-valibot/src/schema.ts:14-56](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/schema.ts#L14-L56)

## Column mapping engine

### Enum and Geometric Type Dispatch

The column mapping engine translates individual Drizzle column definitions into Valibot primitive and structured validators by examining column properties and type metadata. The primary entry point function `columnToSchema` first checks whether a column possesses an enumeration configuration via `isWithEnum`. If enumeration values are present, it transforms them using `mapEnumValues` into a Valibot enum validator, falling back to a standard string validator if the enumeration is empty.

```typescript
export function columnToSchema(column: Column): v.GenericSchema {
	let schema!: v.GenericSchema;

	if (isWithEnum(column)) {
		schema = column.enumValues.length ? v.enum(mapEnumValues(column.enumValues)) : v.string();
	}
```
Sources: [drizzle-valibot/src/column.ts:73-78](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/column.ts#L73-L78)

For columns lacking enums, `columnToSchema` dispatches specialized PostgreSQL geometric and vector types by matching their internal column type identifiers through `isColumnType`. Geometric pairs like point tuples and geometries are mapped to a two-element number tuple, while point and geometry objects map to an `x` and `y` coordinate object. Vector types map to a number array, adding a Valibot length pipe validator if explicit dimensions are defined.

| Column Type Matcher | Identifiers Checked | Generated Valibot Schema Structure |
| :--- | :--- | :--- |
| `PgGeometry` / `PgPointTuple` | `['PgGeometry', 'PgPointTuple']` | `v.tuple([v.number(), v.number()])` |
| `PgGeometryObject` / `PgPointObject` | `['PgGeometryObject', 'PgPointObject']` | `v.object({ x: v.number(), y: v.number() })` |
| `PgHalfVector` / `PgVector` | `['PgHalfVector', 'PgVector']` | `v.array(v.number())` (with optional length pipe) |
| `PgLine` (Tuple) | `['PgLine']` | `v.tuple([v.number(), v.number(), v.number()])` |
| `PgLineABC` (Object) | `['PgLineABC']` | `v.object({ a: v.number(), b: v.number(), c: v.number() })` |

Sources: [drizzle-valibot/src/column.ts:82-95](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/column.ts#L82-L95)

> [!NOTE]
> Vector and array column generators inspect `column.dimensions` or `column.size` properties respectively, attaching a Valibot length validation constraint dynamically if a fixed size constraint is set on the Drizzle column builder.

```typescript
} else if (isColumnType<PgHalfVector<any> | PgVector<any>>(column, ['PgHalfVector', 'PgVector'])) {
	schema = v.array(v.number());
	schema = column.dimensions ? v.pipe(schema as v.ArraySchema<any, any>, v.length(column.dimensions)) : schema;
```
Sources: [drizzle-valibot/src/column.ts:88-90](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/column.ts#L88-L90)

### Scalar and Composite Data Type Mapping

When handling standard data categories, the mapping engine inspects `column.dataType` to route execution to appropriate helper functions or primitive constructors. Array columns recursively map their base column definition or fall back to an unconstrained `v.any()` array if untyped. Numerical, bigint, and string columns delegate to dedicated conversion functions that parse SQL type options, while boolean, date, json, custom, and buffer types map directly to their Valibot equivalents using shared constants like `jsonSchema` and `bufferSchema`.

```typescript
else if (isColumnType<PgArray<any, any>>(column, ['PgArray'])) {
	schema = v.array(columnToSchema(column.baseColumn));
	schema = column.size ? v.pipe(schema as v.ArraySchema<any, any>, v.length(column.size)) : schema;
} else if (column.dataType === 'array') {
	schema = v.array(v.any());
} else if (column.dataType === 'number') {
	schema = numberColumnToSchema(column);
} else if (column.dataType === 'bigint') {
	schema = bigintColumnToSchema(column);
} else if (column.dataType === 'boolean') {
	schema = v.boolean();
} else if (column.dataType === 'date') {
	schema = v.date();
} else if (column.dataType === 'string') {
	schema = stringColumnToSchema(column);
} else if (column.dataType === 'json') {
	schema = jsonSchema;
} else if (column.dataType === 'custom') {
	schema = v.any();
} else if (column.dataType === 'buffer') {
	schema = bufferSchema;
}
```
Sources: [drizzle-valibot/src/column.ts:97-118](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/column.ts#L97-L118)

```typescript
export const literalSchema = v.union([v.string(), v.number(), v.boolean(), v.null()]);
export const jsonSchema: v.GenericSchema<Json> = v.union([
	literalSchema,
	v.array(v.any()),
	v.record(v.string(), v.any()),
]);
export const bufferSchema: v.GenericSchema<Buffer> = v.custom<Buffer>((v) => v instanceof Buffer); // eslint-disable-line no-instanceof/no-instanceof
```
Sources: [drizzle-valibot/src/column.ts:61-67](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/column.ts#L61-L67)

If a column matches none of the recognized database types or data categories, `columnToSchema` defaults the schema to `v.any()` as a safe fallback.

```typescript
if (!schema) {
	schema = v.any();
}

return schema;
```
Sources: [drizzle-valibot/src/column.ts:121-125](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/column.ts#L121-L125)

## Static type inference

### Schema Inference and Property Extraction

Static type inference in `drizzle-valibot` maps Drizzle column configurations and table shapes directly to Valibot schema type arguments at compile time. The conditional type `ExtractAdditionalProperties` inspects a column's internal type definition (`columnType`) to extract maximum lengths, dimensions, or array sizes. For example, character and text columns from PostgreSQL, MySQL, SQLite, and SingleStore resolve to their respective length bounds, while vector columns extract their dimension counts.

```typescript
export type ExtractAdditionalProperties<TColumn extends Column> = {
	max: TColumn['_']['columnType'] extends 'PgVarchar' | 'SQLiteText' | 'PgChar' | 'MySqlChar' | 'SingleStoreChar'
		? Assume<TColumn['_'], { length: number | undefined }>['length']
		: TColumn['_']['columnType'] extends 'MySqlText' | 'MySqlVarChar' | 'SingleStoreText' | 'SingleStoreVarChar'
			? number
		: TColumn['_']['columnType'] extends 'PgBinaryVector' | 'PgHalfVector' | 'PgVector'
			? Assume<TColumn['_'], { dimensions: number }>['dimensions']
		: TColumn['_']['columnType'] extends 'PgArray' ? Assume<TColumn['_'], { size: number | undefined }>['size']
		: undefined;
	fixedLength: TColumn['_']['columnType'] extends
		'PgChar' | 'PgHalfVector' | 'PgVector' | 'PgArray' | 'MySqlChar' | 'SingleStoreChar' ? true
		: false;
};
```
Sources: [drizzle-valibot/src/column.types.ts:12-24](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/column.types.ts#L12-L24)

| Column Type Group | Checked Column Types | Extracted Property Type |
| :--- | :--- | :--- |
| Character Limits | `PgVarchar`, `SQLiteText`, `PgChar`, `MySqlChar`, `SingleStoreChar` | `length` (number \| undefined) |
| Text / VarChar Sizes | `MySqlText`, `MySqlVarChar`, `SingleStoreText`, `SingleStoreVarChar` | `number` |
| Vector Dimensions | `PgBinaryVector`, `PgHalfVector`, `PgVector` | `dimensions` (number) |
| Array Sizes | `PgArray` | `size` (number \| undefined) |

Sources: [drizzle-valibot/src/column.types.ts:13-20](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/column.types.ts#L13-L20)

> [!NOTE]
> The helper `HasBaseColumn` evaluates whether a column possesses a defined base column reference, enabling nested array type resolution for multi-dimensional array structures.

```typescript
export type HasBaseColumn<TColumn> = TColumn extends { _: { baseColumn: Column | undefined } }
	? IsNever<TColumn['_']['baseColumn']> extends false ? true
	: false
	: false;
```
Sources: [drizzle-valibot/src/column.types.ts:5-8](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/column.types.ts#L5-L8)

### Type Mapping and Nullability Handlers

The central type-level mapping function `GetValibotType` processes the extracted data types, column types, enum definitions, and base columns to yield the exact Valibot schema shape. Depending on whether a column enforces a default value or allows nulls, secondary wrapper utilities adjust the final inferred type. Specifically, `HandleSelectColumn`, `HandleInsertColumn`, and `HandleUpdateColumn` wrap underlying Valibot schemas with `v.NullableSchema` or `v.OptionalSchema` conditional containers.

```typescript
type HandleSelectColumn<
	TSchema extends v.GenericSchema,
	TColumn extends Column,
> = TColumn['_']['notNull'] extends true ? TSchema
	: v.NullableSchema<TSchema, undefined>;

type HandleInsertColumn<
	TSchema extends v.GenericSchema,
	TColumn extends Column,
> = TColumn['_']['notNull'] extends true
	? TColumn['_']['hasDefault'] extends true ? v.OptionalSchema<TSchema, undefined>
	: TSchema
	: v.OptionalSchema<v.NullableSchema<TSchema, undefined>, undefined>;

type HandleUpdateColumn<
	TSchema extends v.GenericSchema,
	TColumn extends Column,
> = TColumn['_']['notNull'] extends true ? v.OptionalSchema<TSchema, undefined>
	: v.OptionalSchema<v.NullableSchema<TSchema, undefined>, undefined>;

```
Sources: [drizzle-valibot/src/column.types.ts:133-152](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/column.types.ts#L133-L152)

> [!WARNING]
> `HandleInsertColumn` and `HandleUpdateColumn` mark columns with defaults or nullable constraints as optional, which changes how partial payloads validate during insert and update operations.

```typescript
type HandleInsertColumn<
	TSchema extends v.GenericSchema,
	TColumn extends Column,
> = TColumn['_']['notNull'] extends true
	? TColumn['_']['hasDefault'] extends true ? v.OptionalSchema<TSchema, undefined>
	: TSchema
	: v.OptionalSchema<v.NullableSchema<TSchema, undefined>, undefined>;

type HandleUpdateColumn<
	TSchema extends v.GenericSchema,
	TColumn extends Column,
> = TColumn['_']['notNull'] extends true ? v.OptionalSchema<TSchema, undefined>
	: v.OptionalSchema<v.NullableSchema<TSchema, undefined>, undefined>;

```
Sources: [drizzle-valibot/src/column.types.ts:139-152](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/column.types.ts#L139-L152)

Furthermore, `BuildSchema` iterates over table columns while automatically omitting columns designated with `ColumnIsGeneratedAlwaysAs`. It resolves custom user-provided refinements through `IsRefinementDefined` and `HandleRefinement`, guaranteeing that overridden fields preserve correct nullability and optionality modifiers in the final compiled object schema.

```typescript
export type BuildSchema<
	TType extends 'select' | 'insert' | 'update',
	TColumns extends Record<string, any>,
	TRefinements extends Record<string, any> | undefined,
> = v.ObjectSchema<
	Simplify<
		{
			readonly [K in keyof TColumns as ColumnIsGeneratedAlwaysAs<TColumns[K]> extends true ? never : K]:
				TColumns[K] extends infer TColumn extends Column
					? IsRefinementDefined<TRefinements, Assume<K, string>> extends true
						? Assume<HandleRefinement<TType, TRefinements[K & keyof TRefinements], TColumn>, v.GenericSchema>
					: HandleColumn<TType, TColumn>
					: TColumns[K] extends infer TObject extends SelectedFieldsFlat<Column> | Table | View ? BuildSchema<
							TType,
							GetSelection<TObject>,
							TRefinements extends object ? TRefinements[K & keyof TRefinements] : undefined
						>
					: v.AnySchema;
		}
	>,
	undefined
>;
```
Sources: [drizzle-valibot/src/schema.types.internal.ts:50-71](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/schema.types.internal.ts#L50-L71)

## Custom schema overrides

### Refinement Dispatch and Execution

Schema generation functions (`createSelectSchema`, `createInsertSchema`, and `createUpdateSchema`) accept an optional second argument `refine`, represented as a record of column keys mapped to either direct Valibot validator schemas or transformer functions. During schema compilation, `handleColumns` iterates over table columns and inspects any corresponding entry in the `refinements` dictionary. If a refinement value is provided and is not a function, it directly replaces the generated column schema. If the refinement is instead a function, it receives the automatically generated Valibot schema as its argument, allowing developers to wrap, constrain, or transform the base validator.

```typescript
const refinement = refinements[key];
if (refinement !== undefined && typeof refinement !== 'function') {
	columnSchemas[key] = refinement;
	continue;
}

const column = is(selected, Column) ? selected : undefined;
const schema = column ? columnToSchema(column) : v.any();
const refined = typeof refinement === 'function' ? refinement(schema) : schema;
```
Sources: [drizzle-valibot/src/schema.ts:28-36](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/schema.ts#L28-L36)

> [!NOTE]
> When nesting occurs across relations, views, or embedded object structures, `handleColumns` recursively processes child objects and passes down corresponding nested refinement dictionaries via `refinements[key] ?? {}`.

```typescript
if (!is(selected, Column) && !is(selected, SQL) && !is(selected, SQL.Aliased) && typeof selected === 'object') {
	const columns = isTable(selected) || isView(selected) ? getColumns(selected) : selected;
	columnSchemas[key] = handleColumns(columns, refinements[key] ?? {}, conditions);
	continue;
}
```
Sources: [drizzle-valibot/src/schema.ts:22-26](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/schema.ts#L22-L26)

### Handling Nullability and Optionality in Refinements

After applying a custom refinement function or static schema replacement, `handleColumns` evaluates table-level and column-level conditions to enforce database constraints. Even when a column schema is overridden, subsequent checks verify whether the underlying column is nullable or optional. If the column allows nulls according to the active condition set, the refined schema is automatically wrapped using `v.nullable()`. Similarly, if conditions specify optionality for inserts or updates, an optional wrapper is applied.

```typescript
if (column) {
	if (conditions.nullable(column)) {
		columnSchemas[key] = v.nullable(columnSchemas[key]!);
	}

	if (conditions.optional(column)) {
		columnSchemas[key] = v.optional(columnSchemas[key]!);
	}
}
```
Sources: [drizzle-valibot/src/schema.ts:44-52](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/schema.ts#L44-L52)

> [!WARNING]
> Generated columns whose generation type is set to `'always'` or identity columns configured as `'always'` trigger the `conditions.never` check, causing the column to be omitted entirely from the generated object schema regardless of any supplied refinement.

```typescript
if (conditions.never(column)) {
	continue;
} else {
	columnSchemas[key] = refined;
}
```
Sources: [drizzle-valibot/src/schema.ts:38-42](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-valibot/src/schema.ts#L38-L42)

## Related

- [Drizzle Zod Integration](https://www.doc0.dev/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/ecosystem-packages/drizzle-zod-integration)
- [Table and Column Models](https://www.doc0.dev/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/core-architecture/table-and-column-models)


## Sitemap

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