Worker Setup
Deploy Account UI to Cloudflare Workers
Worker Setup
Deploy the Account UI as a Cloudflare Worker with static asset serving.
Quick Start
Using the Template
npx degit Kardoe-com/quickback-better-auth-account-ui my-account-app
cd my-account-app
npm installUsing the Library
If you're consuming Account UI as an npm package, re-export the worker from the library:
export { default } from 'quickback-better-auth-account-ui/worker';Then continue with the Wrangler configuration below.
2. Configure Wrangler
The template includes a wrangler.toml pre-configured for Cloudflare Workers:
name = "my-account-app"
compatibility_date = "2025-01-01"
compatibility_flags = ["nodejs_compat"]
# Custom domain (uncomment and set your domain)
# routes = [
# { pattern = "account.example.com", custom_domain = true }
# ]
# Worker entry point
main = "src/worker.ts"
# Static assets
[assets]
binding = "ASSETS"
directory = "dist/client"3. Build and Deploy
npm run build
npx wrangler deployWorker Entry Point
The worker is at src/worker.ts. It serves static assets and handles SPA routing:
- Static asset serving via the
ASSETSbinding - SPA routing (all routes serve
index.html) - Health check endpoint (
/health)
Custom Worker Logic
Edit src/worker.ts directly to add custom logic:
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
// Custom health check with more info
if (url.pathname === '/health') {
return new Response(JSON.stringify({
status: 'ok',
app: 'my-account-ui',
version: '1.0.0',
timestamp: new Date().toISOString(),
}), {
headers: { 'Content-Type': 'application/json' }
});
}
// Custom analytics or logging
console.log(`${request.method} ${url.pathname}`);
// Try to serve static asset
const assetResponse = await env.ASSETS.fetch(request);
// If asset found, return it
if (assetResponse.status !== 404) {
return assetResponse;
}
// SPA routing: serve index.html for all other routes
const indexRequest = new Request(`${url.origin}/index.html`, request);
return env.ASSETS.fetch(indexRequest);
},
};Wrangler Configuration
Environment Variables
For production deployment, set environment variables in Cloudflare dashboard or via wrangler:
[env.production]
name = "my-account-app"
[env.production.vars]
VITE_API_URL = "https://api.example.com"
VITE_ACCOUNT_APP_URL = "https://account.example.com"
VITE_APP_NAME = "My App"
VITE_APP_URL = "https://app.example.com"Build-Time Variables
Vite environment variables (VITE_*) are baked into the build at build time. Changing them in wrangler.toml requires rebuilding. Use .env.production for production builds.
Multiple Environments
# Development
[env.dev]
name = "my-account-app-dev"
route = "account-dev.example.com/*"
[env.dev.vars]
VITE_API_URL = "https://api-dev.example.com"
VITE_ACCOUNT_APP_URL = "https://account-dev.example.com"
# Staging
[env.staging]
name = "my-account-app-staging"
route = "account-staging.example.com/*"
[env.staging.vars]
VITE_API_URL = "https://api-staging.example.com"
VITE_ACCOUNT_APP_URL = "https://account-staging.example.com"
# Production
[env.production]
name = "my-account-app"
route = "account.example.com/*"
[env.production.vars]
VITE_API_URL = "https://api.example.com"
VITE_ACCOUNT_APP_URL = "https://account.example.com"Deploy to specific environment:
wrangler deploy --env staging
wrangler deploy --env productionCloudflare Pages Alternative
You can also deploy to Cloudflare Pages instead of Workers:
1. Configure Build
# Remove [assets] section - Pages handles this
name = "my-account-app"
pages_build_output_dir = "dist/client"2. Deploy to Pages
# First time setup
wrangler pages project create my-account-app
# Deploy
wrangler pages deploy dist/client3. Configure Environment Variables
Set environment variables in Cloudflare Pages dashboard:
- Go to your Pages project
- Settings → Environment Variables
- Add
VITE_*variables - Redeploy
Pages vs Workers
Workers: Better for custom server logic, middleware, edge compute Pages: Simpler for static SPAs, automatic preview deployments, built-in analytics
Local Development
Option 1: Vite Dev Server
The fastest way to develop locally:
npx vite devThis starts the Vite dev server with hot module replacement on localhost:5173.
Option 2: Wrangler Dev
Test the worker locally with wrangler dev:
npm run build && wrangler devThis runs the worker on localhost:8787.
Health Check
The worker includes a built-in health check endpoint:
curl https://account.example.com/healthResponse:
{
"status": "ok",
"app": "auth-ui"
}Use this for:
- Uptime monitoring
- Load balancer health checks
- Deployment verification
Security Headers
Add security headers by editing src/worker.ts:
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// ... routing logic ...
// Add security headers to response
const response = await env.ASSETS.fetch(request);
const headers = new Headers(response.headers);
headers.set('X-Frame-Options', 'DENY');
headers.set('X-Content-Type-Options', 'nosniff');
headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
headers.set('Permissions-Policy', 'geolocation=(), microphone=(), camera=()');
return new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers,
});
},
};Custom 404 Page
Serve a custom 404 page for unmatched routes:
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
// Try to serve static asset
const assetResponse = await env.ASSETS.fetch(request);
if (assetResponse.status !== 404) {
return assetResponse;
}
// Serve index.html for SPA routes
if (!url.pathname.startsWith('/api/')) {
const indexRequest = new Request(`${url.origin}/index.html`, request);
return env.ASSETS.fetch(indexRequest);
}
// Custom 404 for API routes
return new Response('Not Found', { status: 404 });
},
};Deployment Checklist
Before deploying to production:
- Set all required environment variables (
VITE_API_URL, etc.) - Configure custom domain in Cloudflare
- Add SSL certificate (automatic with Cloudflare)
- Test all authentication flows
- Configure DNS records
- Set up monitoring/health checks
- Test email sending
- Verify passkey functionality (requires HTTPS)
- Check CORS configuration on API
- Review security headers
- Test organization invitations
- Verify redirection to main app works
Troubleshooting
Assets Not Loading
Problem: 404 errors for static assets (JS, CSS)
Solution: Check directory path in wrangler.toml:
[assets]
binding = "ASSETS"
directory = "dist/client" # Must point to Vite's client build outputEnvironment Variables Not Working
Problem: Config values are undefined
Solution: Remember that VITE_* variables are build-time. Either:
- Set them in
.env.productionbefore building - Use
setAppConfig()insrc/main.tsxfor runtime overrides - Edit
src/config/app.tsdefaults directly
SPA Routing Issues
Problem: Refreshing on /profile returns 404
Solution: Ensure your worker serves index.html for all non-asset routes:
if (assetResponse.status === 404 && !url.pathname.startsWith('/api/')) {
return env.ASSETS.fetch(new Request(`${url.origin}/index.html`, request));
}Next Steps
- Environment Variables - Configure your deployment
- Feature Flags - Enable features
- Customization - Brand your UI