workers-sdk
workers-sdk copied to clipboard
Multi service d1 binding
Fixes #9511 – Vite plugin does not allow for more than one service with D1 binding
Describe your change
This PR adds a local testing workaround for an issue where multiple services using the same D1 binding don't work concurrently during development, even though they work fine in production.
The issue was that only one service was able to run with an active D1 binding at a time when using Vite in dev mode. If the gateway tried to call both identity and passport services (each with its own access to the same D1 DB), only one would respond successfully. This limitation made local development and testing of real-world, multi-service setups quite difficult.
Solution
To solve this, I created a lightweight D1 proxy server inside tools/d1-proxy/server.ts. This proxy takes in a shared SQLite DB path (via .env or CLI) and exposes endpoints (/query and /query-first) to execute SQL. It mimics how multiple services would interact with a shared D1 binding in production.
I also added a Vite fixture under fixtures/vite-d1-multi-service to demo and test this. It includes:
gateway/– the root Vite serviceservices/identity/– one Workerservices/passport/– another Workerservices/shared-state/– the shared SQLite DB file
Each service talks to the proxy, allowing you to test shared state in a multi-service D1 environment locally and concurrently, just like it would run in production.
Unlike the
persistStateworkaround (which only allows one service to work at a time), this proxy-based solution enables multiple services to run concurrently with access to the same SQLite DB — closer to real production behavior.
This approach also prevents SQL query failures like the one shown in the issue (
Failed query: select ...) when multiple Workers try to bind to D1 concurrently during development.
Note: This change does not affect production builds — it only enhances local dev/testing workflows that simulate real-world shared D1 usage.
Why this change?
The original issue (#9511) explains how using auxiliaryWorkers in Vite with more than one service causes conflicts with shared D1 DB state. persistState can partially fix this, but only for one service at a time — not both.
Since there's currently no support for true shared D1 bindings locally, this proxy-based solution acts as a consistent and scalable workaround. It unblocks development and local E2E testing for apps relying on shared data between multiple Workers.
This PR provides a local workaround until true multi-service D1 bindings are supported by Vite/Wrangler. It aims to simplify multi-service app development and improve confidence in local E2E test setups.
Checklist
Tests
- [ ] TODO (before merge)
- [x] Manually tested: Verified identity and passport services share DB correctly
- [ ] Tests not necessary because: fixture added for local dev only
Wrangler / Vite E2E Tests
- [ ] CI Job required? – I don't know
- [x] Required
- [ ] Not required because: this mainly supports manual testing of dev-only behavior
Public documentation
- [ ] TODO (before merge) – Cloudflare docs PR(s):
- [x] Documentation not necessary because: internal testing and fixture setup only
Wrangler V3 Backport
- [ ] TODO (before merge) – Wrangler PR:
- [x] Not necessary because: does not touch Wrangler core code
This is only my second PR to the Cloudflare workers-sdk, so please let me know if there's anything you'd like changed or improved — happy to follow up. Thanks a lot for reviewing!