PHPackages                             ankane/ducklake - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. ankane/ducklake

ActiveLibrary

ankane/ducklake
===============

DuckLake for PHP

v0.1.2(1mo ago)10MITPHPPHP &gt;= 8.3CI passing

Since Nov 5Pushed 1mo agoCompare

[ Source](https://github.com/ankane/ducklake-php)[ Packagist](https://packagist.org/packages/ankane/ducklake)[ RSS](/packages/ankane-ducklake/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (4)Versions (4)Used By (0)

DuckLake PHP
============

[](#ducklake-php)

🦆 [DuckLake](https://ducklake.select/) for PHP

Run your own data lake with a SQL database and file/object storage

```
new DuckLake\Client(
    catalogUrl: 'postgres://user:pass@host:5432/dbname',
    storageUrl: 's3://my-bucket/'
);
```

[Learn more](https://duckdb.org/2025/05/27/ducklake.html)

Note: DuckLake is [not considered production-ready](https://ducklake.select/faq#is-ducklake-production-ready) at the moment

[![Build Status](https://github.com/ankane/ducklake-php/actions/workflows/build.yml/badge.svg)](https://github.com/ankane/ducklake-php/actions)

Installation
------------

[](#installation)

Run:

```
composer require ankane/ducklake
```

Add scripts to `composer.json` to download the shared library:

```
    "scripts": {
        "post-install-cmd": "DuckLake\\Library::check",
        "post-update-cmd": "DuckLake\\Library::check"
    }
```

And run:

```
composer install
```

Getting Started
---------------

[](#getting-started)

Create a client - this one stores everything locally

```
$ducklake = new DuckLake\Client(
    catalogUrl: 'sqlite:///ducklake.sqlite',
    storageUrl: 'data_files/',
    createIfNotExists: true
);
```

Create a table

```
$ducklake->sql('CREATE TABLE events (id bigint, name text)');
```

Load data from a file

```
$ducklake->sql("COPY events FROM 'data.csv'");
```

Confirm a new Parquet file was added to the data lake

```
$ducklake->listFiles('events');
```

Query the data

```
$ducklake->sql('SELECT COUNT(*) FROM events')->toArray();
```

Catalog Database
----------------

[](#catalog-database)

Catalog information can be stored in:

- Postgres: `postgres://user@pass@host:5432/dbname`
- SQLite: `sqlite:///path/to/dbname.sqlite`
- DuckDB: `duckdb:///path/to/dbname.duckdb`

Note: MySQL and MariaDB are not currently supported due to [duckdb/ducklake#70](https://github.com/duckdb/ducklake/issues/70) and [duckdb/ducklake#210](https://github.com/duckdb/ducklake/issues/210)

There are two ways to set up the schema:

1. Run [this script](https://ducklake.select/docs/stable/specification/tables/overview#full-schema-creation-script)
2. Configure the client to do it

```
new DuckLake\Client(createIfNotExists: true, ...);
```

Data Storage
------------

[](#data-storage)

Data can be stored in:

- Local files: `data_files/`
- Amazon S3: `s3://my-bucket/path/`
- [Other providers](https://ducklake.select/docs/stable/duckdb/usage/choosing_storage): todo

### Amazon S3

[](#amazon-s3)

Credentials are detected in the standard AWS SDK locations

IAM permissions

- Read: `s3::ListBucket`, `s3::GetObject`
- Write: `s3::ListBucket`, `s3::PutObject`
- Maintenance: `s3::ListBucket`, `s3::GetObject`, `s3::PutObject`, `s3::DeleteObject`

Operations
----------

[](#operations)

Create an empty table

```
$ducklake->sql('CREATE TABLE events (id bigint, name text)');
```

Or a table from a file

```
$ducklake->sql("CREATE TABLE events AS FROM 'data.csv'");
```

Load data from a file

```
$ducklake->sql("COPY events FROM 'data.csv'");
```

You can also load data directly from other [data sources](https://duckdb.org/docs/stable/data/data_sources)

```
$ducklake->attach('blog', 'postgres://localhost:5432/blog');
$ducklake->sql('INSERT INTO events SELECT * FROM blog.events');
```

Or [register existing data files](https://ducklake.select/docs/stable/duckdb/metadata/adding_files)

```
$ducklake->addDataFiles('events', 'data.parquet');
```

Note: This transfers ownership to the data lake, so the file may be deleted as part of [maintenance](#maintenance)

Update data

```
$ducklake->sql('UPDATE events SET name = ? WHERE id = ?', ['Test', 1]);
```

Delete data

```
$ducklake->sql('DELETE * FROM events WHERE id = ?', [1]);
```

Schema Changes
--------------

[](#schema-changes)

Update the schema

```
$ducklake->sql('ALTER TABLE events ADD COLUMN active BOOLEAN');
```

Set or remove a [partitioning key](https://ducklake.select/docs/stable/duckdb/advanced_features/partitioning)

```
$ducklake->sql('ALTER TABLE events SET PARTITIONED BY (name)');
// or
$ducklake->sql('ALTER TABLE events RESET PARTITIONED BY');
```

Views
-----

[](#views)

Create a view

```
$ducklake->sql('CREATE VIEW events_view AS SELECT * FROM events');
```

Drop a view

```
$ducklake->sql('DROP VIEW events_view');
```

Snapshots
---------

[](#snapshots)

Get snapshots

```
$ducklake->snapshots();
```

Query the data at a specific snapshot version or time

```
$ducklake->sql('SELECT * FROM events AT (VERSION => ?)', [3]);
// or
$ducklake->sql('SELECT * FROM events AT (TIMESTAMP => ?)', [new DateTime()]);
```

You can also specify a snapshot when creating the client

```
new DuckLake\Client(snapshotVersion: 3, ...);
// or
new DuckLake\Client(snapshotTime: new DateTime(), ...);
```

Maintenance
-----------

[](#maintenance)

Merge files

```
$ducklake->mergeAdjacentFiles();
```

Expire snapshots

```
$ducklake->expireSnapshots(olderThan: new DateTime());
```

Clean up old files

```
$ducklake->cleanupOldFiles(olderThan: new DateTime());
```

Rewrite files with a certain percentage of deleted rows

```
$ducklake->rewriteDataFiles(deleteThreshold: 0.5);
```

Configuration
-------------

[](#configuration)

Get [options](https://ducklake.select/docs/stable/duckdb/usage/configuration)

```
$ducklake->options();
```

Set an option globally

```
$ducklake->setOption('parquet_compression', 'zstd');
```

Or for a specific table

```
$ducklake->setOption('parquet_compression', 'zstd', tableName: 'events');
```

SQL Safety
----------

[](#sql-safety)

Use parameterized queries when possible

```
$ducklake->sql('SELECT * FROM events WHERE id = ?', [1]);
```

For places that do not support parameters, use `quote` or `quoteIdentifier`

```
$quotedTable = $ducklake->quoteIdentifier('events');
$quotedFile = $ducklake->quote('path/to/data.csv');
$ducklake->sql("COPY $quotedTable FROM $quotedFile");
```

Reference
---------

[](#reference)

Get table info

```
$ducklake->tableInfo();
```

Drop a table

```
$ducklake->dropTable('events');
// or
$ducklake->dropTable('events', ifExists: true);
```

List files

```
$ducklake->listFiles('events');
```

List files at a specific snapshot version or time

```
$ducklake->listFiles('events', snapshotVersion: 3);
// or
$ducklake->listFiles('events', snapshotTime: new DateTime());
```

History
-------

[](#history)

View the [changelog](https://github.com/ankane/ducklake-php/blob/master/CHANGELOG.md)

Contributing
------------

[](#contributing)

Everyone is encouraged to help improve this project. Here are a few ways you can help:

- [Report bugs](https://github.com/ankane/ducklake-php/issues)
- Fix bugs and [submit pull requests](https://github.com/ankane/ducklake-php/pulls)
- Write, clarify, or fix documentation
- Suggest or add new features

To get started with development:

```
git clone https://github.com/ankane/ducklake-php.git
cd ducklake-php
composer install

# Postgres
createdb ducklake_php_test
createdb ducklake_php_test2
CATALOG=postgres composer test

# MySQL and MariaDB
mysqladmin create ducklake_php_test
mysqladmin create ducklake_php_test2
CATALOG=mysql composer test

# SQLite
CATALOG=sqlite composer test

# DuckDB
CATALOG=duckdb composer test
```

###  Health Score

37

—

LowBetter than 83% of packages

Maintenance91

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity42

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~75 days

Total

3

Last Release

44d ago

PHP version history (2 changes)v0.1.0PHP &gt;= 8.1

v0.1.1PHP &gt;= 8.3

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/220358?v=4)[Andrew Kane](/maintainers/ankane)[@ankane](https://github.com/ankane)

---

Top Contributors

[![ankane](https://avatars.githubusercontent.com/u/220358?v=4)](https://github.com/ankane "ankane (13 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/ankane-ducklake/health.svg)

```
[![Health](https://phpackages.com/badges/ankane-ducklake/health.svg)](https://phpackages.com/packages/ankane-ducklake)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
