User-defined functions and table functions

BigQuery · Advanced · 12 min

UDFs capture reusable logic in one place instead of copy-pasting expressions across queries.

BigQuery has several kinds of user-defined routines.

SQL UDFs wrap an expression: CREATE TEMP FUNCTION f(x INT64) AS (x * 2);. A temporary UDF lives for one query or script; CREATE FUNCTION mydataset.f(...) makes a persistent one others can call as mydataset.f(...). SQL UDFs are inlined into the query plan and are fast. They can take and return ARRAYs and STRUCTs, and they can contain subqueries over UNNEST. Use ANY TYPE parameters for templated functions that accept any compatible type.

JavaScript UDFs (LANGUAGE js AS r""" ... """) handle logic that's awkward in SQL, and can import libraries from Cloud Storage. They run in a sandbox and are much slower than SQL; GoogleSQL types map to JavaScript types, and INT64 is not supported as a JS UDF return type because JavaScript numbers can't represent all 64-bit integers. Prefer SQL when you can.

Table-valued functions (TVFs) are parameterized views: CREATE TABLE FUNCTION ds.orders_since(d DATE) AS SELECT ... WHERE order_date >= d, then SELECT * FROM ds.orders_since('2025-06-01').

Remote functions call an HTTP endpoint on Cloud Run or Cloud Functions for each batch of rows, for example to call an ML API. User-defined aggregate functions (UDAFs) define custom aggregates in SQL or JavaScript.

Persistent routines live in datasets and use IAM. Sharing a dataset of UDFs is a clean way to standardize business logic.

Example

CREATE TEMP FUNCTION net_price(gross NUMERIC, vat NUMERIC) AS (
  ROUND(gross / (1 + vat), 2)
);

CREATE TEMP FUNCTION domain_of(email STRING) AS (
  LOWER(SPLIT(email, '@')[SAFE_OFFSET(1)])
);

CREATE TEMP FUNCTION title_case(s STRING)
RETURNS STRING
LANGUAGE js AS r"""
  return s.split(' ').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
""";

SELECT net_price(121, NUMERIC '0.21')   AS net,     -- 100
       domain_of('Ana@Example.COM')     AS domain,  -- example.com
       title_case('hello big query')    AS title;   -- Hello Big Query

Remember

  • SQL UDFs are inlined and fast; temporary or persistent in a dataset
  • JavaScript UDFs are flexible but much slower
  • Table functions are parameterized views; remote functions call HTTP endpoints

Watch out for

  • Reaching for a JavaScript UDF for logic that plain SQL functions can express.

Check yourself

  1. Which UDF kind generally performs best?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.cloud.google.com/bigquery/docs/user-defined-functions