Deployment Guide
How to deploy your Verani application to Cloudflare.
Prerequisites
- Cloudflare account (free tier works)
- Wrangler CLI installed:
npm install -g wrangler - Logged in to Wrangler:
wrangler login
Project Structure
Your project should look like this:
my-app/
├── src/
│ ├── index.ts # Actor handler export
│ └── rooms/
│ └── chat.ts # Room definitions
├── wrangler.toml # Cloudflare configuration
├── package.json
└── tsconfig.json
Local Development
Test locally before deploying:
npm run dev
# or
wrangler dev
This starts a local server at http://localhost:8787.
Test WebSocket connection:
const ws = new WebSocket("ws://localhost:8787/ws?userId=alice");
ws.onopen = () => {
console.log("Connected!");
ws.send(JSON.stringify({ type: "ping" }));
};
ws.onmessage = (e) => {
console.log("Received:", e.data);
};
Deploy to Production
Deploy your Worker:
wrangler deploy
Your app will be available at:
https://my-verani-app.your-subdomain.workers.dev
WebSocket endpoint:
wss://my-verani-app.your-subdomain.workers.dev/ws
Custom Domain (Optional)
Add a Custom Domain
- Go to Cloudflare Dashboard → Workers & Pages
- Select your Worker
- Go to Settings → Triggers
- Add a custom domain (e.g.,
chat.example.com)
Update Client
const client = new VeraniClient(
"wss://chat.example.com/ws?userId=alice"
);
Common Deployment Issues
Issue: WebSocket connection fails
Solutions:
- Check you're using
wss://for production (notws://) - Verify the
/wspath is correct - Check browser console for errors
- Run
wrangler tailto see server-side errors
Issue: Sessions not restoring after hibernation
Solution: Make sure you're using Verani's storeAttachment():
// This is automatic in Verani
storeAttachment(ws, metadata);
Issue: CORS errors in browser
Solution: Add CORS headers in Worker:
export default {
async fetch(request, env) {
// Handle CORS preflight
if (request.method === "OPTIONS") {
return new Response(null, {
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST",
"Access-Control-Allow-Headers": "Content-Type",
},
});
}
// Your handler
return handler.fetch(request, env);
}
};
Persistence in Production
When using state persistence:
- Test persistence: Verify state survives hibernation and server restarts
- Handle errors: Implement
onPersistErrorto handle persistence failures gracefully - Monitor storage: Check Durable Object storage usage and costs
- Optimize keys: Only persist what you need - each key adds storage overhead
const room = defineRoom({
state: {
// Only persist essential state
messageCount: 0,
settings: { maxUsers: 100 }
},
persistedKeys: ["messageCount", "settings"], // Minimal set
persistOptions: {
shallow: true, // Faster than deep proxying
throwOnError: false // Don't crash on persistence failures
},
onPersistError(key, error) {
// Log to monitoring service
console.error(`[Persistence] Failed to persist ${key}:`, error);
// Maybe notify admins or use fallback storage
}
});
See: Persistence Concepts for full documentation.
Security Checklist
Before going to production:
- Implement authentication (JWT tokens) - See Security Guide - Authentication
- Validate all client input
- Rate limit messages per user
- Sanitize user-generated content
- Use HTTPS/WSS only (never HTTP/WS)
- Don't expose error details to clients
- Log security events
- Set up monitoring and alerts
- Verify Origin header to prevent CSWSH attacks
- Use environment variables for secrets (never commit secrets)
- Test state persistence across hibernation cycles
- Implement error handling for persistence failures
📖 Read the complete Security Guide for implementation details.
Next Steps
- Configuration Guide - Wrangler configuration details
- Monitoring Guide - Logs and metrics
- Scaling Guide - Performance and scaling strategies
- Security Guide - Authentication and security best practices
- API Reference - Complete API documentation
Support
- GitHub Issues: Report bugs
- Discussions: Ask questions
- Discord: Join community (coming soon)