Angular SSR deploy help


I chose Netlify to deploy my Angular 13.3 SPA app with Server Side rendering (Angular universal). Locally and on my VPS, I’m running. I have setup Angular SSR by the official Angular guide, so I’m building SSR app with build:ssr command:

"build:ssr": "ng build && gzipper compress ./dist && ng run my-app:server",

That command creates me dist folder with two builds browser and server.

I have connected my Git repo, and set this in netlify.toml:

  command = "npm run build:ssr"
  functions = "./functions"
  publish = "dist/my-app/server"
  from = "/*"
  to = "/main.js"
  status = 200

Netlify builds the app without errors, but when I hit deploy preview site, there is just JS code from my main.js file in the server folder. I could not find any guide for deploying angular with SSR and serving it. My config is wrong I guess so if someone has a working config and setup, it would be great to share it.

Not sure If I have to do some changes in to the my server.ts file in root on my project, because currently its default angular - node express config in there.


import 'zone.js/dist/zone-node';

import { ngExpressEngine } from '@nguniversal/express-engine';
import * as express from 'express';
import { join } from 'path';

import { AppServerModule } from './src/main.server';
import { APP_BASE_HREF } from '@angular/common';
import { existsSync } from 'fs';

// The Express app is exported so that it can be used by serverless Functions.
export function app(): express.Express {
  const server = express();
  const distFolder = join(process.cwd(), 'dist/my-app/browser');
  const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';

  // Our Universal express-engine (found @
  server.engine('html', ngExpressEngine({
    bootstrap: AppServerModule,

  server.set('view engine', 'html');
  server.set('views', distFolder);

  // Example Express Rest API endpoints
  // server.get('/api/**', (req, res) => { });
  // Serve static files from /browser
  server.get('*.*', express.static(distFolder, {
    maxAge: '1y'

  // All regular routes use the Universal engine
  server.get('*', (req, res) => {
    res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });

  return server;

function run(): void {
  const port = process.env['PORT'] || 4000;

  // Start up the Node server
  const server = app();
  server.listen(port, () => {
    console.log(`Node Express server listening on http://localhost:${port}`);

// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {

export * from './src/main.server';

Thank you

@armingdev It looks like you’re trying to publish an express server to serve your html.

This isn’t what you would do with Netlify, as your files are deployed to CDN, (not to a long running Node.js instance).

The publish folder in the netlify.toml should point to:

Directory that contains the deploy-ready HTML files and assets generated by the build

If all the files that need to be served are static and in dist/my-app/browser then you may be able to set that as your publish folder for Netlify, and change your build command to not try and start the server.

To handle “on request building” (SSR) you can either look into the use of Functions or if you do want a long running Node.js instance, utilize another hosting provider like heroku.

Thank you on detailed answer. Yeah, I was going to deploy SSR for better SEO. Maybe I can build and deploy prerender option and deploy browser files …