Skip to main content
API reference for Vue’s server-side rendering capabilities. These functions allow you to render Vue applications to strings or streams on the server.

renderToString()

Renders a Vue application or VNode to an HTML string. The primary method for server-side rendering. Type Signature:
function renderToString(
  input: App | VNode,
  context?: SSRContext
): Promise<string>
input
App | VNode
required
The Vue application instance (from createSSRApp()) or a VNode to render.
context
SSRContext
Optional SSR context object for collecting metadata during rendering:
  • teleports: Object to collect teleport content
  • __teleportBuffers: Internal buffer for teleport rendering
  • __watcherHandles: Internal array of watchers to clean up
The context object is mutated during rendering to collect server-specific data.

Returns

A Promise that resolves to the rendered HTML string.

Basic Usage

import { createSSRApp } from 'vue'
import { renderToString } from 'vue/server-renderer'
import App from './App.vue'

const app = createSSRApp(App)
const html = await renderToString(app)

console.log(html) // <div>...</div>

With SSR Context

import { createSSRApp } from 'vue'
import { renderToString } from 'vue/server-renderer'
import App from './App.vue'

const app = createSSRApp(App)
const context = {}

const html = await renderToString(app, context)

// Access teleport content
if (context.teleports) {
  console.log(context.teleports['#modal'])
}

Express Integration

import express from 'express'
import { createSSRApp } from 'vue'
import { renderToString } from 'vue/server-renderer'
import App from './App.vue'

const app = express()

app.get('*', async (req, res) => {
  const vueApp = createSSRApp(App)
  const ctx = {}
  
  try {
    const html = await renderToString(vueApp, ctx)
    
    res.send(`
      <!DOCTYPE html>
      <html>
        <head>
          <title>Vue SSR</title>
        </head>
        <body>
          <div id="app">${html}</div>
          <script src="/client.js"></script>
        </body>
      </html>
    `)
  } catch (err) {
    console.error(err)
    res.status(500).send('Internal Server Error')
  }
})

Rendering a VNode

import { createVNode } from 'vue'
import { renderToString } from 'vue/server-renderer'
import MyComponent from './MyComponent.vue'

const vnode = createVNode(MyComponent, { msg: 'Hello' })
const html = await renderToString(vnode)
Always use createSSRApp() instead of createApp() for server-side rendering to enable SSR-specific optimizations.

renderToNodeStream()

Renders a Vue application to a Node.js Readable stream. Useful for streaming responses to clients. Type Signature:
function renderToNodeStream(
  input: App | VNode,
  context?: SSRContext
): Readable
input
App | VNode
required
The Vue application instance or VNode to render.
context
SSRContext
Optional SSR context object for collecting metadata.

Returns

A Node.js Readable stream that emits HTML chunks.

Express Integration

import express from 'express'
import { createSSRApp } from 'vue'
import { renderToNodeStream } from 'vue/server-renderer'
import App from './App.vue'

const app = express()

app.get('*', (req, res) => {
  const vueApp = createSSRApp(App)
  const stream = renderToNodeStream(vueApp)
  
  res.setHeader('Content-Type', 'text/html')
  res.write('<!DOCTYPE html><html><head><title>Vue SSR</title></head><body><div id="app">')
  
  stream.pipe(res, { end: false })
  
  stream.on('end', () => {
    res.end('</div><script src="/client.js"></script></body></html>')
  })
  
  stream.on('error', (err) => {
    console.error(err)
    res.status(500).end('Internal Server Error')
  })
})
renderToNodeStream() is only available in CommonJS builds. For ES module builds, use pipeToNodeWritable().

pipeToNodeWritable()

Pipes the rendering output to a Node.js Writable stream. Available in both CommonJS and ES module builds. Type Signature:
function pipeToNodeWritable(
  input: App | VNode,
  context: SSRContext | undefined,
  writable: Writable
): void
input
App | VNode
required
The Vue application instance or VNode to render.
context
SSRContext | undefined
Optional SSR context object for collecting metadata.
writable
Writable
required
A Node.js Writable stream to pipe the output to (e.g., HTTP response object).

Express Integration

import express from 'express'
import { createSSRApp } from 'vue'
import { pipeToNodeWritable } from 'vue/server-renderer'
import App from './App.vue'

const app = express()

app.get('*', (req, res) => {
  const vueApp = createSSRApp(App)
  
  res.setHeader('Content-Type', 'text/html')
  res.write('<!DOCTYPE html><html><head><title>Vue SSR</title></head><body><div id="app">')
  
  pipeToNodeWritable(vueApp, {}, res)
  
  res.on('finish', () => {
    res.end('</div><script src="/client.js"></script></body></html>')
  })
})

renderToWebStream()

Renders a Vue application to a Web ReadableStream. Useful for modern edge runtimes and service workers. Type Signature:
function renderToWebStream(
  input: App | VNode,
  context?: SSRContext
): ReadableStream
input
App | VNode
required
The Vue application instance or VNode to render.
context
SSRContext
Optional SSR context object for collecting metadata.

Returns

A Web ReadableStream that emits HTML chunks as Uint8Array.

Cloudflare Workers Integration

import { createSSRApp } from 'vue'
import { renderToWebStream } from 'vue/server-renderer'
import App from './App.vue'

export default {
  async fetch(request) {
    const vueApp = createSSRApp(App)
    const stream = renderToWebStream(vueApp)
    
    const { readable, writable } = new TransformStream()
    const writer = writable.getWriter()
    
    writer.write(new TextEncoder().encode(
      '<!DOCTYPE html><html><head><title>Vue SSR</title></head><body><div id="app">'
    ))
    
    stream.pipeTo(writable)
    
    return new Response(readable, {
      headers: { 'Content-Type': 'text/html' }
    })
  }
}

Deno Integration

import { serve } from 'https://deno.land/std/http/server.ts'
import { createSSRApp } from 'vue'
import { renderToWebStream } from 'vue/server-renderer'
import App from './App.vue'

serve(async (req) => {
  const vueApp = createSSRApp(App)
  const stream = renderToWebStream(vueApp)
  
  return new Response(stream, {
    headers: { 'Content-Type': 'text/html' }
  })
})
Requires a runtime that supports Web Streams API (Node.js 16.5+, Deno, Cloudflare Workers, etc.).

pipeToWebWritable()

Pipes the rendering output to a Web WritableStream. Type Signature:
function pipeToWebWritable(
  input: App | VNode,
  context: SSRContext | undefined,
  writable: WritableStream
): void
input
App | VNode
required
The Vue application instance or VNode to render.
context
SSRContext | undefined
Optional SSR context object for collecting metadata.
writable
WritableStream
required
A Web WritableStream to pipe the output to.

Example

import { createSSRApp } from 'vue'
import { pipeToWebWritable } from 'vue/server-renderer'
import App from './App.vue'

const vueApp = createSSRApp(App)
const { readable, writable } = new TransformStream()

pipeToWebWritable(vueApp, {}, writable)

// Use the readable stream
const response = new Response(readable, {
  headers: { 'Content-Type': 'text/html' }
})

renderToSimpleStream()

Renders to a simple stream interface. Lower-level API for custom stream implementations. Type Signature:
interface SimpleReadable {
  push(chunk: string | null): void
  destroy(err: any): void
}

function renderToSimpleStream<T extends SimpleReadable>(
  input: App | VNode,
  context: SSRContext,
  stream: T
): T
input
App | VNode
required
The Vue application instance or VNode to render.
context
SSRContext
required
SSR context object for collecting metadata.
stream
SimpleReadable
required
A simple stream implementation with push() and destroy() methods.

Returns

The same stream instance passed as parameter.

Custom Stream Implementation

import { createSSRApp } from 'vue'
import { renderToSimpleStream } from 'vue/server-renderer'
import App from './App.vue'

const vueApp = createSSRApp(App)

const customStream = {
  chunks: [],
  push(chunk) {
    if (chunk === null) {
      console.log('Stream ended')
    } else {
      this.chunks.push(chunk)
    }
  },
  destroy(err) {
    console.error('Stream error:', err)
  }
}

renderToSimpleStream(vueApp, {}, customStream)

SSRContext

The context object used for server-side rendering. Type Definition:
interface SSRContext {
  /**
   * Teleport content collected during rendering
   */
  teleports?: Record<string, string>
  
  /**
   * @internal
   */
  __teleportBuffers?: Record<string, SSRBuffer>
  
  /**
   * @internal
   */
  __watcherHandles?: (() => void)[]
  
  /**
   * Custom properties (user-defined)
   */
  [key: string]: any
}

Usage

import { createSSRApp } from 'vue'
import { renderToString } from 'vue/server-renderer'
import App from './App.vue'

const app = createSSRApp(App)
const context = {
  url: '/about',
  userAgent: 'Mozilla/5.0...'
}

const html = await renderToString(app, context)

// Access teleport content after rendering
if (context.teleports) {
  const modalContent = context.teleports['#modal']
  // Inject modal content in appropriate place
}
The SSRContext can be used to pass server-specific data to components via inject() and the ssrContextKey.

Best Practices

Performance

  • Use streaming APIs (renderToNodeStream, renderToWebStream) for large applications
  • Streaming starts sending HTML before the entire app is rendered
  • Improves Time to First Byte (TTFB) and perceived performance

Error Handling

import { createSSRApp } from 'vue'
import { renderToString } from 'vue/server-renderer'
import App from './App.vue'

try {
  const app = createSSRApp(App)
  const html = await renderToString(app)
  // Send response
} catch (err) {
  console.error('SSR Error:', err)
  // Send error page or fallback
}

Teleport Handling

import { createSSRApp } from 'vue'
import { renderToString } from 'vue/server-renderer'
import App from './App.vue'

const app = createSSRApp(App)
const ctx = {}
const appHtml = await renderToString(app, ctx)

const html = `
<!DOCTYPE html>
<html>
  <body>
    <div id="app">${appHtml}</div>
    <div id="modal">${ctx.teleports?.['#modal'] || ''}</div>
  </body>
</html>
`
Never use renderToString() in the client. It’s server-only. For client-side hydration, use createSSRApp() with app.mount().

Build docs developers (and LLMs) love