PostgreSQL Connector
Description
PostgreSQL is a popular relational database system. This component allows you to query a PostgreSQL database.
Query formatting
Instead of generating dynamic queries and sanitizing SQL manually, it is possible to use generic queries with query formatting.
Formatted queries can either use numbered parameter placeholders like $1, $2, etc., or can use named parameter placeholders like ${variableKey}.
Index variables
Index variables are numbered parameter placeholders like $1, $2, etc.
To use index variables, write a query that uses indexed placeholders (e.g. SELECT * FROM users WHERE id = $1 AND name = $2).
Then, generate an array like [5, "John Doe"] and reference it from the Parameters Object or Array input.
Note: When indexed variables are used, named variables cannot be used in the same query.
Named variables
Named variables are written in the form ${variableKey}, $<variableKey> or $(variableKey).
For example, enter a query that reads INSERT INTO users (name, email) VALUES (${name}, ${email}).
Then, enter values with keys of name and email, along with any desired values, as Named Parameters Inputs.
Values provided as variables are sanitized automatically.
When dynamically generating SQL queries and the required parameters are not known ahead of time, create a key/value object in another step and reference it through the Parameters Object or Array input.
In the example above, the object could take the form {name: "John doe", email: "john.doe@example.com"}.
Connections
On-Premise Connection
key: postgresCreate a new PostgreSQL connection and enter the connection details for the PostgreSQL server.
Configure the Connection
- Enter the Host, the hostname or IP address of the PostgreSQL server (e.g.,
192.168.0.1). - Enter the Port of the PostgreSQL server (default:
5432). - Enter the Database name to connect to.
- Optionally enter a Username and Password to authenticate to the PostgreSQL server.
- Set Require SSL to require an SSL connection to the PostgreSQL server.
- Optionally set a Connection Timeout in milliseconds to wait before timing out (default:
5000).
Refer to PostgreSQL connection parameters for additional detail on these values.
On-prem enabled: this connection can be configured to connect to an on-prem resource on a private network. Learn more.
| Input | Notes | Example |
|---|---|---|
| Database | The name of the database to connect to. | admin |
| Host | The hostname or IP address of the PostgreSQL server. | 192.168.0.1 |
| Password | The password used to authenticate to the PostgreSQL server. | |
| Port | The port of the PostgreSQL server. | 5432 |
| Require SSL | When true, requires an SSL connection to the PostgreSQL server. | false |
| Connection Timeout | The amount of time (in milliseconds) to wait for a connection to be established before timing out. Default is 5000ms. | 5000 |
| Username | The username used to authenticate to the PostgreSQL server. |
Triggers
New and Updated Records
Retrieves existing and ongoing records from a specified table. Load history once, check for changes on a schedule, or both. | key: pollTable
| Input | Notes | Example |
|---|---|---|
| Cast Timestamps to Strings | When true, timestamp values are cast to strings to retain precision. PostgreSQL tracks microseconds, but JavaScript dates are measured in milliseconds, so precision can be lost when fetching TIME, TIMETZ, TIMESTAMP, and TIMESTAMPTZ fields. Enable this when the cursor field is a timestamp. | true |
| Cursor Field | The column used to track new results. If the table has an auto incrementing integer ID, that ID can be used. If it has a 'created at' or 'updated at' timestamp, those can be used. Each time this trigger runs, it checks for records with values greater than the largest value from the last run. | updated_at |
| Default Cursor Value | The value to use for the cursor when the trigger is run for the first time, given in the units of the column named in Cursor Field: a timestamp for a timestamp column, an integer for an ID column. If present, the trigger fetches every record whose cursor value is greater than this one, so a lower value reaches further back and the table's current maximum reaches nothing. If omitted, the trigger notes the largest value of the cursor field on its first recurrence and fetches newer records from the next recurrence onward. | 1900-01-01 00:00:00 |
| Max Records Per Recurrence | The maximum number of records to fetch each time the trigger runs. Leave this empty to use the default of 1,000. Raising it drains a large backlog in fewer runs. On a flow with batching enabled the value is capped at 1,000 however high it is set, because a batched dispatch is bounded by size as well as by count and the platform limits one to 5 MB; lower it below that when the table has wide rows. | 1000 |
| Connection | The PostgreSQL connection to use. | |
| Table Name | The name of the table to monitor for new and updated records. | people |
The New and Updated Records trigger retrieves existing and ongoing records from a table: load history once, check for changes on a schedule, or both. It tracks a nominated cursor column and, on each recurrence, returns every record whose cursor value is greater than the highest value it has already emitted.
How It Works
Each recurrence queries the configured table for records whose Cursor Field value is greater than the trigger's stored position, ordered by that field ascending, and returns them. The Cursor Field can be any column whose values only increase: an auto-incrementing integer ID, or a created_at or updated_at timestamp.
The trigger stores its position as the cursor value of the last record it actually emitted, rather than the table's maximum value. Advancing only as far as what was emitted means a record committed while the trigger was still reading the table is picked up on the following recurrence instead of being stepped over. The position advances when a recurrence fetches its page, which is before the flow's steps have run on it, so a page whose execution is interrupted between those two points is not re-sent. Paging bounds what one interruption can cost to a single page.
On the first recurrence, with no Default Cursor Value set, the trigger records the table's current maximum cursor value, emits no records, and reports no changes. Records are emitted from the next recurrence onward. Changing Table Name or Cursor Field later re-establishes the position the same way.
Initial sync
Setting Default Cursor Value seeds the starting position instead of taking the table's current maximum, so the first recurrence returns history rather than nothing. The initial sync begins on that first recurrence and emits every record whose cursor value is greater than the value provided, seeding each record exactly once.
The sync has no fixed upper bound. Each recurrence emits at most one page of records, sized by Max Records Per Recurrence, and advances its position to the last record on that page, so a backlog drains across as many scheduled recurrences as it takes. A record modified while the backlog is still draining is emitted by the sync itself whenever its cursor value places it ahead of the current position. There is no separate sync mode, and no field in the payload marks the handoff: once the backlog is exhausted, ordinary incremental behavior continues from the same stored position.
No inputs are suppressed during an initial sync. This trigger has no field or visibility filters to set aside: Table Name and Cursor Field select and order the records, Cast Timestamps to Strings shapes how their values are returned, and Max Records Per Recurrence caps how many rows one recurrence may take. All of them apply during a sync exactly as they apply on any later recurrence.
Records sharing one Cursor Field value are always emitted together, on the same recurrence, because the position resumes strictly after the last value emitted. A column with few distinct values therefore pages poorly: when a single value covers more rows than one page holds, the trigger emits every remaining record from its current position in that one recurrence and the page limit does not apply to it. Prefer a column whose values are close to unique per row, such as a microsecond timestamp or an auto-incrementing id.
Batching
Batching is enabled per flow on this trigger. Once enabled, each changed record is dispatched as its own execution, or grouped by the configured batch size. Batch size and the number of batches dispatched concurrently can both be overridden per instance. Raising concurrency increases the request volume sent to PostgreSQL.
To turn it on, select the flow's trigger, open the Flow control tab, and switch on Enable Batching. Under Batch Size, keep Trigger default to use the size this trigger ships with, or choose Custom batch size to set a specific size. Batch Concurrency is optional; leave it blank to use the limit this trigger ships with.
Once a drain is in progress, the platform re-invokes the trigger until a round returns no further pages, so a single recurrence can produce several rounds of executions before the backlog is exhausted. A recurrence that finds no new records reports no changes and the flow does not execute, while a round the platform drove as part of a drain always reports changes, even when it returns nothing, so that the dispatch which completes the drain is not skipped. Each round records its resume position when it fetches its page, the same way an unbatched recurrence does, and the committed position advances only on the final page of a drain, so a drain whose stored position is lost re-delivers its window from the last committed mark rather than stepping over it.
With batching off, a downstream step reads the array of records at payload.body.data. With batching on, that array is not present: each execution receives a single record, or a batch of records, as its payload instead. Any step that reads payload.body.data, or indexes into it, must be updated to read the record directly before batching is enabled. Because batching is enabled per flow, this change is scoped to the flow it is enabled on and does not affect other flows using the same trigger.
Returned Data
With batching off, the matching records are returned as an array at payload.body.data. Row shape is dynamic and depends on the polled table's schema.
Example Payload
{
"body": {
"data": [
{
"id": 1,
"first_name": "Jane",
"last_name": "Doe",
"email": "jane.doe@example.com",
"created_at": "2025-08-15T14:32:00.000Z",
"updated_at": "2025-08-15T14:32:00.000Z",
"is_active": true
},
{
"id": 2,
"first_name": "John",
"last_name": "Smith",
"email": "john.smith@example.com",
"created_at": "2025-09-01T09:15:00.000Z",
"updated_at": "2025-09-02T11:48:00.000Z",
"is_active": false
}
]
}
}
With batching on, each execution instead receives one record, or a batch of records, taken from that same array.
Example Batched Item
{
"id": 2,
"first_name": "John",
"last_name": "Smith",
"email": "john.smith@example.com",
"created_at": "2025-09-01T09:15:00.000Z",
"updated_at": "2025-09-02T11:48:00.000Z",
"is_active": false
}
Fields shown are representative. The full response object includes additional properties.
Example Payload for New and Updated Records⤓
Actions
Query
Performs a query on a PostgreSQL database. | key: query
| Input | Notes | Example |
|---|---|---|
| Named Parameters | Optional named parameters to insert into a query. | |
| Parameters Object or Array | Optional parameters to insert into a query. Use a key-value object for named inputs (i.e. ${name}), or an array for index variables (i.e. $2). Values from this object are merged with the Named Parameters input when named variables are used. | |
| Connection | The PostgreSQL connection to use. | |
| Query Field | The SQL statement to execute against the database. Use named parameters (i.e. ${name}) or index variables (i.e. $1) to safely interpolate values. |
Example Payload for Query⤓
Changelog
2026-09-03
- Added opt-in batching to the New and Updated Records trigger, dispatching each changed record individually or in configured batches so a large backlog drains within one recurrence; enabling it changes the shape a downstream step receives
- Updated the New and Updated Records trigger to fetch at most one page of records per recurrence, so without batching a large backlog now drains across several scheduled recurrences instead of arriving in a single execution; a recurrence whose entire page shares a single Cursor Field value is exempt, because the position cannot resume inside such a group, and emits every remaining record instead
- Fixed records being silently skipped when they were committed to the table while the trigger was still reading it; records are now returned ordered by the cursor field ascending
- Added an optional Default Cursor Value input for performing an initial sync of records. The initial sync begins on the first recurrence and backfills every record past the specified value, seeding each once. Leave it empty to start from the first recurrence with no backfill
- Added an optional Max Records Per Recurrence input for bounding how many records a single recurrence returns; leave it empty to use the default of 1,000.
- Added an output schema to the Query action for improved field mapping during configuration
2026-06-29
Various modernizations and documentation updates
2026-04-30
Updated spectral version
2026-03-13
Removed the Debug Request input from all action inputs. Debug logging is now controlled internally and no longer appears as a configurable field in actions.
2025-11-25
Enhanced webhook triggers to support simulated test executions for improved manual testing capabilities