Environment: Node.js.

We use createPageRenderer() to create the server middlware that performs server-side rendering:

// server.js
// Environment: Node.js server

// In this example we use Express.js but we could use any other server framework.
const express = require('express')
const { createPageRenderer } = require('vite-plugin-ssr')

const isProduction = process.env.NODE_ENV === 'production'
const root = `${__dirname}/..`
const base = '/'
const baseAssets = '/'
const outDir = `dist`


async function startServer() {
  const app = express()

  let viteDevServer
  if (isProduction) {
  } else {
    const vite = require('vite')
    viteDevServer = await vite.createServer({
      server: { middlewareMode: 'ssr' }

  const renderPage = createPageRenderer({
  app.get('*', async (req, res, next) => {
    const url = req.originalUrl
    const pageContextInit = { url }
    const pageContext = await renderPage(pageContextInit)
    if (!pageContext.httpResponse) return next()
    const { body, statusCode, contentType } = pageContext.httpResponse

  const port = 3000
  console.log(`Server running at http://localhost:${port}`)
  • viteDevServer is the Vite dev server.
  • isProduction is a boolean. When set to true, vite-plugin-ssr loads already-transpiled code from dist/ instead of on-the-fly transpiling code.
  • root is the absolute path of our app's root directory. The root directory is usually the directory where vite.config.js lives. All our .page.js files need to be descendent of the root directory.
  • outDir is the build directory of your project. Default: dist.
  • base is the Base URL.
  • baseAssets is the Base URL of our static assets.
  • pageContext.httpResponse is null when a) an error occurred while rendering, or b) we didn't define the page and and an error occured.
  • pageContext.httpResponse.statusCode is either 200, 404, or 500.
  • pageContext.httpResponse.contentType is either text/html or application/json. (The Content Type is application/json when Client Routing fetches the pageContext of the newly navigated page.)
  • pageContext.httpResponse.body is the HTML-sanitized string returned by the render() hook with added assets that vite-plugin-ssr automatically injected.

Since createPageRenderer() and renderPage() are agnostic to Express.js, we can use vite-plugin-ssr with any server framework (Koa, Hapi, Fastify, vanilla Node.js, ...) and any deploy environment such as Cloudflare Workers or Vercel.