zerovoids.dev
react-domAPIs

resumeToPipeableStream

const { pipe, abort } = resumeToPipeableStream(reactNode, postponedState, options?)

prerenderToNodeStream이 멈춘 지점부터 이어받아, Node.js 스트림으로 SSR을 완성하는 API.

verified v19.2 · 2026-08-05
react-domapisssrstreamingnodejs

무엇

resumeToPipeableStream은 resume의 Node.js 버전이다. prerenderToNodeStream이 미완성으로 남긴 트리를 이어받아, Node.js Stream으로 나머지를 스트리밍 렌더링한다.

Deno나 엣지 런타임처럼 Web Streams를 쓰는 환경이면 이 API 대신 resume을 쓴다.

import { resumeToPipeableStream } from 'react-dom/server'
import { getPostponedState } from './storage'

const postponed = await getPostponedState(request)
const { pipe } = resumeToPipeableStream(<App />, postponed, {
  onShellReady() {
    pipe(response)
  },
})

무슨 일이 일어나나

동작 모델은 resume과 같다 — 루트부터 다시 훑되 이미 완성된 부분은 건너뛰고, 못 끝난 Suspense 경계부터 이어 그린다. 다른 점은 결과를 Web Stream이 아니라 Node.js Writable로 흘려보낸다는 것뿐이다.

renderToPipeableStream과 같은 콜백 모델을 쓴다. onShellReady에서 셸이 준비되면 pipe()를 불러 스트리밍을 시작하고, onShellError는 셸 자체가 실패했을 때(아직 바이트를 하나도 안 보낸 시점) 불린다.

bootstrapScripts, bootstrapModules, identifierPrefix는 여기서 주지 않는다 — 최초 prerenderToNodeStream 호출에서 정한 값을 그대로 이어받는다.

사용법

server.tsx
import { resumeToPipeableStream } from 'react-dom/server'
import { getPostponedState } from './storage'

app.use('/', async (request, response) => {
  const postponed = await getPostponedState(request)
  const { pipe } = resumeToPipeableStream(<App />, postponed, {
    onShellReady() {
      response.setHeader('content-type', 'text/html')
      pipe(response)
    },
    onShellError(error) {
      response.statusCode = 500
      response.send('<h1>문제가 발생했다</h1>')
    },
    onError(error) {
      console.error(error)
    },
  })
})

abort()로 렌더링을 중도에 끊어 나머지를 클라이언트에 넘길 수 있다. nonce는 최초 prerenderToNodeStream에 스크립트를 넘기지 않았을 때만 쓴다.

실무 예시

Node.js 서버(Express, Fastify 등) 위에서 PPR을 직접 구현할 때 쓴다. 정적 셸은 prerenderToNodeStream으로 미리 만들어 두고, 동적 요청이 오면 resumeToPipeableStream으로 이어 그려 응답을 완성한다.

왜 중요한가

resume과 마찬가지로 프레임워크 내부용 저수준 API다. Node.js 기반 커스텀 SSR 서버에서 PPR을 직접 짤 게 아니면 마주칠 일이 거의 없다. 이름이 비슷한 resumeAndPrerenderToNodeStream과는 다른 API라는 점만 헷갈리지 않으면 된다 — 이쪽은 스트리밍 SSR, 저쪽은 정적 생성(SSG)이다.

Reference