All Resources
R-58
Technology
What We Learned Shipping the First Postgres Connector
Building a database connector sounds straightforward until you actually do it. Cursor semantics, late-arriving data, schema drift — all the things we got wrong on the first pass.
PAR2 Labs
August 29, 2026
2 min

The Postgres connector looks like 300 lines of code. The first version was 60 lines. Everything between 60 and 300 was a small humility lesson about all the things production data sources do that demos don't.
01
Lesson 1: information_schema is a contract
Reading column types is easy. Reading column types and primary keys and foreign keys and nullability — and getting all of them consistently across Postgres versions — turned out to be the bulk of the work. Every assumption we made about the schema's stability was wrong at least once. We now run three separate queries to information_schema and reconcile them in code.
02
Lesson 2: cursors are about late data
Our first cursor implementation was WHERE updated_at > last_seen. Worked beautifully on the demo dataset. Broke immediately against real Postgres because applications backdate inserts — a row arriving at 14:05 might have an updated_at of 14:04:30, which our sync had already advanced past. We now optionally pull a configurable overlap window on each poll. The cursor advances, but slightly slower than wall-clock time.
Every “this happened at time T” timestamp in a production database is lying by some amount. The connector either accommodates that or silently loses data.
Every “this happened at time T” timestamp in a production database is lying by some amount.
03
Lesson 3: parametrised queries, always
It's tempting to format the cursor value straight into the SQL string — even when the cursor is a timestamp you control. Don't. The corner cases that break are a long list: special characters in timestamps, locale-sensitive formatting, and injection through field names you thought were trusted. Bind every cursor value as a parameter, validate any identifier you have to interpolate against a strict allowlist, and accept the small rigidity that comes with it.
04
Lesson 4: credentials are a UX problem
The most-asked question wasn't about cursor semantics or schema drift. It was about whether the password we asked them to paste into the wizard was stored safely. The answer — connector credentials are held encrypted at rest, not in plaintext — was already true; the fix was making that explicit in the UI. Once people could see it, the question stopped.
05
What's next
The connector interface is intentionally small: anything that's a cursor-based pull from a structured source can implement it. Today the PostgreSQL connector ships production-validated — it even auto-discovers foreign keys and turns them into graph connections — alongside a REST API connector. MySQL, MongoDB, S3/Parquet, and Kafka are on the roadmap, staged for later releases. The framework was the hard part; each subsequent source is mostly a small, well-bounded adapter. (Connectors are an Enterprise feature.)
Key Takeaways
01
Reading types, keys and nullability consistently across Postgres versions was the bulk of the work.
02
Applications backdate rows, so the cursor can pull an overlap window and advances slower than wall-clock time.
03
Bind every cursor value as a parameter and check any interpolated identifier against a strict allowlist.
04
Credentials were already encrypted at rest; showing that in the UI is what stopped the question.
PAR2 Labs · Technology
Work With Us