What's new with Angular 19 on Netlify

by Michal Piechowiak and Domitrius Clark

With the release of Angular 19, Netlify has added support for a number of new features, including Hybrid Rendering, Incremental Hydration, and customizing request handlers. In this post, we’ll explore some of these changes and how they’ll affect your Angular projects.

#Configure your Angular Project

In the following section we’ll lightly explore creating an application through the Angular CLI and some of the changes you’ll experience.

To get started, let’s create a new Angular project.

Terminal window
npm install -g @angular/cli
ng new my-angular-app

This will launch you into a series of prompts to configure your project. Project name & stylesheet choice are up to you, but for the purposes of this guide, once you land on the prompt to enable SSR, we’re going to select Yes. This will enable you to explore request handling customization.

Once you’ve gotten through the rest of the prompts, we’ll need to do one more thing to finalize enabling custom request handlers. Change directories into your project and run the following command to download the Netlify runtime. This is needed for Angular to be able to find the module once we’ve changed server.ts.

Terminal window
npm install @netlify/angular-runtime

Now, your new Angular project is ready to be deployed to Netlify. Let’s link your project to Netlify:

Terminal window
npm install netlify-cli -g # If you have the Netlify CLI installed, you can skip this step
netlify init

and do your first deploy:

Terminal window
netlify deploy --build --prod

Congratulations! You’ve just deployed your first Angular 19 project to Netlify.

#Customizing request handlers

You’ll notice that your project is now using the server.ts file located in src/server.ts. This is the file that Netlify will use to handle requests. By default, this is a module with an express app setup to serve your Angular application.

When inspecting this module you can find the following comment:

/**
* Example Express Rest API endpoints can be defined here.
* Uncomment and define endpoints as necessary.
*
* Example:
* ```ts
* app.get('/api/**', (req, res) => {
* // Handle API request
* });
* ```
*/

Let’s try to follow the example and add a simple API endpoint.

app.get("/api/hello", (req, res) => {
res.json({ message: "Hello from the API" });
});

Now let’s deploy our application again.

Terminal window
netlify deploy --build --prod

If you’re encountering an error, you’re on the right track! It should say something like:

Error: server.ts doesn't seem to be Netlify compatible and is not known default. Please replace it with Netlify compatible server.ts.....

We were able to previously deploy our application without error because when Netlify’s Angular runtime inspected the contents of server.ts and realized it was the default file, the runtime replaces it with a Netlify compatible equivalent.

#Making server.ts Netlify compatible

Once you’ve edited server.ts, Angular runtime won’t replace it automatically anymore to avoid a production deployment potentially missing your customizations. Instead the Angular Runtime will fail the deployment with an actionable error message containing code snippets to copy as a starting point.

Let’s look at the full error message:

// Error: server.ts doesn't seem to be Netlify compatible and is not known default. Please replace it with Netlify compatible server.ts.
// It seems like you use "CommonEngine" - for this case your server.ts file should contain following:
import { CommonEngine } from '@angular/ssr/node'
import { render } from '@netlify/angular-runtime/common-engine'
const commonEngine = new CommonEngine()
export async function netlifyCommonEngineHandler(request: Request, context: any): Promise<Response {
// Example API endpoints can be defined here.
// Uncomment and define endpoints as necessary.
// const pathname = new URL(request.url).pathname;
// if (pathname === '/api/hello') {
// return Response.json({ message: 'Hello from the API' });
// }
return await render(commonEngine)
}
// If you want to use "AppEngine" instead - your server.ts file should contain following:
import { AngularAppEngine, createRequestHandler } from '@angular/ssr'
import { getContext } from '@netlify/angular-runtime/context'
const angularAppEngine = new AngularAppEngine()
export async function netlifyAppEngineHandler(request: Request): Promise<Response {
const context = getContext()
// Example API endpoints can be defined here.
// Uncomment and define endpoints as necessary.
// const pathname = new URL(request.url).pathname;
// if (pathname === '/api/hello') {
// return Response.json({ message: 'Hello from the API' });
// }
const result = await angularAppEngine.handle(request, context)
return result || new Response('Not found', { status: 404 })
}
/**
* The request handler used by the Angular CLI (dev-server and during build).
*/
export const reqHandler = createRequestHandler(netlifyAppEngineHandler)

Of the two code snippets provided, we’ll be using the CommonEngine snippet. Copy and paste the snippet into your server.ts file, save, and let’s try deploying again.

Netlify's Angular Runtime

The snippet above is exactly what Netlify’s Angular Runtime will use by default when finding an empty server.ts file.

Terminal window
netlify deploy --build --prod

#Customizing request handlers

Now that we’ve got an understanding of how Netlify’s Angular Runtime interacts with your server.ts file, let’s attempt to customize your request handler by uncommenting the example API endpoint from the error snippet.

import { CommonEngine } from '@angular/ssr/node'
import { render } from '@netlify/angular-runtime/common-engine'
const commonEngine = new CommonEngine()
export async function netlifyCommonEngineHandler(request: Request, context: any): Promise<Response {
const pathname = new URL(request.url).pathname;
if (pathname === '/api/hello') {
return Response.json({ message: 'Hello from the API' });
}
return await render(commonEngine)
}

Let’s deploy again:

Terminal window
netlify deploy --build --prod

With a successful deployment, you should be able to navigate to http://localhost:8080/api/hello and see the response from your API endpoint.

#What about migrating an existing project to Angular 19?

The best place for you to start is in Angular’s update guide.

Once you have migrated your project and are able to successfully execute Angular’s build command ng build, there’s only one more step. Similarly to what you did in our new project above, you’ll need to install Netlify’s Angular runtime:

Terminal window
npm install @netlify/angular-runtime

If you’ve previously modified your server.ts file, follow up with the steps above to make sure it’s Netlify compatible!

#Time to build!

The Angular 19 release is packed with new features and improvements, which combined with Netlify’s platform can unlock some really exciting opportunities for your application! If you need help, want to show off your application, or need some motivation, share your thoughts in the feedback forum at the bottom of this page.