Vite's Low-Level SSR API

Vite's SSR API lets you run Vite as a middleware inside your own Node.js server, giving you full control over rendering. It's for building custom SSR solutions, often with Express. The footgun: most apps should use a higher-level SSR plugin, not this API.
Why it exists
Standard SSR frameworks can be opinionated. Vite provides a low-level API for when you need full control over the server environment and rendering logic, decoupling Vite from the production server and allowing it to act as a powerful development tool for a custom setup.
The mental model
Instead of Vite running your server, your server runs Vite. Think of Vite as a specialized middleware for your Express or other Node.js server. It handles asset transformation, module loading, and Hot Module Replacement (HMR) during development, but you control the request/response cycle and how the final HTML is assembled.
How it works
You structure your app with separate entry points for the client (entry-client.js) and server (entry-server.js). In your main server file, you create a Vite server using createViteServer with server: { middlewareMode: true } and appType: 'custom'. This prevents Vite from serving its own HTML. You then apply vite.middlewares to your Express app. In your request handler, you use vite.ssrLoadModule to load your entry-server.js, which exports a function to render your app to an HTML string. Finally, you replace a placeholder in your index.html template with this string and send it to the client. The conditional import.meta.env.SSR allows you to write code that only runs on the server or client, enabling tree-shaking.
When to use it
Use this API when you are a framework or library author building an SSR solution on top of Vite. It's also appropriate for complex applications with unique server requirements that are not met by existing higher-level SSR plugins like those in Nuxt or SvelteKit.
When not to use it
Do not use this low-level API for a standard web application. If you're building an app with Vue, React, or Svelte, use an established meta-framework or a dedicated SSR plugin from the Vite ecosystem. These tools abstract away this complexity for a simpler developer experience.
One canonical example
A common setup involves an Express server. You call createViteServer({ server: { middlewareMode: true }, appType: 'custom' }). Then, in a universal request handler like app.use('*', ...), you read your index.html as a template. You use await vite.ssrLoadModule('/src/entry-server.js') to get your app's render function, call it to generate HTML, inject that HTML into the template, and send the final response.
Interview question
When is Vite's low-level SSR API the most appropriate choice for a project?
- a.When Vite is intended to serve the entire application, including its own HTML, in production.
- b.When building a custom SSR framework or requiring unique server-side rendering control beyond existing plugins.Correct
- c.To achieve the highest possible performance for a standard web application.
- d.For any new web application requiring server-side rendering with popular frameworks like React or Vue.
Why? this is the answer
The low-level SSR API is designed for advanced scenarios like framework development or highly custom server environments, offering full control. It is explicitly advised against for standard applications using popular frameworks, which should leverage higher-level SSR plugins.
Just read this? Test yourself on what you have been reading.
Read the original → vite.dev
You just looked this up. Could you explain it out loud?
That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Every open role lists the topics its interview covers, so you can prepare for the real thing rather than guessing.
See open roles