Skip to content

SQL node

IMPORTANT

This node is an installable component using the sql host capability. It never sees your connection string: it describes the query, and the engine — which owns the driver and does the parameter binding — runs it.

The statement resolves ${secrets.X} only, never flow refs. Request data belongs in the parameters, where it is bound. That split is enforced, not advised.

The SQL node reads or writes a Postgres database mid-flow — the relational counterpart to the MongoDB node. Look up a customer, insert an order, update a status, run a report.

Component id: flowrunner/sql.

How it works

The SQL node connects to Postgres, runs one query, and stores the result. You provide:

  • a connection string, as a secret reference (${secrets.DATABASE_URL}) so the credentials never live in the flow;
  • a query with numbered placeholders — $1, $2, … — for any dynamic value;
  • a list of parameters, one per line: each is a flow reference (start.customerId) whose value is bound, or a literal.

The parameters are passed to Postgres as bound values, never spliced into the SQL text — so a value like start.email can't inject SQL, no matter what a form visitor typed. The query itself only resolves ${env.X} / ${secrets.X}; flow references are never interpolated into it.

The result is stored under your result variable:

text
refs.<resultVar> = { rows: [ ...result rows... ], rowCount: 3 }

Safety

  • The connection host is checked — an author can't point it at localhost, a private IP, or cloud metadata (the same SSRF guard as the HTTP and MongoDB nodes). Self-hosters can opt out with FLOWRUNNER_ALLOW_PRIVATE_EGRESS=1.
  • The node does not auto-retry — a failed INSERT/UPDATE isn't safe to replay blindly. Wire the error port to handle failures.

Config

FieldRequiredDescription
connectionStringYesPostgres connection string, as a secret reference.
queryYesSQL with $1, $2, … placeholders for values.
paramsNoOne value per line — a flow reference (bound) or a literal.
resultVarNo (default rows)The variable the { rows, rowCount } result is written to.

Ports

next and error.

Examples

Look up a customer by an id from the request:

text
SQL  connectionString: ${secrets.DATABASE_URL}
     query: "select id, email, plan from customers where id = $1"
     params: [ start.customerId ]
     resultVar: customer
# → refs.customer.rows[0].email

Insert a row and read the generated id back:

text
SQL  query: "insert into orders (customer_id, total) values ($1, $2) returning id"
     params:
       start.customerId
       start.total
     resultVar: created
# → refs.created.rows[0].id

TIP

Store the connection string once under Secrets as DATABASE_URL. Never build a query by pasting ${start.field} into the SQL — use $1 and a parameter, so form input can't inject SQL.

See also

FlowRunner — the no-code platform for small businesses.