Assets Nodejs

Jets can build a Docker image with the Nodejs runtime installed for apps that need it. For Rails, Nodejs is typically useful for compiling assets that use Node ecocystem libraries.

Install NodeJS

The default = "auto" means Jets will auto-detect whether or not to install NodeJS.


Jets.deploy.configure do = true = "auto"
 # = "20.12.1" # default a stable nodejs version

When a package.json or yarn.lock is detected in the source code, Jets will install nodejs and yarn.

Node Version Precedence

Jets auto-detects what Nodejs version to install for the Docker image it builds. The auto-detection precedence works in this order:

  1. config
  2. .tool-versions or .nvmrc
  3. default

It’s recommended to use #2 .tools-version or .nvmrc


You can configure the NodeJS version to use with a config. It takes the highest precedence.


Jets.deploy.configure do = "20.12.2"


Jets will evaluate the Gemfile and use the NodeJS version if there’s a specified ruby version.


ruby "20.12.2"

.tool-versions or .nvmrc

If your project has a .tool-versions (asdf) or .nvmrc, Jets installs that version. If both .tool-versions and .nvmrc exist, the .tool-versions takes higher precedence.


The Jets default NodeJS version may change in the future. See “NodeJS Version Default” below.

NodeJS Version Default

Jets installs a version of nodejs that we feel is stable. This may mean that the default version is different from the latest LTS version. We cannot guarantee the default version won’t change. The reasons for this are elaborated below.

The NodeJS world tends to move quickly. In some ways, this is great for rapid innovation. However, it can make it a tough experience for someone who does not work on node and javascript on a daily basis. One of the top visited pages from the boltops/jets community forums is for webpack issues. 🤦🏻‍♂️

It seems like some npm package is upgraded every couple of months, which happens to break backward compatibility with other libraries or old configuration schema settings. Speaking from real-world experience, it’s the Wild West.

  • Over the years, schema or interfaces for configurations like babel.config.js, .browserslistrc, config/webpacker/environment.js, postcss.config.js, config/webpacker.yml change in breaking ways.
  • Here are just some examples: webpacker 2059, webpacker 2202, webpacker 2342, jetpacker 4, digital envelope routines::unsupported Error.
  • The error messages could be better, particularly when webpack breaks. I have read a few javascript books Douglas Crockford JavaScript books: JavaScript: The Good Parts and How JavaScript Works, and David Flanagan’s JavaScript: The Definitive Guide. It’s funny that the Good Parts book is short compared to other general Javascript books. 😄
  • I have also worked with both reactjs and vuejs. I’ve even released packages for npm. Albeit it’s a small humble library: @rubyonjets/ujs-compat. Generally, I found that the JavaScript world can still be a frustrating experience. The error messages may be clearer for a node/javascript everyday developer.
  • I have found it’s usually faster to treat things like a black box when there have been webpack issues. IE: Upgrade yarn and node, regenerate the configuration files, and see if that fixes issues. Sometimes, you have to dig deeper, and that takes a decent amount of time.
  • DHH also discusses the move away from node tools like esbuild, rollup.js, and webpack in this Rails 7 will have three great answers to JavaScript in 2021+.
  • Ultimately, there are only so many hours in a day.

Thus, we may change the default node version more liberally than other components. If you need specific versions, you should explicitly set them. You can also precompile your assets locally and add them to git before deployment.


The table below covers each setting. Each option is configured with config.OPTION. The config. portion is not shown for conciseness. IE: logger.level vs config.logger.level.

Name Default Description true If public/assets/manifest-*.js is detected in the source code, Jets assumes you have locally precompiled assets and the remote runner will not attempt to compile assets in the remote runner docker build process. “conditional” When Rails, it’s set to true. For other frameworks like sinatra, it’s set to false. auto The auto value means that it will be auto-detected. When a package.json is detected in the source code, it’ll assume you’ll need nodejs and yarn installed. 20.12.1 The nodejs version to use. We try to default to the latest LTS node. true When is nodejs.enable, it will install for both build and deployment stages for the multi-stage docker build process. You can use this to disable it for the deployment phase. This means the Docker image you’re running won’t have access to the nodejs runtime. It’s only use to build artifacts. “conditional” When Rails, the default command is a jets, which calls rails assets:precompile if it’s available. Otherwise, it is nil.
assets.upload.cache_control nil The cache control header to use for assets uploaded to s3. Example: public, max-age=3600.
assets.upload.enable true Upload the assets from assets.upload.folders, IE: public, to s3.
assets.upload.folders [“public”] Folders to upload to s3.
assets.upload.max_age 3600 The max age in seconds for the cache control header. This is a shorter way to set the cache_control. IE: 3600 => public, max-age=3600

See Full Config Reference