Node.js
Node.js is supported by Scalingo, furthermore, custom support has been added to manage the Meteor framework.
Standard Node.js Applications
Node.js App Detection
The file package.json
should be present at the root of the project.
Dependencies Installation
The dependencies of your project are installed either with the npm package manager or the Yarn package manager.
If a yarn.lock
file is present at the root of your project, yarn will be used
to install the dependencies and run scripts, otherwise npm will build the
dependencies during the deployment.
If a package-lock.json
file is present at the root of your project and you
are using npm version 6 or higher, Scalingo will use npm ci
(for
clean-install
) to install your dependencies. Otherwise Scalingo will fallback
to npm install
.
Private Dependency
NPM Private Modules
First you need to create a read-only token with the NPM account you want to authenticate:
npm token create --read-only
Then set this token as environment variable (replace the 0-value by the token obtained in the previous command):
scalingo env-set NPM_TOKEN=00000000-0000-0000-0000-00000000
Add the following NPM configuration file .npmrc
to the root directory of your project:
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
Add this file and commit it in your Git repository, the environment variable will be automatically used during the build.
Configuring NPM
Sometimes a project needs custom npm behavior to set up proxies, use a different registry, etc. For such behavior, simply include an .npmrc file in the root of your project.
# .npmrc
registry = 'https://custom-registry.com/'
npm will also read the configuration from any environment variable starting with NPM_CONFIG.
Private Modules from SCM (GitHub/GitLab/etc.)
Your private module should be fetched from the SCM service through SSH. You can specify it this way:
"package-name": "git+ssh://git@<SCMhostname>/<workspace>/<repo>.git#master"
To authenticate to the SCM service, you need to use our SSH Private Key Buildpack, this buildpack will let you setup a private SSH key securely in the build environment.
devDependencies Installation
By default, dependencies present in the devDependencies
field are installed. At the end of the deployment, devDependencies
are pruned. Hence only production dependencies are left in the image used for the runtime.
The pruning step can be skipped by setting the environment variable YARN_PRODUCTION
to any value.
Ensure you’re Tracking all your Dependencies
It is important to ensure you are tracking all the dependencies of your project
in the package.json
file. Otherwise your app may build but will potentially
crash during its runtime, failing to find a dependency.
A common mistake is to run npm install
without the --save
flag. In this
case the dependency is installed in the node_modules
directory, but nothing
is tracked in the package.json
file.
You should also avoid to install global packages (i.e. using the -g
flag). In
this case packages are installed at the system level and are not tracked for
your project.
In a nutshell: you should always use the following command when adding a dependency:
npm install --save <module>
Do not Track Modules with Git
When working locally on your code, after running npm install
, a directory
node_modules
containing the dependencies of your application is created. You
should not check this directory in your Git repository. If the dependency is
listed in your package.json
file, it will automatically be installed during
the deployment of your application.
Adding these files to Git will create confusion and unnecessary noise in your code history and we consider it’s a good practice to keep it clean, only add the useful code (the code of your project). Moreover there is an issue with dependencies which build binaries during their installation. If you add these binaries to your repository, it may create incompatibility with Scalingo runtime environment.
The good method to avoid checking in these files is to add the following
content in a .gitignore
file at the root of your project and commit this
file:
node_modules
bower_components
# Any other file created by grunt/gulp/webpack builds
Once done, Git will ignore these directories when making commits.
Specifying a Node.js Version
In your engines
section of your package.json
file, you can specify a
version of Node.js to use.
If no version is defined, Scalingo installs the latest version of v20. Available versions of Node.js are available here: https://nodejs.org/en/about/releases/.
It is exactly the same with npm
if you want to use a specific version of it.
{
"name": "my-app",
"engines": {
"node": "20",
"npm": "6"
}
}
Node.js App Startup
What we use in order of priority
-
Procfile
at the root of your project - The field
.scripts.start
defined in yourpackage.json
Example of package.json
:
{
...
"scripts": {
"start": "node server.js"
}
}
Node.js Build Hooks
If your application has a build step that you would like to run when you
deploy, you can use the build
step defined in the package.json
:
{
...
"scripts": {
"start": "node server.js",
"build": "grunt build"
}
}
If the package.json
has a build
script which needs to be customized for
Scalingo, you should define ascalingo-postbuild
step:
{
...
"scripts": {
"build": "grunt build",
"scalingo-postbuild": "grunt build --prod",
"start": "node server.js"
}
}
You may also want to run a custom command before the installation of
dependencies. This is possible thanks to commands named scalingo-prebuild
:
{
...
"scripts": {
"scalingo-prebuild": "node prebuild.js",
"start": "node server.js"
}
}
Custom Cache Folder
By default, Scalingo stores the directories bower_components
and node_modules
at the root of the
project in the deployment
cache. But you might need to add different folders to this cache. You can override these defaults by
specifying the cacheDirectories
(or cache_directories
) key at the root of your package.json
file.
For example, if your application has a client and a server in the same repository, you can specify these folders to store them in the deployment cache with:
"cacheDirectories": ["client/node_modules", "server/node_modules"]
Meteor Application
If a .meteor
file is detected at the root of your project, your app will
be considered as a Meteor application.
See the Meteor applications documentation
Framework Requiring to Serve Static Files
Some front-end JavaScript frameworks (such as React Native, Ember.js, Ionic,
Next.js, GatsbyJS) build static files and need a minimal web server to serve
them. In order to do so, first update your package.json
to at least
specify the following scripts:
{
// …
"scripts": {
"build": "<build script>",
"start": "node server.js"
},
// …
}
The build
script depends on the framework you use:
- Ember.js:
ember build --environment=production
- GatsbyJS:
gatsby build
- Ionic:
ionic-app-scripts build
- Next.js:
next build
The server.js
file is a minimal web server such as the one presented here to serve the file
generated during the build phase.
Buildpack
More information at https://github.com/Scalingo/nodejs-buildpack.
Next.js
Out of the box, Next.js is configured with a package.json
which looks like:
{
"name": "my-app",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "^10.0.4",
"react": "^17.0.1",
"react-dom": "^17.0.1"
}
}
To make it work on Scalingo, you need to provide the port. Otherwise, you would get a timeout error.
....
Waiting for your application to boot...
! Error deploying the application
! → Timeout: my-app took more than 60 seconds to boot
....
To fix this issue, modify the start
script by adding -p $PORT
{
"name": "my-app",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start -p $PORT"
},
"dependencies": {
"next": "^10.0.4",
"react": "^17.0.1",
"react-dom": "^17.0.1"
}
}
Standalone Mode
The Next.js built image can be quite large, easily exceeding 500MB. If you encounter issues with the image size, you can try “standalone” mode.
More information here: Next.js in standalone mode.
Vite
In package.json
, you need
"scripts": {
"start": "vite --port $PORT",
// others scripts
}
}
In the vite.config
(or vite.config.ts
) file you need to add the following
server: {
host: "0.0.0.0",
},
As a note, vite --port $PORT
may compile components, depending on your configuration. If it does, it leads to a very long first HTTP request that may even crash your container. In this case, in the package.json
, replace the start
rule content to use node server.js
(see section Framework Requiring to Serve Static Files
) or vite preview --port $PORT
.
AngularJS
Please refer to the AngularJS dedicated page for instructions on how to deploy such an application on Scalingo.
Yarn Known Issues
Catch SIGTERM
In an Application Started With Yarn
You may want to catch the SIGTERM
signal in your Node.js application:
process.on('SIGTERM', () => {
log.notice('"SIGTERM" received');
process.exit(0)
});
The good practice is to start the application by defining a start
script in the package.json
. For example:
{
"scripts": {
"start": "node server.js"
}
}
Then define the web
process in the Procfile. Example of Procfile content:
web: yarn run start
The problem with this approach is that Scalingo sends a SIGTERM
signal to stop the application. But Yarn do not correctly forward this signal to the started process.
The solution is to change the content of the Procfile to directly start the Node.js process:
web: node server.js