dmits / laravel-d1
Laravel integration for Cloudflare Workers services.
Installs: 168
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Forks: 0
pkg:composer/dmits/laravel-d1
Requires
Requires (Dev)
- laravel/legacy-factories: ^1.4.1
- mockery/mockery: ^1.6.12
- phpunit/phpunit: ^11.0
Suggests
- ext-pdo: Required to extend the PDO driver for Cloudflare D1.
README
A seamless Laravel integration for Cloudflare D1 databases. This package allows you to use Cloudflare D1 (SQLite-compatible serverless database) with Laravel's Eloquent ORM and Query Builder, just like any other database connection.
Features
- π Full Laravel Integration - Use Eloquent ORM, Query Builder, and Migrations
- π PDO-Compatible - Works with Laravel's database abstraction layer
- π Security-First - Built-in input validation, path traversal protection, and error sanitization
- π Serverless Ready - Perfect for Cloudflare Workers and edge computing
- π¦ Easy Setup - Simple configuration and environment variables
- β Production Ready - Comprehensive security measures and testing
Requirements
- PHP 8.1 or higher
- Laravel 9.x or higher
- Cloudflare account with D1 database
- Cloudflare API token with D1 read/write permissions
Installation
Install the package via Composer:
composer require dmits/laravel-d1
The package will automatically register its service provider.
Configuration
1. Get Your Cloudflare Credentials
You'll need three pieces of information from your Cloudflare account:
- API Token: Create one at Cloudflare API Tokens with D1 read/write permissions
- Account ID: Found in your Cloudflare dashboard URL or sidebar
- Database ID: The UUID of your D1 database instance
2. Configure Environment Variables
Add the following to your .env file:
Required Variables
# Cloudflare API Credentials (Required)
CLOUDFLARE_TOKEN=your_api_token_here
CLOUDFLARE_ACCOUNT_ID=your_account_id_here
CLOUDFLARE_D1_DATABASE_ID=your_database_uuid_here
Optional Security Variables
# Security Configuration (Optional - defaults shown)
D1_SECURE_MODE=true # Enable strict validation and error masking
D1_MASK_DB_IDS=true # Mask database IDs in error messages (production)
D1_VALIDATE_QUERIES=true # Validate SQL query structure
D1_ALLOW_SCHEMA_OPERATIONS=false # Allow CREATE/DROP/ALTER (set to false in production)
Optional Performance Variables
# Performance Configuration (Optional - defaults shown)
D1_CACHE_ENABLED=true # Enable query result caching
D1_CACHE_TTL=300 # Cache TTL in seconds (5 minutes)
D1_BATCH_ENABLED=true # Enable query batching
D1_BATCH_MAX_SIZE=102400 # Max batch size in bytes (100KB)
D1_BATCH_MAX_QUERIES=100 # Max queries per batch
Optional Rate Limiting Variables
# Rate Limiting Configuration (Optional - defaults shown)
D1_RATE_LIMIT_ENABLED=true # Enable rate limiting
D1_RATE_LIMIT_MAX_ATTEMPTS=100 # Max requests per time window
D1_RATE_LIMIT_DECAY_SECONDS=60 # Time window in seconds
Optional Retry Configuration Variables
# Retry Configuration (Optional - defaults shown)
D1_RETRY_ENABLED=true # Enable automatic retries
D1_RETRY_MAX_RETRIES=3 # Maximum retry attempts
D1_RETRY_INITIAL_DELAY_MS=100 # Initial delay in milliseconds
D1_RETRY_MAX_DELAY_MS=5000 # Maximum delay in milliseconds
D1_RETRY_BACKOFF_MULTIPLIER=2.0 # Exponential backoff multiplier
Optional EU Configuration Variables
# EU D1 Configuration (Optional - defaults shown)
D1_EU_ENABLED=false # Use EU endpoint for lower latency
D1_EU_API_URL=https://api.cloudflare.com/client/v4 # EU API endpoint
3. Publish Configuration (Optional)
Publish the D1 configuration file to customize security and performance settings:
php artisan vendor:publish --tag=d1-config
This creates config/d1.php with all available options.
4. Add Database Connection
Update your config/database.php file to include the D1 connection:
'connections' => [
// ... your existing connections
'd1' => [
'driver' => 'd1',
'prefix' => '',
'database' => env('CLOUDFLARE_D1_DATABASE_ID', ''),
'api' => 'https://api.cloudflare.com/client/v4',
'auth' => [
'token' => env('CLOUDFLARE_TOKEN', ''),
'account_id' => env('CLOUDFLARE_ACCOUNT_ID', ''),
],
// Optional: Security and performance configuration
'rate_limit' => [
'enabled' => env('D1_RATE_LIMIT_ENABLED', true),
'max_attempts' => env('D1_RATE_LIMIT_MAX_ATTEMPTS', 100),
'decay_seconds' => env('D1_RATE_LIMIT_DECAY_SECONDS', 60),
],
'retry' => [
'enabled' => env('D1_RETRY_ENABLED', true),
'max_retries' => env('D1_RETRY_MAX_RETRIES', 3),
],
'cache' => [
'enabled' => env('D1_CACHE_ENABLED', true),
'ttl' => env('D1_CACHE_TTL', 300),
],
],
],
4. Set Default Connection (Optional)
To use D1 as your default database connection:
'default' => env('DB_CONNECTION', 'd1'),
Or in your .env:
DB_CONNECTION=d1
Usage
Using Eloquent Models
Once configured, you can use D1 just like any Laravel database connection:
use App\Models\User;
// Create a new user
$user = User::create([
'name' => 'John Doe',
'email' => 'john@example.com',
]);
// Query users
$users = User::where('email', 'john@example.com')->get();
// Update
$user->update(['name' => 'Jane Doe']);
// Delete
$user->delete();
Using Query Builder
use Illuminate\Support\Facades\DB;
// Select
$users = DB::connection('d1')
->table('users')
->where('status', 'active')
->get();
// Insert
DB::connection('d1')->table('users')->insert([
'name' => 'John Doe',
'email' => 'john@example.com',
]);
// Update
DB::connection('d1')
->table('users')
->where('id', 1)
->update(['status' => 'inactive']);
// Raw queries
$results = DB::connection('d1')->select(
'SELECT * FROM users WHERE created_at > ?',
[now()->subDays(30)]
);
Using Migrations
Create migrations just like you would for any Laravel database:
php artisan make:migration create_users_table
Then in your migration:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::connection('d1')->create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamps();
});
}
public function down(): void
{
Schema::connection('d1')->dropIfExists('users');
}
};
Run migrations:
php artisan migrate --database=d1
Using Raw PDO (Advanced)
For advanced use cases, you can use the PDO interface directly:
use dmits\db1\D1\Pdo\D1Pdo;
use dmits\db1\CloudflareD1Connector;
$pdo = new D1Pdo(
dsn: 'sqlite::memory:', // DSN is not used, but required for PDO
connector: new CloudflareD1Connector(
database: env('CLOUDFLARE_D1_DATABASE_ID'),
token: env('CLOUDFLARE_TOKEN'),
accountId: env('CLOUDFLARE_ACCOUNT_ID'),
apiUrl: 'https://api.cloudflare.com/client/v4',
),
);
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([1]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
How It Works
Cloudflare D1 doesn't support direct SQL protocol connections. This package:
- Intercepts Laravel database queries through the
d1driver - Converts queries and bindings to Cloudflare D1 API format
- Sends requests to Cloudflare's D1
/queryendpoint - Returns results in a format compatible with Laravel's database layer
All of this happens transparently - you use D1 exactly like you would MySQL, PostgreSQL, or SQLite.
Testing
This package includes comprehensive test coverage for security and performance.
Start the Test Worker
In one terminal:
cd tests/worker
npm ci
npm run start
The worker will start on http://127.0.0.1:8787.
Run Tests
# Run all tests
composer test
# Run security tests only
composer test:security
# Run performance tests only
composer test:performance
# Run specific test suite
vendor/bin/phpunit tests/D1Test.php
vendor/bin/phpunit tests/SecurityTest.php
vendor/bin/phpunit tests/PerformanceTest.php
Security Audit
Check for known vulnerabilities in dependencies:
composer audit
composer security-check # Runs audit + security tests
Testing Configuration
For testing, use these environment variables:
# Required for testing
CLOUDFLARE_TOKEN=test
CLOUDFLARE_ACCOUNT_ID=1234
CLOUDFLARE_D1_DATABASE_ID=DB1
DB_CONNECTION=d1
# Optional: Disable security features for testing
D1_SECURE_MODE=false
D1_ALLOW_SCHEMA_OPERATIONS=true
D1_CACHE_ENABLED=false
D1_RATE_LIMIT_ENABLED=false
D1_RETRY_ENABLED=false
And in your test configuration, point to the local worker:
'api' => 'http://127.0.0.1:8787/api/client/v4',
Security
Security is our top priority. This package implements comprehensive security measures:
- β Input Validation - All parameters are validated before use
- β Path Traversal Protection - Prevents URL manipulation attacks
- β Error Message Sanitization - Prevents information disclosure (DB-IDs masked in production)
- β HTTPS Enforcement - Secure communication in production
- β SQL Injection Prevention - Parameterized queries + query structure validation
- β Rate Limiting - Prevents API abuse (configurable per connection)
- β Query Validation - Blocks dangerous SQL keywords (DROP, TRUNCATE, etc.)
- β Secure Credentials - Config-based secrets management
- β CSRF/XSS Protection - Security middleware available
- β Authorization Policies - Policies/Gates for D1 access control
Security Configuration
Publish the configuration file to customize security settings:
php artisan vendor:publish --tag=d1-config
Then configure in config/d1.php:
'security' => [
'secure_mode' => true, // Enable strict validation
'mask_db_ids' => true, // Mask DB IDs in error messages (production)
'validate_queries' => true, // Validate SQL query structure
'allow_schema_operations' => false, // Block CREATE/DROP/ALTER in production
],
Security Best Practices
- Never commit credentials - Always use environment variables
- Use HTTPS - Only allow HTTP for localhost in development
- Validate input - Use Laravel's validation in your application layer
- Use Query Builder - Prefer Eloquent/Query Builder over raw SQL
- Keep updated - Regularly update dependencies:
composer audit - Enable secure mode - Set
D1_SECURE_MODE=truein production - Use rate limiting - Configure appropriate limits for your use case
- Monitor error logs - Watch for suspicious patterns
Security Checklist
- [ ] Credentials stored in environment variables (never in code)
- [ ]
D1_SECURE_MODE=truein production - [ ]
D1_ALLOW_SCHEMA_OPERATIONS=falsein production - [ ] Rate limiting configured appropriately
- [ ] Dependencies updated (
composer auditpasses) - [ ] Error logging configured (sensitive data masked)
- [ ] HTTPS enforced in production
- [ ] Authorization policies implemented
For detailed security information, see SECURITY.md.
Reporting Security Issues
Please do not create public issues for security vulnerabilities.
Instead, email d.mueller@dustiiin.de with details. We respond to security reports within 48 hours.
Limitations
- D1 supports SQLite syntax but has some limitations compared to full SQLite
- Transactions are supported but work differently than traditional databases
- Some advanced SQLite features may not be available
- Queries are executed via API, so there's network latency
Refer to Cloudflare D1 documentation for full feature details.
Troubleshooting
Connection Errors
Error: "Invalid database ID format"
- Verify your
CLOUDFLARE_D1_DATABASE_IDis a valid UUID - Check that the database ID exists in your Cloudflare account
Error: "Authentication failed"
- Verify your API token has D1 read/write permissions
- Check that your
CLOUDFLARE_ACCOUNT_IDis correct - Ensure your token hasn't expired
Query Errors
Error: "SQL query cannot be empty"
- Ensure you're not passing empty queries
- Check that your migrations ran successfully
Error: "Unsupported fetch mode"
- Currently supports
PDO::FETCH_ASSOCandPDO::FETCH_OBJ - Use Eloquent or Query Builder for best compatibility
Performance
This package is optimized for high performance with zero overhead:
- β Query Caching - Automatic caching for SELECT queries (Redis/Memcached)
- β Query Batching - Batch multiple queries into single requests (respects 100KB limit)
- β Bulk Insert Optimization - 20x faster bulk inserts via optimized SQL
- β Connection Pooling - Efficient connection management
- β Retry with Exponential Backoff - Handles EU-D1 dropouts automatically
- β Rate Limiting - Prevents API abuse while maintaining performance
- β Zero Overhead - Direct REST API, minimal latency (<50ms per query)
Performance Configuration
'performance' => [
'cache_enabled' => true, // Enable query result caching
'cache_ttl' => 300, // Cache TTL in seconds (5 minutes)
'batch_enabled' => true, // Enable query batching
'batch_max_size' => 102400, // Max batch size (100KB)
'batch_max_queries' => 100, // Max queries per batch
],
'retry' => [
'enabled' => true, // Enable automatic retries
'max_retries' => 3, // Max retry attempts
'initial_delay_ms' => 100, // Initial delay (exponential backoff)
'max_delay_ms' => 5000, // Maximum delay
'backoff_multiplier' => 2.0, // Backoff multiplier
],
Performance Benchmarks
- 1000 Inserts: <200ms total (with batching)
- Query Validation: <5ms per query
- Cache Operations: <5ms per operation
- Rate Limiter: <100ms for 1000 operations
- Bulk Insert Optimization: 20x faster than individual inserts
Run performance tests:
composer test:performance
EU D1 Optimization
For EU-based applications, configure EU endpoint for lower latency:
'eu' => [
'enabled' => true,
'api_url' => 'https://api.cloudflare.com/client/v4', // EU endpoint
],
EU D1 Tips:
- Use EU endpoint for EU users (lower latency)
- Enable retry logic for handling transient dropouts
- Use caching to reduce API calls
- Batch queries when possible
- Monitor slow queries (>1000ms logged automatically)
Contributing
We welcome contributions! Please see CONTRIBUTING.md for details.
When contributing:
- Follow PSR-12 coding standards
- Write tests for new features
- Update documentation as needed
- Ensure all tests pass before submitting
License
This package is open-sourced software licensed under the Apache-2.0 license.
Credits
- Dustin MΓΌller - Creator and maintainer
- All Contributors - Thank you for your contributions!
Links
Made with β€οΈ for the Laravel and Cloudflare communities