What you will be able to do
- Name the four components of an external function (external function, remote service, proxy service, API integration) and say what each one does
- Trace one external function call from the SQL statement to the remote service and back, including the JSON batch format
- Write a CREATE EXTERNAL FUNCTION statement and pick the right optional parameters
- Spot the places where an external function cannot be used, and design a remote service that handles batching and retries
Key concept
External function — An external function is a UDF that holds no code of its own. It is a Snowflake object that stores where to send each row and how to authenticate. The work itself runs in a remote service outside Snowflake, which Snowflake reaches through a cloud proxy service.
1.Four pieces: function, proxy, remote service, integration
An external function is a kind of UDF, but it has no handler code. Inside Snowflake it is a database object in a specific database and schema. It stores what Snowflake needs to reach the code, including the URL of the proxy service. Three other pieces sit around it. The remote service is the code that does the work. It must behave like a function and return a value. It must accept JSON input, return JSON output and expose an HTTPS endpoint. It can be an AWS Lambda function, a Microsoft Azure Function, or an HTTPS server such as Node.js on an EC2 instance. The proxy service relays requests and responses between Snowflake and the remote service. It can also authenticate requests and support subscription billing. The API integration is a Snowflake object that holds the security information needed to work with the proxy.
| Component | Where it lives | Role | Examples |
|---|---|---|---|
| External function | Snowflake database and schema | Stores the proxy URL and the API integration to use; called like any UDF | my_database.my_schema.my_external_function |
| Proxy service | Cloud provider | Relays data to and from the remote service; can authenticate callers and enforce paid subscriptions | Amazon API Gateway, Microsoft Azure API Management service |
| Remote service | Outside Snowflake | Executes the code; accepts JSON, returns JSON, exposes an HTTPS endpoint | AWS Lambda function, Microsoft Azure Function, HTTPS server on EC2 |
| API integration | Snowflake (created with CREATE API INTEGRATION) | Stores security information for the proxy or remote service | — |
Why choose this over an ordinary UDF? The remote code can be written in languages internal UDFs don't support, such as Go and C#. It can use libraries an internal UDF can't reach, such as commercial machine-learning scoring libraries. The same service can also be called from software outside Snowflake. The cost is setup: before the first call, an administrator has to configure the cloud platform, and that work needs knowledge of the platform's security.
Checkpoint 1 of 7· Match them up
Match each component to its job
Tap a term, then the definition that fits it.
Each component has one job. Security information goes in the API integration, relaying is done by the proxy, the code runs in the remote service, and the external function is what SQL calls.
“Snowflake stores security-related external function information in an API integration.”Source: docs.snowflake.com
Sources1
2.One call, end to end: POST, batches and JSON rows
While a query runs, Snowflake reads two things: the external function definition, which gives the proxy URL and the name of the API integration, and the API integration itself, which gives the proxy resource and its authentication details. Snowflake then builds an HTTP POST containing the data as JSON, HTTP headers and the integration's authentication information, and sends it to the proxy. The proxy forwards the request to the remote service. The result travels back the same way to the SQL statement. If the remote service replies with a status code that means 'still processing', Snowflake polls with HTTP GET requests until it gets the result, the call times out or an error comes back.
Checkpoint 2 of 7· Put it in order
Put the steps of an external function call in order
- 1.Snowflake sends an HTTP POST with JSON data, headers and authentication to the proxy service
- 2.The remote service returns the result back through the chain to the SQL statement
- 3.A client program sends Snowflake a SQL statement that calls the external function
- 4.The proxy service forwards the request to the remote service
- 5.Snowflake reads the external function definition and the corresponding API integration
Snowflake resolves the definition and integration first, POSTs to the proxy, and only the proxy calls the remote service.
“The proxy service receives the POST and then processes and forwards the request to the actual remote service.”Source: docs.snowflake.com
Rows go out in batches. Batching allows more parallelism and can keep the remote service from being overloaded. Each batch has a unique batch ID, and retries usually happen one batch at a time. The POST body is a JSON object with a single key, data. Its value is an array with one entry per row. The first element of each row is the row number, and the function arguments follow.
{ "data": [ [0, 10, "Alex", "2014-01-01 16:00:00"], [1, 20, "Steve", "2015-01-01 16:00:00"], [2, 30, "Alice", "2016-01-01 16:00:00"], [3, 40, "Adrian", "2017-01-01 16:00:00"] ] }The response uses the same shape. It returns one row per input row, each holding a row number and exactly one value. The value can be compound, such as an OBJECT. The row numbers must match the request and come back in the same order. Snowflake also sends headers such as sf-external-function-current-query-id, for linking calls back to Snowflake queries, and sf-external-function-query-batch-id.
{
"data":
[
[ 0, { "City" : "Warsaw", "latitude" : 52.23, "longitude" : 21.01 } ],
[ 1, { "City" : "Toronto", "latitude" : 43.65, "longitude" : -79.38 } ]
]
}| Code | Meaning to Snowflake |
|---|---|
| 200 | Batch processed successfully |
| 202 | Batch received and still being processed; Snowflake polls with GET |
| Any other value | Treated as an error |
Checkpoint 3 of 7· Check yourself
In the JSON request Snowflake sends, what is the first element of each row array?
Every row starts with its row number within the batch. The arguments come after it. The batch ID and query ID travel in HTTP headers.
“The first column is always the row number (i.e. the 0-based index of the row within the batch).”Source: docs.snowflake.com
3.Writing CREATE EXTERNAL FUNCTION
The DDL has three parts. The first is the signature: name, arguments and RETURNS type. The arguments should match what the remote service expects. The second is API_INTEGRATION, which names the integration used to authenticate to the proxy. The third is AS, the invocation URL of the proxy and resource. Everything else is optional. Because functions are resolved by name and argument types, external functions can be overloaded. CREATE OR ALTER EXTERNAL FUNCTION updates an existing function in place.
CREATE [ OR REPLACE ] [ SECURE ] EXTERNAL FUNCTION <name> ( [ <arg_name> <arg_data_type> ] [ , ... ] )
RETURNS <result_data_type>
[ [ NOT ] NULL ]
[ { CALLED ON NULL INPUT | { RETURNS NULL ON NULL INPUT | STRICT } } ]
[ { VOLATILE | IMMUTABLE } ]
[ COMMENT = '<string_literal>' ]
API_INTEGRATION = <api_integration_name>
[ HEADERS = ( '<header_1>' = '<value_1>' [ , '<header_2>' = '<value_2>' ... ] ) ]
[ CONTEXT_HEADERS = ( <context_function_1> [ , <context_function_2> ...] ) ]
[ MAX_BATCH_ROWS = <integer> ]
[ COMPRESSION = <compression_type> ]
[ REQUEST_TRANSLATOR = <request_translator_udf_name> ]
[ RESPONSE_TRANSLATOR = <response_translator_udf_name> ]
AS '<url_of_proxy_and_resource>';| Parameter | Default | What to know |
|---|---|---|
| CALLED ON NULL INPUT / RETURNS NULL ON NULL INPUT (STRICT) | CALLED ON NULL INPUT | STRICT skips the call and returns NULL if any input is NULL |
| VOLATILE / IMMUTABLE | VOLATILE | Snowflake does not check IMMUTABLE; set it explicitly |
| HEADERS | none | Constant strings sent as sf-custom-<name>; no underscores in names; total 8 KB or less |
| CONTEXT_HEADERS | none | Context function results such as CURRENT_ROLE() sent as sf-context-<name>, plus a -base64 copy |
| MAX_BATCH_ROWS | Snowflake estimates | A maximum for constrained services, not a tuning knob |
Two defaults catch people out. VOLATILE is the default, and Snowflake doesn't verify IMMUTABLE: if you mark a non-deterministic service IMMUTABLE, the behaviour is undefined. Snowflake therefore recommends always setting the option explicitly. MAX_BATCH_ROWS exists only for remote services with memory or similar limits. Leave it unset unless the service needs a cap. If calls time out while every component looks healthy, one documented step is to try a smaller batch size.
Checkpoint 4 of 7· Check yourself
You define HEADERS = ( 'volume-measure' = 'liters' ). Which HTTP header does the remote service receive?
Snowflake adds the sf-custom- prefix to custom header names. The sf-context- prefix is used only for CONTEXT_HEADERS.
“This causes Snowflake to add two HTTP headers to every HTTPS request: sf-custom-volume-measure and sf-custom-distance-measure”Source: docs.snowflake.com
Checkpoint 5 of 7· Exam question
A data engineer used ACCOUNTADMIN to create an API integration named `address_api_integration` that points to a third-party address validation service. An analyst role now needs to run `CREATE EXTERNAL FUNCTION` bound to that integration, but the statement fails with an insufficient privileges error. What should the engineer grant to let the analyst role create the function without over-provisioning access?
Correct answer: A — Grant the USAGE privilege on `address_api_integration` to the analyst role so it can bind a new external function to that specific integration object.
- A. The USAGE privilege on an API integration is exactly what lets a role reference that integration when creating an external function, without handing over broader control of the object. This is the least-privilege fix for the failing statement.
- B. Ownership transfers control of the integration's configuration, including its proxy URL restrictions and credentials, which is far more access than is needed just to create a function that uses it.
- C. The account-level privilege to create integrations lets a role register brand-new API integration objects; it does nothing to authorize use of the existing `address_api_integration` object.
- D. Task execution privilege controls whether scheduled tasks can run, which is unrelated to the privilege check that blocks `CREATE EXTERNAL FUNCTION` from referencing an API integration.
Sources3
4.Calling it from SQL, and where it can't go
To a SQL user, an external function looks like any other UDF. It takes parameters, returns a value (which can be a VARIANT holding JSON), and can be nested inside larger expressions. You call it by its fully qualified name.
select my_database.my_schema.my_external_function(col1) from table1;The limits are what the exam tests. External functions must be scalar: one value per input row. Only functions can be built this way, not stored procedures. They can't be shared through Secure Data Sharing, and neither can any shared object that uses one, such as a shared view. They can't be used in a CREATE TABLE DEFAULT clause or in a COPY transformation. A batch response can be at most 10MB. Because the optimizer can't see inside the remote service, external functions carry more overhead than built-in functions or internal UDFs and usually run more slowly.
The remote service also has to be designed for how Snowflake calls it. Batch sizes, the order of batches and the order of rows within a batch can all vary. ORDER BY is usually applied after the external function runs. So each row's result must depend only on that row. Snowflake retries on transient network errors, 429 responses and 5XX responses, so the service may see the same row more than once. A retried batch keeps its batch ID, which makes the ID usable as an idempotency token.
Checkpoint 6 of 7· Check yourself
Which use of an external function is supported?
An external function can go in any clause where a UDF can go, views included. DEFAULT clauses, COPY transformations and objects shared through Secure Data Sharing are listed as unsupported.
“An external function can appear in any clause of a SQL statement in which other types of UDF can appear.”Source: docs.snowflake.com
Checkpoint 7 of 7· Exam question
A security reviewer is auditing an AWS-hosted external function. The Lambda proxy is fronted by an IAM role, and the reviewer wants to be certain that only this specific Snowflake account's integration can assume that role, not any other AWS API Gateway caller who discovers the role's ARN. Which mechanism enforces that requirement?
Correct answer: A — The IAM role's trust policy should require the integration's `API_AWS_IAM_USER_ARN` and `API_AWS_EXTERNAL_ID`, which blocks any unrelated caller from assuming that role.
- A. Requiring both the Snowflake-generated IAM user ARN and the unique external ID in the trust policy is the documented defense against the confused-deputy problem, ensuring only this integration's designated principal can assume the role.
- B. Checksum comparison on the request body addresses payload tampering, not the identity of who is allowed to assume the AWS IAM role in the first place, so it does not close this gap.
- C. Throttling limits protect the proxy from excessive call volume but do not verify the identity of the caller, so an unrelated party could still assume the role within the rate limit.
- D. A network policy on the Snowflake account restricts which clients can connect to Snowflake itself; it has no effect on who can assume an IAM role on the AWS side of the proxy.
Exam traps
Each one states something that sounds right. Open it to see what is actually true.
1.Set MAX_BATCH_ROWS to make an external function run faster.Why is that wrong?
MAX_BATCH_ROWS is a ceiling for remote services with memory or similar limits. If you leave it unset, Snowflake picks the batch size.
Covered in Writing CREATE EXTERNAL FUNCTION
2.An external function can enrich rows inside a COPY INTO transformation while loading.Why is that wrong?
COPY transformations are on the list of places where external functions can't be used, along with DEFAULT clauses and shared objects.
Covered in Calling it from SQL, and where it can't go
3.The remote service receives each row exactly once, in ORDER BY order.Why is that wrong?
Snowflake may retry a batch, so a row can arrive more than once. Batch and row order can vary, so each row should be processed independently.
Covered in Calling it from SQL, and where it can't go
Sources
Every claim above is drawn from one of these pages, quoted as it was written on the date shown.
- 1.
“To be called by the Snowflake external function feature, the remote service must: Accept JSON inputs and return JSON outputs.”
↩︎ Four pieces: function, proxy, remote service, integration“The proxy service can increase security by authenticating requests to the remote service.”
↩︎ Four pieces: function, proxy, remote service, integration“Snowflake sends one or more HTTP GET requests to retrieve the result from the remote service”
↩︎ One call, end to end: POST, batches and JSON rows“Currently, external functions must be scalar functions. A scalar external function returns a single value for each input row.”
↩︎ Calling it from SQL, and where it can't go“an external function does not contain its own code; instead, the external function calls code that is stored and executed outside Snowflake”
↩︎ Key concept“A COPY transformation.”
↩︎ Exam trap 2“Snowflake does not call a remote service directly. Instead, Snowflake calls a proxy service, which relays the data to the remote service.”
↩︎ Prediction“Snowflake stores security-related external function information in an API integration.”
↩︎ Checkpoint“The proxy service receives the POST and then processes and forwards the request to the actual remote service.”
↩︎ Checkpoint“An external function can appear in any clause of a SQL statement in which other types of UDF can appear.”
↩︎ Checkpoint - 2.
“the row numbers in the returned data must correspond to the row numbers in the data that Snowflake sent”
↩︎ One call, end to end: POST, batches and JSON rows“The first column is always the row number (i.e. the 0-based index of the row within the batch).”
↩︎ Checkpoint - 3.
“Snowflake recommends that you set this explicitly rather than accept the default.”
↩︎ Writing CREATE EXTERNAL FUNCTION“This is the name of the API integration object that should be used to authenticate the call to the proxy service.”
↩︎ Writing CREATE EXTERNAL FUNCTION“This parameter is not a performance tuning parameter. This parameter specifies a maximum size, not a recommended size.”
↩︎ Exam trap 1“This causes Snowflake to add two HTTP headers to every HTTPS request: sf-custom-volume-measure and sf-custom-distance-measure”
↩︎ Checkpoint - 4.
“When Snowflake retries a request for a specific batch, Snowflake uses the same batch ID as it used earlier for the same batch.”
↩︎ Calling it from SQL, and where it can't go“Snowflake strongly recommends that the remote service process each row independently.”
↩︎ Exam trap 3