Node Renderer Basics
Pro Feature — Available with React on Rails Pro. Free or very low cost for startups and small companies. Upgrade or licensing details →
Requirements
- You must use React on Rails v11.0.7 or higher.
Install the Gem and the Node Module
See Installation.
Memory Management
The Node Renderer reuses V8 VM contexts across requests for performance. This means module-level state in your server bundle persists across all SSR requests. Any unbounded caches, _.memoize calls, or growing data structures at module scope will leak memory until the worker restarts.
Essential for production:
- Set
NODE_OPTIONS=--max-old-space-size=<MB>to prevent V8 from deferring garbage collection - Enable worker rolling restarts via
allWorkersRestartIntervalanddelayBetweenIndividualWorkerRestarts - Audit your server bundle for module-level mutable state
See the Memory Leaks guide for common leak patterns and how to fix them.
Setup Node Renderer Server
node-renderer is a standalone Node application to serve React SSR requests from a Rails client. You don't need any Ruby code to setup and launch it. You can configure with the command line or with a launch file.
Generator shortcut: Running
rails generate react_on_rails:install --pro(orrails generate react_on_rails:profor existing apps) automatically createsclient/node-renderer.js, adds the Node Renderer process toProcfile.dev, and installs the required npm packages. See Installation for details. The manual setup below is for apps that need custom configuration.
Simple Command Line for node-renderer
- ENV values for the default config are (See JS Configuration for more details):
RENDERER_PORTRENDERER_HOSTRENDERER_LOG_LEVELRENDERER_BUNDLE_PATHRENDERER_WORKERS_COUNTRENDERER_PASSWORDRENDERER_ALL_WORKERS_RESTART_INTERVALRENDERER_DELAY_BETWEEN_INDIVIDUAL_WORKER_RESTARTSRENDERER_SUPPORT_MODULES
- Configure ENV values and run the command. Note, you can set port with args
-p <PORT>. For example, assuming node-renderer is in your path:RENDERER_BUNDLE_PATH=/app/.node-renderer-bundles node-renderer - You can use a command line argument of
-p SOME_PORTto override any ENV value for the PORT.
JavaScript Configuration File
For the most control over the setup, create a JavaScript file to start the NodeRenderer.
-
Create some project directory, let's say
renderer-app:mkdir renderer-app
cd renderer-app -
Make sure you have Node.js 18+ and a JavaScript package manager such as npm, pnpm, Yarn, or bun.
-
Initialize a Node application and install the
react-on-rails-pro-node-rendererpackage.npm init -y
npm install react-on-rails-pro-node-renderer
# or: pnpm add react-on-rails-pro-node-renderer
# or: yarn add react-on-rails-pro-node-renderer
# or: bun add react-on-rails-pro-node-renderer -
Configure a JavaScript file that will launch the rendering server per the docs in Node Renderer JavaScript Configuration. For example, create a file
node-renderer.js. Here is a simple example that uses all the defaults except for serverBundleCachePath:import path from 'path';
import reactOnRailsProNodeRenderer from 'react-on-rails-pro-node-renderer';
const config = {
serverBundleCachePath: path.resolve(__dirname, '../.node-renderer-bundles'),
};
reactOnRailsProNodeRenderer(config); -
Now you can launch your renderer server with
node node-renderer.js. You will probably add a script to yourpackage.json. -
You can use a command line argument of
-p SOME_PORTto override any configured or ENV value for the port.
Setup Rails Application
Create config/initializers/react_on_rails_pro.rb and configure the renderer server. See configuration values in Configuration. Pay attention to:
- Set
config.server_renderer = "NodeRenderer" - Decide whether to enable
config.prerender_caching = true. The default isfalse; turn it on only if you want Rails cache-backed SSR result caching and your cache is configured for the additional load. - Configure values beginning with
renderer_ - Use ENV values for values like
renderer_urlso that your deployed server is properly configured. If the ENV value is unset, the default for the renderer_url islocalhost:3800. - Here's a tiny example using mostly defaults:
ReactOnRailsPro.configure do |config|
config.server_renderer = "NodeRenderer"
# when this ENV value is not defined, the local server at localhost:3800 is used
config.renderer_url = ENV["REACT_RENDERER_URL"]
end
Network Security
The Node Renderer executes JavaScript sent to it by the Rails application using Node.js vm.runInContext(). This makes it, by design, a remote code execution service — any client that can reach the HTTP port can execute arbitrary JavaScript on the host machine.
Node.js vm contexts are not a security boundary. Escaping a vm sandbox to access the full Node.js runtime (file system, child processes, network) is well-documented and straightforward.
To mitigate this, the renderer uses the same approach as PostgreSQL: it binds to localhost by default, so it is not reachable from the network at all. This provides two layers of defense:
- Network layer — Only processes on the same machine (or same Kubernetes pod network namespace) can reach the renderer. No remote attacker can connect.
- Authentication layer — The optional
passwordsetting (required in production-like environments) protects against unauthorized local callers.
This means a developer running the renderer locally without a password is safe by default — the renderer is only reachable from their own machine, just as a default PostgreSQL installation only accepts local connections.
When you must bind to 0.0.0.0 (e.g., separate container workloads in Docker Compose or Kubernetes separate-workload deployments):
- Always set
RENDERER_PASSWORDto a strong value - Place the renderer behind private networking or firewall rules
- Never expose the renderer port to the public internet
See JS Configuration for the host and password options, and Container Deployment for architecture-specific guidance.
Troubleshooting
- See Memory Leaks guide.
Upgrading
The NodeRenderer has a protocol version on both the Rails and Node sides. If the Rails server sends a protocol version that does not match the Node side, an error is returned. Ideally, you want to keep both the Rails and Node sides at the same version.
References
- Installation
- Rails Options for node-renderer
- JS Options for node-renderer
- Container Deployment — Sidecar vs. separate workloads, memory tuning, autoscaling, and troubleshooting