Node.js
Railpack builds and deploys Node.js applications with support for various package managers and frameworks.
Detection
Section titled “Detection”Your project will be detected as a Node.js application if a package.json file
exists in the root directory.
Versions
Section titled “Versions”The Node.js version is determined in the following order:
- Set via the
RAILPACK_NODE_VERSIONenvironment variable - Read from the
enginesfield inpackage.json - Read from the
.nvmrcfile - Read from the
.node-versionfile - Read from
mise.tomlor.tool-versionsfiles - Defaults to
22
We officially support actively maintained Node.js LTS versions. Older versions of Node.js will likely still work but are not officially supported.
The Bun version is determined in the following order:
- Set via the
RAILPACK_BUN_VERSIONenvironment variable - Read from the
.bun-versionfile - Read from the
engines.bunfield inpackage.json - Read from
mise.tomlor.tool-versionsfiles - Defaults to
latest
If Bun is used as the package manager, Node.js will still be installed in the following cases:
- If you define a
packageManagerfield in yourpackage.json(for Corepack support) - If any script in your
package.jsoncontainsnode - If you’re using Astro
When Node.js isn’t required in the final image but is needed during installation
(for native modules), Node.js will be installed via mise and will respect
version specifications in mise.toml and .tool-versions files.
Runtime Variables
Section titled “Runtime Variables”These variables are available at runtime:
NODE_ENV=productionNPM_CONFIG_PRODUCTION=falseNPM_CONFIG_UPDATE_NOTIFIER=falseNPM_CONFIG_FUND=falseYARN_PRODUCTION=falseCI=trueConfiguration
Section titled “Configuration”Railpack builds your Node.js application based on your project structure. The build process:
- Installs dependencies using your preferred package manager (npm, yarn, pnpm, or bun)
- Executes the build script if defined in
package.json - Sets up the start command based on your project configuration
Railpack determines the start command in the following order:
- The
startscript inpackage.json - The
mainfield inpackage.json - An
index.jsorindex.tsfile in the root directory
Config Variables
Section titled “Config Variables”| Variable | Description | Example |
|---|---|---|
RAILPACK_NODE_VERSION | Override the Node.js version | 22 |
RAILPACK_BUN_VERSION | Override the Bun version | 1.2 |
RAILPACK_NO_SPA | Disable SPA mode | true |
RAILPACK_SPA_OUTPUT_DIR | Directory containing built static files | dist |
RAILPACK_PRUNE_DEPS | Remove development dependencies | true |
RAILPACK_NODE_PRUNE_CMD | Custom command to prune dependencies | npm prune --omit=dev --ignore-scripts |
RAILPACK_NODE_INSTALL_PATTERNS | Custom patterns to install dependencies | prisma |
RAILPACK_ANGULAR_PROJECT | Name of the Angular project to build | my-app |
Package Managers
Section titled “Package Managers”Railpack detects your package manager in the following order:
- packageManager field: Reads the
packageManagerfield frompackage.json(uses Corepack to install the specified version) - Lock files: Falls back to detecting based on lock files:
pnpm-lock.yamlfor pnpmbun.lockborbun.lockfor Bun.yarnrc.ymlor.yarnrc.yamlfor Yarn Berry (2+)yarn.lockfor Yarn 1
- engines field: As a fallback, checks the
enginesfield inpackage.jsonfor package manager versions:engines.pnpmfor pnpm versionengines.bunfor Bun versionengines.yarnfor Yarn version- Defaults to npm if no package manager is detected
When the packageManager field is present, Railpack will use Corepack to
install the specified package manager version. When a package manager is
detected via the engines field, the specified version constraint will be
used.
Install
Section titled “Install”Railpack will only include the necessary files to install dependencies in order
to improve cache hit rates. This includes the package.json and relevant lock
files, but there are also a few additional framework specific files that are
included if they exist in your app. This behaviour is disabled if a preinstall
or postinstall script is detected in the package.json file.
You can include additional files or directories to include by setting the
RAILPACK_NODE_INSTALL_PATTERNS environment variable. This should be a space
separated list of patterns to include. Patterns will automatically be prefixed
with **/ to match nested files and directories.
Static Sites
Section titled “Static Sites”Railpack can serve a statically built Node project with zero config. You can disable this behaviour by either:
- Setting the
RAILPACK_NO_SPA=1environment variable - Setting a custom start command
These frameworks are supported:
- Vite: Detected if
vite.config.jsorvite.config.tsexists, or if the build script containsvite build - Astro: Detected if
astro.config.jsexists and the output is not type"server" - CRA: Detected if
react-scriptsis in dependencies and build script containsreact-scripts build - Angular: Detected if
angular.jsonexists - React Router: Detected if
react-router.config.jsorreact-router.config.tsexists, or if the build script containsreact-router build. To enable SPA mode, setssr: falsein your React Router config.
For all frameworks, Railpack will try to detect the output directory and will
default to dist (or build/client/ for React Router). Set the
RAILPACK_SPA_OUTPUT_DIR environment variable to specify a custom output
directory.
Static sites are served using the Caddy web server and a default Caddyfile. You can overwrite this file with your own Caddyfile at the root of your project.
Framework Support
Section titled “Framework Support”Railpack detects and configures caches and commands for popular frameworks. Including:
- Next.js: Caches
.next/cachefor each Next.js app in the workspace - Remix: Caches
.cache - Vite: Caches
node_modules/.vite - Tanstack Start: Caches
node_modules/.vite - Astro: Caches
node_modules/.astro - React Router: Caches
.react-router - Nuxt:
- Start command defaults to
node .output/server/index.mjs - Caches
node_modules/.cache
- Start command defaults to
As well as a default cache for node modules:
- Node modules: Caches
node_modules/.cache(with the cache keynode-modules)
Cache & Removing node_modules
Section titled “Cache & Removing node_modules”When you add custom build commands that remove node_modules (such as
npm ci), Railpack automatically detects this and
removes the node_modules/.cache directory from the cache configuration for
those steps. This prevents EBUSY: resource busy or locked errors
that would otherwise occur when trying to remove a cached directory.
This automatic handling applies to build steps that contain commands like:
npm cirm -rf node_modulesrimraf node_modules
The install step always retains its cache configuration regardless of the commands used.
System Dependencies
Section titled “System Dependencies”Railpack automatically installs system dependencies for certain packages:
- Puppeteer: When detected in workspace dependencies, Railpack installs
all necessary system packages for running headless Chrome, including
xvfb,chromiumdependencies, and font libraries