For the complete documentation index, see llms.txt. This page is also available as Markdown.

Handling null and undefined values in where conditions

In 'WHERE' conditions the values null and undefined are not strictly valid values in TypeORM.

Passing a known null value is disallowed by TypeScript (when you've enabled strictNullChecks in tsconfig.json) at compile time. The default behavior is for null and undefined values encountered at runtime to throw an error.

The way in which null and undefined values are handled can be customised through the invalidWhereValuesBehavior configuration option in your data source options. This applies to high-level operations such as find operations, repository methods, and EntityManager methods (update, delete, softDelete, restore).

:::warning This setting does not affect QueryBuilder's .where(), .andWhere(), or .orWhere() methods. QueryBuilder is a low-level API where null/undefined values pass through as-is. Use the IsNull() operator or parameterized conditions in QueryBuilder for explicit null handling. :::

Default Behavior

By default, TypeORM throws an error when null or undefined values are encountered in where conditions. This prevents unexpected results and helps catch potential bugs early:

// Both queries will throw an error
const posts1 = await repository.find({
    where: {
        text: null,
    },
})
// Error: Null value encountered in property 'text' of a where condition.

const posts2 = await repository.find({
    where: {
        text: undefined,
    },
})
// Error: Undefined value encountered in property 'text' of a where condition.

To match null values in where conditions, use the IsNull operator (for details see Find Options):

Configuration

You can customize how null and undefined values are handled using the invalidWhereValuesBehavior option in your data source configuration:

Null Behavior Options

The null behavior can be set to one of three values:

'ignore'

JavaScript null values in where conditions are ignored and the property is skipped:

'sql-null'

JavaScript null values are transformed into SQL NULL conditions:

'throw' (default)

JavaScript null values cause a TypeORMError to be thrown:

Undefined Behavior Options

The undefined behavior can be set to one of two values:

'ignore'

JavaScript undefined values in where conditions are ignored and the property is skipped:

'throw' (default)

JavaScript undefined values cause a TypeORMError to be thrown:

Note that this only applies to explicitly set undefined values, not omitted properties.

Using Both Options Together

You can configure both behaviors independently for comprehensive control:

This configuration will:

  1. Transform JavaScript null values to SQL NULL in where conditions

  2. Throw an error if any undefined values are encountered

  3. Still ignore properties that are not provided in the where clause

This combination is useful when you want to:

  • Be explicit about searching for NULL values in the database

  • Catch potential programming errors where undefined values might slip into your queries

Supported operations

The invalidWhereValuesBehavior configuration applies to high-level TypeORM operations, not QueryBuilder's direct .where() method:

Find Operations

Repository and EntityManager Methods

:::warning Empty criteria are rejected. update, delete, softDelete, and restore require non-empty criteria β€” an empty condition would render as WHERE 1=1 and affect every row. Because "ignore" strips null/undefined properties, a criteria whose keys are all stripped becomes empty. In that case the operation is rejected instead of running as an unfiltered write:

Use the dedicated updateAll() / deleteAll() methods when you intentionally want to affect every row. :::

Only plain-object criteria is normalized

invalidWhereValuesBehavior normalizes plain FindOptionsWhere objects only. Any other criteria value passed to update / delete / softDelete / restore β€” an entity class instance, a FindOperator, an array, a Date, a Buffer, or a primitive id β€” is passed through untouched and is not validated. So an entity instance whose nullable column is null renders as col = NULL (matching nothing), rather than throwing/converting. If you need null handling, pass a plain object with the IsNull() operator (e.g. { text: IsNull() }).

Deep validation of entity-instance criteria requires entity metadata and is out of scope here; use a plain FindOptionsWhere object when you want invalidWhereValuesBehavior applied.

QueryBuilder with setFindOptions

Not affected: QueryBuilder .where()

QueryBuilder's .where(), .andWhere(), and .orWhere() are low-level APIs and are not affected by this setting. Null and undefined values pass through as-is:

How null and undefined behave in QueryBuilder .where()

Since QueryBuilder is a low-level API, null and undefined values are not validated or transformed. Understanding their behavior is important to avoid unexpected results.

null in QueryBuilder .where()

When null is passed as a value in an object-style .where(), it generates a SQL equality check against NULL:

In SQL, column = NULL is always false β€” nothing equals NULL. This query will return zero results, which is almost certainly not what you intended. To match NULL values, use the IsNull() operator:

Or use a string condition:

undefined in QueryBuilder .where()

When undefined is passed as a value, the same behavior applies β€” it generates WHERE column = NULL, which is always false:

Summary table

Value

High-level API (find/repository/manager)

QueryBuilder .where()

null with "ignore"

Property skipped β€” no filter

WHERE col = NULL β€” zero results

null with "sql-null"

WHERE col IS NULL

WHERE col = NULL β€” zero results

null with "throw" (default)

Throws error

WHERE col = NULL β€” zero results

undefined with "ignore"

Property skipped β€” no filter

WHERE col = NULL β€” zero results

undefined with "throw" (default)

Throws error

WHERE col = NULL β€” zero results

IsNull()

WHERE col IS NULL

WHERE col IS NULL

:::tip Always use IsNull() when you want to match SQL NULL values, regardless of which API you use. It works correctly in both high-level and QueryBuilder contexts. :::

Last updated