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:

write_to_neon.py
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:

read_from_neon.py
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:

  1. 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_level to logical). See Neon's Enable logical replication guide. ⚠️ This setting is irreversible — once enabled it cannot be turned off — so consider using a dedicated project.
  2. 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 -pooler suffix. See Neon connection pooling.
  3. 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:

stream_from_neon.py
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