CertSafari
    Snowflake SnowPro Advanced: Data Engineer (DEA-C02)· Lessons

    Domain 5 · Lesson 16/22

    Snowflake UDFs: Scalar, SQL, JavaScript and Secure Functions

    Define User-Defined Functions (UDFs) and outline how to use them.

    11 min read
    3.57% of exam
    4 sources
    Published 5 Oct 2026
    Docs as of 4 Oct 2026

    What you will be able to do

    • Tell scalar UDFs, UDTFs, UDAFs and vectorized variants apart by what each one takes in and returns
    • Choose a handler language based on the variations it supports, where its handler code can live, and whether the UDF can be shared
    • Write and call SQL and JavaScript UDFs, and explain owner-versus-invoker privileges
    • Decide when to make a UDF SECURE, and what that costs and protects

    Key concept

    Handler — A handler is the code that holds a UDF's logic. You write it in a supported language (SQL, JavaScript, Python, Java or Scala). Snowflake runs it each time the function is called. The CREATE FUNCTION statement wraps the handler in a callable function name, its argument types and its return type.

    1.What a UDF is, and its variations: scalar, UDTF, UDAF

    A user-defined function (UDF) adds an operation that Snowflake's built-in functions don't provide. It can also wrap a calculation your organization repeats everywhere. After you create it, you call it the same way you call a built-in function, and you can reuse it as often as you like. A function always returns a value from an expression, so it fits work that computes something and hands it back.

    The word "UDF" covers several variations. They differ in how many rows go in and how many come out. Exam questions often describe what goes in and what comes out, and expect you to name the variation.

    UDF variations by input and output shape
    VariationInputOutput
    User-defined function (UDF), also called a scalar functionOne rowOne row with a single column/value
    User-defined table function (UDTF)One rowA tabular value (a set of rows)
    User-defined aggregate function (UDAF)Values across multiple rowsOne aggregated result (sum, average, count, min/max, standard deviation, estimation and similar)
    Vectorized UDFBatches of rows as Pandas DataFramesBatches of results as Pandas arrays or Series
    Vectorized UDTFBatches of rows as Pandas DataFramesTabular results

    Checkpoint 1 of 6· Match them up

    Match each requirement to the UDF variation that meets it

    Tap a term, then the definition that fits it.

    Sources1

    2.Handler languages, Snowpark (Java, Python, Scala) and sharability

    There are two main ways to create a UDF. In SQL, you run CREATE FUNCTION with a handler written in Java, JavaScript, Python, Scala or SQL. In the Snowpark API, you write Java, Python or Scala code on the client, and Snowflake runs that code where the data is. The Snowflake CLI, the Snowflake Python API and the REST API can also create and manage functions.

    The language you choose limits what you can build. Python is the only language that supports every variation. Through SQL, it covers UDF, UDAF, UDTF and both vectorized types. JavaScript and Java support UDFs and UDTFs. Scala supports scalar UDFs only when created through SQL, but both UDFs and UDTFs through Snowpark. SQL handlers support UDFs and UDTFs. No other language offers a UDAF.

    Where the handler can live and whether the UDF can be shared, by language
    LanguageHandler locationSharable
    JavaIn-line or stagedNo
    JavaScriptIn-lineYes
    PythonIn-line or stagedNo
    ScalaIn-line or stagedNo
    SQLIn-lineYes

    Below is a Python handler written in-line in a CREATE FUNCTION statement. LANGUAGE names the handler language. HANDLER names the Python function to call. RUNTIME_VERSION pins the Python version. You call the result like any other function, for example SELECT addone(3);.

    A scalar Python UDF created with SQL, with the handler in-linesql
    CREATE OR REPLACE FUNCTION addone(i INT)
      RETURNS INT
      LANGUAGE PYTHON
      RUNTIME_VERSION = '3.12'
      HANDLER = 'addone_py'
    AS $$
    def addone_py(i):
     return i+1
    $$;

    Two runtime details often come up in exam questions:

    - If the handler calls CURRENT_DATABASE or CURRENT_SCHEMA, the result is the database or schema that contains the UDF, not the session's current one. - When reading staged files, UDTFs can process several files in parallel, but scalar UDFs currently process them one at a time.

    Checkpoint 2 of 6· Check yourself

    A team needs a custom aggregate function, created with CREATE FUNCTION. Which handler language must they use?

    Checkpoint 3 of 6· Exam question

    A data engineer wants to encapsulate a single repeated business calculation, converting a raw sensor reading to Celsius, so that every analyst-facing SQL query can call it as one reusable expression without duplicating the formula. No procedural branching or external library is required. Which approach fits this requirement best?

    Sources1

    3.SQL UDFs

    A SQL UDF evaluates any SQL expression and returns the result. A plain definition returns one scalar value. A definition declared as a table function returns a set of rows. A SQL UDF needs no LANGUAGE or HANDLER clause, because the body between the $$ delimiters is the logic.

    A scalar SQL UDF that computes a circle's area from its radiussql
    CREATE FUNCTION area_of_circle(radius FLOAT)
      RETURNS FLOAT
      AS
      $$
        pi() * radius * radius
      $$
      ;

    The privilege model makes SQL UDFs useful for access control. If the definition names a table without a schema, Snowflake looks for it in the schema that contains the function. The function's owner must have privileges on every object the definition uses. The caller only needs privileges on the function itself. In the example below, an administrator exposes a user count without giving analysts access to the sensitive users table.

    Exposing an aggregate of a protected table through a function grantsql
    CREATE FUNCTION total_user_count() RETURNS NUMBER AS 'select count(*) from users';
    
    GRANT USAGE ON FUNCTION total_user_count() TO ROLE analyst;

    When the analyst role runs SELECT * FROM users, the query fails because the role has no access to the table. When the same role runs SELECT total_user_count(), the query succeeds.

    Checkpoint 4 of 6· Check yourself

    Role analyst has USAGE on total_user_count() but no privileges on table users. What happens when analyst runs SELECT total_user_count()?

    Sources2

    4.JavaScript UDFs

    A JavaScript UDF is created with SQL and adds LANGUAGE JAVASCRIPT. Snowflake converts arguments and return values between SQL types and JavaScript types. One rule catches many people: inside the JavaScript body, you must refer to parameter names in all uppercase, even if you declared them in lowercase in SQL. In the example, the parameter is declared as a but read as A.

    A JavaScript UDF that reverses an ARRAYsql
    -- Create the UDF.
    CREATE OR REPLACE FUNCTION my_array_reverse(a ARRAY)
      RETURNS ARRAY
      LANGUAGE JAVASCRIPT
    AS
    $$
      return A.reverse();
    $$
    ;

    JavaScript handlers are always written in-line; they cannot live on a stage. Like SQL UDFs, JavaScript UDFs can be shared through Secure Data Sharing. Handler code can also write log and trace data while it runs.

    Checkpoint 5 of 6· Fill the gap

    The SQL signature declares the parameter as lowercase a. What must the JavaScript body use to refer to it?

    -- Create the UDF.
    CREATE OR REPLACE FUNCTION my_array_reverse(a ARRAY)
      RETURNS ARRAY
      LANGUAGE JAVASCRIPT
    AS
    $$
      return  ? .reverse();
    $$
    ;

    Sources3

    5.Secure UDFs

    To hide a function's internals from users who shouldn't see them, add the SECURE keyword when you create or alter the UDF. A secure UDF protects two things.

    First, it protects the definition. Only users granted a role that owns the function can see its body (the handler code), its list of imports, its handler name and its packages list. Other users can still see its parameter types, return type, handler language, null handling and volatility.

    Second, it protects the data. Some internal optimizations for regular UDFs, such as pushdown, need access to the underlying base tables, and that access could reveal data hidden from the function's users. A secure UDF prevents this. For handlers written in Java, Python or Scala, SECURE also runs each function in its own sandbox, so no resources are shared between functions.

    That cost is why the guidance is narrow. Make a UDF secure when its purpose is data privacy, meaning it limits access to sensitive data that not every user of the underlying tables should see. Don't make a UDF secure when it only exists to make queries more convenient.

    Checkpoint 6 of 6· Check yourself

    A non-owner queries a secure Python UDF. Which detail is hidden from them?

    Sources4

    Exam traps

    Each one states something that sounds right. Open it to see what is actually true.

    1. 1.Declaring every UDF SECURE is a free security improvement.Why is that wrong?

      Secure UDFs skip the optimizer shortcuts that regular UDFs get, so they can run slower. Use SECURE only for functions meant to protect data privacy, not for convenience functions.

      Covered in Secure UDFs

    2. 2.A Python UDF can be shared with a consumer account through Secure Data Sharing.Why is that wrong?

      Only UDFs with JavaScript or SQL handlers can be shared. Java, Python and Scala UDFs cannot.

      Covered in Handler languages, Snowpark (Java, Python, Scala) and sharability

    3. 3.To call a SQL UDF that reads a table, the caller needs SELECT on that table.Why is that wrong?

      Objects in the definition are checked against the function owner's privileges. The caller only needs privileges on the function.

      Covered in SQL UDFs

    Sources

    Every claim above is drawn from one of these pages, quoted as it was written on the date shown.

    1. 1.
      “Also known as a scalar function, returns one output row for each input row.”
      ↩︎ What a UDF is, and its variations: scalar, UDTF, UDAF
      “Returns a tabular value for each input row.”
      ↩︎ What a UDF is, and its variations: scalar, UDTF, UDAF
      “Not all languages support referring to the handler on a stage (the handler code must instead be in-line).”
      ↩︎ Handler languages, Snowpark (Java, Python, Scala) and sharability
      “the function returns the database or schema that contains the UDF, not the database or schema in use for the session.”
      ↩︎ Handler languages, Snowpark (Java, Python, Scala) and sharability
      “UDTFs can process multiple files in parallel; however, UDFs currently process files serially.”
      ↩︎ Handler languages, Snowpark (Java, Python, Scala) and sharability
      “Once you have a handler, you can create a UDF using any of several tools included in Snowflake, then execute the UDF.”
      ↩︎ Key concept
      “A sharable UDF can be used with the Snowflake Secure Data Sharing feature.”
      ↩︎ Exam trap 2
      “A sharable UDF can be used with the Snowflake Secure Data Sharing feature.”
      ↩︎ Prediction
      “Java:UDF, UDTFJavaScript:UDF, UDTFPython:UDF, UDAF, UDTF, Vectorized UDF, Vectorized UDTFScala:UDFSQL:UDF, UDTF”
      ↩︎ Checkpoint
    2. 2.
      “A SQL UDF evaluates an arbitrary SQL expression and returns the results of the expression.”
      ↩︎ SQL UDFs
      “If a function definition refers to an unqualified table, then that table is resolved in the schema containing the function.”
      ↩︎ SQL UDFs
      “The invoker of the function need not have access to the objects referenced in the function definition”
      ↩︎ Exam trap 3
      “The invoker of the function need not have access to the objects referenced in the function definition”
      ↩︎ Checkpoint
    3. 3.
      “the JavaScript code must refer to the input parameter names as all uppercase, even if the names are not uppercase in the SQL code.”
      ↩︎ JavaScript UDFs
    4. 4.
      “you can use the SECURE keyword when creating a user-defined function (UDF) and stored procedure.”
      ↩︎ Secure UDFs
      “making the functions and procedures secure ensures that they are executed in separate sandboxes, such that no resources are shared between them.”
      ↩︎ Secure UDFs
      “Define a UDF as secure when it is specifically designated for data privacy”
      ↩︎ Secure UDFs
      “You should not make a UDF secure when it is defined for query convenience”
      ↩︎ Exam trap 1
      “bypasses the optimizations used for regular UDFs. This might reduce query performance for secure UDFs.”
      ↩︎ Prediction
      “For a UDF or stored procedure, you can prevent users from seeing definition specifics.”
      ↩︎ Checkpoint

    Continue to page 2 of 2

    UDTFs, UDAFs and Snowpark Python UDFs in Snowflake

    Spotted a mistake, or was something unclear? Tell us.