New to Kestra?
Use blueprints to kickstart your first workflows.
Download a CSV, create a Postgres table, and bulk load it with the COPY protocol in Kestra. Fast, declarative ETL ingestion for reference and seed data.
Loading CSV files into PostgreSQL row by row with INSERT statements is slow and brittle at scale. This blueprint shows the production way to do it: download a CSV dataset, ensure the target table exists, and bulk load the file into Postgres using the native COPY protocol, which is the fastest and most reliable path for ingesting structured data. It is a reusable foundation for PostgreSQL-centric ETL, database seeding, and reference-table refreshes orchestrated end to end with Kestra.
The flow runs four sequential tasks:
download (io.kestra.plugin.core.http.Download) fetches a public CSV dataset (ISO 3166 country codes) over HTTP and stores it in Kestra's internal storage.create_table (io.kestra.plugin.jdbc.postgresql.Query) runs a CREATE TABLE IF NOT EXISTS statement so the country_referential table and its columns are in place before any load.copyin (io.kestra.plugin.jdbc.postgresql.CopyIn) streams the downloaded file straight into the table using format: CSV, header: true, and from: "{{ outputs.download.uri }}", mapping the prior task's output directly into the bulk load.read (io.kestra.plugin.jdbc.postgresql.Query) issues a SELECT ... LIMIT 10 with fetchType: FETCH to confirm the rows landed correctly.COPY protocol instead of slow per-row inserts.psql \copy scripts to orchestrated runs.Postgres COPY is fast, but on its own it is just a statement: it has no scheduler, no retry logic, no dependency handling, and no record of what ran. Kestra wraps the load in a declarative YAML flow where the download, table creation, load, and validation run as ordered, observable tasks. You get event and schedule triggers, automatic retries, execution history, and full data lineage across the download and load steps, the orchestration layer that a database engine alone cannot provide.
jdbc:postgresql://sample_postgres:5433/world).This blueprint reads the Postgres password from a Kestra secret ({{ secret('POSTGRES_PASSWORD') }}) and uses a demo username (postgres). For production, also move the username and connection URL into secrets and store them in your secret backend.
url, username, and password properties at your own Postgres database.create_table schema to match your dataset.read task output to verify ingestion.download for an upload input, an S3/GCS fetch, or a database extract.Schedule or event trigger to refresh the table on a cadence.copyin for full-refresh loads.