The State of Angular SSR Deployment in 2024
Tags: angular, webdev, javascript, deployment
Published: 2024-03-03 01:45:37

Angular Universal is now called Angular SSR, and it is built into the framework.  The year is 2024. Two things are changing: serverless, and CSR (Client Side Rendering). Sure, there are many valid use cases for both. However, in order to have good SEO, speed, and security, you need Server Side Rendering. In order to get rid of cold starts and location loading delays, you need Edge Computing. This is over simplification, but you get the point. 

Angular needs to be at least on par with ALL other mainstream SSR frameworks and offer these things in deployment, easily. These other frameworks include SvelteKit, NextJS, Remix, Nuxt, Qwik (City), and Solid Start. The Signals addition is wonderful, but we need better deployment, or nothing else matters.

## Google Edge
Google has an [Edge Network](https://cloud.google.com/distributed-cloud/edge/latest/docs/overview), but they push serverless functions like [Cloud Run](https://cloud.google.com/functions/docs/concepts/version-comparison), which is also what version 2 of Firebase Cloud Functions use. Firebase Functions need a Version 3, which is built on the Edge. However, first Firebase, specifically [firebase-admin](https://firebase.google.com/docs/admin/setup) would need to work on the edge. Google, who makes Angular, might then be able to compete better for deployment options. Cold Starts are terrible and should die IMHO, unless you have have specific use cases for them.

## 1. Firebase Deployment (serverless)
So, let's start with the Google way, which you would think would be seamless. Don't get me wrong, it has come a LONG way. You used to have to bundle things up manually like in [Fireship Angular 12 Course](https://fireship.io/courses/angular/). You could do Cloud Run or Functions, but it was a pain. Now things are automatic. Here is the thing, they have been automatic since Angular 14-ish. 

You can use `firebase init hosting` or `ng deploy` and follow the options, but you can't use both. It is odd to me that they don't work seamlessly together, as they do the same thing. You must have a Firebase project, and turn on the Blaze plan to use hosting.

### Note 1

>    Thank you for trying our early preview of Angular support on Firebase Hosting.
>    During the preview, support is best-effort and breaking changes can be expected. Proceed with caution.

Why is this still in "early preview." I have been using this for at least 3 versions of Angular. Were the other versions early early alpha preview? 

### Note 2
Apparently you need to ignore the `index.html` file when deploying if you have dynamic content. Maybe someone in the comments can tell me why this is default.
#### firebase.json
```
{
  "hosting": {
    "source": ".",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**",
      "index.html"
    ],
    "frameworksBackend": {
      "region": "us-central1"
    }
  }
}
```
You also have to change pre-rendering to `false` in `angular.json` under `projects.architect.options.prerender`. We have dynamic content for this app.
### Note 3
And it seems to deploy on first try, but then I got a loop error. Turns out after posting a bug, and getting sent to [GitHub](https://github.com/firebase/firebase-tools/issues/6651), this is a known issue when deploying to Cloud Functions. The fix is to edit your `server.ts` file, and don't use the `process.env['PORT']` variable, as it apparently is already in use.
```ts
// const port = process.env['PORT'] || 4000;
const port = 4000;
```

### Note 4
Every time I deployed, I got this error:

> functions: Unhandled error cleaning up build images. This could result in a small monthly bill if not corrected. You can attempt to delete these images by redeploying or you can delete them manually at https://console.cloud.google.com/gcr/images/YOUR-PROJECT-ID/us/gcf

So, if you get this, click the link and delete the gcr image. I don't understand why there is an artifact, or one every time, but I don't want to waste space I could pay for.

All in all, deploying to Cloud Functions Gen 2 was a pain, and all that for serverless...

## 2. Netlify (Edge)

Netlify was remarkably easy to deploy and use. Set `prerender: false` in `angular.json` to make sure it uses the functions.

Create your Angular app, commit it to GitHub, and simply connect your app on Netlify. Done! Edge Deployment!

I suspect this process is entirely possible and easy due to Netlify using Deno. While Deno is terrible, it is also powerful. When you don't have to fool with configuring it, it can be nice!

## 3. Vercel (serverless)
I wrote a whole article just on deploying [Angular Universal to Vercel](https://dev.to/jdgamble555/how-to-deploy-angular-universal-to-vercel-31d0). I updated it before I wrote this article to make sure it is working with Angular 17.2.

I have not seen a working Vercel Edge deployment, but considering Vercel uses Cloudflare under the hood, I imagine you could modify the Cloudflare code to get it working. However, Cloudflare has its own problems.

## 4. Cloudflare (Edge)

Cloudflare only offers Edge deployment, and is the backbone of all the great sites. There is a [Cloudflare Angular Guide](https://developers.cloudflare.com/pages/framework-guides/deploy-an-angular-site/) with bad information. Unfortunately, there is not a simple add package like these:
```
Amazon S3: ng add @jefiozie/ngx-aws-deploy
Firebase: ng add @angular/fire
Netlify: ng add @netlify-builder/deploy
GitHub Pages: ng add angular-cli-ghpages
```
There needs to be. We need `ng add @cloudflare/angular` or something similar.

In any case, you have to create a new repository:
```
npm create cloudflare@latest my-angular-app -- --framework=angular
```
Then you connect your GitHub account in Cloudflare. However, the settings on the Guide are wrong. You need to use these:

| Configuration Option | Value |
| --- | --- |
| Production branch | main |
| Build command * | npm run pages:build |
| Build directory | dist/cloudflare |

I also had to set prerender to false in `angular.json` under `projects.architect.options.prerender`. Otherwise my index page would get prerendered. Again, not sure why this is default.

### Adding it to your repository
If you have an existing project, you should be able to add the `tools` folder as well as updating your `server.ts` file. Just create a new cloudflare angular project and copy them over. Check your `package.json` in case there are required dependencies. I have not tested this, but no reason it shouldn't work.

### Problem - Critical CSS Inlining
One of the issues with the Cloudflare deployment, as it works, but only without [critical css inlining](https://github.com/angular/angular-cli/issues/25718#issuecomment-1821073667). I believe Vite supports this, and Angular SSR is able to do this on Node servers (and apparently Deno on Netlify, probably with npm imports). Notice in the Cloudflare repo there is **a jump** where the CSS loads later from the stylesheet. I am frankly ignorant on the subject, but you can blatantly see a CSS loading difference.

## 5. Analog
Analog allows you to deploy anywhere, literally. It uses [Nitro](https://nitro.unjs.io/) toolkit which has options for anything while working with Vite.

![Analog Deployment Options](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w7032n6vyl47mn05qqwp.png)

There is a small learning curve, but I got deployment working immediately.

## What now?
Well, scream though I have, the Angular team desperately needs to [Remove NodeJS Dependencies](https://github.com/angular/angular-cli/issues/25718), as it has already fallen behind from all frameworks concerning deployment. I'm still waiting for the [response on this](https://github.com/angular/angular/issues/52929#issuecomment-1834308941)... 🦗 🦗 🦗 🦗

## Does Vercel Hate Angular?
I thought about writing a whole article on this, but I figured I would sum it up here. When I first wrote my [Vercel Deployment](https://dev.to/jdgamble555/how-to-deploy-angular-universal-to-vercel-31d0) article in 2021, which BTW the original `vercel.json` took weeks to figure out without any clear direction, I emailed Vercel:
**12/28/21**

> Unfortunately, there are no plans to add this since this is using a Serverless Function to start your server on Vercel, instead of a Node.js server, making this not ideal.

I then received a email explaining why Nuxt and SvelteKit could work fine, but not Angular. Their reasonings had a incredible misunderstanding of how Angular works. Angular is just JavaScript, just like every other Framework. So, I made it work using their own `vercel.json` file and some small tweaks. I then asked them to add it to the **Framework Presets**. Here was my response:

> These adapters, for example, were built by the community:
> https://github.com/sveltejs/kit/tree/master/packages/adapter-vercel
> https://github.com/nuxt/vercel-builder
> If somebody builds a working one for Angular Universal, we will gladly add it to our Framework Presets → https://vercel.com/docs/concepts/deployments/build-step#framework-preset.

It had taken weeks without direction to figure out a simple `vercel.json` file, so building a preset was out of my wheelhouse. 

Since the Angular Team has stepped up their game in the last 2 years, I saw this post by [Alan Agius](https://github.com/angular/angular-cli/issues/25718#issuecomment-1821073667) from Angular Team (who gave me the crickets, but also who is a huge reason Angular is doing great now!):

> We actually did reach out to Vercel, to work with them to support SSR. Unfortunately in the near term they do not have a priority to add support for Angular SSR/SSG.

Netlify and Cloudflare worked with Vercel to get the Angular adapters working, but Vercel doesn't seem to want to help Google!? Wow. The answer is for someone to take [my code](https://dev.to/jdgamble555/how-to-deploy-angular-universal-to-vercel-31d0) (modified now thanks to several contributors) and create a [Framework Preset](https://vercel.com/docs/deployments/configure-a-build#framework-preset). Of course, I suspect, if the Node Dependencies go away, it will be extremely easy to get it to work on Vercel Edge (once they figure out the css issues).

## In 2025
I will write a new article in 2025. Hopefully these problems will be solved:
- Critical CSS Inlining will work on Cloudflare
- Vercel Framework Preset will exist (with Edge option)
- Angular SSR will have [.env variables](https://dev.to/jdgamble555/angular-universal-env-variables-on-vercel-e6j) built in
- Angular SSR will simplify [preloading data](https://dev.to/jdgamble555/preloading-data-in-angular-universal-20lj)
- Angular SSR will simplify [rest endpoints](https://dev.to/jdgamble555/angular-universal-rest-api-endpoints-23fj)
- ZoneJS will be fully optional (important for faster deployments)

## Summary
Use Netlify if you want Edge deployment, otherwise AnalogJS is freaking amazing and solves all the problems above. [Sponsor AnalogJS](https://github.com/analogjs/analog) the project if you can give a few bucks!


## Demos
- [Firebase Cloud Function](https://test-projects-19046.web.app/)
- [Vercel Serverless](https://angular-vercel-ssr.vercel.app/)
- [Netlify Edge](https://angular-firebase-deploy.netlify.app/)
- [Cloudflare Edge](https://angular-cloudflare-cjz.pages.dev/)
- [Analog Vercel Edge](https://analog-test-mu.vercel.app/)

## Repos
- [Vercel Repo](https://github.com/jdgamble555/angular-vercel-ssr)
- [Netlify and Firebase Repo](https://github.com/jdgamble555/angular-firebase-deploy)
- [Cloudflare Repo](https://github.com/jdgamble555/angular-cloudflare)
- [Analog Repo](https://github.com/jdgamble555/analog-test/tree/master)

## Angular with Firebase Deployment
For a modern Angular App with Firebase, see my latest post:
https://code.build/p/angular-todo-app-with-firebase-fmLJ37

Currently Building a Free Firebase Course on [Code.Build](https://code.build).

J