Thomas Bley has released version 1.0 of a DuckDB driver for Doctrine DBAL. The package lets PHP applications use Doctrine's connection, query builder, and schema tools with DuckDB. Its Symfony examples also cover Doctrine ORM, entities, DQL, and migrations.

The main draw is DuckDB's support for reading CSV, newline-delimited JSON, and Parquet files as tables. An application can query those files without importing them into a database first.

Query Files Without Importing Them

You give Doctrine's SQL query builder a file path where a table name would normally go:

$result = $entityManager->getConnection()->createQueryBuilder()
    ->select('*')
    ->from("'/tmp/test.csv'") // or multiple files using /tmp/*.csv
    ->fetchAllAssociative();

DuckDB reads the CSV, detects its column types, and returns the rows. The same approach works with newline-delimited JSON and Parquet. A COPY statement can also convert data from one format to another:

$sql = "COPY (SELECT * FROM '/tmp/logs.json') TO '/tmp/logs.parquet'";
$entityManager->getConnection()->executeStatement($sql);

The README also shows how to map a Doctrine ORM class to a file. The table name becomes the file path, while row_number() provides the identifier Doctrine requires:

#[ORM\MappedSuperclass]
#[ORM\Table(name: "'/tmp/test.csv'")]
readonly class TestCsv
{
    #[ORM\Id]
    #[ORM\Column(name: 'row_number() over ()')] # emulate unique id
    public int $id;

    #[ORM\Column()]
    public ?string $aaa;
}

This mapping is read-only. It lets a repository call such as findAll() return rows from the CSV as objects.

Regular Doctrine Still Works

The package also supports regular DuckDB tables. In a Symfony application with Doctrine ORM installed, developers can create an entity, run a migration, and use the entity manager:

$product = new Product();
$product->setName('foo');
$product->setPrice(12.34);

$entityManager->persist($product);
$entityManager->flush();

The README includes examples for DQL, both Doctrine query builders, and the DBAL schema manager. DuckDB sequences can provide generated IDs for ORM entities.

Configuration

The driver registers through driver_schemes in config/packages/doctrine.yaml, and DuckDB's own settings go under options:

doctrine:
    dbal:
        url: 'duckdb://_/%kernel.project_dir%/var/db.duckdb'
        driver_schemes:
            duckdb: DuckDb\DBAL\Driver
        options:
            !php/const PDO::DUCKDB_ATTR_CONFIG:
                TimeZone: 'Europe/Berlin'
                # threads: 4 # max. number of threads
                # memory_limit: '4GB' # max. memory usage
                # access_mode: 'read_only' # open database file read-only
    orm:
        identity_generation_preferences:
            DuckDb\DBAL\Platforms\DuckDBPlatform: sequence

Clear var/cache after changing the file, then confirm the connection with php bin/console dbal:run-sql 'SELECT version(), current_database()'.

How to Install It

The Composer package requires PHP 8.2 or newer, Doctrine DBAL 4.4, and the pdo_duckdb extension. The README's full application setup uses Symfony 7 or newer, though Symfony is not a Composer requirement of the driver itself.

The extension is Bley's other project. It is a native PDO driver written in C and C++, so it does not need FFI or preloading. Its releases include DuckDB and prebuilt binaries for supported platforms. The project also says it is thread-safe and tested with FrankenPHP on PHP-ZTS.

Install the extension with PIE, then the package with Composer:

pie install thomas-0816/pdo-duckdb-php
composer require thomas-0816/doctrine-dbal-duckdb

Both projects use the MIT license. Version 1.0 of the DBAL driver was released on August 20, 2026. Visit the Doctrine DBAL for DuckDB repository for more examples, and the pdo_duckdb repository for the extension.