New to Kestra?
Use blueprints to kickstart your first workflows.
Load any REST API into DuckDB with dlt orchestrated by Kestra. Merge on primary keys for rerun-safe ingestion, and report per-table row counts to Slack.
Turn any REST API into a queryable DuckDB dataset with about twenty lines of Python. This blueprint runs an inline dlt pipeline through io.kestra.plugin.dlt.Run: two @dlt.resource functions pull users and todos from a REST API, and dlt handles everything ingestion scripts usually get wrong, schema inference, typing, normalization of nested JSON, and merge semantics on primary keys so reruns update rows instead of duplicating them. After each load, the flow surfaces per-table row counts as Kestra outputs and posts them to Slack.
load_rest_api (io.kestra.plugin.dlt.Run) executes the inline Python script in the task's container image. Each @dlt.resource declares a primary_key and write_disposition: merge, so the pipeline is rerun-safe by construction.dlt.pipeline(...) targets the duckdb destination with a raw dataset name; dlt creates tables, infers the schema, and versions it.pipeline.last_trace.last_normalize_info.row_counts, filters out dlt's internal tables, and emits the counts through Kestra's output protocol, making them available as {{ outputs.load_rest_api.vars.row_counts }}.notify posts the per-table counts to Slack; the errors block posts a distinct alert when the extract or load fails.Schedule trigger refreshes the dataset daily at 06:00.dlt solves extraction and loading, but a Python script still needs somewhere to run on schedule, retry on transient API failures, keep an execution history, and tell someone when it breaks. Kestra provides exactly that around the unchanged dlt code: the Run task ships with a container image that has dlt preinstalled, outputs flow into notifications and downstream tasks, and every load is auditable in the execution history.
warehouse_path input), so merges see previous loads.env from {{ secret('...') }}.SLACK_WEBHOOK_URL: Slack incoming webhook URL.SLACK_WEBHOOK_URL secret to your Kestra namespace.users and todos.disabled: false on the daily trigger.postgres, bigquery, or snowflake by changing the destination argument and providing credentials through task env variables.dlt.sources.incremental for endpoints that expose an updated-at cursor, as shown in the dlt incremental sync blueprint.io.kestra.plugin.jdbc.duckdb.Query, as shown in the dlt analytics chain blueprint.