Back to Drizzle Orm

PostgreSQL column types

src/content/docs/column-types/pg.mdx

latest25.3 KB
Original Source

import Section from '@mdx/Section.astro'; import Callout from '@mdx/Callout.astro';

We have native support for all of them, yet if that's not enough for you, feel free to create custom types.

<Callout title='important' type='warning'> All examples in this part of the documentation do not use database column name aliases, and column names are generated from TypeScript keys.

You can use database aliases in column names if you want, and you can also use the casing parameter to define a mapping strategy for Drizzle.

You can read more about it here </Callout>

integer

integer int int4
Signed 4-byte integer

If you need integer autoincrement please refer to serial.

<Section> ```typescript import { integer, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', { int: integer() });


```sql
CREATE TABLE "table" (
	"int" integer
);
</Section> <Section> ```typescript import { sql } from "drizzle-orm"; import { integer, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', { int1: integer().default(10), int2: integer().default(sql'10'::int) });


```sql
CREATE TABLE "table" (
	"int1" integer DEFAULT 10,
	"int2" integer DEFAULT '10'::int
);
</Section>

smallint

smallint int2
Small-range signed 2-byte integer

If you need smallint autoincrement please refer to smallserial.

<Section> ```typescript import { smallint, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', { smallint: smallint() });


```sql
CREATE TABLE "table" (
	"smallint" smallint
);
</Section> <Section> ```typescript import { sql } from "drizzle-orm"; import { smallint, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', { smallint1: smallint().default(10), smallint2: smallint().default(sql'10'::smallint) });


```sql
CREATE TABLE "table" (
	"smallint1" smallint DEFAULT 10,
	"smallint2" smallint DEFAULT '10'::smallint
);
</Section>

bigint

bigint int8
Signed 8-byte integer

If you need bigint autoincrement please refer to bigserial.

If you're expecting values above 2^31 but below 2^53, you can utilise mode: 'number' and deal with javascript number as opposed to bigint.

<Section> ```typescript import { bigint, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', { bigint: bigint({ mode: 'number' }) });

// will be inferred as number bigint: bigint({ mode: 'number' })

// will be inferred as bigint bigint: bigint({ mode: 'bigint' })


```sql
CREATE TABLE "table" (
	"bigint" bigint
);
</Section> <Section> ```typescript import { sql } from "drizzle-orm"; import { bigint, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', { bigint1: bigint().default(10), bigint2: bigint().default(sql'10'::bigint) });


```sql
CREATE TABLE "table" (
	"bigint1" bigint DEFAULT 10,
	"bigint2" bigint DEFAULT '10'::bigint
);
</Section>

---

serial

serial serial4
Auto incrementing 4-bytes integer, notational convenience for creating unique identifier columns (similar to the AUTO_INCREMENT property supported by some other databases).

For more info please refer to the official PostgreSQL docs.

<Section> ```typescript import { serial, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', { serial: serial(), });


```sql
CREATE TABLE "table" (
	"serial" serial NOT NULL
);
</Section>

smallserial

smallserial serial2
Auto incrementing 2-bytes integer, notational convenience for creating unique identifier columns (similar to the AUTO_INCREMENT property supported by some other databases).

For more info please refer to the official PostgreSQL docs.

<Section> ```typescript import { smallserial, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', { smallserial: smallserial(), });


```sql
CREATE TABLE "table" (
	"smallserial" smallserial NOT NULL
);
</Section>

bigserial

bigserial serial8
Auto incrementing 8-bytes integer, notational convenience for creating unique identifier columns (similar to the AUTO_INCREMENT property supported by some other databases).

For more info please refer to the official PostgreSQL docs.

If you're expecting values above 2^31 but below 2^53, you can utilise mode: 'number' and deal with javascript number as opposed to bigint.

<Section> ```typescript import { bigserial, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', { bigserial: bigserial({ mode: 'number' }), });


```sql
CREATE TABLE "table" (
	"bigserial" bigserial NOT NULL
);
</Section>

---

boolean

PostgreSQL provides the standard SQL type boolean.

For more info please refer to the official PostgreSQL docs.

<Section> ```typescript import { boolean, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', { boolean: boolean() });


```sql
CREATE TABLE "table" (
	"boolean" boolean
);
</Section>

---

bytea

PostgreSQL provides the standard SQL type bytea.

For more info please refer to the official PostgreSQL docs.

<Section> ```typescript import { bytea, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', { bytea: bytea() });


```sql
CREATE TABLE IF NOT EXISTS "table" (
	"bytea" bytea,
);
</Section>

---

text

text
Variable-length(unlimited) character string.

For more info please refer to the official PostgreSQL docs.

You can define { enum: ["value1", "value2"] } config to infer insert and select types, it won't check runtime values.

<Section> ```typescript import { text, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', { text: text() });

// will be inferred as text: "value1" | "value2" | null text: text({ enum: ["value1", "value2"] })


```sql
CREATE TABLE "table" (
	"text" text
);
</Section>

varchar

character varying(n) varchar(n)
Variable-length character string, can store strings up to n characters (not bytes).

For more info please refer to the official PostgreSQL docs.

You can define { enum: ["value1", "value2"] } config to infer insert and select types, it won't check runtime values.

The length parameter is optional according to PostgreSQL docs.

<Section> ```typescript import { varchar, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', { varchar1: varchar(), varchar2: varchar({ length: 256 }), });

// will be inferred as text: "value1" | "value2" | null varchar: varchar({ enum: ["value1", "value2"] }),


```sql
CREATE TABLE "table" (
	"varchar1" varchar,
	"varchar2" varchar(256)
);
</Section>

char

character(n) char(n)
Fixed-length, blank padded character string, can store strings up to n characters(not bytes).

For more info please refer to the official PostgreSQL docs.

You can define { enum: ["value1", "value2"] } config to infer insert and select types, it won't check runtime values.

The length parameter is optional according to PostgreSQL docs.

<Section> ```typescript import { char, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', { char1: char(), char2: char({ length: 256 }), });

// will be inferred as text: "value1" | "value2" | null char: char({ enum: ["value1", "value2"] }),


```sql
CREATE TABLE "table" (
	"char1" char,
	"char2" char(256)
);
</Section>

---

numeric

numeric decimal
Exact numeric of selectable precision. Can store numbers with a very large number of digits, up to 131072 digits before the decimal point and up to 16383 digits after the decimal point.

For more info please refer to the official PostgreSQL docs.

<Section> ```typescript import { numeric, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', { numeric1: numeric(), numeric2: numeric({ precision: 100 }), numeric3: numeric({ precision: 100, scale: 20 }), numericNum: numeric({ mode: 'number' }), numericBig: numeric({ mode: 'bigint' }), });


```sql
CREATE TABLE "table" (
	"numeric1" numeric,
	"numeric2" numeric(100),
	"numeric3" numeric(100, 20),
	"numericNum" numeric,
	"numericBig" numeric
);
</Section>

decimal

An alias of numeric.

real

real float4
Single precision floating-point number (4 bytes)

For more info please refer to the official PostgreSQL docs.

<Section> ```typescript import { sql } from "drizzle-orm"; import { real, pgTable } from "drizzle-orm/pg-core";

const table = pgTable('table', { real1: real(), real2: real().default(10.10), real3: real().default(sql'10.10'::real), });


```sql
CREATE TABLE "table" (
	"real1" real,
	"real2" real default 10.10,
	"real3" real default '10.10'::real
);
</Section>

double precision

double precision float8
Double precision floating-point number (8 bytes)

For more info please refer to the official PostgreSQL docs.

<Section> ```typescript import { sql } from "drizzle-orm"; import { doublePrecision, pgTable } from "drizzle-orm/pg-core";

const table = pgTable('table', { double1: doublePrecision(), double2: doublePrecision().default(10.10), double3: doublePrecision().default(sql'10.10'::double precision), });


```sql
CREATE TABLE "table" (
	"double1" double precision,
	"double2" double precision default 10.10,
	"double3" double precision default '10.10'::double precision
);
</Section>

---

json

json
Textual JSON data, as specified in RFC 7159.

For more info please refer to the official PostgreSQL docs.

<Section> ```typescript import { sql } from "drizzle-orm"; import { json, pgTable } from "drizzle-orm/pg-core";

const table = pgTable('table', { json1: json(), json2: json().default({ foo: "bar" }), json3: json().default(sql'{foo: "bar"}'::json), });


```sql
CREATE TABLE "table" (
	"json1" json,
	"json2" json default '{"foo": "bar"}'::json,
	"json3" json default '{"foo": "bar"}'::json
);
</Section>

You can specify .$type<..>() for json object inference, it won't check runtime values. It provides compile time protection for default values, insert and select schemas.

typescript
// will be inferred as { foo: string }
json: json().$type<{ foo: string }>();

// will be inferred as string[]
json: json().$type<string[]>();

// won't compile
json: json().$type<string[]>().default({});

jsonb

jsonb
Binary JSON data, decomposed.

For more info please refer to the official PostgreSQL docs.

<Section> ```typescript import { jsonb, pgTable } from "drizzle-orm/pg-core";

const table = pgTable('table', { jsonb1: jsonb(), jsonb2: jsonb().default({ foo: "bar" }), jsonb3: jsonb().default(sql'{foo: "bar"}'::jsonb), });

```sql
CREATE TABLE "table" (
	"jsonb1" jsonb,
	"jsonb2" jsonb default '{"foo": "bar"}'::jsonb,
	"jsonb3" jsonb default '{"foo": "bar"}'::jsonb
);
</Section>

You can specify .$type<..>() for json object inference, it won't check runtime values. It provides compile time protection for default values, insert and select schemas.

typescript
// will be inferred as { foo: string }
jsonb: jsonb().$type<{ foo: string }>();

// will be inferred as string[]
jsonb: jsonb().$type<string[]>();

// won't compile
jsonb: jsonb().$type<string[]>().default({});

---

uuid

uuid

The data type uuid stores Universally Unique Identifiers (UUID) as defined by RFC 4122, ISO/IEC 9834-8:2005, and related standards

For more info please refer to the official PostgreSQL docs.

ts
import { uuid, pgTable } from "drizzle-orm/pg-core";

const table = pgTable('table', {
  uuid1: uuid(),
  uuid2: uuid().defaultRandom(),
  uuid3: uuid().default('a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11')
});
sql
CREATE TABLE "table" (
	"uuid1" uuid,
	"uuid2" uuid default gen_random_uuid(),
	"uuid3" uuid default 'a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11'
);

---

time

time timetz time with timezone time without timezone
Time of day with or without time zone.

For more info please refer to the official PostgreSQL docs.

<Section> ```typescript import { time, pgTable } from "drizzle-orm/pg-core";

const table = pgTable('table', { time1: time(), time2: time({ withTimezone: true }), time3: time({ precision: 6 }), time4: time({ precision: 6, withTimezone: true }) });


```sql
CREATE TABLE "table" (
	"time1" time,
	"time2" time with timezone,
	"time3" time(6),
	"time4" time(6) with timezone
);
</Section>

timestamp

timestamp timestamptz timestamp with time zone timestamp without time zone
Date and time with or without time zone.

For more info please refer to the official PostgreSQL docs.

<Section> ```typescript import { sql } from "drizzle-orm"; import { timestamp, pgTable } from "drizzle-orm/pg-core";

const table = pgTable('table', { timestamp1: timestamp(), timestamp2: timestamp({ precision: 6, withTimezone: true }), timestamp3: timestamp().defaultNow(), timestamp4: timestamp().default(sqlnow()), });

```sql
CREATE TABLE "table" (
	"timestamp1" timestamp,
	"timestamp2" timestamp (6) with time zone,
	"timestamp3" timestamp default now(),
	"timestamp4" timestamp default now()
);
</Section>

You can specify either date or string infer modes:

typescript
// will infer as date
timestamp: timestamp({ mode: "date" }),

// will infer as string
timestamp: timestamp({ mode: "string" }),

The string mode does not perform any mappings for you. This mode was added to Drizzle ORM to provide developers with the possibility to handle dates and date mappings themselves, depending on their needs. Drizzle will pass raw dates as strings to and from the database, so the behavior should be as predictable as possible and aligned 100% with the database behavior

The date mode is the regular way to work with dates. Drizzle will take care of all mappings between the database and the JS Date object

<Callout type='info' emoji='ℹ️'> How mapping works for `timestamp` and `timestamp with timezone`:

As PostgreSQL docs stated:

In a literal that has been determined to be timestamp without time zone, PostgreSQL will silently ignore any time zone indication. That is, the resulting value is derived from the date/time fields in the input value, and is not adjusted for time zone.

For timestamp with time zone, the internally stored value is always in UTC (Universal Coordinated Time, traditionally known as Greenwich Mean Time, GMT). An input value that has an explicit time zone specified is converted to UTC using the appropriate offset for that time zone. If no time zone is stated in the input string, then it is assumed to be in the time zone indicated by the system's TimeZone parameter, and is converted to UTC using the offset for the timezone zone.

So for timestamp with timezone you will get back string converted to a timezone set in your Postgres instance. You can check timezone using this sql query:

sql
show timezone;
</Callout>

date

date
Calendar date (year, month, day)

For more info please refer to the official PostgreSQL docs.

<Section> ```typescript import { date, pgTable } from "drizzle-orm/pg-core";

const table = pgTable('table', { date: date(), });


```sql
CREATE TABLE "table" (
	"date" date
);
</Section> You can specify either `date` or `string` infer modes: ```typescript // will infer as date date: date({ mode: "date" }),

// will infer as string date: date({ mode: "string" }),

### interval
`interval`  
Time span

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-datetime.html)** 

<Section>
```typescript
import { interval, pgTable } from "drizzle-orm/pg-core";

const table = pgTable('table', {
	interval1: interval(),
  interval2: interval({ fields: 'day' }),
  interval3: interval({ fields: 'month' , precision: 6 }),
});

sql
CREATE TABLE "table" (
	"interval1" interval,
	"interval2" interval day,
	"interval3" interval(6) month
);
</Section>

---

point

point
Geometric point type

For more info please refer to the official PostgreSQL docs.

Type point has 2 modes for mappings from the database: tuple and xy.

  • tuple will be accepted for insert and mapped on select to a tuple. So, the database Point(1,2) will be typed as [1,2] with drizzle.

  • xy will be accepted for insert and mapped on select to an object with x, y coordinates. So, the database Point(1,2) will be typed as { x: 1, y: 2 } with drizzle

<Section> ```typescript const items = pgTable('items', { point: point(), pointObj: point({ mode: 'xy' }), }); ```
sql
CREATE TABLE "items" (
	"point" point,
	"pointObj" point
);
</Section>

line

line
Geometric line type

For more info please refer to the official PostgreSQL docs.

Type line has 2 modes for mappings from the database: tuple and abc.

  • tuple will be accepted for insert and mapped on select to a tuple. So, the database Line{1,2,3} will be typed as [1,2,3] with drizzle.

  • abc will be accepted for insert and mapped on select to an object with a, b, and c constants from the equation Ax + By + C = 0. So, the database Line{1,2,3} will be typed as { a: 1, b: 2, c: 3 } with drizzle.

<Section> ```typescript const items = pgTable('items', { line: line(), lineObj: line({ mode: 'abc' }), }); ```
sql
CREATE TABLE "items" (
	"line" line,
	"lineObj" line
);
</Section>

---

enum

enum enumerated types
Enumerated (enum) types are data types that comprise a static, ordered set of values. They are equivalent to the enum types supported in a number of programming languages. An example of an enum type might be the days of the week, or a set of status values for a piece of data.

For more info please refer to the official PostgreSQL docs.

<Section> ```typescript import { pgEnum, pgTable } from "drizzle-orm/pg-core";

export const moodEnum = pgEnum('mood', ['sad', 'ok', 'happy']);

export const table = pgTable('table', { mood: moodEnum(), });


```sql
CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');

CREATE TABLE "table" (
	"mood" mood
);
</Section>

---

Customizing data type

Every column builder has a .$type() method, which allows you to customize the data type of the column.

This is useful, for example, with unknown or branded types:

ts
type UserId = number & { __brand: 'user_id' };
type Data = {
	foo: string;
	bar: number;
};

const users = pgTable('users', {
  id: serial().$type<UserId>().primaryKey(),
  jsonField: json().$type<Data>(),
});

Identity Columns

<Callout type="info"> To use this feature you would need to have `[email protected]` or higher and `[email protected]` or higher </Callout>

PostgreSQL supports identity columns as a way to automatically generate unique integer values for a column. These values are generated using sequences and can be defined using the GENERATED AS IDENTITY clause.

Types of Identity Columns

  • GENERATED ALWAYS AS IDENTITY: The database always generates a value for the column. Manual insertion or updates to this column are not allowed unless the OVERRIDING SYSTEM VALUE clause is used.
  • GENERATED BY DEFAULT AS IDENTITY: The database generates a value by default, but manual values can also be inserted or updated. If a manual value is provided, it will be used instead of the system-generated value.

Key Features

  • Automatic Value Generation: Utilizes sequences to generate unique values for each new row.
  • Customizable Sequence Options: You can define starting values, increments, and other sequence options.
  • Support for Multiple Identity Columns: PostgreSQL allows more than one identity column per table.

Limitations

  • Manual Insertion Restrictions: For columns defined with GENERATED ALWAYS AS IDENTITY, manual insertion or updates require the OVERRIDING SYSTEM VALUE clause.
  • Sequence Constraints: Identity columns depend on sequences, which must be managed correctly to avoid conflicts or gaps.

Usage example

ts
import { pgTable, integer, text } from 'drizzle-orm/pg-core' 

export const ingredients = pgTable("ingredients", {
  id: integer().primaryKey().generatedAlwaysAsIdentity({ startWith: 1000 }),
  name: text().notNull(),
  description: text(),
});

You can specify all properties available for sequences in the .generatedAlwaysAsIdentity() function. Additionally, you can specify custom names for these sequences

PostgreSQL docs reference.

Default value

The DEFAULT clause specifies a default value to use for the column if no value is explicitly provided by the user when doing an INSERT. If there is no explicit DEFAULT clause attached to a column definition, then the default value of the column is NULL.

An explicit DEFAULT clause may specify that the default value is NULL, a string constant, a blob constant, a signed-number, or any constant expression enclosed in parentheses.

<Section> ```typescript import { sql } from "drizzle-orm"; import { integer, pgTable, uuid } from "drizzle-orm/pg-core";

const table = pgTable('table', { integer1: integer().default(42), integer2: integer().default(sql'42'::integer), uuid1: uuid().defaultRandom(), uuid2: uuid().default(sqlgen_random_uuid()), });


```sql
CREATE TABLE "table" (
	"integer1" integer DEFAULT 42,
	"integer2" integer DEFAULT '42'::integer,
	"uuid1" uuid DEFAULT gen_random_uuid(),
	"uuid2" uuid DEFAULT gen_random_uuid()
);
</Section>

When using $default() or $defaultFn(), which are simply different aliases for the same function, you can generate defaults at runtime and use these values in all insert queries.

These functions can assist you in utilizing various implementations such as uuid, cuid, cuid2, and many more.

<Callout type="info" emoji="ℹ️"> Note: This value does not affect the `drizzle-kit` behavior, it is only used at runtime in `drizzle-orm` </Callout>
ts
import { text, pgTable } from "drizzle-orm/pg-core";
import { createId } from '@paralleldrive/cuid2';

const table = pgTable('table', {
	id: text().$defaultFn(() => createId()),
});

When using $onUpdate() or $onUpdateFn(), which are simply different aliases for the same function, you can generate defaults at runtime and use these values in all update queries.

Adds a dynamic update value to the column. The function will be called when the row is updated, and the returned value will be used as the column value if none is provided. If no default (or $defaultFn) value is provided, the function will be called when the row is inserted as well, and the returned value will be used as the column value.

<Callout type="info" emoji="ℹ️"> Note: This value does not affect the `drizzle-kit` behavior, it is only used at runtime in `drizzle-orm` </Callout>
ts
import { integer, timestamp, text, pgTable } from "drizzle-orm/pg-core";

const table = pgTable('table', {
	updateCounter: integer().default(sql`1`).$onUpdateFn((): SQL => sql`${table.update_counter} + 1`),
	updatedAt: timestamp({ mode: 'date', precision: 3 }).$onUpdate(() => new Date()),
    	alwaysNull: text().$type<string | null>().$onUpdate(() => null),
});

Not null

NOT NULL constraint dictates that the associated column may not contain a NULL value.

<Section> ```typescript import { integer, pgTable } from "drizzle-orm/pg-core";

const table = pgTable('table', { integer: integer().notNull(), });


```sql
CREATE TABLE "table" (
	"integer" integer NOT NULL
);
</Section>

Primary key

A primary key constraint indicates that a column, or group of columns, can be used as a unique identifier for rows in the table. This requires that the values be both unique and not null.

<Section> ```typescript import { serial, pgTable } from "drizzle-orm/pg-core";

const table = pgTable('table', { id: serial().primaryKey(), });


```sql
CREATE TABLE "table" (
	"id" serial PRIMARY KEY NOT NULL
);
</Section>