Templates

Import Data from PostgreSQL into Google Sheets

A scheduled run queries a PostgreSQL table, formats the returned rows into spreadsheet-ready values, and appends them to a Google Sheet. If the query returns nothing, the workflow exits cleanly instead of writing an empty row.

5 minutes setupUpdated 2026-06-19

What this is

Getting data out of a database and in front of non-technical people usually means a one-off export, a manual copy-paste, or a brittle script someone forgets to run. This workflow turns that into a repeatable step: query PostgreSQL, hand the rows to Google Sheets, done. Run it on a schedule and your sheet stays in sync with whatever the query returns.

How it runs

The flow is linear with one guard. A PostgreSQL step runs a SELECT against your table. A JavaScript step reshapes the result set into the 2D array of values Google Sheets expects, deriving the column order from the first row. A Switch then checks whether anything came back: if there are rows, they are appended to the sheet; if not, the workflow exits cleanly without touching the spreadsheet.

The steps

  • PostgreSQL (sql_postgres_1): Runs SELECT * FROM your_table. Supports named parameters with the :#param syntax for filtered imports.
  • JavaScript (format_rows): Converts the array of row objects into a 2D array of values. Null-safes empty fields, serializes dates to ISO strings, and stringifies nested objects so every cell lands clean.
  • Switch (decide_has_rows): Reads the formatted row count. Rows present go to the append branch; an empty result routes to the exit.
  • Google Sheets (google_sheets_1): Appends the formatted rows to the target spreadsheet and range.
  • Exit (exit_no_rows): Completes the run with a clear message when there is nothing to import.

Design notes

The empty-result guard skips the write when the query returns nothing, keeping your sheet free of blank rows and making scheduled runs safe to fire as often as you like.

Column order is derived from the first returned row rather than hardcoded, so the workflow keeps working when you add or reorder columns in the query, with no mapping to maintain.

Parameters live in the query's messageBody using :#param placeholders. That keeps values out of the SQL string and lets you drive the import from workflow input when you need a filtered or incremental pull.

Setup

  1. Connect your PostgreSQL and Google Sheets integrations.
  2. In the sql_postgres_1 step, replace SELECT * FROM your_table with your query. For a filtered import, add named parameters, for example: SELECT * FROM orders WHERE status = :#status with parameters: { "status": "new" }.
  3. In the google_sheets_1 step, set spreadsheetId to your sheet's ID and adjust range (default Sheet1!A:Z) to match your tab and columns.
  4. If your integrations are named in Unmeshed, set the connection name on the PostgreSQL and Google Sheets steps.
  5. Attach a schedule to the workflow for automatic runs, or invoke it on demand via the API.

When to use it

  • You want a live or near-live mirror of a database table in a spreadsheet for reporting or sharing.
  • Non-technical teammates need the data in Google Sheets, not in a SQL client.
  • You are moving a MySQL-to-Sheets sync to PostgreSQL and want it running on Unmeshed.

Adapt this template in Unmeshed

Start from the sequence above, then connect your APIs, approvals, decision logic, and notifications as durable workflow steps.