Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Cloudflare D1 Database Laravel Package

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...

View on GitHub
Deep Wiki
Context7
v0.11.0

v0.11.0

Highlights

  • Harden Worker driver with optional HMAC request signing, nonce-based replay detection, and oversized body guard.
  • Add configurable D1 transaction handling via transaction_mode: silent, log, or exception.
  • Add Worker endpoints and validation improvements for /query, /batch, /exec, and /raw.
  • Improve Laravel 10-13 compatibility and D1 schema grammar handling.

Security

  • Use constant-time Worker secret comparison.
  • Sign HMAC payloads as timestamp.nonce.body using X-D1-Timestamp, X-D1-Nonce, and X-D1-Signature.
  • Track used nonces per Worker isolate and prune expired entries.

Reliability

  • Avoid automatic retries for mutating batch operations.
  • Limit retry behavior to safe read queries.
  • Normalize malformed JSON responses into driver exceptions or query logger failures.
  • Count circuit breaker failures once per logical request.

Verification

  • PHP Pint, PHPStan, Pest, Composer validation, Worker Vitest, Worker TypeScript, and mock Worker tests pass.
v0.10.0

Highlights

  • 🔐 HMAC Request Signing — Optional per-request HMAC-SHA256 signatures for replay protection. Enable with CF_D1_HMAC=true.
  • 🛡️ Security: Worker auth upgraded to timing-safe comparison (crypto.subtle.timingSafeEqual).
  • 📐 D1ConnectorInterface — New interface contract decouples code from Saloon implementation.
  • ⚙️ Config merge fix — Credentials missing from user config now properly trigger validation errors.

⚠️ Breaking Changes

  • accountId and apiUrl on CloudflareConnector changed from public to protected. Use getAccountId() accessor.
  • D1PdoStatement::execute($params) now merges with previously bound values (matching real PDO behavior).
  • Worker error responses return HTTP 500 for D1 execution failures instead of 200.

Added

  • databaseExec() and databaseRaw() methods on CloudflareWorkerConnector
  • Input validation on all Worker endpoints (HTTP 400 for malformed requests)
  • d1_driver config validation
  • HMAC_REQUIRED and HMAC_WINDOW_SECONDS Worker env vars for HMAC enforcement
  • R/W Splitting now configurable via CF_D1_RW_SPLITTING=true env var (no more uncommenting config blocks)
  • CHANGELOG.md following Keep a Changelog format

Changed

  • Config merge simplified — only operational defaults merged; missing credentials trigger errors
  • CircuitBreaker uses now()->timestamp for deterministic testability
  • Test Worker rewritten to match production switch-based routing; removed itty-router
  • README latency claims replaced with relative descriptions
  • Cleaned up composer.json keywords

Removed

  • printStarReminder() from D1ServiceProvider
  • Legacy tests/database/factories/UserFactory.php
  • Dead code in tests/Pest.php

Fixed

  • ✅ Laravel 10 CI fully green — all command tests converted to $this->artisan()
  • Circuit breaker test flakiness on slow CI runners
  • Fix package:discover crash when other packages (e.g. spatie/permission) reference d1 connection during boot
  • README npm run start → npm run dev
  • autoload-dev trailing slash (PSR-4)
v0.9.1

🐛 Fix

  • 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).

⬆️ Upgrade

composer update ntanduy/cloudflare-d1-database

Full Changelog: v0.9.0...v0.9.1

v0.9.0

What's New in v0.9.0

🚀 New Features

Import (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:

  1. Computes MD5 hash and sends init request to get a presigned R2 upload URL
  2. Uploads the SQL file
  3. Triggers ingestion
  4. Polls until import is complete — shows progress, query count, duration, and final DB size

Uses the D1 Import REST API. Worker-only users need REST credentials (CF_D1_API_TOKEN, CF_D1_ACCOUNT_ID, CF_D1_DATABASE_ID).

Time Travel (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.

🐛 Bug Fixes

  • Fixed 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.

🔧 Improvements

  • Extracted FormatsBytes trait — shared byte formatting logic between D1ImportCommand and D1InfoCommand (was duplicated)
  • Moved D1ImportCommand properties to top of class per PSR conventions

📊 Test Summary

  • 250 tests, 546 assertions — all passing
  • Pint ✅ | PHPStan level 5 ✅ | Pest ✅
  • PHP 8.2 / 8.3 / 8.4 × Laravel 10 / 11 / 12 / 13

📁 Files Changed

New files:

  • src/D1/Requests/Rest/D1ImportRequest.php
  • src/D1/Requests/Rest/D1TimeTravelBookmarkRequest.php
  • src/D1/Requests/Rest/D1TimeTravelRestoreRequest.php
  • src/Console/Commands/D1ImportCommand.php
  • src/Console/Commands/D1TimeTravelCommand.php
  • src/Console/Concerns/FormatsBytes.php
  • tests/Unit/D1ImportRequestTest.php
  • tests/Unit/D1TimeTravelRequestTest.php
  • tests/Feature/D1ImportCommandTest.php
  • tests/Feature/D1TimeTravelCommandTest.php

Modified files:

  • src/Connectors/CloudflareD1Connector.php — added databaseImport(), timeTravelBookmark(), timeTravelRestore()
  • src/D1/Requests/Rest/D1ExportRequest.php — fixed dump_options nesting
  • src/Console/Commands/D1InfoCommand.php — use FormatsBytes trait
  • src/D1ServiceProvider.php — registered new commands
  • tests/Unit/D1ExportRequestTest.php — updated for dump_options, added no_schema test
  • README.md — added Import, Time Travel docs + feature matrix

⬆️ Upgrade

composer update ntanduy/cloudflare-d1-database

No breaking changes. Fully backward compatible with v0.8.0.

Full Changelog: v0.8.0...v0.9.0

v0.8.0

v0.8.0 — Auto Read/Write Splitting + d1:info Command

New Features

Auto Read/Write Splitting (Worker Driver)

Automatically 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 reads (sticky => true, default) — after a write, subsequent reads in the same request use the primary for sequential consistency
  • Uses D1 Sessions API under the hood — two separate Worker connectors with different session modes
  • Circuit breaker applies to both read and write connectors independently
  • REST driver gracefully ignores read/write config (no session support)
  • Fully backward compatible — without read/write keys, behavior is identical to v0.7.0

d1:info Artisan Command

Inspect your D1 database metadata and connection status:

php artisan d1:info

Displays:

  • Database name, UUID, size, table count (via D1 REST API)
  • Read replication mode and version
  • R/W splitting status (enabled/disabled, sticky)
  • Circuit breaker state (enabled/disabled, threshold, cooldown)
  • Query test with latency measurement (SELECT 1)
php artisan d1:info --connection=d1

Files Changed

  • src/D1/D1Connection.php — dual connector support, sticky read behavior via $recordsModified
  • src/D1ServiceProvider.php — detects read/write config, creates dual Worker connectors
  • src/Connectors/CloudflareD1Connector.php — new databaseInfo() method
  • src/D1/Requests/Rest/D1DatabaseInfoRequest.php — Saloon GET request for D1 metadata API
  • src/Console/Commands/D1InfoCommand.php — new Artisan command
  • config/d1-database.php — R/W splitting config documentation (commented out by default)
  • README.md — documentation for both features, updated Driver Feature Matrix

Upgrade from v0.7.0

composer update ntanduy/cloudflare-d1-database

No breaking changes. Both features are opt-in:

  • R/W splitting: add read/write keys to your D1 connection config
  • d1:info: just run php artisan d1:info

If you previously published the config, re-publish to get the new R/W splitting documentation:

php artisan vendor:publish --tag="d1-config" --force
v0.7.0

v0.7.0 — Sessions, Bulk Insert & Schema Dump

Three new D1 capabilities with full backward compatibility.

New Features

D1 Sessions / Read Replication (Worker driver only)

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();
  • Enable via config (CF_D1_SESSION_ENABLED=true) or programmatically
  • Modes: first-unconstrained, first-primary, or bookmark-based
  • Automatic bookmark tracking across queries
  • REST driver throws D1UnsupportedFeatureException with clear message

Bulk Insert

Insert 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
]);
  • One HTTP round-trip per 100 rows (D1 batch limit)
  • Atomic execution — if any row fails, none are applied
  • Parameterized queries (SQL injection safe)
  • Column names properly escaped (SQLite "" standard)
  • Validates all rows have consistent column structure
  • Works with both REST and Worker drivers

Schema Dump (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
  • Uses D1 export API with polling mode
  • Saves to database/schema/{connection}-schema.sql
  • Download retries (3 attempts, 2s delay) for network resilience
  • Requires REST credentials even when using Worker driver

Worker Template Update

The 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

Configuration

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

Bug Fixes

  • Fixed config comment block ordering (session config separated from its docblock)
  • Column names in bulkInsert() now properly escape " characters
  • Schema dump download step now retries on network failures

Driver Feature Matrix

Feature REST Worker
Bulk Insert ✅ ✅
Sessions / Read Replication ❌ Not supported ✅ Full support
Schema Dump ✅ ✅ (via REST credentials)
Batch Queries ✅ ✅
Circuit Breaker ✅ ✅

New Files

  • src/D1/Requests/Rest/D1ExportRequest.php
  • src/Console/Commands/D1SchemaDumpCommand.php
  • tests/Unit/BulkInsertTest.php (7 tests)
  • tests/Unit/SessionTest.php (14 tests)
  • tests/Unit/D1ExportRequestTest.php (5 tests)

Test Results

  • 216 tests, 471 assertions — all passing
  • PHPStan level 5 — 0 errors
  • Laravel Pint — clean

Upgrade Notes

  • No breaking changes — all new features are opt-in
  • Worker users wanting sessions must redeploy the Worker template
  • d1:schema-dump requires REST API credentials (CF_D1_API_TOKEN, CF_D1_ACCOUNT_ID, CF_D1_DATABASE_ID)
v0.6.2

What's Changed

Bug Fixes

  • Fix REST batch request format — Body now sends {"batch": [...]} instead of a bare JSON array, matching the Cloudflare D1 REST API specification
  • Fix circuit breaker incorrectly reset by 4xx responses — Only 2xx responses now call recordSuccess(); client errors no longer close the circuit
  • Fix inconsistent exception on retry exhaustion — Connection failures (timeouts, DNS) now throw D1Exception consistently instead of raw Throwable
  • Fix D1SchemaGrammar constructor crash on Laravel 10/11 — Added method_exists() guard since Grammar::__construct() only exists in Laravel 12+
  • Fix lastInsertId() return value — Returns "0" instead of false when no insert has occurred, matching native PDO behavior
  • Remove dead D1TransactionException class — Was defined but never thrown anywhere

Improvements

  • Transaction method documentation — Added prominent WARNING docblocks to beginTransaction(), commit(), rollBack() explaining they are no-ops with no atomicity
  • README updated — Expanded Limitations section with clear guidance on DB::transaction() behavior and recommending batch() for atomic operations
  • D1Exception::fromApiError() now accepts $previous — Original exceptions are chained for better debugging
  • PHPStan ignore for cross-version compatibility — Suppresses false positive on method_exists() check

Full Changelog

All 190 tests passing across PHP 8.2/8.3/8.4 × Laravel 10/11/12/13.

v0.6.1

Bug Fixes

Transaction methods are now no-ops instead of throwing exceptions

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.

Changes

  • D1Pdo::beginTransaction(), commit(), rollBack() — return true instead of throwing D1TransactionException
  • D1Connection — delegates to Laravel's ManagesTransactions trait for transaction depth tracking and event dispatching
  • D1Connection::executeBeginTransactionStatement() — no-op to prevent BEGIN SQL from reaching D1 (fixes PHP 8.4 compatibility)
  • D1Connection::createSavepoint() / performRollBack() — no-op to prevent unsupported SAVEPOINT / ROLLBACK TO SAVEPOINT SQL

Important Note

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.

v0.6.0

v0.6.0 — 2026-04-07

New Features

  • Batch Query — execute multiple statements in a single HTTP round-trip via $db->batch([...]). Uses D1 native batch() on Worker driver.
  • Circuit Breaker — fail-fast mechanism to prevent blocking retries during Worker cold starts or sustained outages. Disabled by default, opt-in via circuit_breaker.enabled config.

Bug Fixes

  • sendWithRetry() now throws D1Exception when retries are exhausted on 5xx/429 responses instead of silently returning the error response.

Notes

  • All existing APIs unchanged — safe to upgrade from v0.5.x
  • Circuit Breaker requires Laravel Cache (recommend file or redis driver)
  • Run php artisan vendor:publish --tag=d1-config to get new config keys
v0.5.3
v0.5.2

What's Changed

✨ Improvements

  • Added a one-time star reminder message displayed in the console after the first installation

🔧 Maintenance

  • Added MIT License

Full Changelog: https://github.com/TanDuy03/cloudflare-d1-database/compare/v0.5.1...v0.5.2

v0.5.1

✨ What's New

php artisan d1:health Command

  • Validates D1 config (REST or Worker credentials)
  • Runs a live test query (SELECT 1 as ok)
  • Measures end-to-end latency
  • Table output with masked secrets
  • Exit code 0/1 for CI/CD integration

Other Changes

  • Code style fixes (Pint compliance)
  • README improvements
v0.5.0

🚀 What's New

✨ Worker Driver — Low Latency D1 Access

  • New worker driver for ~10-50ms latency (vs ~100-500ms with REST API)
  • Deploy a Cloudflare Worker as proxy between Laravel and D1
  • Endpoints: /query, /batch, /exec, /raw with Bearer token auth
  • Ready-to-deploy Worker template included in Worker/ directory

🏗️ Architecture Refactor

⚠️ Breaking Changes

Environment Variables Renamed

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

Migration Guide

  1. Update your .env file with the new variable names
  2. Re-publish config: php artisan vendor:publish --tag="d1-config" --force

🐛 Bug Fixes

  • Fixed TokenAuthenticator null token TypeError in test environment
  • Fixed missing $latestResponse property in D1ServiceProviderWorkerTest
v0.4.1

What's changed

  • Restore support for Laravel 10–13 by removing saloonphp/laravel-plugin
  • Use Saloon core v4 only (no Laravel plugin dependency)
  • Update test matrix to cover Laravel 10–13 on PHP 8.2–8.4

Note: v0.4.0 dropped Laravel 10 support.
v0.4.1 restores Laravel 10 support without changing the public API.

v0.4.0

Added

  • Support for Laravel 11, 12 and 13.
  • Test matrix for PHP 8.2, 8.3 and 8.4.

Changed

  • Upgraded saloonphp/saloon and saloonphp/laravel-plugin to v4 for security fixes.
  • Updated orchestra/testbench and pestphp/pest versions for Laravel 11–13.

Removed

  • Dropped official support for Laravel 10 (use v0.3.x if you still need it).
v0.2.9

🚀 Features

  • Query Logging Support: Added CloudflareD1Connector::setQueryLogger() to allow global query monitoring. Now supports tracking execution time (latency), success status, and detailed error parsing (code, message, status).

🐛 Bug Fixes

  • Nested Transactions: Fixed "There is no active transaction" error when running Laravel tests (or nested DB transactions) by implementing transaction depth tracking in D1Pdo.
  • Smart Retry Logic: Fixed a state management issue where disabling retries for Schema Builder caused retries to be disabled globally. Now uses regex to automatically detect DDL statements (CREATE, DROP, ALTER) and disable retries only for those queries.

🛠 Improvements

  • Type Safety: Added strict type hinting (array) for the $config parameter in D1Connection.
  • Code Cleanup: Removed redundant transaction handling in D1Connection to rely on standard Laravel/PDO behavior.
  • Error Handling: Improved mapping of Cloudflare D1 errors to standard PDO exceptions.
v0.2.5

Release version 1.0.0: Support Laravel 10-12, D1 compatibility fixes

v0.2.4

Added

  • Add illuminate/support package dependency

Improved

  • Add config validation with clear error messages
  • Support both nested and flat config structure
v0.2.2
v0.2.1
v0.2.0
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
marcelgwerder/laravel-api-handler
firebrikdotcom/conveyor-laravel-broadcaster
kanata-php/conveyor-laravel-broadcaster
alish/short-message
sonrac/lumen-league-oauth2
pushery/sanctum-hardening-for-laravel
evanschleret/laravel-uuidable
yigit-serin/laravel-openvidu
adachsoft/command-executor-lib
tagixo/document-builder
tagixo/page-builder
tagixo/mail-builder
tagixo/form-builder
primix/primix
tagixo/core
alesima/laravel-azure-service-bus
tomshaw/shopcart
likyly/laravel
darthsoup/shoppingcart
tdt/core