Download the PHP package ntanduy/cloudflare-d1-database without Composer
On this page you can find all versions of the php package ntanduy/cloudflare-d1-database. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download ntanduy/cloudflare-d1-database
More information about ntanduy/cloudflare-d1-database
Files in ntanduy/cloudflare-d1-database
Package cloudflare-d1-database
Short Description Cloudflare D1 database driver for Laravel — full Eloquent & Query Builder support.
License MIT
Homepage https://github.com/TanDuy03/cloudflare-d1-database
Informations about the package cloudflare-d1-database
Cloudflare D1 Database Driver for Laravel
Use Cloudflare D1 as a native Laravel database driver — full Eloquent ORM, Query Builder, and Migration support.
🎯 Requirements
- PHP: >= 8.2
- Laravel: 10.x, 11.x, 12.x, or 13.x
✨ Features
- Full Laravel Integration — Eloquent ORM, Query Builder, Migrations, Seeding
- Two Connection Drivers — REST API (zero infrastructure) or Worker (low latency)
- Batch Queries — Execute multiple statements in a single HTTP round-trip
- Bulk Insert — Insert hundreds of rows efficiently via D1 batch execution
- Sessions / Read Replication — Leverage D1 global read replicas for lower-latency reads (Worker driver)
- Auto Read/Write Splitting — Automatic routing of SELECTs to replicas and writes to primary (Worker driver)
- Import — Import SQL files into D1 via
php artisan d1:import - Schema Dump — Export your D1 database via
php artisan d1:schema-dump - Time Travel — Point-in-time recovery via
php artisan d1:time-travel - Database Info — Inspect your D1 database with
php artisan d1:info - Circuit Breaker — Fail fast on sustained outages instead of blocking on retries
- Automatic Retries — Exponential backoff with jitter for 5xx/429 errors
- Query Logging — Optional callback for monitoring and debugging
- Health Check — Built-in
php artisan d1:healthto verify connection and measure latency
🚀 Installation
👏 Usage
Step 1: Publish Configuration
This creates config/d1-database.php with all available options.
Step 2: Choose a Driver
This package supports two drivers to connect Laravel with Cloudflare D1:
| Driver | How it works | Latency | Setup |
|---|---|---|---|
| REST (default) | Calls Cloudflare D1 REST API directly | Higher (extra HTTP hop) | API Token only |
| Worker | Routes queries through your own Cloudflare Worker | Lower (co-located with D1) | Requires deploying a Worker |
Driver 1: REST API (Default)
The simplest setup — no extra infrastructure needed. Queries are sent to Cloudflare's REST API.
Add to your .env:
How to get these values:
- API Token — Go to Cloudflare Dashboard → API Tokens → Create Token → use the "Edit Cloudflare D1" template
- Account ID — Found on your Cloudflare Dashboard overview page (right sidebar)
- Database ID — Go to Workers & Pages → D1 → click your database → copy the Database ID
That's it! Your Laravel app can now use D1.
Driver 2: Worker (Low Latency)
For production apps that need lower latency, deploy a Cloudflare Worker as a proxy between Laravel and D1.
Add to your .env:
Deploy the Worker
A ready-to-deploy Worker template is included in the Worker/ directory. To deploy:
Before deploying, update wrangler.jsonc with your D1 database binding:
Important: Set
WORKER_SECRETusingnpx wrangler secret put WORKER_SECRET— never put secrets inwrangler.jsonc. This secret must match theCF_D1_WORKER_SECRETin your Laravel.env.
HMAC Request Signing (Optional)
For additional security, enable HMAC request signing. Each request gets a unique signature that prevents body tampering and provides per-isolate replay detection.
Laravel .env:
Worker (optional enforcement):
When enabled, the PHP driver adds three headers to every request:
X-D1-Timestamp— current Unix timestampX-D1-Nonce— random 32-character hex string (unique per request)X-D1-Signature— HMAC-SHA256 oftimestamp.nonce.bodyusing the shared secret
The Worker verifies these when present, rejects expired timestamps, and tracks seen nonces to prevent replay within the same isolate. The per-request nonce ensures that two identical requests within the same second produce different signatures and are not falsely rejected as replays. Without HMAC_REQUIRED=true, unsigned requests still work (backward compatible).
Note: Replay detection is per-isolate — it resets on Worker cold starts and is separate per Cloudflare colo. For stricter guarantees, consider using Durable Objects for global nonce storage.
Worker Endpoints
The Worker exposes these endpoints:
| Endpoint | Method | Auth | Description |
|---|---|---|---|
/health |
GET | ❌ | Health check |
/query |
POST | ✅ Bearer | Execute a single SQL query |
/batch |
POST | ✅ Bearer | Execute multiple statements atomically |
/exec |
POST | ✅ Bearer | Execute raw DDL/migration SQL |
/raw |
POST | ✅ Bearer | Execute a query and return raw array-of-arrays |
Step 3: Set as Default Connection
To use D1 as the default database, add to your .env:
Step 4: Verify Connection
Run the built-in health check to verify your setup:
Step 5: Run Migrations
📖 Examples
Eloquent ORM
Query Builder
Query Logger
Monitor queries for debugging or performance analysis:
Runtime Driver Detection
Batch Queries
Execute multiple SQL statements in a single HTTP round-trip. On the Worker driver, this uses D1's native batch() for atomic execution.
If any statement fails, a D1BatchException is thrown with the index of the failing statement:
Driver Feature Matrix
| Feature | REST | Worker |
|---|---|---|
| Bulk Insert | ✅ | ✅ |
| Sessions / Read Replication | ❌ Not supported | ✅ Full support |
| Auto Read/Write Splitting | ❌ Not supported | ✅ Full support |
Import (d1:import) |
✅ | ✅ (via REST credentials) |
Time Travel (d1:time-travel) |
✅ | ✅ (via REST credentials) |
| Schema Dump | ✅ | ✅ (via REST credentials) |
Database Info (d1:info) |
✅ Full metadata | ✅ Query test + REST metadata |
| Batch Queries | ✅ | ✅ |
| Circuit Breaker | ✅ | ✅ |
| Automatic Retries | ✅ | ✅ |
Bulk Insert
Insert multiple rows efficiently using D1 batch execution:
- Each row becomes a parameterized INSERT (SQL injection safe)
- Each chunk of up to 100 rows is sent as a D1 batch (atomic per chunk — if any statement in a chunk fails, that chunk is rolled back)
- Datasets exceeding D1's 100-statement batch limit are automatically chunked into multiple HTTP calls — earlier chunks are committed even if a later chunk fails
- Works with both REST and Worker drivers
Sessions / Read Replication (Worker Driver Only)
D1 supports global read replication — read queries can be served by nearby replicas for lower latency. The Sessions API ensures sequential consistency across queries.
Important: Sessions are only available with the Worker driver. The REST API does not support D1 Sessions — this is a Cloudflare platform limitation.
Enable via Config
Add to your .env:
This automatically enables sessions for all queries on the Worker driver.
Enable Programmatically
Session Modes
| Mode | First Query | Use When |
|---|---|---|
first-unconstrained |
Any instance (primary or replica) | Lowest latency, eventual consistency OK |
first-primary |
Primary database | Need the latest data for first query |
<bookmark> |
At least as fresh as the bookmark | Continuing from a previous session |
How It Works
- PHP sends a
sessionparameter with each query to the Worker - Worker calls
env.DB.withSession(param)to create a D1 session - Worker returns a
bookmarkin the response - PHP stores the bookmark and uses it for the next query
- This ensures sequential consistency across HTTP calls
Worker Template
The Worker template in Worker/ already includes session support. If you're upgrading from a previous version, redeploy the Worker:
Auto Read/Write Splitting (Worker Driver Only)
Automatically route SELECT queries to D1 replicas and INSERT/UPDATE/DELETE to the primary — zero code changes required.
Once configured, Laravel handles everything:
sticky(default:true) — after a write, subsequent reads in the same request use the write connector's bookmark for sequential consistency- Works alongside manual
withSession()— R/W splitting handles the base routing, you can still use sessions for fine-grained control - REST driver ignores
read/writeconfig — no sessions support, all queries go to primary
Database Info
Inspect your D1 database metadata and connection status:
Displays database name, UUID, size, table count, read replication mode, R/W splitting status, circuit breaker state, and runs a query test.
Uses the D1 REST API for metadata. Worker-only users see table count and query test but need REST credentials for full metadata.
Import
Import a SQL file into your D1 database:
The command handles the full import flow automatically:
- Computes MD5 hash and sends
initrequest to get a presigned upload URL - Uploads the SQL file to R2
- Triggers ingestion
- Polls until import is complete
Note: Like
d1:schema-dump, the import command always uses the REST API. Worker-only users must also setCF_D1_API_TOKEN,CF_D1_ACCOUNT_ID, andCF_D1_DATABASE_IDin their.env.
Time Travel
D1 automatically creates restore points (bookmarks) for up to 30 days. Use d1:time-travel to get the current bookmark or restore your database to any point in time:
To restore the database to a previous state:
Warning: Restore is a destructive operation — it overwrites the database in place. In-flight queries will be cancelled. The command will prompt for confirmation before proceeding. The previous bookmark is shown after restore so you can undo if needed.
Schema Dump
Export your D1 database schema (and optionally data) as a SQL file:
This uses the D1 export REST API with polling mode. The dump is saved to database/schema/{connection}-schema.sql.
Options
Note:
d1:schema-dumpalways uses the REST API for export, even when the Worker driver is your primary connection. Worker-only users must also setCF_D1_API_TOKEN,CF_D1_ACCOUNT_ID, andCF_D1_DATABASE_IDin their.envfor the dump command to work.
Circuit Breaker
Prevents cascading failures when Cloudflare Workers experience cold starts or sustained outages. Instead of blocking for 30s+ on retries, the circuit breaker fails fast after consecutive failures.
States:
Enable in your config (config/database.php or config/d1-database.php):
Handle the exception:
Note: Use
fileorredisas thecache_driver. Avoiddatabaseto prevent a dependency loop when D1 itself is down.
Retry & Backoff
The driver automatically retries failed requests with exponential backoff and jitter:
- Retried: 5xx server errors, 429 rate limiting, connection timeouts
- Not retried: 4xx client errors (400, 401, 403, 404, etc.)
Backoff formula: delay × 2^(attempt-1) + random jitter (0-100ms)
| Attempt | Base Delay (100ms) |
|---|---|
| 1 | ~100-200ms |
| 2 | ~200-300ms |
⚙️ Configuration Reference
Manual Setup (Alternative)
Instead of publishing the config, you can add the connection directly to config/database.php:
Options Reference
| Option | Default | Description |
|---|---|---|
d1_driver |
rest |
Connection driver: rest (Cloudflare REST API) or worker (custom Worker) |
database |
— | Your Cloudflare D1 Database ID |
api |
https://api.cloudflare.com/client/v4 |
Cloudflare API base URL (REST driver only) |
auth.token |
— | Cloudflare API Token (REST driver only) |
auth.account_id |
— | Cloudflare Account ID (REST driver only) |
worker_url |
— | Your Worker URL (Worker driver only) |
worker_secret |
— | Shared secret for Worker auth (Worker driver only) |
hmac |
false |
Enable HMAC request signing for body-tamper protection and replay detection (Worker driver only) |
timeout |
10 |
HTTP request timeout in seconds |
connect_timeout |
5 |
HTTP connection timeout in seconds |
retries |
2 |
Max retry attempts on 5xx/429 errors |
retry_delay |
100 |
Base delay between retries in milliseconds |
transaction_mode |
silent |
How transaction APIs are handled: silent (no-op), log (warn once), exception (throw) |
session.enabled |
false |
Enable D1 sessions for read replication (Worker driver only) |
session.mode |
first-unconstrained |
Session mode: first-primary or first-unconstrained |
read_write_splitting.enabled |
false |
Route SELECT to read replicas, writes to primary (Worker driver only) |
read_write_splitting.sticky |
true |
After a write, route subsequent reads to write connector for consistency |
read_write_splitting.read_mode |
first-unconstrained |
Session mode for the read connector |
read_write_splitting.write_mode |
first-primary |
Session mode for the write connector |
circuit_breaker.enabled |
false |
Enable circuit breaker for fail-fast behavior |
circuit_breaker.threshold |
5 |
Consecutive failures before opening the circuit |
circuit_breaker.cooldown |
30 |
Seconds before allowing a probe request |
circuit_breaker.cache_driver |
file |
Laravel cache driver for circuit state (file, redis) |
Environment Variables
⚠️ Limitations
-
No real transactions — D1 is stateless over HTTP and doesn't support
BEGIN/COMMIT/ROLLBACK. The driver makes these methods no-ops so Laravel internals (auth, sessions, middleware) work without crashing.DB::transaction(Closure)will execute the closure, but provides no atomicity — each query runs immediately and cannot be rolled back on failure.DB::transaction(Closure, attempts: N)retries the closure on any exception, but without real deadlock detection or isolation.- Manual
beginTransaction(),commit(), androllBack()calls are also no-ops.transaction_mode=logwarns once per connection/request;transaction_mode=exceptionthrows immediately. - For atomic multi-statement execution, use
batch()which leverages D1's native batch API:
- REST API latency — Each query is an HTTP request routed through the Cloudflare API. The Worker driver offers significantly lower latency because the Worker is co-located with your D1 database. Latency varies by region, database size, and query complexity.
- Sessions / Read Replication — Worker driver only — The D1 Sessions API is only available via the Worker Binding. The REST API does not support sessions; all queries go to the primary database. This is a Cloudflare platform limitation.
- Schema dump requires REST credentials —
d1:schema-dumpuses the D1 export REST API. Even Worker-only users must setCF_D1_API_TOKEN,CF_D1_ACCOUNT_ID, andCF_D1_DATABASE_ID. - Export blocks queries — During export, D1 may be unavailable for queries (Cloudflare limitation for large databases).
- Bulk insert batch limit — D1 batch supports max 100 statements.
bulkInsert()automatically chunks larger datasets but each chunk is a separate HTTP call. - No streaming — Large result sets are loaded entirely into memory.
🌱 Testing
PHP Tests
Worker Tests (Vitest)
Local Development with Worker
Start the built-in Worker to test against a local D1 instance:
🤝 Contributing
Contributions are welcome! Please open an issue or pull request on GitHub.
🔒 Security
If you discover any security related issues, please email [email protected] instead of using the issue tracker.
🎉 Credits
- TanDuy03
- All Contributors
All versions of cloudflare-d1-database with dependencies
ext-pdo Version *
ext-pdo_sqlite Version *
guzzlehttp/psr7 Version ^2.4
illuminate/cache Version ^10.0|^11.0|^12.0|^13.0
illuminate/contracts Version ^10.0|^11.0|^12.0|^13.0
illuminate/database Version ^10.0|^11.0|^12.0|^13.0
illuminate/http Version ^10.0|^11.0|^12.0|^13.0
illuminate/support Version ^10.0|^11.0|^12.0|^13.0
saloonphp/saloon Version ^4.0