In this guide, I will walk you through the steps to deploy a server-side rendered Angular 20+ application on Cloudflare Workers, a powerful serverless platform that allows you to run your Angular app on Cloudflare’s global edge network.
Prerequisites
You’ll need the following:
- Node.js 22 or later
- A Cloudflare account
Demo Application
You can see a working example of this deployment in action at https://angular-ssr-app.launchfast.workers.dev/posts. This demonstrates a fully server-side rendered Angular application running on Cloudflare Workers with zero cold starts.
Understanding the Architecture
When deploying Angular SSR to Cloudflare Workers, the application is split into two parts:
- Browser Build (
dist/<app>/browser/*) - Static assets served directly by Cloudflare’s asset handling, bypassing the Worker - Server Build (
dist/<app>/server/*) - Bundled into the Worker for server-side rendering
The Cloudflare Worker Bridge
Create an entry point for your Cloudflare deployment lives at cloudflare/worker.ts. This file bridges your Angular SSR application to the Cloudflare Workers runtime. Here’s what it does:
import { AngularAppEngine, createRequestHandler, ɵsetAngularAppEngineManifest as setAngularAppEngineManifest,} from '@angular/ssr';
// Generated build artifact containing the engine manifestimport engineManifest from '../dist/angular-ssr-app/server/angular-app-engine-manifest.mjs';
setAngularAppEngineManifest(engineManifest);
const angularApp = new AngularAppEngine();
/** * createRequestHandler returns a Web-standard (Request) => Response handler, * which is exactly the shape Cloudflare's fetch handler expects. */const fetch = createRequestHandler(async (request: Request) => { const response = await angularApp.handle(request); return response ?? new Response('Not found', { status: 404 });});
export default { fetch };Key Points
AngularAppEngineis initialized to handle SSR rendering- The
engine manifestis imported from your build output: it contains inlined HTML templates and build metadata createRequestHandlerwraps Angular’s engine in a Web-standardfetchhandler that Cloudflare expects- Any request that doesn’t match a route returns a 404
Update Wrangler Configuration
Update your wrangler.jsonc file to the following:
{ "$schema": "node_modules/wrangler/config-schema.json", "name": "angular-ssr-app", "main": "cloudflare/worker.ts", "compatibility_date": "2025-05-05", // Enable Node.js compatibility for Angular's SSR dependencies "compatibility_flags": ["nodejs_compat"], // Define import.meta.url for polyfills compatibility "define": { "import.meta.url": "\"file:///worker.mjs\"" }, // Serve browser build as static assets "assets": { "directory": "./dist/angular-ssr-app/browser", "binding": "ASSETS" },}Configuration Explained
compatibility_flags: ["nodejs_compat"]- Required because Angular’s server polyfills use Node.js built-insdefine- Provides a fallback forimport.meta.urlwhich gets collapsed during bundlingassets.directory- Points to your browser build for static file serving
Build Configuration for Cloudflare
Your angular.json configures how Angular builds for the Cloudflare platform:
{ "projects": { "angular-ssr-app": { "architect": { "build": { "builder": "@angular/build:application", "options": { "browser": "src/main.ts", "server": "src/main.server.ts", "outputMode": "server", "ssr": { "entry": "src/server.ts" }, "security": { "allowedHosts": [ "localhost", "angular-ssr-app.launchfast.workers.dev" ] } } } } } }}SSRF Protection with Allowed Hosts
The allowedHosts setting prevents Server-Side Request Forgery (SSRF) attacks:
- Only the hostnames listed here can be server-side rendered
- Add your production domain and preview domains
- At deploy time, you can add additional hosts via the
NG_ALLOWED_HOSTSenvironment variable without rebuilding
Building and Deploying
Your package.json includes convenient scripts for testing and deploying:
{ "scripts": { "build": "ng build", "preview:cf": "npm run build && wrangler dev", "deploy:cf": "npm run build && wrangler deploy" }}Local Testing
To test your application locally before deploying:
npm run preview:cfThis builds your Angular application and starts the Wrangler dev server on http://localhost:8787.
Deployment to Cloudflare
When ready to deploy to production:
npm run deploy:cfThis:
- Builds your Angular SSR application for production
- Bundles the server code into the Worker using esbuild
- Uploads your browser assets to Cloudflare
- Deploys your Worker globally across Cloudflare’s network
Environment Variables and Allowed Hosts
For staging or preview deployments with different domains, you can specify additional allowed hosts at deploy time without rebuilding:
NG_ALLOWED_HOSTS=staging.example.com,preview.example.com npm run deploy:cfThe environment variable accepts comma-separated hostnames and is merged with the hosts defined in angular.json at runtime.
Conclusion
Yay! You now have an Angular 20+ SSR project that automatically deploys to Cloudflare without any additional configuration within the Angular scope.
If you have questions or encounter issues, refer to the Angular SSR documentation and Cloudflare Workers documentation.