New to Kestra?
Use blueprints to kickstart your first workflows.
Download a CSV over HTTP, run an in-process DuckDB SQL aggregation, and export results to CSV. A serverless analytics pipeline orchestrated with Kestra.
id: duckdb-query
namespace: company.team
tasks:
- id: download_csv
type: io.kestra.plugin.core.http.Download
description: salaries of data professionals from 2020 to 2023 (source ai-jobs.net)
uri: https://huggingface.co/datasets/kestra/datasets/raw/main/csv/salaries.csv
- id: avg_salary_by_job_title
type: io.kestra.plugin.jdbc.duckdb.Query
inputFiles:
data.csv: "{{ outputs.download_csv.uri }}"
sql: |
SELECT
job_title,
ROUND(AVG(salary),2) AS avg_salary
FROM read_csv_auto('{{ workingDir }}/data.csv', header=True)
GROUP BY job_title
HAVING COUNT(job_title) > 10
ORDER BY avg_salary DESC;
fetchType: STORE
- id: result
type: io.kestra.plugin.serdes.csv.IonToCsv
from: "{{ outputs.avg_salary_by_job_title.uri }}"
Run fast, in-process SQL analytics on a remote CSV without standing up a database server. This blueprint downloads a public salaries dataset over HTTP, queries it with DuckDB to compute the average salary per job title, and exports the aggregated result back to a clean CSV file. It is a practical pattern for ad-hoc analytics, data profiling, and lightweight ETL where you want columnar SQL performance directly over flat files.
download_csv uses io.kestra.plugin.core.http.Download to fetch a public salaries.csv dataset (data professional salaries, 2020 to 2023, source ai-jobs.net) and stores it in Kestra internal storage.avg_salary_by_job_title uses io.kestra.plugin.jdbc.duckdb.Query to mount the downloaded file via inputFiles as data.csv, then runs SQL with read_csv_auto('{{ workingDir }}/data.csv', header=True). It groups by job_title, keeps titles with more than 10 records via HAVING COUNT(job_title) > 10, and orders by descending average salary. Results are persisted with fetchType: STORE.result uses io.kestra.plugin.serdes.csv.IonToCsv to convert the stored Ion output into a downloadable CSV artifact.DuckDB is an embedded engine: it has no scheduler, no retry logic, and no built-in way to react to events. Kestra wraps the query in a declarative YAML workflow so you can attach event or schedule triggers, add retries on transient HTTP failures, capture full execution lineage and outputs, and chain the download, query, and export steps with explicit dependencies. You get production orchestration around an engine that, on its own, only runs a single query.
This flow uses no secrets. The dataset is fetched from a public URL and DuckDB runs in-process, so no credentials are required. If you point it at a private source, add credentials with {{ secret('NAME') }}.
result task output and download the generated CSV.uri to your own CSV, Parquet, or JSON file and adjust the SQL.Schedule or event trigger to refresh results automatically.IonToCsv with a JSON or Parquet serializer, or load results into a warehouse.