Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.chatblocks.ai/llms.txt

Use this file to discover all available pages before exploring further.

The Postgres connector lets a block read from your own database with a SQL query you write. The platform wraps every customer query in a read-only safety envelope, defeats SSRF and DNS rebinding, and refreshes on a cron cadence.

Add a Postgres data source

1

Go to the wizard

/settings/data-sources/new/postgres.
2

Paste a postgres:// connection string

A standard Postgres URI. The connection string is envelope-encrypted with your workspace’s DEK before it’s written to Convex.The SSRF check (see below) runs synchronously on the URL — bad URLs (private IPs, localhost, plaintext schemes) are rejected immediately.
3

Click Test Connection

Optional but recommended. The wizard runs a one-off connection probe (admin-gated) against your database with the same safety envelope it uses for every refresh. You get back { ok: true } or a useful error.
4

Pick a cadence and save

5, 15, 60, 360, or 1440 minutes. Postgres is cron-mode only in v1 — no LISTEN/NOTIFY (long-running connections don’t fit Convex actions cleanly). Push-mode for Postgres is on the roadmap.

The SQL safety envelope

Every query you write — every refresh, every preview — is wrapped server-side in this transaction:
BEGIN TRANSACTION READ ONLY;
SET LOCAL statement_timeout = 5000;
SET LOCAL idle_in_transaction_session_timeout = 6000;
SELECT * FROM (<your SQL>) AS q LIMIT 10000;
COMMIT;
What this gives you:
  • Read-only. BEGIN TRANSACTION READ ONLY rejects any write at the Postgres level. INSERT, UPDATE, DELETE, DDL — all fail with a Postgres error.
  • 5-second statement timeout. A runaway query kills itself instead of holding the connection.
  • Hard 10 000 row cap. No accidental million-row pull.
  • Subquery wrapper. Your SQL is parenthesized as a derived table. You write SELECT ... FROM ... WHERE ... and the platform plugs it in.
What the validator rejects before the wrap:
  • Trailing ; on your SQL — stripped automatically.
  • Inner ; — rejected as potential statement chaining.
  • Empty SQL — rejected.
CTEs (WITH ... SELECT ...) work because they’re valid inside the subquery position. Window functions, joins, subqueries — all fine. Multi-statement scripts won’t fit.

SSRF protection

Two-layer defense before the platform connects to your database:
The wizard validates the connection string the moment you paste it:
  • Scheme must be postgres: or postgresql: — no http:, no file:, no internal:.
  • Hostname blocklist: localhost, anything ending in .local.
  • Literal IP check: IPv4 private ranges (10/8, 172.16/12, 192.168/16, 127/8, 169.254/16, 0.0.0.0), IPv6 private ranges (::1, fc00::/7, fe80::/10).
Pasting postgres://postgres@localhost/db is rejected up front.

Bind a block

{
  "binding": {
    "dataSourceId": "<postgres-data-source-id>",
    "queryConfig": {
      "type": "postgres.sql",
      "params": {
        "sql": "SELECT count(*) AS signups FROM users WHERE created_at > now() - interval '24 hours'"
      }
    },
    "projection": {
      "fields": {
        "value": { "source": "rows.0.signups", "format": "number" },
        "label": { "literal": "Signups (24h)" }
      }
    }
  },
  "widget": {
    "template": "metric",
    "data": { "value": "0", "label": "Signups (24h)" }
  }
}
The query result is shaped { rows: Row[], rowCount: number }. The projection paths into rows.0.signups to pluck the count.

Agent-driven schema introspection

Your coding agent can discover your database structure through two MCP tools without seeing the connection string. Useful when telling an agent “build me a block off my Postgres” and letting it figure out what to query:
Lists the top 50 tables sorted by activity (from pg_stat_user_tables). Returns table name, schema, and approximate row count.Postgres-only — other source types return isError: true.
Lists columns + types for a given table (from information_schema.columns).Postgres-only.
Both run in the same safety envelope (read-only transaction, statement timeout, DNS re-check). Both decrypt the credential and write an auditLog row before connecting.

Credential storage

A single-secret credential (just the connection string). Encrypted via the workspace DEK. Every decryption is audit-logged with the calling actor.

What’s next

Webhook

Push-mode delivery from your own systems.

Outbound MCP

Point at a third-party MCP server (Linear, GitHub, Notion).