Loading...
Loading...
Creates, deploys, and troubleshoots BigQuery User-Defined Functions (UDFs) and Remote Functions across SQL, JavaScript, Python, and Cloud Run endpoints. Use when writing custom scalar or aggregate functions in BigQuery, installing PyPI packages or Cloud Storage libraries in a Python or JavaScript UDF, or calling Google Cloud and external APIs from a Python UDF (WITH CONNECTION) or Remote Function. Don't use for standard BigQuery table/dataset CRUD (use bigquery-basics), DataFrames client workflows (use bigquery-bigframes), or BigQuery ML models (use bigquery-ai-ml).
npx skill4agent add google/skills bigquery-udfspython-3.11gcloudCLOUDSDK_METRICS_REQUEST_ATTRIBUTION="agent-skills/1.0 (skill:bigquery-udfs)" \
gcloud <command> [flags]gcloud config setcurlagent-skills/<version>skill:<name>User-Agent: <existing_user_agent> agent-skills/1.0 (skill:bigquery-udfs)| UDF Type | Connection Required? | When to Use | Key Constraints |
|---|---|---|---|
| SQL UDF (Default) | No | Composable expressions, regex, struct/array manipulation, aggregate functions ( | Lowest latency; zero external dependencies; supports |
| JavaScript UDF | No | Custom string/JSON logic or bundling | Runs in V8 sandbox; |
| Managed Python UDF (Offline) | No | Pure compute using Python 3.11, PyPI wheels ( | Persistent functions only ( |
Managed Python UDF ( | Yes ( | Invoking Google Cloud APIs (e.g., Cloud Translation, Gemini Enterprise Agent Platform) or online HTTP endpoints directly from Python inside BigQuery containers. | Requires |
Remote Function ( | Yes ( | Calling external APIs or microservices when you need non-Python runtimes (Go, Java, Node.js), private VPC network access, GPUs, or custom Cloud Run scaling. | Requires Cloud Run HTTPS endpoint implementing BigQuery JSON batch contract and |
gcloud auth login--project={project_id}--region={region}--locationbqgcloud config setus-central1bigquery.googleapis.comWITH CONNECTIONbigqueryconnection.googleapis.comrun.googleapis.comCLOUDSDK_METRICS_REQUEST_ATTRIBUTION="agent-skills/1.0 (skill:bigquery-udfs)" \
gcloud services enable bigquery.googleapis.com \
bigqueryconnection.googleapis.com \
run.googleapis.com --quietroles/bigquery.dataEditorroles/bigquery.jobUserWITH CONNECTIONroles/bigquery.connectionAdminresourcemanager.projects.setIamPolicyroles/resourcemanager.projectIamAdminGRANT ... ON PROJECTroles/bigquery.connectionUserCREATE OR REPLACE FUNCTIONCREATE TEMP FUNCTIONANY TYPECREATE OR REPLACE FUNCTION `{project_id}.{dataset_id}.normalize_phone`(
raw_phone STRING,
country_code ANY TYPE
)
RETURNS STRING
AS (
CONCAT('+', CAST(country_code AS STRING), '-', REGEXP_REPLACE(raw_phone, r'[^0-9]', ''))
);CREATE AGGREGATE FUNCTIONr"""..."""CREATE OR REPLACE FUNCTION `{project_id}.{dataset_id}.extract_url_query_keys`(
url_str STRING
)
RETURNS ARRAY<STRING>
DETERMINISTIC
LANGUAGE js
OPTIONS (
library = ['gs://{bucket_name}/libs/uri-parser.js']
)
AS r"""
if (!url_str) return [];
try {
return URIParser.getQueryKeys(url_str);
} catch (err) {
return [];
}
""";TEMPruntime_version = 'python-3.11'entry_pointnumpypandaspyarrowpython-3.11container_memory = '512Mi'container_cpu = 1.0container_request_concurrency = 80importdef {entry_point}(...)AS r'''...'''IndentationErrorWITH CONNECTIONpackages=[...]library=['gs://...']pd.DataFramepyarrow.RecordBatchpd.Series[!WARNING] Vectorized operations must be row-independent: BigQuery calls vectorized UDFs on arbitrary row batches (up to). Do NOT compute global column statistics (such as z-scores, dataset mean/std, or rank) acrossmax_batching_rows, because each batch only sees an arbitrary slice of rows. Use SQL window functions (df) for dataset-wide statistics. Vectorized Python UDFs should perform row-independent calculations (e.g. geometric distances or multi-column math).(val - AVG(val) OVER()) / NULLIF(STDDEV(val) OVER(), 0)
CREATE OR REPLACE FUNCTION `{project_id}.{dataset_id}.vectorized_distance`(
x1 FLOAT64, y1 FLOAT64, x2 FLOAT64, y2 FLOAT64
)
RETURNS FLOAT64
LANGUAGE python
OPTIONS (
runtime_version = 'python-3.11',
entry_point = 'compute_distance'
)
AS r'''
import numpy as np
import pandas as pd
def compute_distance(df: pd.DataFrame) -> pd.Series:
return pd.Series(
np.hypot(df['x2'] - df['x1'], df['y2'] - df['y1']),
index=df.index,
)
''';WITH CONNECTIONWITH CONNECTIONtry...exceptNULLgoogle.api_core.exceptions.TooManyRequestsServiceUnavailableDeadlineExceededInternalServerErrorRetryErrorlogging.warningNoneGoogleAPICallErrorPermissionDeniedUnauthenticatedInvalidArgumentRuntimeErrorNULLSET @@udf.properties = JSON '{"enableDebugOutput": true}';timeoutRetry(timeout=...)timeout=bq mk --connection --connection_type=CLOUD_RESOURCE \
--location={region} --project_id={project_id} {connection_id}
bq show --connection {project_id}.{region}.{connection_id}roles/serviceusage.serviceUsageConsumer{project_id}roles/cloudtranslate.userGRANT ... ON PROJECTresourcemanager.projects.setIamPolicyroles/resourcemanager.projectIamAdminconnection:[project_id.]location.connection_id"serviceAccount:{connection_sa_email}"GRANT `roles/serviceusage.serviceUsageConsumer`
ON PROJECT `{project_id}`
TO "connection:{project_id}.{region}.{connection_id}";
GRANT `roles/cloudtranslate.user`
ON PROJECT `{project_id}`
TO "connection:{project_id}.{region}.{connection_id}";WITH CONNECTIONCREATE OR REPLACE FUNCTION `{project_id}.{dataset_id}.translate_to_es`(
text STRING
)
RETURNS STRING
LANGUAGE python
WITH CONNECTION `{project_id}.{region}.{connection_id}`
OPTIONS (
entry_point = 'do_translate',
runtime_version = 'python-3.11',
packages = ['google-cloud-translate>=3.11', 'google-api-core']
)
AS r'''
import logging
from google.api_core import exceptions
from google.api_core.retry import Retry
from google.cloud import translate
client = translate.TranslationServiceClient()
TRANSIENT_ERRORS = (
exceptions.TooManyRequests,
exceptions.ServiceUnavailable,
exceptions.DeadlineExceeded,
exceptions.InternalServerError,
exceptions.RetryError,
)
def do_translate(text: str) -> str:
if not text:
return None
try:
# Note: Replace {project_id} with your Google Cloud Project ID
response = client.translate_text(
request={
"parent": "projects/{project_id}/locations/us-central1",
"contents": [text],
"target_language_code": "es",
"mime_type": "text/plain",
},
retry=Retry(timeout=30.0), # Total retry budget.
timeout=10.0, # Per-attempt deadline.
)
return response.translations[0].translated_text
except TRANSIENT_ERRORS as e:
# Log the error type only; never log row values.
logging.warning("Transient Translation API error: %s", type(e).__name__)
return None
except exceptions.GoogleAPICallError as e:
# PermissionDenied, Unauthenticated, InvalidArgument, etc. are fatal.
logging.error("Fatal Translation API error: %s: %s", type(e).__name__, e)
raise RuntimeError(f"Translation failed: {type(e).__name__}") from e
''';container_cpucontainer_memorycontainer_request_concurrencySET @@udf.properties = JSON '{"enableDebugOutput": true}';INFORMATION_SCHEMA.ROUTINESroles/run.invokerCLOUDSDK_METRICS_REQUEST_ATTRIBUTION="agent-skills/1.0 (skill:bigquery-udfs)" \
gcloud run services add-iam-policy-binding {cloud_run_service} \
--region={region} \
--member="serviceAccount:{connection_sa_email}" \
--role="roles/run.invoker"{"calls": [[arg1, ...], ...]}{"replies": [res1, ...]}CREATE OR REPLACE FUNCTION `{project_id}.{dataset_id}.enrich_address`(
street STRING, postal_code STRING
)
RETURNS JSON
REMOTE WITH CONNECTION `{project_id}.{region}.{connection_id}`
OPTIONS (
endpoint = 'https://{cloud_run_service_url}',
max_batching_rows = 1000
);packagespython3Nonepd.DataFramegcloud run jobs deploy {job_name} --source . --region={region}gcloud run jobs execute {job_name} --region={region} --waitCREATE OR REPLACE FUNCTIONINFORMATION_SCHEMA.ROUTINESbuild_stateIN_PROGRESSSUCCEEDEDFAILEDSELECT build_status.*
FROM `{project_id}.{dataset_id}`.INFORMATION_SCHEMA.ROUTINES
WHERE routine_name = '{udf_name}';SELECTbuild_state = 'SUCCEEDED'SELECTNULLbq query --use_legacy_sql=false "DROP FUNCTION IF EXISTS \`{project_id}.{dataset_id}.{udf_name}\`;"
bq rm --connection --location={region} {connection_id}
CLOUDSDK_METRICS_REQUEST_ATTRIBUTION="agent-skills/1.0 (skill:bigquery-udfs)" \
gcloud run services delete {cloud_run_service} --region={region} --project={project_id}
CLOUDSDK_METRICS_REQUEST_ATTRIBUTION="agent-skills/1.0 (skill:bigquery-udfs)" \
gcloud storage rm gs://{bucket_name}/udf_libs/bundle.jsANY TYPEhttps://docs.cloud.google.com/bigquery/docs/user-defined-functions.md.txtWITH CONNECTIONcontainer_cpucontainer_memoryhttps://docs.cloud.google.com/bigquery/docs/user-defined-functions-python.md.txthttps://docs.cloud.google.com/bigquery/docs/remote-functions.md.txtAuthorized Routinesbigquery-basics@bpd.udfML.GENERATE_TEXTAI.GENERATE