ServicesAboutNotesContact Get in touch →
EN FR
Note

dbt-utils v1.0 Migration: What Moved to dbt-core

The complete list of macros that moved from dbt-utils to the dbt namespace at v1.0, what was removed entirely, and how to migrate an existing project.

Planted
dbtdata engineering

The biggest change in dbt-utils history happened with v1.0. Every cross-database macro — dates, strings, type casting, aggregations, set operations — was removed from dbt_utils and moved to the dbt namespace in dbt-core. If your project still calls dbt_utils.datediff(), you’re calling a path that no longer exists in v1.x.

This isn’t an academic concern. A codebase migrating from dbt-utils 0.x to 1.x will break on first run without updating these calls.

What Moved to dbt-core

All of these moved to dbt.* and no longer exist in dbt_utils.*:

Date and time: dateadd, datediff, date_trunc, last_day, current_timestamp

String: concat, length, position, replace, right, split_part, string_literal, escape_single_quotes

Type casting: safe_cast, cast (dbt v1.8+), type_bigint, type_float, type_int, type_numeric, type_string, type_timestamp

Aggregation: any_value, bool_or, listagg

Set operations: except, intersect

Other: hash, cast_bool_to_text, array_append, array_concat, array_construct (dbt-core 1.3+), date (dbt v1.8+)

The full reference for these is in dbt Built-In Cross-Database Macros.

What Was Removed Entirely

A handful of dbt-utils macros were removed without a replacement in dbt-core — they either became obsolete or were absorbed into native dbt functionality:

  • surrogate_key() → replaced by generate_surrogate_key(). These are not drop-in compatible: null handling changed. See dbt-utils generate_surrogate_key for the gotcha.
  • unique_where and not_null_where tests → the native where config on built-in unique and not_null tests handles this now. Use config.where instead.
  • insert_by_period materialization → moved to the experimental-features repository. Not part of dbt-utils anymore.
  • condition argument on expression_is_true → replaced by the native where config on the test. Any test YAML using condition: needs updating.

How to Migrate

Step 1: Update dbt-utils to v1.x in your packages.yml.

packages:
- package: dbt-labs/dbt_utils
version: [">=1.0.0", "<2.0.0"]

Step 2: Find all dbt_utils cross-database macro calls.

Search your project for dbt_utils.dateadd, dbt_utils.datediff, dbt_utils.date_trunc, dbt_utils.concat, dbt_utils.safe_cast, and the rest of the moved list. A global find-and-replace handles most cases. The function signatures are identical — only the namespace changes.

Before: {{ dbt_utils.dateadd('day', 7, 'order_date') }}
After: {{ dbt.dateadd('day', 7, 'order_date') }}

Step 3: Handle surrogate_key() if you used it.

If your project used the old surrogate_key() macro and you’re upgrading, add this to dbt_project.yml first to preserve backward-compatible null handling:

vars:
surrogate_key_treat_nulls_as_empty_strings: true

Without this, null values hash differently in generate_surrogate_key(), which changes surrogate key values for rows with nulls. This breaks incremental models and snapshots that used the old key. See dbt-utils generate_surrogate_key for the full explanation.

Step 4: Update any tests using condition: argument.

If you have expression_is_true tests with a condition: argument, replace with the native where config:

# Before (v0.x)
- dbt_utils.expression_is_true:
expression: "invoice__total >= invoice__tax"
condition: "status != 'voided'"
# After (v1.x)
- dbt_utils.expression_is_true:
expression: "invoice__total >= invoice__tax"
config:
where: "status != 'voided'"

Step 5: Update deduplicate calls if you used group_by.

The group_by argument was renamed to partition_by in v1.0. The relation_alias argument was removed. And order_by is now mandatory — pass 1 if you don’t care about ordering.

What Stayed in dbt-utils

After the migration, dbt-utils still owns: SQL generators (date_spine, deduplicate, star, union_relations, generate_surrogate_key, pivot, unpivot), introspective macros (get_column_values, get_relations_by_pattern, get_query_results_as_dict), generic tests, and web macros. See the dbt-utils Hub for the full current scope.

Why This Migration Happened

The cross-database macros lived in dbt-utils because when they were written, dbt-core had no standard mechanism for adapter-specific SQL. Once dbt-core built out adapter.dispatch() as a first-class feature, it made sense to move the universal functions into core where every project can use them without installing a package.

From a maintenance perspective, it also means cross-database function fixes now land in dbt-core releases, which ship more frequently and with broader testing coverage than any community package.

If you’re on a non-standard adapter like Databricks, you may still need spark_utils in your dispatch configuration for macros that dbt-core doesn’t cover. See dbt Dispatch Configuration for how to wire that up.