Skip to main content

Server Side Rendering

Analog supports server-side rendering during development and building for production.

Transforming Packages for SSR Compatibility

Some dependencies may need additional transforms to work for server-side rendering. If you receive an error during SSR in development, one option is to add the package(s) to the ssr.noExternal array in the Vite config.

You can use glob patterns to include sets of packages or libraries. Some examples are listed below.

import { defineConfig } from 'vite';
import analog from '@analogjs/platform';

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => ({
ssr: {
noExternal: [
'apollo-angular', // npm package import
'apollo-angular/**', // npm package import along with sub-packages
'@spartan-ng/**', // libs under the npmScope inside an Nx workspace
],
},
// ...other config
}));

For more information about externals with SSR, check out the Vite documentation.

Hybrid Rendering with Client-Only Routes

SSR is enabled by default. For a hybrid approach, you can specify some routes to only be rendered client-side, and not be server side rendered. This is done through the routeRules configuration object by specifying an ssr option.

import { defineConfig } from 'vite';
import analog from '@analogjs/platform';

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => ({
// ...other config
plugins: [
analog({
prerender: {
routes: ['/', '/404.html'],
},
nitro: {
routeRules: {
// All admin URLs are only rendered on the client
'/admin/**': { ssr: false },

// Render a 404 page as a fallback page
'/404.html': { ssr: false },
},
},
}),
],
}));

Disabling SSR

You can opt-out of it and generate a client-only build by adding the following option to the analog() plugin in your vite.config.ts:

import { defineConfig } from 'vite';
import analog from '@analogjs/platform';

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => ({
// ...other config
plugins: [
analog({
ssr: false,
prerender: {
routes: [],
},
}),
],
}));

Prerendering routes

With SSR, the "/" route is prerendered by default.

It is a necessary step to return a rendered HTML when the user visits the root of the application. The prerendered routes can be customized, but keep in mind to include the "/" route also.

import { defineConfig } from 'vite';
import analog from '@analogjs/platform';
// https://vitejs.dev/config/
export default defineConfig(({ mode }) => ({
// ...other config
plugins: [
analog({
prerender: {
routes: ['/', '/about'],
},
}),
],
}));

Advanced Code Splitting (Vite 8+ / Rolldown)

When using Vite 8+ with Rolldown as the bundler, you can control how client-side chunks are created by passing codeSplitting through the vite.build.rolldownOptions.output config path. This is useful for further optimizing bundle sizes by grouping vendor or shared modules into separate chunks.

import { defineConfig } from 'vite';
import analog from '@analogjs/platform';

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => ({
// ...other config
plugins: [analog()],
build: {
rolldownOptions: {
output: {
codeSplitting: {
minSize: 10000,
groups: [
{
name: 'vendor',
test: /node_modules/,
priority: 10,
},
],
},
},
},
},
}));

Code Splitting Options

OptionTypeDescription
groupsarrayDefine custom chunk groups
minSizenumberMinimum chunk size in bytes before splitting
maxSizenumberMaximum chunk size in bytes

Code Splitting Group Options

OptionTypeDescription
namestring | functionChunk name or function returning a chunk name
testRegExp | string | functionPattern or predicate used to match module IDs for the group
prioritynumberPriority when a module matches multiple groups
minSizenumberMinimum size for this group's chunks
maxSizenumberMaximum size for this group's chunks
minShareCountnumberMinimum number of chunks sharing a module before splitting

This option only applies when using Rolldown as the bundler (Vite 8+). It has no effect with Rollup-based builds.

You can opt-out of prerendering altogether by passing an empty array of routes.

import { defineConfig } from 'vite';
import analog from '@analogjs/platform';

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => ({
// ...other config
plugins: [
analog({
ssr: true,
prerender: {
routes: async () => {
return [];
},
},
}),
],
}));