A single Bunny Edge Script serves unlimited companies from one codebase. Here’s exactly how tenant isolation, provisioning, request routing, and data security work — no hand-waving.
One Edge Script runs on Bunny’s global network. No per-tenant infrastructure, no separate deployments, no region configuration. Add a client row — they’re live.
Every company gets its own Bunny Database. Not a shared schema with row filters — a physically separate database. True isolation from day one.
Requests are handled at Bunny’s nearest PoP, globally. Deno TypeScript runtime with no cold starts. Sub-50ms response times worldwide.
The entire platform is a single TypeScript file deployed to Bunny Edge Scripting.
It reads the Host header on every incoming request to determine which
company is being served — then routes to the right handler with a fully-populated
RequestContext.
There’s one platform database for metadata (company records, admin users, audit log) and one isolated database per company for all event, ticket, order, and attendee data. The platform DB connection details are environment variables. Company DB tokens are encrypted in the platform DB and decrypted per-request.
jose (JWT) and @libsql/client
On every incoming request, the Edge Script reads the Host header and
looks up the matching company in the platform database — either by
custom_domain or subdomain.
The result is cached per-host for 5 minutes to avoid a platform DB round-trip on every request. Once resolved, the company’s AES-256-GCM encrypted DB token is decrypted in memory and used to create a per-request LibSQL client pointed at that company’s isolated database.
tickets.acme-events.comcustom_domain or subdomain → company rowdb_token_enc in memory{ db, tenantId, companyId, company } passed to handler
Creating a new company is a single API call to
POST /api/platform/companies. The platform handles everything:
it creates an isolated Bunny Database, runs the full schema, encrypts and
stores the connection token, seeds an admin user, and returns one-time credentials.
The client receives a login URL, an admin email, and a temporary password. They log in to the admin dashboard, set up their branding, connect their payment account, and create their first event. From provisioning to first ticket sale can happen in under an hour.
provisioning → activeprovisioningIF NOT EXISTSOnce provisioned, the client logs in to their admin dashboard. They set their brand colours, upload a logo, configure their email sender domain, and connect their own Stripe or SumUp account. None of this requires a deployment or any change on your end.
All branding and payment configuration is stored in the client’s own isolated database. The ticketing site re-reads it on every page load. Changes are live immediately.
Every layer is locked down — from database isolation to webhook signatures to password hashing.
Every company’s database token is encrypted with AES-256-GCM using a platform-level key stored as an environment variable. Tokens are decrypted in memory per request only.
Admin passwords are hashed with PBKDF2-SHA256 and a random salt. Plaintext passwords are never stored or logged. Brute-force is computationally expensive by design.
Every incoming payment webhook is verified against the provider’s HMAC signature before any database operation. Unverified payloads are rejected with a 400 response.
Checkout and mutation endpoints accept Idempotency-Key headers. Safe to retry on network failure. Duplicate requests return the cached response without re-processing.
HS256 JWTs with 24-hour expiry for admin sessions. Check-in tokens are scoped to a specific event. Platform admin tokens are a separate key entirely.
Per-IP rate limiting on all public endpoints. Configurable thresholds per route. Abuse is blocked at the edge before it reaches the database.
Every response includes Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, and Strict-Transport-Security. Configured at the handler level, not bolted on.
Every admin action is recorded in a tenant-scoped audit log: who, what, when, from which IP. Immutable. Non-repudiation baked in.
Built on Bunny’s global edge network. No region selection, no warm-up, no capacity planning.
Bunny Edge Scripting runs at Bunny’s global network of Points of Presence. Requests are handled at the nearest PoP to the user — automatically, without any configuration.
Edge Scripts are always warm. There are no Lambda-style cold start delays, no container spin-up times, no gradual warm-up periods. Every request gets the same response time.
Tenant resolution results are cached per hostname for 5 minutes. A busy event page doesn’t hammer the platform database on every page load.
The infrastructure footprint is deliberately minimal. You need Bunny, a payment provider, and an email service. That’s it.
PLATFORM_DB_URL, PLATFORM_DB_TOKEN, PLATFORM_ENCRYPTION_KEY, JWT_SECRET, BUNNY_API_KEY, and a few more. Set once, never touched again.
We’ll walk you through the deployment and have your first company live within the hour.