Large data: S3, R2, MinIO, Azure Blob, Google Cloud Storage
This page is part of our section on Persistent storage & databases which covers where to effectively store and manage the data manipulated by Windmill. Check that page for more options on data storage.
On heavier data objects & unstructured data storage, Amazon S3 (Simple Storage Service) and its alternatives Cloudflare R2 and MinIO as well as Azure Blob Storage and Google Cloud Storage are highly scalable and durable object storage services that provide secure, reliable, and cost-effective storage for a wide range of data types and use cases.
Windmill comes with a native integration with S3, Azure Blob, and Google Cloud Storage, making them the recommended storage for large objects like files and binary data.
Workspace object storage
Connect your Windmill workspace to your S3 bucket, Azure Blob storage, or Google Cloud Storage to enable users to read and write from S3 without having to have access to the credentials.
On the Community Edition, total workspace storage is limited to 10GiB per workspace (there is no per-file size limit) and the bucket browser will not work for buckets containing more than 20 files. Consider upgrading to Windmill Enterprise Edition for unlimited workspace storage.

Windmill integration with DuckDB for data pipelines
ETLs are easily implemented in Windmill using its integration with DuckDB to work with tabular data. You don't need to manually interact with the S3 bucket: DuckDB reads and writes datasets to S3 natively and efficiently.
- DuckDB
- DuckDB (Python)
-- $file1 (s3object)
-- Run queries directly on an S3 parquet file passed as an argument
SELECT * FROM read_parquet($file1)
-- Or using an explicit path in a workspace storage
SELECT * FROM read_json('s3:///demo/data.json')
-- You can also specify a secondary workspace storage
SELECT * FROM read_csv('s3://secondary_storage/demo/data.csv')
-- Write the result of a query to a different parquet file on S3
COPY (
SELECT COUNT(*) FROM read_parquet($file1)
) TO 's3:///demo/output.pq' (FORMAT 'parquet');
#requirements:
wmill>=1.229.0
#duckdb==0.9.1
import wmill
from wmill import S3Object
import duckdb
def main(input_file: S3Object):
bucket = wmill.get_resource("u/admin/windmill-cloud-demo")["bucket"]
# create a DuckDB database in memory
# see https://duckdb.org/docs/api/python/dbapi
conn = duckdb.connect()
# this will default to the workspace S3 resource
args = wmill.duckdb_connection_settings().connection_settings_str
# this will use the designated resource
# args = wmill.duckdb_connection_settings("<PATH_TO_S3_RESOURCE>").connection_settings_str
# connect duck db to the S3 bucket - this will default to the workspace S3 resource
conn.execute(args)
input_uri = "s3://{}/{}".format(bucket, input_file["s3"])
output_file = "output/result.parquet"
output_uri = "s3://{}/{}".format(bucket, output_file)
# Run queries directly on the parquet file
query_result = conn.sql(
"""
SELECT * FROM read_parquet('{}')
""".format(
input_uri
)
)
query_result.show()
# Write the result of a query to a different parquet file on S3
conn.execute(
"""
COPY (
SELECT COUNT(*) FROM read_parquet('{input_uri}')
) TO '{output_uri}' (FORMAT 'parquet');
""".format(
input_uri=input_uri, output_uri=output_uri
)
)
conn.close()
return S3Object(s3=output_file)
We recommend using the native DuckDB scripts integration, which uses the Windmill S3 proxy with no additional configuration needed. When using DuckDB from Python, the S3 resource details need to be visible to the user, or set to public in the workspace settings.
For more info on Data pipelines in Windmill, see Data pipelines.
Use Amazon S3, R2, MinIO, Azure Blob, and Google Cloud Storage directly
Amazon S3, Cloudflare R2 and MinIO all follow the same API schema and therefore have a common Windmill resource type. Azure Blob and Google Cloud Storage have slightly different APIs than S3 but work with Windmill as well using their dedicated resource types (Azure Blob, Google Cloud Storage)