Quickback Docs

Multi-Domain Architecture

Serve CMS, Account UI, and Admin on separate custom domains from a single Cloudflare Worker.

A single Quickback-compiled Cloudflare Worker can serve your API, CMS, Account UI, and Admin panel on separate custom domains. The compiler generates hostname-based routing so each domain serves the right content.

How It Works

When you configure custom domains for CMS, Account, or Admin, the compiler:

  1. Adds custom_domain routes to wrangler.toml
  2. Generates hostname-based middleware in the Worker
  3. Auto-configures cross-subdomain cookies for shared authentication
  4. Auto-infers a unified quickback.{baseDomain} fallback domain

All five domains point to the same Worker — there's only one deployment.

Domain Types

DomainConfigServesAPI Routes
api.example.comproviders.runtime.config.routesAPI onlyAll
cms.example.comcms: { domain }CMS SPABlocked (404)
auth.example.comaccount: { domain }Account SPAPass-through
admin.example.comaccount: { adminDomain }Account SPAPass-through
quickback.example.comAuto-inferredEverythingAll

CMS Domain

Serves the CMS SPA at root (/). API routes (/api/, /auth/, /admin/, /storage/, /health) return 404 — preventing direct API access on the CMS domain.

Account Domain

Serves the Account SPA at root (/). API and auth routes pass through to the Worker so authentication flows work directly on this domain.

Admin Domain

Identical behavior to the Account domain — serves the same Account SPA at root. The Account SPA's client-side router handles the /admin route, restricting access to users with the admin role.

Unified Domain

The compiler auto-infers a quickback.{baseDomain} domain from your configured custom domains. For example, if you have cms.example.com, it creates quickback.example.com.

On this domain, everything is available on a single origin:

PathContent
/Redirects to /cms/
/cms/CMS SPA
/account/Account SPA
/api/v1/...API routes
/auth/...Auth routes
/admin/...Admin API routes
/storage/...File storage
/healthHealth check
/openapi.jsonOpenAPI spec

The unified domain is useful for development and debugging. You can override it with an explicit domain field in your config.

Configuration

quickback/quickback.config.ts
export default {
  name: "my-app",
  template: "hono",
  cms: { domain: "cms.example.com", access: "admin" },
  account: {
    domain: "auth.example.com",
    adminDomain: "admin.example.com",
    name: "My App",
    auth: { password: true, admin: true },
  },
  trustedOrigins: [
    "https://auth.example.com",
    "https://admin.example.com",
    "https://cms.example.com",
  ],
  providers: {
    runtime: { name: "cloudflare", config: {
      routes: [{ pattern: "api.example.com", custom_domain: true }],
    }},
    // ...database, auth
  },
};

This generates the following wrangler.toml routes:

routes = [
  { pattern = "api.example.com", custom_domain = true },
  { pattern = "cms.example.com", custom_domain = true },
  { pattern = "auth.example.com", custom_domain = true },
  { pattern = "admin.example.com", custom_domain = true },
  { pattern = "quickback.example.com", custom_domain = true }
]

Cross-Subdomain Authentication

When two or more custom domains share a parent domain (e.g., cms.example.com + auth.example.com), the compiler automatically configures Better Auth for cross-subdomain cookie sharing:

  • Sets crossSubDomainCookies: { enabled: true, domain: '.example.com' }
  • Sets sameSite: 'none' and secure: true on auth cookies

This means a user who logs in on auth.example.com is automatically authenticated on cms.example.com and admin.example.com — no additional setup needed.

Automatic Detection

Cross-subdomain cookies are configured automatically. You only need to set them manually if your domains don't share a common parent (e.g., auth.myapp.com + cms.different.com).

Compile-Time Feature Gating

When the compiler builds the Account SPA, it excludes route files for disabled features before the Vite build. This means disabled features never appear in the JavaScript bundle.

Feature FlagRoutes Excluded When false
auth.organizationsDashboard, organization CRUD, org switching ($slug)
auth.passkeyPasskey management and setup
auth.adminAdmin panel routes

This keeps bundle sizes minimal and prevents dead code in production. Users can't access disabled features even if they navigate to the URL directly — the routes don't exist in the build.

Hostname Routing Details

The compiler generates middleware that checks new URL(c.req.url).hostname on every request:

CMS domain — Blocks API routes with 404. All other paths are mapped to the /cms/ asset prefix and served with SPA fallback to /cms/index.html.

Account/Admin domain — API and auth routes (/api/, /auth/, /admin/, /storage/, /health) pass through to Hono handlers. All other paths are mapped to the /account/ asset prefix and served with SPA fallback to /account/index.html.

Unified domain — No hostname filtering. CMS is served at /cms/, Account at /account/. Root (/) redirects to /cms/. API routes work at their standard paths.

Without Custom Domains

If you enable cms and account without custom domains, everything is served on a single domain:

  • CMS at /cms/ (root / redirects to /cms/)
  • Account UI at /account/
  • API at /api/v1/
  • Auth at /auth/

This is the simplest setup — no DNS configuration needed, no cross-subdomain cookies. Auth cookies work naturally because everything is same-origin.

See Also

On this page