ntanduy/cloudflare-d1-database
Use Cloudflare D1 as a native Laravel database driver with full Eloquent ORM, Query Builder, and migration support. Choose REST API or Worker connections, batch queries, bulk inserts, read replication, import and schema dump commands, time travel, retries, and circuit breaking. Requires PHP 8.2+ and...
transaction_mode: silent, log, or exception./query, /batch, /exec, and /raw.timestamp.nonce.body using X-D1-Timestamp, X-D1-Nonce, and X-D1-Signature.formatBytes() now uses SI units (kB/MB/GB, ÷1000) to match Cloudflare Dashboard display. Previously used binary units (KB/MB/GB, ÷1024) which showed slightly different values (e.g. 256 KB vs Dashboard's 262 kB).composer update ntanduy/cloudflare-d1-database
Full Changelog: v0.9.0...v0.9.1
d1:import)Import SQL files into your D1 database directly from Laravel:
php artisan d1:import path/to/file.sql
php artisan d1:import database/seeds/data.sql --connection=d1
The command handles the full import flow automatically:
init request to get a presigned R2 upload URLUses the D1 Import REST API. Worker-only users need REST credentials (
CF_D1_API_TOKEN,CF_D1_ACCOUNT_ID,CF_D1_DATABASE_ID).
d1:time-travel)Point-in-time recovery for your D1 database — restore to any minute within the last 30 days:
# Get the current bookmark
php artisan d1:time-travel
# Get bookmark at a specific timestamp (ISO 8601 or Unix)
php artisan d1:time-travel --timestamp="2024-01-15T10:30:00+00:00"
php artisan d1:time-travel --timestamp=1705312200
# Restore to a bookmark (destructive — prompts for confirmation)
php artisan d1:time-travel --restore --bookmark="00000085-0000024c-00004c6d-abc123"
# Restore to a timestamp
php artisan d1:time-travel --restore --timestamp="2024-01-15T10:30:00+00:00"
After restore, the previous bookmark is displayed so you can undo if needed.
Uses the D1 Time Travel REST API. Worker-only users need REST credentials.
D1ExportRequest body structure — no_data, no_schema, and tables options are now correctly nested under dump_options as required by the Cloudflare API. Previously these were sent at the top level and silently ignored.FormatsBytes trait — shared byte formatting logic between D1ImportCommand and D1InfoCommand (was duplicated)D1ImportCommand properties to top of class per PSR conventionsNew files:
src/D1/Requests/Rest/D1ImportRequest.phpsrc/D1/Requests/Rest/D1TimeTravelBookmarkRequest.phpsrc/D1/Requests/Rest/D1TimeTravelRestoreRequest.phpsrc/Console/Commands/D1ImportCommand.phpsrc/Console/Commands/D1TimeTravelCommand.phpsrc/Console/Concerns/FormatsBytes.phptests/Unit/D1ImportRequestTest.phptests/Unit/D1TimeTravelRequestTest.phptests/Feature/D1ImportCommandTest.phptests/Feature/D1TimeTravelCommandTest.phpModified files:
src/Connectors/CloudflareD1Connector.php — added databaseImport(), timeTravelBookmark(), timeTravelRestore()src/D1/Requests/Rest/D1ExportRequest.php — fixed dump_options nestingsrc/Console/Commands/D1InfoCommand.php — use FormatsBytes traitsrc/D1ServiceProvider.php — registered new commandstests/Unit/D1ExportRequestTest.php — updated for dump_options, added no_schema testREADME.md — added Import, Time Travel docs + feature matrixcomposer update ntanduy/cloudflare-d1-database
No breaking changes. Fully backward compatible with v0.8.0.
Full Changelog: v0.8.0...v0.9.0
d1:info CommandAutomatically route SELECT queries to D1 read replicas and INSERT/UPDATE/DELETE to the primary database — zero code changes required.
'd1' => [
'driver' => 'd1',
'd1_driver' => 'worker',
'read' => [
'session' => ['mode' => 'first-unconstrained'],
],
'write' => [
'session' => ['mode' => 'first-primary'],
],
'sticky' => true,
],
sticky => true, default) — after a write, subsequent reads in the same request use the primary for sequential consistencyread/write config (no session support)read/write keys, behavior is identical to v0.7.0d1:info Artisan CommandInspect your D1 database metadata and connection status:
php artisan d1:info
Displays:
SELECT 1)php artisan d1:info --connection=d1
src/D1/D1Connection.php — dual connector support, sticky read behavior via $recordsModifiedsrc/D1ServiceProvider.php — detects read/write config, creates dual Worker connectorssrc/Connectors/CloudflareD1Connector.php — new databaseInfo() methodsrc/D1/Requests/Rest/D1DatabaseInfoRequest.php — Saloon GET request for D1 metadata APIsrc/Console/Commands/D1InfoCommand.php — new Artisan commandconfig/d1-database.php — R/W splitting config documentation (commented out by default)README.md — documentation for both features, updated Driver Feature Matrixcomposer update ntanduy/cloudflare-d1-database
No breaking changes. Both features are opt-in:
read/write keys to your D1 connection configd1:info: just run php artisan d1:infoIf you previously published the config, re-publish to get the new R/W splitting documentation:
php artisan vendor:publish --tag="d1-config" --force
Three new D1 capabilities with full backward compatibility.
Leverage D1 global read replicas for lower-latency reads with sequential consistency.
$connection = DB::connection('d1');
// Enable session — first query goes to any nearby replica
$connection->withSession('first-unconstrained');
// Queries automatically track bookmarks for consistency
$users = DB::table('users')->get();
// Get bookmark for cross-request continuity
$bookmark = $connection->getBookmark();
// End session when done
$connection->endSession();
CF_D1_SESSION_ENABLED=true) or programmaticallyfirst-unconstrained, first-primary, or bookmark-basedD1UnsupportedFeatureException with clear messageInsert hundreds of rows in a single atomic D1 batch call:
$connection->bulkInsert('users', [
['name' => 'Alice', 'email' => '[email protected]'],
['name' => 'Bob', 'email' => '[email protected]'],
// ...up to thousands of rows
]);
"" standard)d1:schema-dump)Export your D1 database via the Cloudflare REST API:
php artisan d1:schema-dump # Full dump (schema + data)
php artisan d1:schema-dump --no-data # Schema only
php artisan d1:schema-dump --prune # Delete migrations after dump
php artisan d1:schema-dump --path=./backup.sql
database/schema/{connection}-schema.sqlThe Worker template (Worker/src/index.ts) now supports sessions in /query and /batch endpoints. If upgrading from v0.6.x, redeploy your Worker:
cd Worker && npm run deploy
New config options (all optional, backward compatible):
CF_D1_SESSION_ENABLED=false # Enable D1 sessions (Worker only)
CF_D1_SESSION_MODE=first-unconstrained # Session mode
bulkInsert() now properly escape " characters| Feature | REST | Worker |
|---|---|---|
| Bulk Insert | ✅ | ✅ |
| Sessions / Read Replication | ❌ Not supported | ✅ Full support |
| Schema Dump | ✅ | ✅ (via REST credentials) |
| Batch Queries | ✅ | ✅ |
| Circuit Breaker | ✅ | ✅ |
src/D1/Requests/Rest/D1ExportRequest.phpsrc/Console/Commands/D1SchemaDumpCommand.phptests/Unit/BulkInsertTest.php (7 tests)tests/Unit/SessionTest.php (14 tests)tests/Unit/D1ExportRequestTest.php (5 tests)d1:schema-dump requires REST API credentials (CF_D1_API_TOKEN, CF_D1_ACCOUNT_ID, CF_D1_DATABASE_ID){"batch": [...]} instead of a bare JSON array, matching the Cloudflare D1 REST API specificationrecordSuccess(); client errors no longer close the circuitD1Exception consistently instead of raw ThrowableD1SchemaGrammar constructor crash on Laravel 10/11 — Added method_exists() guard since Grammar::__construct() only exists in Laravel 12+lastInsertId() return value — Returns "0" instead of false when no insert has occurred, matching native PDO behaviorD1TransactionException class — Was defined but never thrown anywherebeginTransaction(), commit(), rollBack() explaining they are no-ops with no atomicityDB::transaction() behavior and recommending batch() for atomic operationsD1Exception::fromApiError() now accepts $previous — Original exceptions are chained for better debuggingmethod_exists() checkAll 190 tests passing across PHP 8.2/8.3/8.4 × Laravel 10/11/12/13.
Previously, calling DB::beginTransaction(), DB::commit(), DB::rollBack(), or DB::transaction() would throw a D1TransactionException, breaking Laravel features that rely on transactions internally (authentication, sessions, middleware).
Now these methods are silently ignored, allowing Laravel to function normally with D1. This fix works with both REST and Worker drivers.
D1 is stateless over HTTP — transactions do not provide real atomicity. Queries execute immediately and cannot be rolled back. For atomic operations, use DB::connection('d1')->batch() which leverages D1's native batch API.
$db->batch([...]). Uses D1 native batch() on Worker driver.circuit_breaker.enabled config.sendWithRetry() now throws D1Exception when retries are exhausted
on 5xx/429 responses instead of silently returning the error response.file or redis driver)php artisan vendor:publish --tag=d1-config to get new config keysFull Changelog: https://github.com/TanDuy03/cloudflare-d1-database/compare/v0.5.1...v0.5.2
php artisan d1:health CommandSELECT 1 as ok)/query, /batch, /exec, /raw with Bearer token authConnectors/ namespace: CloudflareConnector, CloudflareD1Connector, CloudflareWorkerConnectorRequests/Rest/ and Requests/Worker/D1Connection supports driver switching (rest / worker)All env vars now use a consistent CF_D1_ prefix:
| Old | New |
|---|---|
D1_DRIVER |
CF_D1_DRIVER |
CLOUDFLARE_TOKEN |
CF_D1_API_TOKEN |
CLOUDFLARE_ACCOUNT_ID |
CF_D1_ACCOUNT_ID |
CLOUDFLARE_D1_DATABASE_ID |
CF_D1_DATABASE_ID |
D1_WORKER_URL |
CF_D1_WORKER_URL |
D1_WORKER_SECRET |
CF_D1_WORKER_SECRET |
D1_TIMEOUT |
CF_D1_TIMEOUT |
D1_CONNECT_TIMEOUT |
CF_D1_CONNECT_TIMEOUT |
D1_RETRIES |
CF_D1_RETRIES |
D1_RETRY_DELAY |
CF_D1_RETRY_DELAY |
.env file with the new variable namesphp artisan vendor:publish --tag="d1-config" --forceTokenAuthenticator null token TypeError in test environment$latestResponse property in D1ServiceProviderWorkerTestsaloonphp/laravel-pluginNote: v0.4.0 dropped Laravel 10 support.
v0.4.1 restores Laravel 10 support without changing the public API.
saloonphp/saloon and saloonphp/laravel-plugin to v4 for security fixes.orchestra/testbench and pestphp/pest versions for Laravel 11–13.CloudflareD1Connector::setQueryLogger() to allow global query monitoring. Now supports tracking execution time (latency), success status, and detailed error parsing (code, message, status).D1Pdo.array) for the $config parameter in D1Connection.D1Connection to rely on standard Laravel/PDO behavior.Release version 1.0.0: Support Laravel 10-12, D1 compatibility fixes
illuminate/support package dependencyFull Changelog: https://github.com/TanDuy03/cloudflare-d1-database/compare/v0.2.2...v0.2.3
How can I help you explore Laravel packages today?