Deploy and operate
Deploy to Cloudflare
Cloudflare Workers and R2 are the reference ThimbleDB deployment.
The design uses:
- one Worker for static assets, writes, sessions, and scope-key grants
- one R2 data bucket for encrypted application objects
- one private R2 auth bucket for users, sessions, and rate records
- an optional native rate-limit binding
- an authenticated Worker read broker for private scopes
R2 Standard currently includes 10 GB-month storage, 1 million Class A operations, 10 million Class B operations, and free egress each month.
1. Build
npm install
npm run build:client
npm run build:worker
The Worker bundle is about 33.8 KB gzip. Track bundle growth before deploying an upgrade.
2. Authenticate Wrangler
npx wrangler login
3. Create R2 storage
Create separate data and auth buckets:
npx wrangler r2 bucket create <data-bucket-name>
npx wrangler r2 bucket create <auth-bucket-name>
Do not use Infrequent Access for the initial deployment. The R2 free tier applies to Standard storage. Never attach a custom domain to the auth bucket.
4. Configure the application domain
Use one Worker hostname:
db.example.com
Object reads pass through the Worker and require a valid session and scope grant. No R2 custom domain or browser CORS rule is required.
5. Create Wrangler configuration
Copy the disabled example beside the original so its relative paths remain valid:
Copy-Item deploy\cloudflare\wrangler.example.jsonc deploy\cloudflare\wrangler.local.jsonc
Edit deploy\cloudflare\wrangler.local.jsonc:
- Uncomment the
r2_bucketsblock. - Set the real data and auth bucket names.
- Optionally configure
AUTH_RATE_LIMITERfor low-latency source-IP limits. OIDC-subject limits always use the encrypted R2-backed limiter. - Uncomment the Worker custom-domain route.
- Set the exact
THIMBLE_ALLOWED_ORIGIN.
The example keeps bindings and routes commented so copying the repository cannot deploy infrastructure accidentally.
6. Configure authentication
Every deployment uses Entra or another OIDC identity provider. ThimbleDB stores only the stable external-identity mapping, current application roles and tenants, and revocable sessions.
For Entra, set ENTRA_TENANT_ID and ENTRA_AUDIENCE. The application obtains
an API access token through a reviewed OIDC client and exchanges it at
/api/auth/oidc/entra/session.
Also set ENTRA_REQUIRED_SCOPE or ENTRA_REQUIRED_ROLE.
Generate the recommended Entra entries with
npx thimbledb generate-entra-roles --out entra-authorization.json. See
Machine and service access before accepting
client-credentials tokens.
For another provider, set OIDC_PROVIDER_ID, OIDC_ISSUER,
OIDC_AUDIENCE, and OIDC_JWKS_URI, plus at least one of
OIDC_REQUIRED_SCOPE or OIDC_REQUIRED_ROLE. A valid first exchange creates
the minimal internal mapping and stable user:<uuid> data scope.
Cloudflare Access can remain an additional outer boundary around the application hostname.
Optional Studio
Enable the Studio API in the authority factory or set:
THIMBLE_STUDIO=true
THIMBLE_STUDIO_ORIGIN=https://database.example.com
Build the browser application and copy the package-owned Studio assets after the final client build:
npm run build:client-assets
Keep run_worker_first: true so /api/* requests reach the Worker before
asset fallback. Open /studio/ on the configured exact origin.
See ThimbleDB Studio.
7. Create secrets
Generate the deployment master key:
$masterKey = node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
Store them through Wrangler without writing them to a file:
$masterKey | npx wrangler secret put THIMBLE_MASTER_KEY
$masterKey = $null
8. Deploy
npm run build:client-assets
npx wrangler deploy --config deploy\cloudflare\wrangler.local.jsonc
9. Verify
- Open
https://db.example.com. - Sign in through the configured identity provider.
- Seed the tiny store.
- Confirm
/api/configreturns providerr2. - Confirm private object GETs use
/api/objects/scopes/.... - Confirm raw object bodies start with
TDB1and contain no plaintext JSON. - Confirm a second HEAD request returns 304.
- Confirm the browser key is non-extractable.
- Confirm logout revokes the session and blocks brokered reads.
- Delete and restore a test document.
- Confirm administrator user listing is restricted to
thimble.admin. - Enable maintenance mode in a non-production scope and verify writes return
503 maintenance_mode.
10. Operations
Monitor:
- Worker CPU time and errors
- R2 Class A writes
- R2 Class B reads
- conditional-write conflicts
- envelope bytes before and after gzip
- key-grant counts
- garbage-collection object counts
Add R2 lifecycle rules for abandoned key versions and benchmark prefixes only
after retention requirements are defined. Configure the private auth bucket to
expire objects below auth-v1/sessions/ and auth-v1/rate-limits/ after the
maximum operational retention period:
npx wrangler r2 bucket lifecycle set <auth-bucket-name> `
--file deploy\cloudflare\auth-lifecycle.example.json