Running your own code inside Snowflake rather than pulling data out to it.
Snowpark is Snowflake's set of developer interfaces for running non-SQL code inside the Snowflake account instead of extracting data to an external cluster. The Snowpark DataFrame API (Python, Java, Scala) lets you write transformations in a familiar style; the client builds the operations lazily and translates them to SQL that executes on a virtual warehouse when an action such as collect() or save_as_table() runs. For logic that SQL cannot express, Python, Java and Scala UDFs, UDTFs and stored procedures run in a secure sandbox on the warehouse, with packages from the Anaconda channel available. Snowpark Container Services (SPCS) goes further and runs arbitrary container images, including GPU workloads, long-running services and web apps, on compute pools inside the account.
A useful mental model is a ladder of increasing flexibility and operational effort. DataFrames are the cheapest and most scalable because the Snowflake optimiser sees the whole plan. UDFs and stored procedures add custom code but keep the managed warehouse runtime. Container Services gives full control of the runtime at the cost of building images, sizing compute pools and managing service lifecycles. Start at the lowest rung that can express the job, and move up only when a constraint forces it.
| Need | Use |
|---|---|
| Transformations expressible as relational operations | Snowpark DataFrames (compiles to SQL, scales with the warehouse) |
| Row-level custom logic, ML inference with Python libraries | Python UDFs / vectorised UDFs |
| Multi-step procedural jobs, orchestration from SQL tasks | Stored procedures |
| Custom runtimes, GPUs, long-running APIs or UIs, non-Python languages | Snowpark Container Services |
from snowflake.snowpark import Session
from snowflake.snowpark.functions import col, sum as sum_
session = Session.builder.configs({"account": "...", "user": "...", "authenticator": "externalbrowser",
"warehouse": "WH", "database": "DB", "schema": "PUBLIC"}).create()
df = (session.table("orders")
.filter(col("status") == "SHIPPED")
.group_by("region")
.agg(sum_("amount").alias("revenue")))
df.write.save_as_table("revenue_by_region", mode="overwrite") # executes as SQL in Snowflake
The main benefit across all of these is governance and simplicity: data never leaves Snowflake's security boundary, the same role-based access control applies, and there is no separate Spark or Kubernetes cluster to run. The trade-off is that you are bound to Snowflake's compute pricing and runtime constraints.