Python UDFs
On this page
Note
This is a Preview feature.
A Python User-Defined Function (UDF) is an external function that allows you to execute Python code outside of the SingleStore engine's process.
Prerequisites
To enable Python UDFs in the SingleStore deployment, ensure the following:
-
SingleStore Version: SingleStore version 8.
9 or later. -
Environment: The SingleStore deployment must run in an AWS EKS IRSA-supported environment.
-
Engine Global Variable:
enable_must be enabled.managed_ functions SET GLOBAL enable_managed_functions = 1;Once this engine variable is enabled, create and deploy Python UDFs and TVFs.
Publish a Python UDF
Create a Python UDF
Python UDFs can be created in Shared notebook only.
-
In the left navigation, select Editor > Shared.
-
Select Publish (on the top right).
New Python UDF
After selecting Publish, a new dialog box appears.
Publish Settings
|
Publish as |
Select Python UDF. |
|
Name |
Enter a name of the Python UDF. |
|
Description |
Enter the Python UDF description. |
|
Notebook |
Select a shared notebook to publish as a Python UDF. |
|
Deployment |
Select the SingleStore deployment (workspace) the notebook connects to. Selecting a workspace allows connecting to the SingleStore databases referenced in the notebook natively. |
|
Runtime |
Select a runtime from the following:
Note This field is in preview. |
|
Region |
Select a region. |
|
Idle Timeout |
Select an idle timeout. Note This field is in preview. |
Select Next.
Select Publish to publish the notebook as Python UDF.
Note
Creating a new Python UDF with the same name replaces the existing function.
Run your first Python UDF
Note
This notebook can be run on a Free Starter Workspace. To create a Free Starter Workspace navigate to Start using the left nav. You can also use your existing Standard or Premium workspace with this Notebook.
This feature is currently in Private Preview. Please reach out support@singlestore.com to confirm if this feature can be enabled in your org.
This Jupyter notebook will help you build your first Python UDF using Notebooks, registering it with your database and calling it as part of SQL query.
Create some simple tables
This setup establishes a basic relational structure to store some reviews for restaurants. Ensure you have selected a database.
%%sqlDROP TABLE IF EXISTS reviews;CREATE TABLE IF NOT EXISTSreviews (review_id INT PRIMARY KEY,store_name VARCHAR(255) NOT NULL,review TEXT NOT NULL);
Insert sample data
%%sql INSERT into reviews (review_id, store_name, review) values("1", "Single Pizza", "The staff were very respectful and made thoughtful suggestions. I will definitely go again. 10/10!"),("2", "Single Pizza", "The food was absolutely amazing and the service was fantastic!"),("3", "Single Pizza", "The experience was terrible. The food was cold and the waiter was rude."),("4", "Single Pizza", "I loved the ambiance and the desserts were out of this world!"),("5", "Single Pizza", "Not worth the price. I expected more based on the reviews");
Importing Logging module to enable live logs
import logging
Define Python UDF functions
Next, we will be Python UDF function using the @udf annotation. We will be using the VADER model of nltk library to perform sentiment analysis on the review text.
!pip install nltk
from singlestoredb.functions import udfimport nltkfrom nltk.sentiment import SentimentIntensityAnalyzernltk.download('vader_lexicon')sia = SentimentIntensityAnalyzer()@udfdef review_sentiment(review: str) -> str:logging.info(f"Processing review: {review}")scores = sia.polarity_scores(review)logging.info(f"Sentiment scores: {scores}")sentiment = ("Positive" if scores['compound'] > 0.05 else"Negative" if scores['compound'] < -0.05 else"Neutral")logging.info(f"Sentiment: {sentiment}")return sentiment
Start the Python UDF server
This will start the server as well as register all the functions annotated with @udf as external user defined functions on your selected database.
import singlestoredb.apps as appsconnection_info = await apps.run_udf_app()
List all registered UDFs
In interactive notebooks, the udf function will be suffixed with _test to differentiate it from the published version
%%sqlSHOW functions
Call the UDF from SQL
You will now be able to run queries like
SELECT review_id, store_name, review, review_sentiment_test(review) from reviews order by review_id;
from the SQL editor or any other SQL client.
Try it out by opening another notebook, selecting the current Database and running this query in a new cell.
Publish Python UDF
After validating the Python UDF interactively, you can publish it and access it like
%%sql
SELECT review_id, store_name, review, review_sentiment(review) from reviews order by review_id
enriching your data exploration experience seamlessly!

Manage an Existing Python UDF
To view an existing Python UDF, select Python UDFs in the left navigation.
-
View
-
Update
-
Delete
View an Existing Python UDF
To view an existing Python UDF, select the Python UDF from the Name column.
-
View Live Logs
-
Update
-
Delete
View Live Logs
To view live logs of the selected Python UDF, select View Live Logs from the ellipsis on the right side.
Update an Existing Python UDF
To update an existing Python UDF, select the ellipsis in the Actions column of the Python UDF, and select Update.
Delete an Existing Python UDF
To delete an existing Python UDF, select the ellipsis in the Actions column of the Python UDF, and select Delete.
Defining Python UDFs
Each Python UDF must meet these requirements:
-
The function's parameters and return types must be annotated.
-
The function must be wrapped with the
@udfdecorator, which is located insinglestoredb..functions
The @udf decorator is a critical component, as it automatically analyzes the type annotations to map Python data types to SingleStore data types.CREATE EXTERNAL FUNCTION statement in the SingleStore database, ensuring a reliable connection between the Python code and the SQL queries.
There are two main types of Python UDFs, defined by the type annotations:
-
Scalar
-
Vectorized
Scalar Python UDFs
Scalar Python UDFs are defined with standard Python type annotations, such as int, float, or str.
The following example demonstrates a scalar Python UDF:
from singlestoredb.functions import udfimport singlestoredb.apps as apps@udfasync def multiply(x: float, y: float) -> float:return x * y# Start Python UDF serverconnection_info = await apps.run_udf_app()print("UDF server running. Connection info:", connection_info)
This creates the following external function:
CREATE EXTERNAL FUNCTION multiply(x DOUBLE NOT NULL, y DOUBLE NOT NULL)RETURNS DOUBLE NOT NULLAS REMOTE SERVICE "http://<svchost>/<endpoint>/invoke" FORMAT ROWDAT_1;
Use async def for improved cancellation handling.
Vectorized Python UDFs
Vectorized Python UDFs are defined with vector type annotations, such as numpy., pandas., polars., or pyarrow..
The following example demonstrates a vectorized Python UDF.
import numpy as npimport numpy.typing as nptfrom singlestoredb.functions import udf@udfasync def vec_multiply(x: npt.NDArray[np.float64],y: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:return x * y# Start Python UDF serverimport singlestoredb.apps as appsconnection_info = await apps.run_udf_app()
This creates the following external function:
CREATE EXTERNAL FUNCTION vec_multiply(x DOUBLE NOT NULL, y DOUBLE NOT NULL)RETURNS DOUBLE NOT NULLAS REMOTE SERVICE "http://<svchost>/<endpoint>/invoke" FORMAT ROWDAT_1;
Scalar Python TVFs
Scalar Python TVFs are defined in the same way as scalar Python UDFs, except that a scalar TVF uses a Table annotation to indicate that the function returns a table.Table object.
The following example demonstrates a scalar Python TVF:
import numpy as npimport numpy.typing as nptfrom singlestoredb.functions import udf, Table@udfdef async number_stats(n: npt.NDArray[np.int_],) -> Table[npt.NDArray[np.int_], npt.NDArray[np.int_], npt.NDArray[np.float64]]:numbers = np.arange(1, n[0] + 1, dtype=np.int_)squares = numbers ** 2roots = np.sqrt(numbers).round(2)return Table(numbers, squares, roots)# Start Python UDF serverimport singlestoredb.apps as appsconnection_info = await apps.run_udf_app()
This creates the following external function:
CREATE EXTERNAL FUNCTION`number_stats`(`n` BIGINT NOT NULL)RETURNS TABLE(`a` BIGINT NOT NULL)AS REMOTE SERVICE "http://<svchost>/<endpoint>/invoke" FORMAT ROWDAT_1;
SingleStore automatically generates generic column names if no names are associated with the return fields (a in this example).
Vectorized Python TVFs
Vectorized Python TVFs operate in a way similar to vectorized Python UDFs.
The following example demonstrates a vectorized Python TVF:
import numpy as npimport numpy.typing as nptfrom singlestoredb.functions import udf, Table@udfdef vec_table_function(n: npt.NDArray[np.int_],) -> Table[npt.NDArray[np.int_], npt.NDArray[np.float64], npt.NDArray[np.str_]]:x = np.array([10] * n[0], dtype=np.int_)y = np.array([10.0] * n[0], dtype=np.float64)z = np.array(['ten'] * n[0], dtype=np.str_)# Returns a tuple of vectors (each column of the output)return Table(x, y, z)# Start Python UDF serverimport singlestoredb.apps as appsconnection_info = await apps.run_udf_app()
This creates the following external function:
CREATE EXTERNAL FUNCTION`vec_table_function`(`n` BIGINT NOT NULL)RETURNS TABLE(`a` BIGINT NOT NULL,`b` DOUBLE NOT NULL,`c` TEXT NOT NULL)AS REMOTE SERVICE "http://<svchost>/<endpoint>/invoke" FORMAT ROWDAT_1;
SingleStore automatically generates generic column names if no names are associated with the return fields (a, b, c).
In this section
Last modified: February 3, 2026