Skip to content

PostgreSQL Array Operators ​

Operators for PostgreSQL array columns (varchar[], text[], integer[], etc.).

OperatorPostgreSQLDescription
contains@>Array contains ALL specified elements
containedBy<@Array is a subset of specified elements
overlaps&&Array shares ANY element with specified

contains (@>) ​

Find rows where the array column contains all specified elements.

typescript
// Schema: tags varchar(100)[]
// Data: Product A has ['electronics', 'featured', 'sale']

{ where: { tags: { contains: ['electronics', 'featured'] } } }
// SQL: "tags"::text[] @> ARRAY['electronics', 'featured']::text[]

NOTE

A single value is wrapped in an array automatically: { contains: 'featured' } is treated as { contains: ['featured'] }.

containedBy (<@) ​

Find rows where all array elements are within the specified set.

typescript
{ where: { tags: { containedBy: ['sale', 'featured', 'new', 'popular'] } } }
// SQL: "tags"::text[] <@ ARRAY['sale', 'featured', 'new', 'popular']::text[]

NOTE

An empty array is a subset of every set, so tags: [] always matches containedBy.

overlaps (&&) ​

Find rows where the arrays share at least one common element.

typescript
{ where: { tags: { overlaps: ['premium', 'sale'] } } }
// SQL: "tags"::text[] && ARRAY['premium', 'sale']::text[]

Visual Comparison ​

Producttagscontains ['featured']containedBy ['a','b','featured']overlaps ['sale','premium']
A['featured', 'sale']YesNo (has 'sale')Yes (has 'sale')
B['featured']YesYesNo
C['a', 'b']NoYesNo
D['premium']NoNoYes (has 'premium')
E[]NoYes (empty subset)No

Decision Guide ​

QuestionUse
"Must have ALL these tags"contains
"Tags must only be from this list"containedBy
"Must have AT LEAST ONE of these tags"overlaps

Type Handling ​

The element type of the array column decides the cast in the generated SQL.

typescript
// String arrays (varchar[], text[], char[]) - both sides cast to text[]
{ where: { tags: { contains: ['a', 'b'] } } }
// SQL: "tags"::text[] @> ARRAY['a', 'b']::text[]

// Numeric arrays (integer[], numeric[]) - no cast needed
{ where: { scores: { contains: [100, 200] } } }
// SQL: "scores" @> ARRAY[100, 200]

// Boolean arrays - no cast needed
{ where: { flags: { contains: [true, false] } } }
// SQL: "flags" @> ARRAY[true, false]

Empty Array Behavior ​

OperatorSQL generatedBehavior
contains: []WHERE trueReturns ALL rows
containedBy: []WHERE "col" = '{}'Returns only rows with empty arrays
overlaps: []WHERE falseReturns NO rows

Security: Parameterized Values ​

Every element of contains/containedBy/overlaps is bound as a query parameter - only the operator token (@>/<@/&&) is raw SQL. See The Hardening Round for the prior injection this closed.

Defining Array Columns ​

typescript
import { pgTable, text, varchar, integer } from 'drizzle-orm/pg-core';

export const productTable = pgTable('Product', {
  id: text('id').primaryKey(),
  name: text('name').notNull(),

  tags: varchar('tags', { length: 100 }).array(),      // varchar(100)[]
  categories: text('categories').array(),              // text[]
  scores: integer('scores').array(),                   // integer[]
});

See also ​

Files: