Overview
Introduction
Sometimes your application needs to store data types that are specific to your business logic or not natively supported out of the box. Custom Column Types let you define your own data types and map them directly to database columns. This feature bridges the gap between your application's TypeScript data models and how values are represented, serialized, and retrieved from your database.
By defining a custom column type, you can control the exact database data type string used for migrations, automatically serialize JavaScript or TypeScript objects into driver-accepted parameters before writing to the database, and deserialize incoming database values back into your desired runtime format.
Defining a Custom Type
To create a custom column type, use the customType function. You provide configuration parameters that dictate how the column behaves during database interactions and type-checking.
import { customType } from 'drizzle-orm/pg-core';
const customVarchar = customType<{
data: string;
driverData: string;
config: { length: number };
configRequired: true;
}>({
dataType(config) {
return `varchar(${config.length})`;
},
toDriver(value) {
return value;
},
fromDriver(value) {
return value;
},
});Configuration Options
When defining a custom type, you configure its parameters using standard type definitions:
| Option | Description | Default |
|---|---|---|
data | The TypeScript type used in your application after selecting or when inserting. | unknown |
driverData | The type accepted by the database driver for this database type. | unknown |
config | The configuration object type passed into dataType generation. | Record<string, any> |
configRequired | Whether the configuration argument is mandatory when defining the column. | false |
notNull | Marks the custom data type as non-nullable by default. | false |
default | Marks the custom data type as having a default value by default. | false |
Mapping Values Between Application and Driver
Custom types allow you to transform data seamlessly as it travels between your TypeScript code and the database driver using two main mapping functions:
toDriver: Converts your application data model into a format accepted by the database driver right before an insert or update query executes (for example, serializing an object into a JSON string).fromDriver: Converts raw database values coming from the driver back into your application's preferred runtime data type (for example, parsing a date string into a real JavaScriptDateobject).
Tip
The toDriver function can return either the expected driver parameter type or a custom raw SQL expression object when advanced query manipulation is needed.
Working with Optional and Required Configurations
You can configure your custom types to accept optional settings or enforce required parameters depending on your database schema needs.
// Example with an optional configuration
const flexibleString = customType<{
data: string;
driverData: string;
config: { length: number };
}>({
dataType(config) {
return config ? `varchar(${config.length})` : 'text';
},
toDriver(value) {
return value;
},
fromDriver(value) {
return value;
},
});
// Usage with config
const col1 = flexibleString('col1', { length: 50 });
// Usage without config (falls back to text)
const col2 = flexibleString('col2');Warning
If you set configRequired: true in your custom type definition, omitting the configuration object when declaring the column will trigger a TypeScript compilation error.