New to Kestra?
Use blueprints to kickstart your first workflows.
Build a privacy-preserving text-to-SQL pipeline with Kestra and OpenAI GPT-4o. Generate SQL from schema only, execute queries, and return structured JSON.
Build a privacy-preserving text-to-SQL pipeline that turns natural language questions into executable PostgreSQL queries using OpenAI GPT-4o. Instead of shipping table contents to an external model, this flow sends only the database schema (table and column names) to the LLM, so the model has enough context to write correct SQL without ever seeing a single row of sensitive data. It solves the core problem of LLM-driven analytics: giving non-technical users self-service access to a database in plain English while keeping production records private and queries safe.
fetch_schema task (io.kestra.plugin.jdbc.postgresql.Queries) introspects the information_schema.columns catalog with fetchType: FETCH, returning every table in the public schema with its column names and data types and no row data.generate_sql task (io.kestra.plugin.openai.ChatCompletion) sends that schema plus the user's question input to GPT-4o (model: gpt-4o). A system prompt instructs the model to output a raw SELECT statement grounded only in the provided schema, or NO_SQL: <reason> when the question cannot be answered.check_sql task (io.kestra.plugin.core.flow.If) tests whether the model returned valid SQL. When it did, execute_query runs the generated statement against PostgreSQL and format_results (io.kestra.plugin.serdes.json.IonToJson) converts the output to JSON.NO_SQL, the log_no_sql task records the reason instead of running anything against the database.OpenAI and PostgreSQL have no shared scheduler or workflow engine. Kestra ties them together in one declarative YAML flow with event triggers, automatic retries on transient API or database failures, and full execution lineage so every generated query and result is auditable. The If task gives you conditional execution that a raw prompt or a cron job cannot: queries run only when the model produces valid SQL, and the gap an LLM API alone cannot fill, deciding what to do next based on the model output, is handled natively.
public schema.gpt-4o.OPENAI_API_KEY: API key used by the generate_sql task.POSTGRES_URL: JDBC connection URL for your PostgreSQL database.POSTGRES_USER: database username.POSTGRES_PASSWORD: database password.question, for example "How many orders were placed last month?".generate_sql output for the SQL and format_results for the JSON answer.fetch_schema query.execute_query.format_results into a Slack or email task to deliver answers automatically.