# Ingest with DuckDB

The [DuckDB Altertable extension](https://github.com/altertable-ai/duckdb-altertable) lets DuckDB write to attached Altertable catalogs. Use it when your data already lives in DuckDB, local files, or a DuckDB-compatible source and you want to load it into Altertable with SQL.

The extension supports:

- **Attached databases** for ingesting into Altertable catalogs with standard SQL
- **Direct table access** through DuckDB's catalog
- **Remote writes** for bulk loads, appends, and schema updates

## Installation

Install and load the community extension from DuckDB:

```sql
INSTALL altertable FROM community;
LOAD altertable;
```

## Attach a database

Use your lakehouse username, lakehouse password, and catalog in the connection string:

```sql
ATTACH
'user={{LAKEHOUSE_USERNAME}} password={{LAKEHOUSE_PASSWORD}} catalog=your-lakehouse-catalog'
AS remote_db (TYPE ALTERTABLE);
```

### Connection parameters

| Parameter  | Description               | Example                   |
| ---------- | ------------------------- | ------------------------- |
| `user`     | Lakehouse username        | `your_lakehouse_username` |
| `password` | Lakehouse password        | `your_lakehouse_password` |
| `catalog`  | Remote Altertable catalog | `analytics`               |

Or use DuckDB secrets:

```sql
CREATE SECRET my_altertable (
  TYPE altertable,
  USER '{{LAKEHOUSE_USERNAME}}',
  PASSWORD '{{LAKEHOUSE_PASSWORD}}',
  CATALOG 'your-lakehouse-catalog'
);

ATTACH '' AS remote_db (TYPE altertable, SECRET my_altertable);
```

To disconnect the attached catalog:

```sql
DETACH remote_db;
```

## Create a remote table

Create tables through the attached Altertable database:

```sql
CREATE TABLE remote_db.main.orders (
    order_id INTEGER,
    amount DOUBLE,
    status VARCHAR
);
```

## Load local data

Create an Altertable table from a local DuckDB table:

```sql
CREATE TABLE remote_db.main.orders AS
SELECT *
FROM local_db.main.orders;
```

You can also load files that DuckDB can read:

```sql
CREATE TABLE remote_db.main.orders AS
SELECT *
FROM read_parquet('orders.parquet');
```

## Append rows

Append new records from a query:

```sql
INSERT INTO remote_db.main.orders
SELECT order_id, amount, status
FROM read_csv('new-orders.csv');
```

Append individual rows when you need a quick manual load:

```sql
INSERT INTO remote_db.main.orders VALUES
    (1001, 42.50, 'open'),
    (1002, 19.99, 'paid');
```

## Update table definitions

Use `ALTER TABLE` when incoming data needs a new column:

```sql
ALTER TABLE remote_db.main.orders ADD COLUMN note VARCHAR;
```

For Python DataFrame workflows, see [Ingest with Pandas, Polars, and Ibis](/docs/ingest-data/pandas-polars-ibis.md). For querying attached Altertable tables from DuckDB, see [Query data with DuckDB](/docs/query-data/duckdb.md). For more examples and source builds, see the [DuckDB Altertable extension repository](https://github.com/altertable-ai/duckdb-altertable).