Remote functions in BigQuery
A remote function calls your own Cloud Run service from SQL, sending rows in batches as JSON. Results are never cached, requests can repeat, ARRAY and STRUCT arguments aren't supported, and a project runs at most 10 such queries at once.
A remote function is a SQL function whose body runs outside BigQuery, in a Cloud Run service or Cloud Run function that you deploy. You call it like any other function, and BigQuery sends the arguments over HTTP in batches. Use one when the logic needs something SQL and JavaScript UDFs can’t do: a private API, a library in another language, or a model served elsewhere.
How a call works
- You deploy an HTTP endpoint on Cloud Run or Cloud Run functions.
- You create a connection of type
CLOUD_RESOURCEin BigQuery and give its service account permission to invoke the endpoint. - You create the function:
CREATE FUNCTION mydataset.risk_score(customer_id STRING, amount NUMERIC)
RETURNS FLOAT64
REMOTE WITH CONNECTION `myproject.us.my-connection`
OPTIONS (
endpoint = 'https://risk-score-abc123-uc.a.run.app',
max_batching_rows = 500,
user_defined_context = [('model', 'v3')]
);
SELECT order_id, mydataset.risk_score(customer_id, amount) AS risk
FROM mydataset.orders
WHERE order_date = '2026-03-02';
For each batch of rows, BigQuery sends one POST request with a JSON body. calls holds one argument list per row, and the endpoint must answer with replies holding exactly one value per call, in the same order:
{
"requestId": "124ab1c",
"caller": "//bigquery.googleapis.com/projects/myproject/jobs/myproject:US.bquxjob_...",
"sessionUser": "[email protected]",
"userDefinedContext": {"model": "v3"},
"calls": [["c-17", "120.5"], ["c-42", "9.99"]]
}
{"replies": [0.12, 0.87]}
Values are encoded the way TO_JSON_STRING encodes them, so a NUMERIC with a fraction ("120.5") and an INT64 beyond ±2^53 arrive as JSON strings. Parse them as decimals or big integers, not as floats. See JSON.
max_batching_rows caps the rows per request. Without it, BigQuery chooses. Lower it when your endpoint is slow per row and requests time out.
Rules that affect your endpoint
- Requests can repeat. BigQuery retries after network or internal errors, even after your endpoint answered successfully. Make the endpoint idempotent: the same input must give the same output and must not, for example, send an email twice.
- Retries on 408, 429, 500, 503 and 504. For an error that won’t go away on retry (bad input), return another status code and a JSON body with
errorMessage; BigQuery puts that message in the query’s error. Catch exceptions yourself, since an uncaught one usually becomes a 500 and gets retried. - No batching in conditional branches. When BigQuery skips the function for some rows, as in
IF,CASEor aMERGEWHENclause, it sends each call in its own request. Calls inside aCASEcan be much slower. - Never cached. BigQuery treats remote functions as non-deterministic, so a query that calls one never uses the query cache.
Types and limits
| Limit | Value |
|---|---|
| Argument and return types | BOOL, BYTES, numeric types, STRING, DATE, DATETIME, TIME, TIMESTAMP, JSON |
| Not supported | ARRAY, STRUCT, INTERVAL, GEOGRAPHY (pass them as JSON with TO_JSON) |
| Input size per row | 5 MB for all arguments together |
| Queries with remote functions running at once | 10 per project |
| Table functions, materialized views | can’t be remote / can’t call remote functions |
Cost and speed
The query is billed as usual, and Cloud Run bills separately for the requests. Each row that reaches the function is an HTTP round trip shared with the rest of its batch, so the cheapest and fastest remote function call is the one you don’t make:
- Filter rows before the call, in
WHEREor a CTE, rather than calling the function on everything and filtering its result. - Call it once per distinct value: compute the function over
SELECT DISTINCT customer_id, then join the result back. - Set a maximum instance count on the service that matches what the backend behind it can take. BigQuery can send many requests in parallel.
Alternatives
- Logic that fits in SQL: a SQL UDF, the fastest option.
- Pure computation in code: a JavaScript or Python UDF, which runs inside BigQuery without a service to deploy.
- Calling a Vertex AI model: the built-in
AI.andML.functions use a connection in the same way without your own endpoint. See Generative AI functions.