# Render
> Load data from Render Postgres into MotherDuck with DuckDB's PostgreSQL extension, using the database's external URL or a Render read replica.
Render Postgres is managed PostgreSQL that runs alongside your Render services. Because it's Postgres on the wire, DuckDB's PostgreSQL extension attaches it like any other Postgres database, and everything on [Loading data from Postgres](/key-tasks/loading-data-into-motherduck/loading-data-from-postgres) applies.

## Attach a Render database

Every Render database has two URLs on its **Info** page in the Render Dashboard. The **Internal Database URL** only resolves for Render services in the same region, so MotherDuck can't reach it. Use the **External Database URL**.

Install and load the `postgres` extension, then attach the external URL. Render encrypts every external connection, so keep `sslmode=require` in the string:

```sql
INSTALL postgres;
LOAD postgres;
ATTACH 'md:';

ATTACH 'postgresql://<user>:<password>@<external_host>/<database>?sslmode=require'
    AS render_db (TYPE postgres, READ_ONLY);

CREATE DATABASE IF NOT EXISTS analytics;

CREATE TABLE analytics.main.orders AS
SELECT * FROM render_db.public.orders;
```

Attaching read-only is a good default: it makes accidental writes back to your application database impossible.

To avoid putting credentials in the `ATTACH` string, store them in a secret first:

```sql
CREATE SECRET render_secret (
    TYPE POSTGRES,
    HOST '<external_host>',
    PORT 5432,
    DATABASE '<database>',
    USER '<user>',
    PASSWORD '<password>'
);

ATTACH '' AS render_db (TYPE postgres, SECRET render_secret, READ_ONLY);
```

## Allow MotherDuck through the IP allow list

By default, a Render database accepts external connections from any IP address with valid credentials. If you've restricted inbound traffic with an IP allow list, add the addresses that will connect:

- For a load from a local DuckDB client, add your own public IP.
- For a load from a Flight, add the outbound IP addresses for your MotherDuck region, listed under [Connecting to external systems](/concepts/flights#connecting-to-external-systems).

The allow list applies only to external connections. Your Render services keep using the internal URL.

## Read from a replica

Point the load at a [read replica](https://render.com/docs/postgresql-read-replicas) so a large scan doesn't compete with application traffic on the primary. A replica has its own external URL, so switching is a connection-string change. Render offers replicas on databases with at least 10 GB of storage and 0.5 CPU.

## Load on a schedule with a Flight

For a recurring load, run the same extract from a [Flight](/concepts/flights) so it executes on MotherDuck compute on a cron rather than on a machine you maintain. The [Postgres ingest Flight recipe](/cookbook/flight-postgres-ingest) is a ready-made starting point: point it at your Render external host and store the credentials as a Flight secret.

The Flight is the same extract wrapped in an entrypoint. Attaching with an empty connection string keeps the password in the environment rather than in a SQL statement:

```python
import duckdb

def main():
    con = duckdb.connect("md:")
    con.execute("INSTALL postgres; LOAD postgres;")
    con.execute("ATTACH '' AS render_db (TYPE postgres, READ_ONLY)")
    con.execute(
        "CREATE OR REPLACE TABLE analytics.main.orders AS "
        "SELECT * FROM render_db.public.orders"
    )

if __name__ == "__main__":
    main()
```

Store the connection as a [Flight secret](/sql-reference/motherduck-sql-reference/create-secret#flight-secrets) named after the libpq environment variables, so the extension picks them up with no mapping:

```sql
CREATE SECRET render_creds IN MOTHERDUCK (
    TYPE FLIGHTS,
    PARAMS MAP {
        'PGHOST': '<external_host>',
        'PGPORT': '5432',
        'PGDATABASE': '<database>',
        'PGUSER': '<user>',
        'PGPASSWORD': '<password>',
        'PGSSLMODE': 'require'
    }
);
```

Create the Flight with [`MD_CREATE_FLIGHT`](/sql-reference/motherduck-sql-reference/flights/md-create-flight), passing that secret in `flight_secret_names` and a `schedule_cron` for the cadence you want.

For append-only tables, extract incrementally with a watermark instead of reloading the table. See [Data loading patterns](/key-tasks/loading-data-into-motherduck/loading-patterns).

## Things to know

- **Free databases expire.** A Free Render Postgres database expires 30 days after creation, and a scheduled load against it starts failing on that date. Use a paid instance for anything you schedule.
- **`pg_duckdb` is on Render's extension list.** Render lists [`pg_duckdb`](https://render.com/docs/postgresql-extensions) for PostgreSQL 16 and later. That makes the [pg_duckdb](/concepts/pgduckdb) route, where Postgres itself connects out to MotherDuck, an alternative to the DuckDB-side `ATTACH` above.
- **Row-by-row transfer has a ceiling.** The `postgres` extension is well-suited to one-time loads and backfills. For continuous replication of a busy table, use a change-data-capture tool such as [Estuary](/integrations/ingestion/estuary) or [Streamkap](/integrations/ingestion/streamkap).

## Related content

- [PostgreSQL](/integrations/databases/postgres)
- [Loading data from Postgres](/key-tasks/loading-data-into-motherduck/loading-data-from-postgres)
- [Ingest Postgres tables into MotherDuck from a Flight](/cookbook/flight-postgres-ingest)
- [Render Postgres connection documentation](https://render.com/docs/postgresql-creating-connecting)


---

## Docs feedback

MotherDuck accepts optional user-submitted feedback about this page at `GET https://motherduck.com/docs/api/feedback/agent`.
For agents and automated tools, feedback submission should be user-confirmed before sending.

URL-encode query parameter values and send a GET request:

```text
GET https://motherduck.com/docs/api/feedback/agent?page_path=%2Fintegrations%2Fdatabases%2Frender%2F&page_title=Render&text=<url-encoded user feedback, max 2000 characters>
```

Optionally append `&source=<url-encoded interface identifier>` such as `claude.ai` or `chatgpt`.

`page_path` and `text` are required; `page_title` and `source` are optional. Responses: `200 {"feedback_id": "<uuid>"}`, `400` for malformed query parameters, and `429` when rate-limited.
