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']

// Find products with BOTH 'electronics' AND 'featured'
{ where: { tags: { contains: ['electronics', 'featured'] } } }
// SQL: "tags"::text[] @> ARRAY['electronics', 'featured']::text[]

// Single element
{ where: { tags: { contains: ['featured'] } } }
// Matches: ['featured'], ['featured', 'sale'], ['a', 'featured', 'b']

containedBy (<@)

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

typescript
// Find products where ALL tags are in the allowed list
{ where: { tags: { containedBy: ['sale', 'featured', 'new', 'popular'] } } }
// SQL: "tags"::text[] <@ ARRAY['sale', 'featured', 'new', 'popular']::text[]

// Product A ['featured', 'sale'] -> matches (all in list)
// Product B ['featured', 'clearance'] -> no match ('clearance' not in list)
// Product C [] -> matches (empty is subset of everything)

overlaps (&&)

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

typescript
// Find products with 'premium' OR 'sale' tag
{ where: { tags: { overlaps: ['premium', 'sale'] } } }
// SQL: "tags"::text[] && ARRAY['premium', 'sale']::text[]

// Product A ['featured', 'sale'] -> matches (has 'sale')
// Product B ['premium', 'luxury'] -> matches (has 'premium')
// Product C ['new', 'featured'] -> no match (no overlap)

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

Empty Array Behavior

OperatorEmpty Value []Behavior
contains: []Returns ALL rowsEverything contains empty set
containedBy: []Returns only rows with empty arraysOnly [] is subset of []
overlaps: []Returns NO rowsNothing overlaps with empty

Type Handling

String Arrays (varchar[], text[], char[]):

typescript
{ where: { tags: { contains: ['a', 'b'] } } }
// SQL: "tags"::text[] @> ARRAY['a', 'b']::text[]

Numeric Arrays (integer[], numeric[]):

typescript
{ where: { scores: { contains: [100, 200] } } }
// SQL: "scores" @> ARRAY[100, 200]

Boolean Arrays:

typescript
{ where: { flags: { contains: [true, false] } } }
// SQL: "flags" @> ARRAY[true, false]

Defining Array Columns

In your Drizzle schema:

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

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

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