> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tape.network/llms.txt
> Use this file to discover all available pages before exploring further.

# DuckDB

[DuckDB](https://duckdb.org) is an in-process analytics database that can read files straight from S3 storage and write results back. Its `httpfs` extension works against a Tapedrive bucket with a secret that holds the gateway and your keys.

## Before you start

You need a bucket and a credential. A bucket is a tape that has delegated writes to the gateway, and a credential is an access key pair the gateway operator issues you. [Set up a bucket](/tools/s3-gateway#set-up-a-bucket) walks through both.

## Configure

```sql theme={null}
CREATE SECRET (
    TYPE s3,
    KEY_ID 'TAPE4Q7ZK2M9XH3PD8AW',
    SECRET 'mZ9vQ3nL8kR2tW6yB4cX7dF1hJ5pS0aG3uE8iO2q',
    ENDPOINT 's3.example.com',
    REGION 'solana'
);
```

DuckDB addresses buckets as subdomains by default, which needs a wildcard DNS record on your gateway. If you do not have one, add `URL_STYLE 'path'` to the secret. Both work.

## Everyday queries

```sql theme={null}
-- write a table to the bucket as Parquet
COPY (SELECT * FROM events) TO 's3://my-bucket/events.parquet';

-- read it back, with a filter
SELECT count(*) FROM read_parquet('s3://my-bucket/events.parquet') WHERE event_type = 'upload';

-- glob over many files
SELECT * FROM read_parquet('s3://my-bucket/events/*.parquet');

-- CSV and JSON work the same way
SELECT * FROM read_csv('s3://my-bucket/reports/sales.csv', header = true);
SELECT * FROM read_json_auto('s3://my-bucket/logs/*.json');

-- partitioned output and reads
COPY (SELECT * FROM events) TO 's3://my-bucket/by-day' (FORMAT parquet, PARTITION_BY (day));
SELECT count(*) FROM read_parquet('s3://my-bucket/by-day/*/*.parquet', hive_partitioning = true);

-- list what is there
SELECT * FROM glob('s3://my-bucket/**');
```

A filtered read fetches only the byte ranges it needs, so a query over a large Parquet file does not download the file. Writing 2,000,000 rows to Parquet takes about a second and produces a file identical to the same `COPY` written locally.

## Good to know

* Each `COPY` is one object write. Partitioned output writes one object per partition.

## Next

* [Downloads](/tools/s3-gateway/downloads) for how range requests are served.
* [ClickHouse](/tools/quickstarts/clickhouse) for tables that live on the bucket.
