Connecting Pathway to NeonDB
NeonDB is a serverless, PostgreSQL-compatible database. Because Neon speaks the standard PostgreSQL wire protocol, Pathway connects to it with the regular PostgreSQL connector — pw.io.postgres.read and pw.io.postgres.write. There is no NeonDB-specific connector and no special configuration on the Pathway side: you point the connector at your Neon endpoint exactly as you would at any PostgreSQL server.
This guide covers the two Neon-specific things worth knowing:
- how to turn a Neon connection string into Pathway connection settings (including the mandatory TLS), and
- what to enable on the Neon side so that Change Data Capture (CDC / streaming reads) works.
If you are looking for the general PostgreSQL + Debezium tutorial instead, see Using database connectors.
Connection settings
In the Neon Console, open your project and copy its connection string from the Connection Details panel. It looks like this:
postgresql://neondb_owner:<password>@ep-cool-darkness-12345678.us-east-2.aws.neon.tech/neondb?sslmode=require
Pathway's PostgreSQL connector takes these as a postgres_settings dictionary (the keys are standard libpq connection parameters):
neon_settings = {
"host": "ep-cool-darkness-12345678.us-east-2.aws.neon.tech",
"port": "5432",
"dbname": "neondb",
"user": "neondb_owner",
"password": "<password>",
"sslmode": "require",
}
⚠️ Neon requires TLS. It rejects unencrypted connections, so always use an SSL-enabled sslmode. require encrypts the connection; for full certificate verification use verify-full together with sslrootcert pointing at Neon's CA certificate:
neon_settings = {
# ... host, port, dbname, user, password ...
"sslmode": "verify-full",
"sslrootcert": "/path/to/neon-root.crt",
}
Pathway's default sslmode (prefer) also works — it negotiates TLS first and Neon accepts it — but setting require/verify-full explicitly is clearer and stricter.
Writing to NeonDB
Use pw.io.postgres.write to send a Pathway table to Neon. With init_mode="create_if_not_exists" (or "replace") Pathway creates the destination table for you:
import pathway as pw
neon_settings = {
"host": "ep-cool-darkness-12345678.us-east-2.aws.neon.tech",
"port": "5432",
"dbname": "neondb",
"user": "neondb_owner",
"password": "<password>",
"sslmode": "require",
}
table = pw.debug.table_from_markdown(
"""
name | count
Milk | 500
Water | 600
"""
)
pw.io.postgres.write(
table,
neon_settings,
table_name="products",
init_mode="create_if_not_exists",
)
pw.run()
By default the connector appends the full stream of changes (each row carries the extra time and diff columns describing when the change happened and whether it is an insertion or a deletion). To instead maintain a primary-key-keyed snapshot of the latest state, pass output_table_type="snapshot" and a primary_key:
pw.io.postgres.write(
table,
neon_settings,
table_name="products",
output_table_type="snapshot",
primary_key=[table.name],
init_mode="create_if_not_exists",
)
Reading from NeonDB
Use pw.io.postgres.read to read a Neon table. In mode="static" it reads a one-shot snapshot — useful for batch jobs and quick experiments:
import pathway as pw
class TableSchema(pw.Schema):
id: int = pw.column_definition(primary_key=True)
value: str
table = pw.io.postgres.read(
neon_settings,
table_name="events",
schema=TableSchema,
mode="static",
)
pw.io.jsonlines.write(table, "events.jsonl")
pw.run()
Streaming changes (CDC) from NeonDB
In mode="streaming", pw.io.postgres.read follows the table in real time using PostgreSQL logical replication (the pgoutput plugin). Pathway creates a temporary replication slot automatically; you only need to provide a publication. To make this work on Neon:
- Enable logical replication on the Neon project. In the Neon Console, go to Project Settings → Logical Replication and enable it (this flips the project's
wal_leveltological). See Neon's Enable logical replication guide. ⚠️ This setting is irreversible — once enabled it cannot be turned off — so consider using a dedicated project. - Use a direct (non-pooled) endpoint. Logical replication requires a direct connection to the compute, not Neon's connection pooler. In the connection string, use the host without the
-poolersuffix. See Neon connection pooling. - Create a publication for the table(s) you want to follow, before starting the pipeline:
CREATE PUBLICATION my_publication FOR TABLE events;
Then read in streaming mode, passing the publication name:
import pathway as pw
class TableSchema(pw.Schema):
id: int = pw.column_definition(primary_key=True)
value: str
table = pw.io.postgres.read(
neon_settings,
table_name="events",
schema=TableSchema,
mode="streaming",
publication_name="my_publication",
)
pw.io.jsonlines.write(table, "events_stream.jsonl")
pw.run()
Every insert, update, and delete on events is now streamed into Pathway and propagated through your pipeline. The table must have a primary key for streaming reads.
⚠️ While a replication subscriber is connected, the Neon compute stays active and will not scale to zero, which affects compute usage. Logical-replication traffic also counts toward your project's data-transfer/egress quota.
NeonDB branches
A Neon branch is just a separate compute with its own connection string. To read from or write to a specific branch, point postgres_settings at that branch's endpoint host — no Pathway-side change is needed. Creating and deleting branches is a Neon control-plane operation (Console, Neon CLI, API, or Neon Local for ephemeral branches in development/CI); Pathway simply consumes the resulting endpoint.
Further reading
- Pathway PostgreSQL connector API:
pw.io.postgres.read/pw.io.postgres.write - Neon: Connect from any application · Connect securely (TLS/SSL) · Logical replication · Connection pooling