From 539e841237c27fbe0b4844899725aa4612a05300 Mon Sep 17 00:00:00 2001 From: SC-Samir Date: Thu, 6 Aug 2026 11:47:30 +0200 Subject: [PATCH] This commit permit to show what Chatgpt have generated for the JS documentation --- redirections.yml | 18 + .../languages/nodejs/2000-01-01-angular.md | 255 --------- .../nodejs/2000-01-01-customizing.md | 287 +++++++++++ .../nodejs/2000-01-01-default-behavior.md | 244 +++++++++ .../nodejs/2000-01-01-deployment-errors.md | 110 ---- .../languages/nodejs/2000-01-01-extensions.md | 249 +++++++++ .../2000-01-01-managing-web-concurrency.md | 178 +++++++ .../nodejs/2000-01-01-nextjs-standalone.md | 126 ----- src/_posts/languages/nodejs/2000-01-01-npm.md | 258 ++++++++++ .../languages/nodejs/2000-01-01-pnpm.md | 234 +++++++++ .../languages/nodejs/2000-01-01-puppeteer.md | 51 -- .../nodejs/2000-01-01-selecting-a-version.md | 191 +++++++ .../languages/nodejs/2000-01-01-start.md | 484 ++++-------------- .../nodejs/2000-01-01-troubleshooting.md | 371 ++++++++++++++ .../languages/nodejs/2000-01-01-tutorial.md | 242 +++++++-- .../2000-01-01-websocket-web-same-port.md | 41 -- .../languages/nodejs/2000-01-01-yarn-2.md | 132 ----- .../languages/nodejs/2000-01-01-yarn.md | 237 +++++++++ .../nodejs/frameworks/2000-01-01-nextjs.md | 280 ++++++++++ .../platform/app/2000-01-01-slugignore.md | 2 +- .../buildpacks/2000-01-01-wkhtmltopdf.md | 2 +- 21 files changed, 2838 insertions(+), 1154 deletions(-) delete mode 100644 src/_posts/languages/nodejs/2000-01-01-angular.md create mode 100644 src/_posts/languages/nodejs/2000-01-01-customizing.md create mode 100644 src/_posts/languages/nodejs/2000-01-01-default-behavior.md delete mode 100644 src/_posts/languages/nodejs/2000-01-01-deployment-errors.md create mode 100644 src/_posts/languages/nodejs/2000-01-01-extensions.md create mode 100644 src/_posts/languages/nodejs/2000-01-01-managing-web-concurrency.md delete mode 100644 src/_posts/languages/nodejs/2000-01-01-nextjs-standalone.md create mode 100644 src/_posts/languages/nodejs/2000-01-01-npm.md create mode 100644 src/_posts/languages/nodejs/2000-01-01-pnpm.md delete mode 100644 src/_posts/languages/nodejs/2000-01-01-puppeteer.md create mode 100644 src/_posts/languages/nodejs/2000-01-01-selecting-a-version.md create mode 100644 src/_posts/languages/nodejs/2000-01-01-troubleshooting.md delete mode 100644 src/_posts/languages/nodejs/2000-01-01-websocket-web-same-port.md delete mode 100644 src/_posts/languages/nodejs/2000-01-01-yarn-2.md create mode 100644 src/_posts/languages/nodejs/2000-01-01-yarn.md create mode 100644 src/_posts/languages/nodejs/frameworks/2000-01-01-nextjs.md diff --git a/redirections.yml b/redirections.yml index 388585d6f..4c182589b 100644 --- a/redirections.yml +++ b/redirections.yml @@ -933,6 +933,24 @@ - old: "/platform/cli/introduction" new: "/tools/cli/start" + - old: "/languages/nodejs/angular" + new: "/languages/nodejs/start" + + - old: "/languages/nodejs/deployment-errors" + new: "/languages/nodejs/troubleshooting" + + - old: "/languages/nodejs/nextjs-standalone" + new: "/languages/nodejs/frameworks/nextjs#standalone-mode" + + - old: "/languages/nodejs/puppeteer" + new: "/languages/nodejs/extensions#use-puppeteer-or-another-headless-browser" + + - old: "/languages/nodejs/websocket-web-same-port" + new: "/languages/nodejs/start#starting-the-application" + + - old: "/languages/nodejs/yarn-2" + new: "/languages/nodejs/yarn" + obsolete: - "/how-to-migrate-from-cloudcontrol/" - "/how-to-migrate-from-shelly-cloud/" diff --git a/src/_posts/languages/nodejs/2000-01-01-angular.md b/src/_posts/languages/nodejs/2000-01-01-angular.md deleted file mode 100644 index 3f1303b74..000000000 --- a/src/_posts/languages/nodejs/2000-01-01-angular.md +++ /dev/null @@ -1,255 +0,0 @@ ---- -title: Deploying Angular on Scalingo -nav: Angular -modified_at: 2025-08-13 00:00:00 -tags: nodejs angular -index: 4 ---- - -Angular applications can be hosted on Scalingo. It requires some specific instructions as usually the application generates static files during the deployment. And these files require a web server to be served to your clients. - -Deploying an Angular application requires to use the [Multi Buildpacks]({% post_url platform/deployment/buildpacks/2000-01-01-multi %}). It will be used to generate the static files using Node.js during the deployment, and run a Nginx to serve the generated files. - -### Buildpacks Configuration - -Create a `.buildpacks` file: - -``` -https://github.com/Scalingo/nodejs-buildpack -https://github.com/Scalingo/nginx-buildpack -``` - -### Package.json Configuration - -Make sure your `package.json` contains the appropriate build scripts for Angular: - -``` -{ - "name": "my-angular-app", - "version": "1.0.0", - "scripts": { - "ng": "ng", - "start": "ng serve", - "build": "ng build --configuration=production", - "build:prod": "ng build --configuration=production --output-path=dist", - "test": "ng test", - "lint": "ng lint" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=9.0.0" - }, - "dependencies": { - "@angular/animations": "^20.0.0", - "@angular/common": "^20.0.0", - "@angular/compiler": "^20.0.0", - "@angular/core": "^20.0.0", - "@angular/forms": "^20.0.0", - "@angular/platform-browser": "^20.0.0", - "@angular/platform-browser-dynamic": "^20.0.0", - "@angular/router": "^20.0.0" - }, - "devDependencies": { - "@angular-devkit/build-angular": "^20.0.0", - "@angular/cli": "^20.0.0", - "@angular/compiler-cli": "^20.0.0", - "typescript": "~5.6.0" - } -} -``` - -### Nginx Configuration - -Configure Nginx to serve the generated files by creating a `nginx.conf` file. The following configuration assumes that the files have been generated in the `dist` folder: - -```nginx -root /app/dist/browser; - -location / { - try_files $uri $uri/ /index.html =404; - - # Cache configuration for assets - location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { - expires 1y; - add_header Cache-Control "public, immutable"; - } - - # Security configuration - add_header X-Frame-Options "SAMEORIGIN" always; - add_header X-Content-Type-Options "nosniff" always; - add_header Referrer-Policy "no-referrer-when-downgrade" always; - add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always; -} - -# API configuration (optional) -location /api/ { - # Proxy to your backend API if needed - proxy_pass http://backend-service; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; -} -``` - -### Procfile Configuration - -Then instruct Scalingo how to start the application with a [`Procfile`]({% post_url platform/app/2000-01-01-procfile %}): - -```yaml -web: bin/run -``` - -The `bin/run` script is generated during the deployment by the Nginx buildpack and starts a Nginx listening on the port defined in the `PORT` environment variable. - - -## Angular Configuration - -### Production Configuration - -Create or modify your `angular.json` file to optimize production builds: - -``` -{ - "projects": { - "my-app": { - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:browser", - "options": { - "outputPath": "dist", - "index": "src/index.html", - "main": "src/main.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "tsconfig.app.json", - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "src/styles.css" - ], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "2mb", - "maximumError": "5mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "6kb", - "maximumError": "10kb" - } - ], - "outputHashing": "all", - "sourceMap": false, - "optimization": true, - "aot": true, - "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true - } - } - } - } - } - } -} -``` - -## Environment Variables - -### environment.prod.ts - -``` -export const environment = { - production: true, - apiUrl: 'https://your-api.scalingo.io/api', - appName: 'My Angular 20 App' -}; -``` - -### environment.ts - -``` -export const environment = { - production: false, - apiUrl: 'http://localhost:3000/api', - appName: 'My Angular 20 App (Dev)' -}; -``` - -## Angular Optimizations - -### Lazy Loading and Code Splitting - -Use lazy loading to optimize performances: - -``` -// app-routing.module.ts -const routes: Routes = [ - { - path: 'feature', - loadChildren: () => import('./feature/feature.module').then(m => m.FeatureModule) - } -]; -``` - -### Service Worker (Optional) - -To add PWA support: - -``` -ng add @angular/pwa -``` - -Then configure in `ngsw-config.json` - -``` -{ - "$schema": "./node_modules/@angular/service-worker/config/schema.json", - "index": "/index.html", - "assetGroups": [ - { - "name": "app", - "installMode": "prefetch", - "resources": { - "files": [ - "/favicon.ico", - "/index.html", - "/manifest.webmanifest", - "/*.css", - "/*.js" - ] - } - } - ] -} -``` - -## Deployment - -Ensure all configuration files are present, commit changes, and deploy to Scalingo: - -``` -git push scalingo main -``` - -## Troubleshooting - -### Common Errors - -#### Build Error: - -Check that Node.js and npm version are compatible with Angular. - -#### 404 Error on Routes: - -Ensure the Nginx configuration includes `try_files $uri $uri/ /index.html =404;`. - -#### Performance Issues: - -Enable gzip compression in Nginx and optimize bundles with tree-shaking. - diff --git a/src/_posts/languages/nodejs/2000-01-01-customizing.md b/src/_posts/languages/nodejs/2000-01-01-customizing.md new file mode 100644 index 000000000..51d182dac --- /dev/null +++ b/src/_posts/languages/nodejs/2000-01-01-customizing.md @@ -0,0 +1,287 @@ +--- +title: Customize Node.js Builds +nav: Customize Builds +modified_at: 2026-08-06 00:00:00 +tags: nodejs build +index: 5 +--- + +Configure the Node.js buildpack through `package.json`, package-manager files, and Scalingo environment variables. Start with [Default Node.js Build and Runtime Behavior]({% post_url languages/nodejs/2000-01-01-default-behavior %}), then change only the behavior the application needs. + +## Configuration sources + +| Source | Typical use | +| --- | --- | +| `package.json` | Runtime and package-manager versions, scripts, custom cache paths | +| Lockfile | Package-manager selection and reproducible dependency graph | +| `.npmrc` | npm and pnpm registry, authentication, proxy, and install configuration | +| `.yarnrc.yml` | Yarn Berry configuration, linker mode, registry settings, optional vendored Yarn path | +| Scalingo environment variables | Buildpack switches, credentials, application configuration | +| Scalingo stack | Ubuntu base image and system-library compatibility | +| `Procfile` | Explicit runtime process types and commands | + +Do not store credentials directly in committed configuration. Reference an environment variable instead. + +## Choose or migrate the Scalingo stack + +The stack is an application-level platform setting rather than a Node.js buildpack environment variable. + +Each listed stack uses an Ubuntu long-term support (LTS) release. + +| Stack | Base operating system | Status | Lifecycle | +| --- | --- | --- | --- | +| `scalingo-22` | Ubuntu 22.04 LTS | Deprecated | Discontinued on 1 June 2027 | +| `scalingo-24` | Ubuntu 24.04 LTS | Supported | Supported through May 2029 | +| `scalingo-26` | Ubuntu 26.04 LTS | Supported and latest | Supported through May 2031 | + +Inspect the current value: + +```bash +scalingo --app my-app apps-info +``` + +Move an application to `scalingo-26` and redeploy: + +```bash +scalingo --app my-app stacks-set scalingo-26 +git commit --allow-empty --message="Migrate to scalingo-26" +git push scalingo main +``` + +{% warning %} +A stack migration changes the Ubuntu base image. Test native modules, browser binaries, image-processing libraries, database clients, and any APT-installed packages in staging or a Review App before production. +{% endwarning %} + +The buildpack's normal cache signature includes the stack and is invalidated by a stack change. Review custom `cacheDirectories` separately because they can retain generated artifacts outside the default cache policy. + +## Build scripts and hook order + +The buildpack recognizes three Scalingo-specific scripts and the standard `build` script. + +| Script | When it runs | Typical use | +| --- | --- | --- | +| `scalingo-prebuild` | Before dependency installation | Generate package-manager configuration or verify required build inputs | +| `build` | After dependency installation | Compile TypeScript, bundle assets, or run a framework production build | +| `scalingo-postbuild` | In place of `build` when present | Use a Scalingo-specific production build command | +| `scalingo-cleanup` | After caching and production pruning | Remove build-only files from the runtime image | + +Example: + +```json +{ + "scripts": { + "scalingo-prebuild": "node scripts/check-build-env.js", + "build": "tsc -p tsconfig.build.json", + "scalingo-cleanup": "node scripts/cleanup.js", + "start": "node dist/server.js" + } +} +``` + +{% warning %} +When both `build` and `scalingo-postbuild` exist, the buildpack runs only `scalingo-postbuild`. +{% endwarning %} + +Package-manager lifecycle scripts such as `preinstall`, `install`, `postinstall`, and `prepare` can also run during dependency installation. Keep those scripts portable because they also run in local and continuous integration (CI) installations. + +## Pass flags to the standard build script + +`NODE_BUILD_FLAGS` is forwarded to the standard `build` script. + +```bash +scalingo --app my-app env-set NODE_BUILD_FLAGS="--mode production" +``` + +With: + +```json +{ + "scripts": { + "build": "vite build" + } +} +``` + +The resulting command is package-manager-specific but includes the configured flags. `NODE_BUILD_FLAGS` is not forwarded to `scalingo-prebuild`, `scalingo-postbuild`, or `scalingo-cleanup`. + +For complex arguments, prefer an explicit `scalingo-postbuild` command in `package.json`; it is easier to review and test. + +## Control dependency pruning + +The buildpack installs development dependencies during the build by default, then removes them from a production runtime. + +Use the package-manager-specific controls only when necessary: + +| Package manager | Install-time control | Skip-pruning control | +| --- | --- | --- | +| npm | `NPM_CONFIG_PRODUCTION` | No dedicated verified skip-pruning variable in the audited path | +| Yarn Classic | `YARN_PRODUCTION` | See the Yarn page | +| Yarn Berry | Do not use `YARN_PRODUCTION` | `YARN2_SKIP_PRUNING=true` | +| pnpm | Installs with development dependencies by default | `PNPM_SKIP_PRUNING=true` | + +A package used by the start command belongs in `dependencies`. Skipping pruning should not be the normal way to repair an incorrect dependency classification. + +## Configure the build cache + +Caching is enabled by default: + +```text +NODE_MODULES_CACHE=true +``` + +Disable it temporarily when diagnosing a cache-related build problem: + +```bash +scalingo --app my-app env-set NODE_MODULES_CACHE=false +``` + +Re-enable it after diagnosis: + +```bash +scalingo --app my-app env-set NODE_MODULES_CACHE=true +``` + +The default cached content depends on the package manager. To cache additional relative paths, add `cacheDirectories` to `package.json`: + +```json +{ + "cacheDirectories": [ + ".next/cache", + "packages/frontend/.cache" + ] +} +``` + +The legacy key `cache_directories` is also recognized. Prefer `cacheDirectories` for new applications. + +{% warning %} +Custom cache directories replace the normal directory list. Cache only reproducible build artifacts. Do not cache secrets, user uploads, or state required for correctness. +{% endwarning %} + +pnpm-managed `node_modules` paths are not restored as custom cache paths; the buildpack includes the pnpm store separately. + +## Increase build log detail + +Set `NODE_VERBOSE=true` to print a top-level dependency summary near the end of a successful build. + +```bash +scalingo --app my-app env-set NODE_VERBOSE=true +``` + +npm log verbosity is controlled with `NPM_CONFIG_LOGLEVEL`: + +```bash +scalingo --app my-app env-set NPM_CONFIG_LOGLEVEL=info +``` + +Remove or lower verbose settings after troubleshooting to keep build logs readable. + +## Configure Node.js memory options + +When `NODE_OPTIONS` is not defined, the audited buildpack supplies: + +```text +--max_old_space_size=2560 +``` + +Set your own Node.js options when the application or build needs a different value: + +```bash +scalingo --app my-app env-set NODE_OPTIONS="--max-old-space-size=1536" +``` + +This variable can affect both build-time Node.js commands and the runtime process. A higher old-space limit does not increase the container memory limit and does not repair a memory leak. Leave enough memory for native allocations, buffers, the package manager, and other processes in the container. + +See [Manage Node.js Web Concurrency]({% post_url languages/nodejs/2000-01-01-managing-web-concurrency %}) before combining several Node.js worker processes with a large old-space limit. + +## Select package-manager versions + +Node.js and package-manager versions are separate settings. + +### npm + +```json +{ + "engines": { + "node": "24.x", + "npm": "11.x" + } +} +``` + +### Yarn + +Prefer the `packageManager` field for modern Yarn: + +```json +{ + "packageManager": "yarn@4.9.2" +} +``` + +### pnpm + +```json +{ + "packageManager": "pnpm@10.15.0" +} +``` + +When both `packageManager` and the corresponding `engines.yarn` or `engines.pnpm` field exist, `packageManager` takes precedence and the build emits a warning. + +## Force `npm install` + +With a supported npm lockfile and npm 6 or newer, the buildpack normally chooses `npm ci`. Set `USE_NPM_INSTALL=true` to force the install path: + +```bash +scalingo --app my-app env-set USE_NPM_INSTALL=true +``` + +Use this only for an identified compatibility requirement. `npm ci` is usually preferable because it enforces the lockfile and starts from a clean dependency tree. + +## Configure certificate authorities + +The buildpack defaults `NODE_EXTRA_CA_CERTS` to Scalingo’s database certificate authority (CA) bundle. Override it only when the application must trust an additional CA file available in the application image: + +```bash +scalingo --app my-app env-set NODE_EXTRA_CA_CERTS=/app/config/company-ca.pem +``` + +The file must exist at runtime. Do not replace the default without checking database Transport Layer Security (TLS) connectivity and other outbound TLS requirements. + +## Advanced binary overrides + +The buildpack contains advanced overrides for downloading Node.js or Yarn from custom URLs: + +- `NODE_BINARY_URL` +- `YARN_BINARY_URL` + +These bypass normal inventory or package resolution and can reduce reproducibility or supportability. + +{% warning %} +Treat custom binary URLs as an advanced escape hatch. Pin an immutable HTTPS artifact, verify its provenance, and test checksum and stack compatibility. Confirm the support policy with Scalingo before documenting this as a standard deployment method. +{% endwarning %} + +## Committed `node_modules` + +Do not commit `node_modules`. The buildpack can detect prebuilt modules and may rebuild native dependencies, but locally generated packages can still be incompatible with the Scalingo stack. + +`SKIP_NODE_MODULES_CHECK=true` preserves committed modules in part of the Yarn path. This is an advanced compatibility control, not a recommended dependency-delivery method. + +## Configuration reference + +| Variable or option | Default | Scope | Purpose | +| --- | --- | --- | --- | +| `NODEJS_ALLOW_WIDE_RANGE` | Unset | Build | Opt out of the Active-LTS cap for a wide Node.js range | +| `NODE_MODULES_CACHE` | `true` | Build | Enable or disable build caching | +| `NODE_VERBOSE` | `false` | Build | Print a dependency summary | +| `NODE_BUILD_FLAGS` | Empty | Build | Pass flags to `build` | +| `NODE_ENV` | `production` | Build and runtime | Application environment and pruning condition | +| `NODE_OPTIONS` | `--max_old_space_size=2560` when absent | Build and runtime | Node.js runtime options | +| `NODE_EXTRA_CA_CERTS` | Scalingo database CA path | Build and runtime | Additional trusted CA file | +| `USE_NPM_INSTALL` | Automatic selection | Build | Force npm install instead of npm ci | +| `USE_YARN_CACHE` | `true` for Yarn | Build | Control Yarn cache behavior | +| `PNPM_INSTALL_REPORTER` | pnpm default | Build | Select pnpm output reporter | +| `cacheDirectories` | Manager-specific defaults | Build | Replace default cached paths | + +See the npm, Yarn, and pnpm pages for manager-specific variables. diff --git a/src/_posts/languages/nodejs/2000-01-01-default-behavior.md b/src/_posts/languages/nodejs/2000-01-01-default-behavior.md new file mode 100644 index 000000000..3a67f04e7 --- /dev/null +++ b/src/_posts/languages/nodejs/2000-01-01-default-behavior.md @@ -0,0 +1,244 @@ +--- +title: Default Node.js Build and Runtime Behavior +nav: Default Behavior +modified_at: 2026-08-06 00:00:00 +tags: nodejs build runtime +index: 3 +--- + +This page describes the Node.js build and runtime lifecycle. It explains which files control the process and what remains in the runtime image. + +## Required application files + +A normal Node.js application needs a root `package.json` file. A lockfile is strongly recommended. + +```text +my-app/ +├── package.json +├── package-lock.json +└── server.js +``` + +The buildpack itself does not search nested directories. For monorepos, configure the deployed application root through Scalingo platform features before the Node.js buildpack runs. + +## Stack used for build and runtime + +The application is built for its selected Scalingo stack and the resulting runtime container uses the same Ubuntu base. + +Each listed stack uses an Ubuntu long-term support (LTS) release. + +| Stack | Base operating system | Status | Lifecycle | +| --- | --- | --- | --- | +| `scalingo-22` | Ubuntu 22.04 LTS | Deprecated | Discontinued on 1 June 2027 | +| `scalingo-24` | Ubuntu 24.04 LTS | Supported | Supported through May 2029 | +| `scalingo-26` | Ubuntu 26.04 LTS | Supported and latest | Supported through May 2031 | + +The stack influences: + +- operating-system libraries available to native dependencies; +- compiler and toolchain compatibility during source builds; +- compatibility of prebuilt native binaries; +- the build cache signature. + +The buildpack cache signature includes the stack. When the application moves between `scalingo-22`, `scalingo-24`, and `scalingo-26`, the normal build cache is not restored as compatible. Custom paths listed in `cacheDirectories` still require care because they can contain generated files the buildpack cannot validate. + +A stack change only applies after redeployment. Test migrations in staging or a Review App before changing a production application. + +## Package-manager selection + +The committed lockfile selects the active package manager. + +| File | Selected package manager | +| --- | --- | +| `package-lock.json` | npm | +| `npm-shrinkwrap.json` | npm | +| `yarn.lock` | Yarn | +| `pnpm-lock.yaml` | pnpm | +| No lockfile | npm | + +{% warning %} +The buildpack fails when it finds lockfiles for multiple package managers. It does not apply a hidden precedence rule. Remove unused lockfiles, commit the change, and redeploy. +{% endwarning %} + +The `packageManager` field can request a Yarn or pnpm version, but the lockfile still selects which manager runs. + +## Build lifecycle + +The default lifecycle is: + +### 1. Create the build environment + +The buildpack exports configuration variables supplied by Scalingo, applies Node.js defaults, creates runtime profile files, and adds buildpack-managed binaries to `PATH`. + +Important defaults include: + +- `NODE_ENV=production`, unless already defined; +- `NODE_MODULES_CACHE=true`; +- `NODE_VERBOSE=false`; +- `NPM_CONFIG_LOGLEVEL=error`; +- `NODE_OPTIONS=--max_old_space_size=2560`, when `NODE_OPTIONS` is absent. + +### 2. Install Node.js and package-manager binaries + +The buildpack reads `engines.node`, resolves an available version, downloads it, verifies its checksum, and installs it under the application’s `.scalingo` directory. + +npm is available with Node.js. Yarn or pnpm is installed when the selected lockfile requires it. See the manager-specific pages for version selection. + +### 3. Restore a compatible cache + +The buildpack checks a cache signature before restoring cached content. The default cached content depends on the package manager and installation mode: + +- npm with `npm ci`: npm download cache; +- npm install or rebuild path: `node_modules`; +- Yarn: Yarn cache, with additional handling for Berry and zero-install projects; +- pnpm: pnpm store; +- custom paths: values from `cacheDirectories` or `cache_directories`. + +A cache is an optimization, not the source of dependency truth. Frozen, immutable, or clean installation modes still validate the lockfile. + +### 4. Run `scalingo-prebuild` + +When present, `scalingo-prebuild` runs before dependency installation. + +```json +{ + "scripts": { + "scalingo-prebuild": "node scripts/prepare-build-environment.js" + } +} +``` + +Use this hook only for work that must happen before the package manager installs dependencies. + +### 5. Install dependencies + +By default, development dependencies are installed so that compilers, bundlers, linters used by build scripts, and framework CLIs are available during the build. + +The exact command depends on the manager: + +| Manager | Typical build installation | +| --- | --- | +| npm with a supported lockfile and npm 6+ | `npm ci` | +| npm fallback | `npm install` | +| Yarn Classic | `yarn install --frozen-lockfile` with buildpack options | +| Yarn Berry | `yarn install --immutable` | +| pnpm | `pnpm install --prod=false --frozen-lockfile` | + +Package-manager lifecycle scripts such as `preinstall`, `install`, `postinstall`, and `prepare` run as part of the normal package-manager command. They are not separate Scalingo hooks. + +### 6. Run the application build script + +The buildpack applies this precedence: + +1. If `scalingo-postbuild` exists, run it. +2. Otherwise, if `build` exists, run it. +3. If both exist, only `scalingo-postbuild` runs. + +```json +{ + "scripts": { + "build": "vite build", + "scalingo-postbuild": "vite build --mode scalingo" + } +} +``` + +`NODE_BUILD_FLAGS` is appended only to the standard `build` script. It is not forwarded to the Scalingo-specific hooks. + +### 7. Save the cache and prune development dependencies + +After the build, the buildpack saves cache content and prepares production dependencies. The exact cache/prune ordering differs by package manager so that useful cache data is preserved. + +When `NODE_ENV=production`, development dependencies are normally removed from the runtime image. Manager-specific controls can skip pruning, but a package required at application startup should normally be declared in `dependencies`, not `devDependencies`. + +### 8. Run `scalingo-cleanup` + +When defined, `scalingo-cleanup` runs after dependency pruning and framework-specific build work. + +```json +{ + "scripts": { + "scalingo-cleanup": "node scripts/remove-build-only-files.js" + } +} +``` + +Use this hook to remove build-only artifacts that should not remain in the runtime image. Do not remove files required by the start command. + +### 9. Prepare runtime metadata + +The buildpack writes runtime paths and default environment values, installs its metrics integration, and emits default process metadata. + +## Default process type + +For a normal Node.js application, the buildpack emits: + +```text +web: npm start +``` + +The command works with npm, Yarn, or pnpm projects because `npm start` executes the `scripts.start` entry in `package.json` without reinstalling dependencies. + +```json +{ + "scripts": { + "start": "node server.js" + } +} +``` + +If a root `Procfile` defines `web`, the platform uses the explicit process declaration. + +```text +web: node server.js +worker: node worker.js +``` + +A web process must listen on `PORT`. Binding only to a fixed local port or only to `127.0.0.1` can cause a boot timeout. + +## Runtime environment + +The runtime `PATH` includes: + +- the buildpack-installed Node.js binary; +- the buildpack-installed Yarn binary, when present; +- `$HOME/bin`; +- the application’s `node_modules/.bin`. + +This means locally installed command-line packages can be used in scripts without being installed globally. + +The buildpack also sets or defaults: + +- `NODE_HOME`; +- `NODE_ENV=production`; +- `NODE_EXTRA_CA_CERTS` to the Scalingo database CA bundle; +- `NODE_OPTIONS` to a 2560 MB old-space limit when the user did not define it. + +## Build-time and runtime dependencies + +| Dependency type | Available during build | Expected at runtime | +| --- | :---: | :---: | +| `dependencies` | Yes | Yes | +| `devDependencies` | Yes by default | No after production pruning | +| `optionalDependencies` | According to package-manager behavior | If successfully installed and not pruned | +| Native dependencies | Built or downloaded during install | Must match the Scalingo runtime stack | + +If the application crashes with `module not found`, `ng: not found`, `nest: not found`, or a similar error after a successful build, check whether a runtime requirement was placed in `devDependencies`. + +## Files that should not be committed + +Do not commit `node_modules`. Locally compiled native modules may be incompatible with the Scalingo Linux stack, and committed dependencies make cache and installation behavior harder to predict. + +```text +node_modules/ +``` + +Commit the lockfile instead. + +## Next steps + +- [Customize Node.js Builds]({% post_url languages/nodejs/2000-01-01-customizing %}) +- [Use npm]({% post_url languages/nodejs/2000-01-01-npm %}) +- [Use Yarn]({% post_url languages/nodejs/2000-01-01-yarn %}) +- [Use pnpm]({% post_url languages/nodejs/2000-01-01-pnpm %}) +- [Troubleshoot Node.js Deployments]({% post_url languages/nodejs/2000-01-01-troubleshooting %}) diff --git a/src/_posts/languages/nodejs/2000-01-01-deployment-errors.md b/src/_posts/languages/nodejs/2000-01-01-deployment-errors.md deleted file mode 100644 index b16ba8cf7..000000000 --- a/src/_posts/languages/nodejs/2000-01-01-deployment-errors.md +++ /dev/null @@ -1,110 +0,0 @@ ---- -title: Node.js Common Deployment Errors -nav: Deployment Errors -modified_at: 2025-01-27 00:00:00 -tags: nodejs -index: 3 ---- - -You may experience an error in your Node.js application that many customers -faced when first deploying such application on Scalingo. Here is a list of the -most common error messages. - -## devDependencies Also Contain Some Dependencies Required at Startup or Runtime {#dep} - -In case the app fails to start, or crashes at runtime, due to some missing dependencies or -libraries, it may be because some of the dependencies required -during startup or at runtime are declared as `devDependencies`. - -In such case, you may face error messages such as `ng: not found` or `nest: not found`. - -By default, Scalingo deployments prune the dependencies from the `devDependencies` -section of the `package.json` file. In such situation, you have a couple of solutions: - -- Move the `devDependencies` needed for runtime into the `dependencies` - section of the `package.json` file: if the dependencies are required during startup - or at runtime, they are actual dependencies, not development dependencies. - -- Use Yarn 2+ and [skip pruning dependencies]({% post_url languages/nodejs/2000-01-01-start %}#devdependencies-installation). - - ```bash - $ scalingo --app my-app env-set YARN2_SKIP_PRUNING=true - ``` - -## Boot Timeout {#timeout} - -You may see the following log lines at the end of your application deployment -logs: - -```text -[...] - Build complete, shipping your container... - Waiting for your application to boot... - ! Error deploying the application - ! → Timeout: my-app took more than 60 seconds to boot - ! Application Logs: https://dashboard.scalingo.com/apps/my-app/logs - ! Documentation: https://doc.scalingo.com/deployment/start-error#timeout - -To ssh.osc-fr1.scalingo.com:my-app.git - ! [remote rejected] master -> master (pre-receive hook declined) -error: failed to push some refs to 'ssh.osc-fr1.scalingo.com:my-app.git' -``` - -Most of the time, this timeout occurs when your application does not bind the -port declared by the platform in the environment variable `PORT`. You can see -how to do that in this [Express example]({% post_url -languages/nodejs/2000-01-01-tutorial %}#write-a-base-server-file). - -Here is a short excerpt of this example: - -```js -var express = require('express') -var app = express() - -var server = app.listen(process.env.PORT || 3000, function () { - var host = server.address().address - var port = server.address().port - console.log('App listening at https://%s:%s', host, port) -}) -``` - -If you face a boot timeout error and use the Next.js framework, please refer to [this specific page]({% post_url languages/nodejs/2000-01-01-start %}#nextjs). - - -## Host key verification failed - -``` -Installing node modules -npm ERR! Error while executing: -npm ERR! /usr/bin/git ls-remote -h -t ssh://git@github.com/scalingo/scalingo.js.git -npm ERR! -npm ERR! Host key verification failed. -npm ERR! fatal: Could not read from remote repository. -npm ERR! -npm ERR! Please make sure you have the correct access rights -npm ERR! and the repository exists. -npm ERR! -npm ERR! exited with error code: 128 ------> Build failed -``` - -This issue happens when in your package.json you're using a git repository instead of a npm package. If you are doing that, you can only use the `https` format and not the `ssh` one. - -These requirements correctly resolve to HTTPS URLs: - -```json -"scalingo": "https://git@github.com/scalingo/scalingo.js.git" -"scalingo": "git+https://git@github.com/scalingo/scalingo.js.git" -``` - -{% warning %} -Do no forget the `git@` part in front of the hostname. -{% endwarning %} - -These requirements incorrectly resolve to SSH URLs: -```json -"scalingo": "github:scalingo/scalingo.js" -"scalingo": "https://github.com/scalingo/scalingo.js.git" -"scalingo": "git+https://github.com/scalingo/scalingo.js.git" -"scalingo": "git@github.com:Scalingo/scalingo.js.git" -``` diff --git a/src/_posts/languages/nodejs/2000-01-01-extensions.md b/src/_posts/languages/nodejs/2000-01-01-extensions.md new file mode 100644 index 000000000..992e9e941 --- /dev/null +++ b/src/_posts/languages/nodejs/2000-01-01-extensions.md @@ -0,0 +1,249 @@ +--- +title: Manage Native Modules and System Dependencies +nav: Native Modules +modified_at: 2026-08-06 00:00:00 +tags: nodejs native-modules dependencies +index: 10 +--- + +Some Node.js packages contain native code or depend on operating-system libraries. Examples include database drivers, image-processing libraries, cryptography packages, browser automation tools, and packages built with `node-gyp`. + +The installed artifact must match: + +- the Node.js version and application binary interface (ABI); +- the Scalingo Linux stack; +- the container CPU architecture; +- required compiler and system libraries. + +## Scalingo stack compatibility + +A Scalingo stack is the Ubuntu base image used while compiling dependencies and while running the resulting application. + +Each listed stack uses an Ubuntu long-term support (LTS) release. + +| Stack | Base operating system | Status | Lifecycle | +| --- | --- | --- | --- | +| `scalingo-22` | Ubuntu 22.04 LTS | Deprecated | Discontinued on 1 June 2027 | +| `scalingo-24` | Ubuntu 24.04 LTS | Supported | Supported through May 2029 | +| `scalingo-26` | Ubuntu 26.04 LTS | Supported and latest | Supported through May 2031 | + +The stack name does not select Node.js. For example, Node.js 24 can run on each of these stacks when it is available in the buildpack inventory. + +The stack can change the versions of `glibc`, OpenSSL, compiler runtimes, image libraries, browser dependencies, and other shared libraries. A native package that works on one stack can therefore require a newer package release, a fresh compilation, or an additional operating-system package on another. + +Inspect the current stack: + +```bash +scalingo --app my-app apps-info +``` + +Inspect a stack image locally when reproducing an operating-system-level problem: + +```bash +docker pull scalingo/scalingo-26:latest +docker run --rm -it scalingo/scalingo-26:latest bash +``` + +{% warning %} +Do not copy compiled modules between `scalingo-22`, `scalingo-24`, and `scalingo-26`. Redeploy and reinstall dependencies after a stack change. +{% endwarning %} + +Before migration, test the application on the target stack and verify every dependency that compiles code, downloads a platform binary, launches a browser, or links to a shared library. + +## Prefer maintained prebuilt binaries + +Many native packages publish prebuilt binaries for common Node.js and Linux combinations. During installation, the package can download a matching binary instead of compiling from source. + +Prefer packages that: + +- publish binaries for supported Node.js LTS lines; +- verify downloaded artifacts; +- document supported operating systems and architectures; +- release updates promptly when Node.js changes its ABI; +- fall back to source compilation with clear errors. + +A package upgrade can be required after changing Node.js major versions, even when the JavaScript API has not changed. + +## Do not commit `node_modules` + +Never use a locally generated `node_modules` directory as the deployment artifact. + +```text +node_modules/ +``` + +A native module compiled on macOS, Windows, another Linux distribution, or another CPU architecture can fail to load on Scalingo. + +The npm compatibility path attempts `npm rebuild` when committed modules are detected, then installs missing dependencies. This does not guarantee that every committed artifact becomes valid, and it does not make committed modules a supported best practice. + +Commit `package.json` and the package-manager lockfile instead. + +## Source compilation during dependency installation + +npm, Yarn, and pnpm run package lifecycle scripts during dependency installation. A package can use those scripts to invoke `node-gyp`, CMake, Rust, or another build system. + +The availability of compiler tools, Python, and headers depends on the active Scalingo stack and build environment. + +{% warning %} +Do not publish a fixed list of guaranteed compilers or Python versions until Engineering confirms it for every supported stack. When a package requires a specific toolchain, test it on each supported stack and document the requirement with the sample application. +{% endwarning %} + +## Add operating-system packages + +When a dependency requires an additional shared library or executable, add the [Advanced Package Tool (APT) Buildpack]({% post_url platform/deployment/buildpacks/2000-01-01-apt %}) before the Node.js buildpack in a multi-buildpack configuration. + +A typical application contains an `Aptfile` at the repository root: + +```text + + +``` + +The exact package names depend on the Scalingo stack. Verify them against the stack’s package repository rather than copying names from another provider or Linux release. + +After changing system dependencies: + +1. clear or disable the deployment cache for one build; +2. rebuild native dependencies; +3. run the application’s startup and smoke tests; +4. verify that required shared libraries exist in the runtime image. + +## Diagnose a native compilation failure + +Look for the first compiler or package-manager error above the final buildpack summary. Common causes include: + +- no prebuilt binary exists for the selected Node.js version; +- the package does not support the current CPU architecture or operating system; +- a required header or development library is missing; +- Python or a compiler is not available in the expected version; +- the package version is too old for the Node.js ABI; +- the build runs out of memory or disk space; +- an install script is blocked by package-manager policy. + +A useful diagnostic sequence is: + +```bash +rm -rf node_modules +npm ci +# or: yarn install --immutable +# or: pnpm install --frozen-lockfile +``` + +Then compare the local Node.js version with `engines.node` and the version printed in the Scalingo build log. + +## Rebuild after a Node.js upgrade + +When moving to another Node.js major: + +1. update `engines.node`; +2. remove local `node_modules`; +3. reinstall dependencies; +4. update packages that do not support the new Node.js version; +5. commit the refreshed lockfile when it changes; +6. deploy with a clean cache if an old native artifact appears to be reused; +7. test every code path that loads the native module. + +An error such as `NODE_MODULE_VERSION` mismatch usually means a binary was built for another Node.js ABI. + +## Use Puppeteer or another headless browser + +Browser automation packages often require a browser binary and several operating-system libraries. Treat them as a system-dependency deployment, not as a Node.js framework feature. + +Recommended approach: + +1. choose whether the project downloads its own compatible browser or uses a stack-installed browser; +2. add required system packages through the APT Buildpack; +3. configure the executable path through an environment variable or package configuration; +4. test startup, page rendering, fonts, Transport Layer Security (TLS), and sandbox behavior on the target stack; +5. monitor image size and memory. + +Example application code: + +```js +const browser = await puppeteer.launch({ + executablePath: process.env.PUPPETEER_EXECUTABLE_PATH, + headless: true, +}); +``` + +Avoid copying an old list of distribution packages into this page. Browser dependencies change frequently and differ by stack. + +### Sandbox configuration + +Some container recipes use `--no-sandbox` or `--disable-setuid-sandbox`. These flags reduce browser isolation. + +{% warning %} +Document sandbox-disabling flags only when Scalingo Security and Engineering have validated the threat model and there is no supported sandboxed configuration. Do not present them as harmless defaults. +{% endwarning %} + +## Packages with runtime shared libraries + +A module can compile successfully but fail at runtime when a shared library is absent from the final image. + +Typical symptoms include: + +```text +error while loading shared libraries +``` + +or: + +```text +Cannot open shared object file +``` + +Confirm that the system package is installed by a buildpack whose files remain available at runtime, not only in a transient build step. + +## TypeScript and JavaScript build tools + +TypeScript, Vite, webpack, esbuild, the Speedy Web Compiler (SWC), and similar tools are not native extensions by definition, but some of their packages can include native binaries. + +Keep build-only tools in `devDependencies`. The buildpack installs them before the build script and prunes them afterward. A compiler needed by the runtime start command belongs in `dependencies`, or preferably the application should start from compiled output. + +```json +{ + "scripts": { + "build": "tsc -p tsconfig.build.json", + "start": "node dist/server.js" + }, + "devDependencies": { + "typescript": "" + } +} +``` + +## Cache considerations + +Native artifacts can become invalid when the Node.js version, package-manager behavior, stack, or system libraries change. + +The buildpack invalidates its normal cache for several version and stack changes, but custom caches can preserve files that the buildpack cannot reason about. Do not place compiled native outputs in `cacheDirectories` unless the project validates their compatibility. + +Temporarily disable cache during diagnosis: + +```bash +scalingo --app my-app env-set NODE_MODULES_CACHE=false +``` + +## Information to include in a support request + +Provide: + +- application and region; +- Scalingo stack; +- requested and resolved Node.js versions; +- package manager and version; +- package name and version; +- the first relevant compiler or loader error; +- whether the failure occurs during build or runtime; +- the application’s APT or multi-buildpack configuration; +- whether a clean-cache build changes the result. + +Remove registry tokens, private repository credentials, and other secrets from logs before sharing them. + +## Related documentation + +- [Select a Node.js Version]({% post_url languages/nodejs/2000-01-01-selecting-a-version %}) +- [Customize Node.js Builds]({% post_url languages/nodejs/2000-01-01-customizing %}) +- [APT Buildpack]({% post_url platform/deployment/buildpacks/2000-01-01-apt %}) +- [Multi Buildpacks]({% post_url platform/deployment/buildpacks/2000-01-01-multi %}) +- [Troubleshoot Node.js Deployments]({% post_url languages/nodejs/2000-01-01-troubleshooting %}) diff --git a/src/_posts/languages/nodejs/2000-01-01-managing-web-concurrency.md b/src/_posts/languages/nodejs/2000-01-01-managing-web-concurrency.md new file mode 100644 index 000000000..ed07fbb83 --- /dev/null +++ b/src/_posts/languages/nodejs/2000-01-01-managing-web-concurrency.md @@ -0,0 +1,178 @@ +--- +title: Manage Node.js Web Concurrency +nav: Web Concurrency +modified_at: 2026-08-06 00:00:00 +tags: nodejs scaling concurrency +index: 6 +--- + +Node.js concurrency can be increased in two different places: + +- **Across containers:** run more Scalingo `web` containers. The router distributes requests between them. +- **Inside a container:** run several Node.js worker processes or threads in one container. + +Start with one Node.js process per container unless measurements show that additional in-container workers improve throughput without causing memory pressure. + +{% note %} +`scalingo-22`, `scalingo-24`, and `scalingo-26` identify Ubuntu base images. They do not identify the container size or available memory. Memory and CPU capacity come from the selected container type. Record the active stack when benchmarking because changes in Node.js, native libraries, or the operating-system image can affect measured performance. +{% endnote %} + +## Horizontal scaling across containers + +Horizontal scaling adds independent application instances. It improves capacity and resilience when the application is stateless or stores shared state in external services. + +View the current formation: + +```bash +scalingo --app my-app scale +``` + +Run three `web` containers using the `M` size: + +```bash +scalingo --app my-app scale web:3:M +``` + +The platform routes HTTP traffic to the available `web` containers. Sessions, uploaded files, queues, and locks must therefore not depend on the local filesystem or memory of a single container. + +See [Scaling Your Application]({% post_url platform/app/scaling/2000-01-01-scaling %}) for vertical scaling, horizontal scaling, limits, and autoscaling. + +## Concurrency inside one container + +A single Node.js process can handle many concurrent I/O-bound requests through the event loop. It does not automatically make CPU-bound JavaScript run in parallel. + +Use several workers only when: + +- the container has CPU capacity that one process cannot use effectively; +- the application or process manager has a tested worker model; +- memory remains below the container limit under peak load; +- graceful shutdown and health behavior are verified for every worker. + +Common approaches include: + +- the Node.js `cluster` module; +- `worker_threads` for specific CPU-intensive tasks; +- a process manager configured to start a fixed number of workers; +- separate Scalingo process types for background or CPU-heavy work. + +Avoid using a development server as a production worker manager. + +## Use `WEB_CONCURRENCY` explicitly + +`WEB_CONCURRENCY` is a convention, not a Node.js built-in setting. It has an effect only when the application or process manager reads it. + +Example using `cluster`: + +```js +const cluster = require("node:cluster"); +const os = require("node:os"); + +const requestedWorkers = Number.parseInt( + process.env.WEB_CONCURRENCY ?? "1", + 10, +); +const workers = Number.isFinite(requestedWorkers) + ? Math.max(1, requestedWorkers) + : 1; + +if (cluster.isPrimary) { + console.log(`Starting ${workers} workers on ${os.availableParallelism()} CPUs`); + + for (let index = 0; index < workers; index += 1) { + cluster.fork(); + } + + cluster.on("exit", () => cluster.fork()); +} else { + require("./server"); +} +``` + +Configure the value explicitly: + +```bash +scalingo --app my-app env-set WEB_CONCURRENCY=2 +``` + +{% warning %} +Do not publish or rely on an automatically calculated `WEB_CONCURRENCY` value until Scalingo Engineering confirms which active component sets it, how container memory is detected, and which tests guarantee the behavior. +{% endwarning %} + +## Estimate memory per worker + +Every Node.js process has its own JavaScript heap, native allocations, buffers, module state, and connection pools. Two workers can use substantially more than twice the idle memory of one process after traffic and caches are loaded. + +Measure memory with one worker under representative load, then leave headroom for: + +- native modules and shared libraries; +- HTTP and database buffers; +- package-manager or shell wrapper processes; +- temporary spikes during garbage collection; +- operating-system overhead. + +The buildpack supplies a default `NODE_OPTIONS` old-space value when the variable is absent. If you set your own limit, remember that it applies to each Node.js process: + +```bash +scalingo --app my-app env-set \ + WEB_CONCURRENCY=2 \ + NODE_OPTIONS="--max-old-space-size=768" +``` + +This example allows up to roughly 768 MB of V8 old space per process; it does not cap total process memory at 768 MB. + +## Separate web and background workloads + +Long-running jobs should not block HTTP request handling. Define separate process types: + +```text +web: node server.js +worker: node worker.js +``` + +Scale them independently: + +```bash +scalingo --app my-app scale web:2:M worker:1:L +``` + +This makes it possible to give web and worker processes different container sizes and scaling policies. + +## Choose a scaling strategy + +| Symptom | First action | +| --- | --- | +| One container is near its memory limit even at low traffic | Use a larger container or reduce per-process memory | +| CPU rises with request volume but each container remains healthy | Add web containers | +| One Node.js process cannot use available CPU and memory is comfortable | Test a small fixed worker count | +| Long jobs cause request latency | Move the jobs to a worker process type | +| Traffic varies predictably or rapidly | Evaluate the Scalingo Autoscaler | +| One request or job needs more memory than the container provides | Scale vertically; more containers will not repair a single oversized workload | + +## Validate changes + +Change one variable at a time and observe: + +- request rate per container; +- response latency; +- CPU saturation; +- memory high-water mark; +- restart and out-of-memory events; +- database connection count; +- event-loop delay; +- graceful shutdown during deploys and scaling events. + +A safe rollout is: + +1. Record baseline metrics. +2. Change container count or worker count, not both. +3. Apply representative load. +4. Compare throughput, latency, and memory. +5. Roll back when the change reduces stability or cost efficiency. + +## Related documentation + +- [Scaling Your Application]({% post_url platform/app/scaling/2000-01-01-scaling %}) +- [Optimizing Application Workloads]({% post_url platform/app/scaling/2000-01-01-optimizing-application-workloads %}) +- [Procfile]({% post_url platform/app/2000-01-01-procfile %}) +- [Customize Node.js Builds]({% post_url languages/nodejs/2000-01-01-customizing %}) +- [Troubleshoot Node.js Deployments]({% post_url languages/nodejs/2000-01-01-troubleshooting %}) diff --git a/src/_posts/languages/nodejs/2000-01-01-nextjs-standalone.md b/src/_posts/languages/nodejs/2000-01-01-nextjs-standalone.md deleted file mode 100644 index 06b90f4ab..000000000 --- a/src/_posts/languages/nodejs/2000-01-01-nextjs-standalone.md +++ /dev/null @@ -1,126 +0,0 @@ ---- -title: Next.js in standalone mode -modified_at: 2024-07-26 11:26:57 -tags: nodejs nextjs standalone -index: 5 ---- -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. - -Standalone mode can significantly reduce your image size: -* At the time of writing a fresh Next.js build image is **547MB**, -* A standalone image is **200MB**. - -### Enable standalone mode: - -#### 1. Add the following to your `next.config.js` file: -```js -module.exports = { - output: 'standalone', -} -``` -or in `next.config.mjs`: -```js -const nextConfig = { - output: 'standalone', -}; -``` - -#### 2. Add `node_modules` to the `.slugignore` file - -This will prevent the `node_modules` directory from being included in the image. - - -#### 3. Set start script in the package.json - -Start the server using Node.js. - -```json -{ - "scripts": { - "start": "node .next/standalone/server.js --hostname 0.0.0.0" - // others scripts - } -} -``` - -{% warning %} - Ensure that the `--hostname` is set to 0.0.0.0 to avoid the [boot timeout issue]({% post_url languages/nodejs/2000-01-01-start %}#nextjs). -{% endwarning %} - -{% note %} -Reason: after build node_modules will have been removed, so the original command `next start` will error: `"sh: 1: next: not found"` -{% endnote %} - -#### 4. Finally, copy assets - -As indicated in the [Next.js documentation](https://nextjs.org/docs/advanced-features/output-file), it doesn't copy assets, so it's up to us to copy them. -To accomplish this, we can create a script that runs at build time to copy the assets to the correct location. - -Create a file called `copy-assets.js` in the root of your project with the following content: -```js -const fs = require('fs').promises; -const path = require('path'); - -const staticSrcPath = path.join(__dirname, '.next/static'); -const staticDestPath = path.join(__dirname, '.next/standalone/.next/static'); - -const publicSrcPath = path.join(__dirname, 'public'); -const publicDestPath = path.join(__dirname, '.next/standalone/public'); - -function copyAssets(src, dest) { - return fs.mkdir(dest, { recursive: true }) - .then(() => fs.readdir(src, { withFileTypes: true })) - .then(items => { - const promises = items.map(item => { - const srcPath = path.join(src, item.name); - const destPath = path.join(dest, item.name); - - if (item.isDirectory()) { - return copyAssets(srcPath, destPath); - } else { - return fs.copyFile(srcPath, destPath); - } - }); - return Promise.all(promises); - }) - .catch(err => { - console.error(`Error: ${err}`); - throw err; - }); -} - -const greenTick = `\x1b[32m\u2713\x1b[0m`; -const redCross = `\x1b[31m\u274C\x1b[0m`; -copyAssets(staticSrcPath, staticDestPath) - .then(() => copyAssets(publicSrcPath, publicDestPath)) - .then(() => console.log(`${greenTick} Assets copied successfully`)) - .catch(err => console.error(`${redCross} Failed to copy assets: ${err}`)); -``` - -Update package.json to run the script at build time: -```json -{ - "scripts": { - "build": "next build && node copy-assets.js", - // other scripts - } -} -``` - -Your full `scripts` property of your `package.json` should now look like this: -```json -{ - // other properties - "scripts": { - "dev": "next dev", - "build": "next build && node copy-assets.js", - "start": "node .next/standalone/server.js", - "lint": "next lint" - }, - // other properties -} -``` - -### Sample application - -You can find a sample application here: [https://github.com/Scalingo/sample-nextjs-standalone](https://github.com/Scalingo/sample-nextjs-standalone). diff --git a/src/_posts/languages/nodejs/2000-01-01-npm.md b/src/_posts/languages/nodejs/2000-01-01-npm.md new file mode 100644 index 000000000..f757775d2 --- /dev/null +++ b/src/_posts/languages/nodejs/2000-01-01-npm.md @@ -0,0 +1,258 @@ +--- +title: Use npm on Scalingo +nav: npm +modified_at: 2026-08-06 00:00:00 +tags: nodejs npm +index: 7 +--- + +npm is the default package manager for Node.js applications on Scalingo. It is selected when the deployed source contains `package-lock.json` or `npm-shrinkwrap.json`, or when no supported package-manager lockfile is present. + +A lockfile is strongly recommended. + +## Select npm + +Commit one npm lockfile at the repository root: + +```text +package.json +package-lock.json +``` + +The build fails if `yarn.lock` or `pnpm-lock.yaml` is committed alongside an npm lockfile. It also fails when `npm-shrinkwrap.json` conflicts with another modern lockfile. + +Generate or refresh `package-lock.json` locally: + +```bash +npm install +``` + +Commit both files: + +```bash +git add package.json package-lock.json +git commit -m "Update npm dependencies" +``` + +## Select an npm version + +Node.js includes a bundled npm version. Request another npm version with `engines.npm`: + +```json +{ + "engines": { + "node": "24.x", + "npm": "11.x" + } +} +``` + +Node.js and npm versions are separate. Test the selected combination locally and in continuous integration (CI) before deploying. + +## Installation command + +With an npm lockfile and npm major version 6 or newer, the buildpack normally uses: + +```bash +npm ci +``` + +Otherwise it uses: + +```bash +npm install +``` + +The install command also receives buildpack configuration for production dependency handling and the root `.npmrc` file. + +Set `USE_NPM_INSTALL=true` only when the application has an identified requirement for `npm install`: + +```bash +scalingo --app my-app env-set USE_NPM_INSTALL=true +``` + +Remove the variable to return to automatic selection: + +```bash +scalingo --app my-app env-unset USE_NPM_INSTALL +``` + +## Lockfile behavior + +`npm ci` requires `package.json` and the lockfile to agree. When they differ, the build fails rather than modifying the lockfile during deployment. + +Repair the mismatch locally: + +```bash +npm install +npm test +git add package.json package-lock.json +git commit -m "Synchronize npm lockfile" +``` + +Do not generate a lockfile with one package manager and deploy with another. + +## Development and production dependencies + +By default, npm development dependencies are installed during the build. This allows tools such as TypeScript, Vite, webpack, or framework CLIs to run from the `build` script. + +After the application build, development dependencies are normally pruned from a production runtime. + +Place a package in `dependencies` when the start command or runtime code needs it: + +```bash +npm install express +``` + +Place a build-only or test-only package in `devDependencies`: + +```bash +npm install --save-dev typescript +``` + +{% warning %} +Setting `NPM_CONFIG_PRODUCTION=true` prevents development dependencies from being installed. A build script that uses a development dependency can then fail with `command not found` or `module not found`. +{% endwarning %} + +## Configure npm + +Commit a root `.npmrc` for non-secret npm settings: + +```ini +fund=false +audit=false +registry=https://registry.npmjs.org/ +``` + +npm also reads environment variables beginning with `NPM_CONFIG_`. + +Example: + +```bash +scalingo --app my-app env-set NPM_CONFIG_LOGLEVEL=info +``` + +## Use a private npm registry + +Create a read-only or least-privilege token in the registry, then store it as a Scalingo environment variable: + +```bash +scalingo --app my-app env-set NPM_TOKEN=replace-with-token +``` + +Reference the variable from `.npmrc`: + +```ini +//registry.npmjs.org/:_authToken=${NPM_TOKEN} +always-auth=true +``` + +Commit `.npmrc`, but never commit the expanded token. + +For a scoped registry: + +```ini +@my-company:registry=https://registry.example.com/ +//registry.example.com/:_authToken=${NPM_TOKEN} +``` + +Confirm that build logs do not print credentials. Rotate the token immediately if it appears in Git history or logs. + +## Install a dependency from Git + +Prefer an HTTPS dependency URL when public access is sufficient: + +```json +{ + "dependencies": { + "example-package": "git+https://github.com/example/example-package.git#v1.2.3" + } +} +``` + +For private SSH repositories, configure the [SSH Private Key Buildpack]({% post_url platform/deployment/buildpacks/2000-01-01-ssh-key %}) in the multi-buildpack chain. Pin a tag or commit rather than a mutable branch when reproducibility matters. + +## npm workspaces + +npm workspace installation follows npm’s normal behavior because the buildpack runs npm from the repository root. + +Example: + +```json +{ + "private": true, + "workspaces": [ + "packages/*" + ], + "scripts": { + "build": "npm run build --workspaces", + "start": "npm run start --workspace @my-company/web" + } +} +``` + +The deployed root must still contain the root `package.json` and lockfile. The Node.js buildpack does not automatically select a nested workspace as the application root. + +## Stack considerations + +npm selection and lockfile behavior are the same on `scalingo-22`, `scalingo-24`, and `scalingo-26`. The stack becomes relevant when dependency installation runs native lifecycle scripts or downloads an operating-system-specific binary. + +After a stack migration: + +- redeploy so dependencies are installed for the new Ubuntu base; +- do not reuse committed `node_modules`; +- verify packages with native bindings or shared-library requirements; +- review custom cache paths if a clean build behaves differently. + +`scalingo-22` is deprecated. Prefer `scalingo-24` or `scalingo-26`, and use `scalingo-26` for new compatibility testing. + +## Caching + +When the buildpack uses `npm ci`, it normally caches npm’s download cache rather than restoring `node_modules`. With the install or rebuild path, it can cache `node_modules`. + +Disable cache temporarily for diagnosis: + +```bash +scalingo --app my-app env-set NODE_MODULES_CACHE=false +``` + +A lockfile mismatch is not repaired by clearing the cache; update and commit the lockfile. + +## Do not commit `node_modules` + +Committed dependencies can contain binaries compiled for a developer workstation rather than the Scalingo Linux stack. + +```text +node_modules/ +``` + +If committed modules are detected in the npm path, the buildpack attempts `npm rebuild` and then installs missing dependencies. This compatibility path does not make committed modules a recommended deployment method. + +## Common npm errors + +### `npm ci` reports that the lockfile is out of sync + +Run `npm install`, test, and commit the resulting lockfile. + +### `ERESOLVE` + +npm could not resolve peer dependencies. Review the packages named in the error, update incompatible dependencies, and avoid using a force flag as a permanent fix without understanding the resulting graph. + +### `E404` + +Check the package name, version, registry URL, token access, and scope configuration. + +### `EBADPLATFORM` + +A dependency or prebuilt native binary does not support the Scalingo operating system or architecture. Update the dependency or see [Manage Native Modules and System Dependencies]({% post_url languages/nodejs/2000-01-01-extensions %}). + +### A runtime package is missing + +Move it from `devDependencies` to `dependencies`, reinstall, commit the lockfile, and redeploy. + +## Related documentation + +- [Default Node.js Build and Runtime Behavior]({% post_url languages/nodejs/2000-01-01-default-behavior %}) +- [Customize Node.js Builds]({% post_url languages/nodejs/2000-01-01-customizing %}) +- [Manage Native Modules and System Dependencies]({% post_url languages/nodejs/2000-01-01-extensions %}) +- [Troubleshoot Node.js Deployments]({% post_url languages/nodejs/2000-01-01-troubleshooting %}) diff --git a/src/_posts/languages/nodejs/2000-01-01-pnpm.md b/src/_posts/languages/nodejs/2000-01-01-pnpm.md new file mode 100644 index 000000000..7d117dc1f --- /dev/null +++ b/src/_posts/languages/nodejs/2000-01-01-pnpm.md @@ -0,0 +1,234 @@ +--- +title: Use pnpm on Scalingo +nav: pnpm +modified_at: 2026-08-06 00:00:00 +tags: nodejs pnpm +index: 9 +--- + +pnpm is selected when `pnpm-lock.yaml` is committed at the root of the deployed source. The Node.js buildpack installs pnpm, restores its store cache, installs dependencies with a frozen lockfile, runs package scripts through pnpm, and prepares production dependencies for the runtime image. + +## Select pnpm + +Commit: + +```text +package.json +pnpm-lock.yaml +``` + +Remove `package-lock.json`, `npm-shrinkwrap.json`, and `yarn.lock`. The build fails when several package-manager lockfiles are present. + +The `packageManager` field requests a pnpm version but does not select pnpm by itself. The lockfile remains required. + +## Select a pnpm version + +The buildpack applies this order: + +1. `packageManager` in `package.json`; +2. `engines.pnpm`; +3. `pnpm@latest`, with a build warning. + +Prefer an explicit version: + +```json +{ + "engines": { + "node": "24.x" + }, + "packageManager": "pnpm@10.15.0" +} +``` + +When both `packageManager` and `engines.pnpm` are present, `packageManager` takes precedence and the build emits a warning. Remove the duplicate declaration to make the intended version unambiguous. + +{% warning %} +When no pnpm version is declared, the buildpack installs `pnpm@latest`. A new pnpm major can change lockfile or runtime behavior. Pin the same version for local development and continuous integration (CI). +{% endwarning %} + +The audited classic buildpack installs pnpm through npm. It does not rely on a general Corepack execution path. + +## Dependency installation + +The buildpack runs: + +```bash +pnpm install --prod=false --frozen-lockfile +``` + +This provides development dependencies to build scripts and refuses to rewrite `pnpm-lock.yaml` during deployment. + +Repair a lockfile mismatch locally: + +```bash +pnpm install +pnpm test +git add package.json pnpm-lock.yaml +git commit -m "Synchronize pnpm lockfile" +``` + +## Build scripts + +The active package manager runs Scalingo and application scripts. The normal build-script precedence applies: `scalingo-postbuild` replaces `build` when it exists. + +```json +{ + "scripts": { + "scalingo-prebuild": "node scripts/check-env.js", + "build": "pnpm --filter @my-company/web build", + "start": "pnpm --filter @my-company/web start" + } +} +``` + +## Development dependency pruning + +After the build, pnpm dependencies are prepared for production when `NODE_ENV=production`. + +Pruning is skipped when: + +- `NODE_ENV=test`; +- `NODE_ENV` is not `production`; +- `PNPM_SKIP_PRUNING=true`; +- the buildpack detects a workspace or lifecycle-script situation where pruning cannot be performed safely. + +Set the explicit skip only when required: + +```bash +scalingo --app my-app env-set PNPM_SKIP_PRUNING=true +``` + +A runtime package should still be declared in `dependencies` rather than relying on a skipped prune. + +## pnpm workspaces + +The buildpack explicitly recognizes a root `pnpm-workspace.yaml` containing a `packages` declaration. + +```yaml +packages: + - "apps/*" + - "packages/*" +``` + +Example root `package.json`: + +```json +{ + "private": true, + "packageManager": "pnpm@10.15.0", + "scripts": { + "build": "pnpm --filter @my-company/web build", + "start": "pnpm --filter @my-company/web start" + } +} +``` + +The deployed root must contain the root `package.json`, `pnpm-lock.yaml`, and workspace file. The Node.js buildpack does not search for a nested workspace application. + +For production pruning, the buildpack lists workspace projects, removes project-level `node_modules`, and can reinstall production dependencies with a frozen lockfile. When a project contains install-related lifecycle scripts that make this unsafe, the buildpack warns and skips pruning rather than risking an incorrect runtime tree. + +{% note %} +Workspace support is implementation-backed, but Scalingo should maintain a smoke-tested public workspace sample before promising compatibility with every pnpm workspace layout or orchestrator. +{% endnote %} + +## Configure a private registry + +pnpm reads npm-compatible configuration from `.npmrc`. + +Set a token as an environment variable: + +```bash +scalingo --app my-app env-set NPM_TOKEN=replace-with-token +``` + +Commit `.npmrc` with a variable reference: + +```ini +@my-company:registry=https://registry.example.com/ +//registry.example.com/:_authToken=${NPM_TOKEN} +always-auth=true +``` + +Never commit the resolved token. Test registry authentication with the same pnpm version used in `packageManager`. + +## Stack considerations + +pnpm selection and lockfile behavior are the same on `scalingo-22`, `scalingo-24`, and `scalingo-26`. The stack becomes relevant when dependency installation runs native lifecycle scripts or downloads an operating-system-specific binary. + +After a stack migration: + +- redeploy so dependencies are installed for the new Ubuntu base; +- do not reuse committed `node_modules`; +- verify packages with native bindings or shared-library requirements; +- review custom cache paths if a clean build behaves differently. + +`scalingo-22` is deprecated. Prefer `scalingo-24` or `scalingo-26`, and use `scalingo-26` for new compatibility testing. + +## Cache behavior + +The buildpack caches the pnpm store rather than copying pnpm-managed `node_modules` directories between builds. + +Custom `cacheDirectories` can add other reproducible build paths, but custom paths under `node_modules` are skipped when pnpm is active. The pnpm store remains included. + +Disable Node.js build caching temporarily: + +```bash +scalingo --app my-app env-set NODE_MODULES_CACHE=false +``` + +Re-enable it after troubleshooting. + +The visible buildpack cache signature does not include the pnpm version. If a pnpm upgrade produces unexpected cache behavior, clear or disable the deployment cache and report the case to Scalingo. + +## Configure pnpm build output + +`PNPM_INSTALL_REPORTER` accepts: + +- `default`; +- `ndjson`; +- `append-only`; +- `silent`. + +Example: + +```bash +scalingo --app my-app env-set PNPM_INSTALL_REPORTER=append-only +``` + +An unsupported value produces a warning and the build continues with the default reporter. + +## pnpm 11 runtime behavior + +pnpm 11 can verify that dependencies are synchronized before commands run. Its workspace state can contain absolute paths from the temporary build directory, while the runtime application is mounted at a different path. + +To prevent this difference from triggering an automatic non-interactive reinstall and crashing the process, the buildpack defaults the pnpm 11 runtime setting to warning mode when the user has not supplied another value. + +Do not remove or override this behavior without testing application startup in a Scalingo runtime container. + +## Common pnpm errors + +### The frozen lockfile is out of date + +Run `pnpm install` locally and commit `pnpm-lock.yaml`. + +### pnpm cannot be installed + +Confirm that the requested version exists and supports the selected Node.js version. Remove conflicting `packageManager` and `engines.pnpm` entries. + +### Workspace pruning is skipped + +Review the build warning. If install lifecycle scripts exist in workspace packages, verify whether they are needed at prune time. Keeping the skip can increase the runtime image size. + +### The pnpm store is not restored + +Check whether caching is disabled, whether the Node.js or stack signature changed, and whether the pnpm store path was overridden by project configuration. + +### The runtime tries to reinstall dependencies + +Confirm the pnpm major version and the `verify-deps-before-run` setting. Include startup logs and relevant `pnpm_config_*` variables in a support request. + +## Related documentation + +- [Default Node.js Build and Runtime Behavior]({% post_url languages/nodejs/2000-01-01-default-behavior %}) +- [Customize Node.js Builds]({% post_url languages/nodejs/2000-01-01-customizing %}) +- [Troubleshoot Node.js Deployments]({% post_url languages/nodejs/2000-01-01-troubleshooting %}) diff --git a/src/_posts/languages/nodejs/2000-01-01-puppeteer.md b/src/_posts/languages/nodejs/2000-01-01-puppeteer.md deleted file mode 100644 index ec71e3b2a..000000000 --- a/src/_posts/languages/nodejs/2000-01-01-puppeteer.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -title: Install Puppeteer -modified_at: 2026-04-09 00:00:00 -tags: nodejs puppeteer ---- - -Puppeteer is a library to headless Chrome API. In short, most things that you can do manually in the browser can be achieved with a program using Puppeteer. By default, installing Puppeteer on a Scalingo application fails because the X11 library are not included in Scalingo base image. The error message is: - -``` -[Nest] 31 - 10/24/2019, 4:08:50 PM [ExceptionsHandler] Failed to launch chrome! -/app/node_modules/puppeteer/.local-chromium/linux-686378/chrome-linux/chrome: error while loading shared libraries: libX11-xcb.so.1: cannot open shared object file: No such file or directory -``` - -## Install Puppeteer on a Scalingo Application - -To install Puppeteer on a Scalingo application, you need to make use of [the APT buildpack]({% post_url platform/deployment/buildpacks/2000-01-01-apt %}). Such a buildpack should be used as part of a [multi-buildpack]({% post_url platform/deployment/buildpacks/2000-01-01-multi %}). - -```bash -echo 'https://github.com/Scalingo/apt-buildpack' > .buildpacks -echo 'https://github.com/Scalingo/nodejs-buildpack' >> .buildpacks -git add .buildpacks -git commit --message="Add multi-buildpack" -``` - -Depending on your stack, you'll need different system dependencies in the `Aptfile` at the root of your project. - -- For `scalingo-22`: - -``` -libgtk-3-0 libgbm-dev libnotify-dev libnss3 libxss1 libasound2 libxtst6 xauth xvfb -``` - -- For `scalingo-24`: - -``` -libgtk-3-0t64 libgbm-dev libnotify-dev libnss3 libxss1 libasound2t64 libxtst6 xauth xvfb -``` - -- For `scalingo-26`: - -``` -libgtk-3-0t64 libgbm-dev libnotify-dev libnss3 libxss1 libasound2t64 libxtst6 xauth xvfb -``` - -{% note %} -These are minimal dependencies originally documented by [cypress](https://docs.cypress.io/app/get-started/install-cypress#Linux-Prerequisites). A more thorough list of system dependencies is available in the chromium [source repository](https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/debian/dist_package_versions.json;l=150) -{% endnote %} - -{% warning %} -Puppeteer must be run with the option `--no-sandbox` on Scalingo. This option must be added with care. You should only add this option against some code you own. -{% endwarning %} diff --git a/src/_posts/languages/nodejs/2000-01-01-selecting-a-version.md b/src/_posts/languages/nodejs/2000-01-01-selecting-a-version.md new file mode 100644 index 000000000..623a42edf --- /dev/null +++ b/src/_posts/languages/nodejs/2000-01-01-selecting-a-version.md @@ -0,0 +1,191 @@ +--- +title: Select a Node.js Version +nav: Select a Version +modified_at: 2026-08-06 00:00:00 +tags: nodejs versions +index: 2 +--- + +Declare the Node.js version for an application in the `engines.node` field of the root `package.json` file. + +```json +{ + "engines": { + "node": "24.x" + } +} +``` + +When `engines.node` is absent, the buildpack resolves the current recommended long-term support (LTS) release. Declaring a version is still recommended because it makes the runtime policy visible in the repository and reduces unexpected changes when the default LTS line moves. + +## Stack and Node.js version are separate + +The Scalingo stack selects the Ubuntu base image. The `engines.node` field selects Node.js. Do not infer one from the other. + +Each listed stack uses an Ubuntu long-term support (LTS) release. + +| Stack | Base operating system | Status | Lifecycle | +| --- | --- | --- | --- | +| `scalingo-22` | Ubuntu 22.04 LTS | Deprecated | Discontinued on 1 June 2027 | +| `scalingo-24` | Ubuntu 24.04 LTS | Supported | Supported through May 2029 | +| `scalingo-26` | Ubuntu 26.04 LTS | Supported and latest | Supported through May 2031 | + +At the time this draft was written, the Node.js buildpack exposed the same Node.js patch inventory on `scalingo-22`, `scalingo-24`, and `scalingo-26`: + +| Node.js release line | `scalingo-22` (deprecated) | `scalingo-24` | `scalingo-26` | +| --- | ---: | ---: | ---: | +| Node.js 26 | `26.5.1` | `26.5.1` | `26.5.1` | +| Node.js 24 LTS | `24.18.1` | `24.18.1` | `24.18.1` | +| Node.js 22 LTS | `22.23.2` | `22.23.2` | `22.23.2` | + +Changing the stack does not change `engines.node`, but it rebuilds the application against a different operating-system image. Retest native dependencies and system-library integrations after a stack migration. + +## Recommended version format + +Use a supported major-version range for most production applications: + +```json +{ + "engines": { + "node": "24.x" + } +} +``` + +A major range allows a rebuild to receive patch and security updates within the selected release line. + +| Requirement | Example | Update behavior | Recommended use | +| --- | --- | --- | --- | +| Major range | `24.x` | Receives newer 24.x patch releases | Recommended default | +| Compatible range | `^24.10.0` | Receives compatible versions allowed by semver | Use when the lower bound matters | +| Exact version | `24.18.1` | Remains on that exact release | Use only when a verified compatibility issue requires it | +| Wide range | `>=22` | Can cross major versions | Avoid unless the application is tested across every allowed major | + +{% warning %} +An exact patch pin does not automatically move to a newer security or bug-fix release. Review and update exact pins regularly. +{% endwarning %} + +## How the buildpack resolves the request + +The buildpack reads `engines.node` as a semantic-version requirement and resolves it against the versions available in its inventory. + +For example: + +```json +{ + "engines": { + "node": ">=24 <25" + } +} +``` + +The build succeeds when at least one inventoried version matches the requirement. The most appropriate available version is installed and used both during the build and at runtime. + +The build fails with a targeted message when: + +- the value is not a valid semantic-version requirement; +- the value is valid but no available Node.js release matches it; +- the requested binary cannot be downloaded or its checksum cannot be verified. + +## Wide ranges + +Avoid a range such as `*` or `>=20` that can resolve across many future major versions. A new Node.js major can contain runtime, module ABI, or dependency-manager changes that the application has not been tested against. + +The current buildpack warns about wide ranges and can limit their resolution to the Active LTS line. To opt out of that protection, set: + +```bash +scalingo --app my-app env-set NODEJS_ALLOW_WIDE_RANGE=true +``` + +{% warning %} +Use `NODEJS_ALLOW_WIDE_RANGE=true` only when the application test suite validates every Node.js major version allowed by the range. A major-version range such as `24.x` is more predictable. +{% endwarning %} + +## Available versions + +The available patch versions are maintained in the buildpack inventory and change frequently. The [Node.js overview]({% post_url languages/nodejs/2000-01-01-start %}#nodejs-versions) shows the currently documented release lines. + +For implementation-level verification, inspect: + +- [the buildpack inventory][nodejs-buildpack-inventory]; +- [the buildpack changelog][nodejs-buildpack-changelog]. + +Do not copy a patch-version table into several pages. Keep a single public source of truth and link to it. + +## End-of-life versions + +Node.js versions and Scalingo stacks have separate lifecycle policies. Node.js versions eventually stop receiving upstream security and maintenance updates. When the resolver identifies an end-of-life version, the current buildpack emits a warning that the release is unsupported and may become a build error in a future buildpack release. + +Treat an end-of-life warning as an upgrade requirement, not as an informational message. + +A safe upgrade workflow is: + +1. Choose a supported target major line. +2. Update local development and continuous integration (CI) to that line. +3. Update `engines.node`. +4. Reinstall dependencies and refresh the lockfile with the selected package manager. +5. Test native dependencies, build tooling, and runtime behavior. +6. Deploy to a non-production application or review app. +7. Promote the change after checking startup logs, HTTP health, memory, and error rates. + +Example upgrade: + +```diff + { + "engines": { +- "node": "22.x" ++ "node": "24.x" + } + } +``` + +## Node.js and package-manager versions are separate + +`engines.node` selects Node.js. Package-manager versions are configured separately: + +```json +{ + "engines": { + "node": "24.x", + "npm": "11.x" + }, + "packageManager": "pnpm@10.15.0" +} +``` + +Use only the fields relevant to the committed lockfile. See [Use npm]({% post_url languages/nodejs/2000-01-01-npm %}), [Use Yarn]({% post_url languages/nodejs/2000-01-01-yarn %}), or [Use pnpm]({% post_url languages/nodejs/2000-01-01-pnpm %}). + +## Troubleshooting version selection + +### Invalid semantic-version requirement + +Check that `engines.node` contains a valid semver expression rather than a label such as `lts`, `latest`, or a mistyped version. + +```json +{ + "engines": { + "node": "24.x" + } +} +``` + +### No published version matches + +The requested range is syntactically valid but does not match the buildpack inventory. Choose a currently available release line and redeploy. + +### A native dependency fails after an upgrade + +A Node.js upgrade can change the native module ABI or expose an outdated prebuilt binary. Remove locally generated `node_modules`, reinstall dependencies, update the affected package, and see [Manage Native Modules and System Dependencies]({% post_url languages/nodejs/2000-01-01-extensions %}). + +### The build still uses an older version + +Confirm that: + +- `package.json` is at the deployed source root; +- the updated file was committed; +- the deployment log prints the expected `engines.node` request; +- the application was rebuilt rather than only restarted. + +[nodejs-buildpack-changelog]: https://github.com/Scalingo/nodejs-buildpack/blob/master/CHANGELOG.md + +[nodejs-buildpack-inventory]: https://github.com/Scalingo/nodejs-buildpack/tree/master/inventory diff --git a/src/_posts/languages/nodejs/2000-01-01-start.md b/src/_posts/languages/nodejs/2000-01-01-start.md index 5b26614b0..69e84d1e4 100644 --- a/src/_posts/languages/nodejs/2000-01-01-start.md +++ b/src/_posts/languages/nodejs/2000-01-01-start.md @@ -1,470 +1,186 @@ --- title: Node.js nav: Introduction -modified_at: 2026-07-31 12:00:00 +modified_at: 2026-08-06 00:00:00 tags: nodejs index: 1 --- -Node.js is supported by Scalingo, furthermore, custom support has been added to -manage the [__Meteor__]({% post_url languages/meteorjs/2000-01-01-start %}) -framework. +Node.js applications run on Scalingo through the [Scalingo Node.js buildpack][nodejs-buildpack]. The buildpack detects the application, installs Node.js and the selected package manager, installs dependencies, runs the application build, prepares the runtime image, and defines a default web process. -## Detection +Node.js is a good fit for HTTP APIs, web applications, background workers, real-time services, and JavaScript or TypeScript applications whose build and runtime can be expressed through `package.json` scripts. -The file `package.json` should be present at the root of the project. +## Scalingo stack context -## Node.js Versions +A Scalingo stack is the Ubuntu-based operating-system image used by the application's build and runtime containers. The stack is separate from the Node.js release selected through `engines.node`. -### Availability +Each listed stack uses an Ubuntu long-term support (LTS) release. -The following Node.js versions are available: +| Stack | Base operating system | Status | Lifecycle | +| --- | --- | --- | --- | +| `scalingo-22` | Ubuntu 22.04 LTS | Deprecated | Discontinued on 1 June 2027 | +| `scalingo-24` | Ubuntu 24.04 LTS | Supported | Supported through May 2029 | +| `scalingo-26` | Ubuntu 26.04 LTS | Supported and latest | Supported through May 2031 | -| Node.js version | `scalingo-22` ([EOL]) | `scalingo-24` | `scalingo-26` | -| --------------: | --------------------: | --------------: | --------------: | -| `v26` | up to `26.5.1` | up to `26.5.1` | up to `26.5.1` | -| `v24` (LTS) | up to `24.18.1` | up to `24.18.1` | up to `24.18.1` | -| `v22` (LTS) | up to `22.23.2` | up to `22.23.2` | up to `22.23.2` | +New applications currently use `scalingo-26` by default. Existing applications keep their selected stack until it is changed and the application is redeployed. -{% include scalingo_22_deprecation_note.md %} - -### Select a Version - -The default Node.js version on all stacks is the latest `v24` version. If you -need to install another version, specify it in the `engines.node` key of your -`package.json` file.\\ -For example, to install the latest Node.js version of the `v24` branch: - -```json -{ - "name": "my-app", - "engines": { - "node": "24" - } -} -``` - -### Dependencies Installation - -The dependencies of your project are installed either with the [npm package -manager](https://www.npmjs.com/) or the [Yarn package -manager](https://yarnpkg.com/). - -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`. - -{% note %} - You can specify the version of yarn you want to use by defining it in the - `package.json` file, with the key `engines.yarn`. -{% endnote %} - -### Private Dependency - -{% note %} - Yarn does not handle private modules, if you use them, keep using npm -{% endnote %} - -#### 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): +Check an application's stack: ```bash -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} +scalingo --app my-app apps-info ``` -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. +List the stacks available to your account: -``` -# .npmrc -registry = 'https://custom-registry.com/' +```bash +scalingo stacks ``` -npm will also read the configuration from any environment variable starting with NPM_CONFIG. - {% note %} -If NPM_CONFIG_PRODUCTION is true, npm will automatically run all scripts in a subshell where NODE_ENV is 'production'. +The number in a stack name identifies the Ubuntu release, not the Node.js release. An application using `scalingo-24` can run Node.js 22, 24, or 26 when that Node.js line is available in the buildpack inventory. {% endnote %} -#### 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: +The stack matters most for native Node.js modules and packages that use operating-system libraries. A stack migration rebuilds the application against a different Ubuntu base and should be tested before production. See [Scalingo Stacks]({% post_url platform/internals/stacks/2000-01-01-stacks %}). -``` -"package-name": "git+ssh://git@//.git#master" -``` - -To authenticate to the SCM service, you need to use our [SSH Private Key -Buildpack]({% post_url platform/deployment/buildpacks/2000-01-01-ssh-key %}), -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. - -`devDependencies` can be totally ignored and not installed at all by setting `NPM_CONFIG_PRODUCTION=true` npm or `YARN_PRODUCTION=true` with Yarn 1. - -#### Skip Pruning - -If you need access to packages declared under `devDependencies` at runtime, you may -consider declaring those as `dependencies`. If required at runtime, they are not really development dependencies. - -If you still need access to packages declared under `devDependencies` after the -build has finished without moving those in `dependencies` - to be used in a different -buildpack for example - then you'll need to use Yarn 2+ and set `YARN2_SKIP_PRUNING=true`. +## Application detection -| Package Manager | Environment Variable | Install Dev Deps | Prune | -| --------------- | ----------------------- | :--------------: | :---: | -| npm | none | Yes | Yes | -| npm | `NPM_CONFIG_PRODUCTION` | No | - | -| Yarn | none | Yes | Yes | -| Yarn | `YARN_PRODUCTION` | No | - | -| Yarn 2+ | none | Yes | Yes | -| Yarn 2+ | `YARN2_SKIP_PRUNING` | Yes | No | +A Node.js application must contain a `package.json` file at the root of the source deployed to Scalingo. -### 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 +```text +my-app/ +├── package.json +├── package-lock.json +└── server.js ``` -{% note %} - If the module contains a binary like `grunt` or `gulp`, they will be - installed in the `node_modules/.bin` directory, keeping them local and - trackable. On Scalingo, the `node_modules/.bin` directory is added to your - `PATH`, so you can directly use them. -{% endnote %} - -### Do not Track Modules with Git +The Node.js buildpack does not search subdirectories for `package.json`. For an application stored inside a monorepo, configure the deployed source so that the application directory becomes the root seen by the buildpack. Set the `PROJECT_DIR` environment variable or use another documented deployment-root mechanism so that the application directory becomes the root seen by the buildpack. See [Deploying a Monorepo]({% post_url platform/app/2000-01-01-monorepo %}). -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. +{% warning %} +Only commit one package-manager lockfile. A deployment fails when the buildpack finds conflicting npm, Yarn, or pnpm lockfiles. +{% endwarning %} -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. +Detection also has a separate path for legacy Meteor applications containing a root `.meteor` directory. Meteor-specific instructions remain in the [MeteorJS documentation]({% post_url languages/meteorjs/2000-01-01-start %}). -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.js versions -```text -node_modules -bower_components -# Any other file created by grunt/gulp/webpack builds -``` +The buildpack installs the Node.js version requested through `engines.node` in `package.json`. When no version is specified, it uses the current recommended long-term support (LTS) release. -Once done, Git will ignore these directories when making commits. +At the time this draft was written, the same inventoried Node.js release lines were available on all three listed stacks: -### Node.js App Startup +| Node.js release line | `scalingo-22` (deprecated) | `scalingo-24` | `scalingo-26` | +| --- | ---: | ---: | ---: | +| Node.js 26 | `26.5.1` | `26.5.1` | `26.5.1` | +| Node.js 24 LTS | `24.18.1` | `24.18.1` | `24.18.1` | +| Node.js 22 LTS | `22.23.2` | `22.23.2` | `22.23.2` | -What we use in order of priority +The exact patch versions change frequently. Use [Select a Node.js Version]({% post_url languages/nodejs/2000-01-01-selecting-a-version %}) for version syntax, update behavior, and end-of-life guidance. -1. `Procfile` at the root of your project -2. The field `.scripts.start` defined in your `package.json` - -Example of `package.json`: +A major-version range is generally the best choice: ```json { - ... - "scripts": { - "start": "node server.js" + "engines": { + "node": "24.x" } } ``` -## Memory Management +This allows the buildpack to select newer patch releases in the same major line when the application is rebuilt. -On Scalingo, the Node.js buildpack automatically defines `WEB_CONCURRENCY` -when it is not already set. The value is calculated from the memory available -in the container and the `WEB_MEMORY` value: - -```text -WEB_CONCURRENCY = MEMORY_AVAILABLE / WEB_MEMORY -``` - -By default, `WEB_MEMORY` is set to `512` MB. - -You can override `WEB_CONCURRENCY` or `WEB_MEMORY` if the default values do not -fit your application workload. - -If your application needs an explicit V8 old-space limit, use `NODE_OPTIONS`: - -```bash -$ scalingo --app my-app env-set NODE_OPTIONS="--max-old-space-size=512" -``` +## Package managers -The value is expressed in megabytes. This setting can help make memory usage -more predictable, but increasing it does not fix memory leaks. +Scalingo supports npm, Yarn, and pnpm. The committed lockfile selects the package manager used to install dependencies and run build scripts. -For more details, refer to the [official Node.js memory guide][nodejs-memory-guide]. +| Lockfile | Package manager | +| --- | --- | +| `package-lock.json` or `npm-shrinkwrap.json` | npm | +| `yarn.lock` | Yarn | +| `pnpm-lock.yaml` | pnpm | +| No lockfile | npm | -### Node.js Build Hooks +A lockfile is strongly recommended because it makes dependency installation reproducible. -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`: +The `packageManager` field can request a Yarn or pnpm version, but it does not replace the lockfile as the package-manager selector. ```json { - ... - "scripts": { - "start": "node server.js", - "build": "grunt build" - } + "packageManager": "pnpm@10.15.0" } ``` -If the `package.json` has a `build` script which needs to be customized for -Scalingo, you should define a`scalingo-postbuild` step: - -```json -{ - ... - "scripts": { - "build": "grunt build", - "scalingo-postbuild": "grunt build --prod", - "start": "node server.js" - } -} -``` +See the package-manager-specific pages for installation, pruning, caching, private registries, and workspaces: -{% warning %} -If the `scalingo-postbuild` hook is defined, the `build` step will **not** run. -{% endwarning %} +- [Use npm on Scalingo]({% post_url languages/nodejs/2000-01-01-npm %}) +- [Use Yarn on Scalingo]({% post_url languages/nodejs/2000-01-01-yarn %}) +- [Use pnpm on Scalingo]({% post_url languages/nodejs/2000-01-01-pnpm %}) -You may also want to run a custom command before the installation of -dependencies. This is possible thanks to commands named `scalingo-prebuild`: +## Default build and runtime behavior -```json -{ - ... - "scripts": { - "scalingo-prebuild": "node prebuild.js", - "start": "node server.js" - } -} -``` +For a typical application, the buildpack performs these steps: -{% note %} -You can disable the build phase for your app by setting the environment -variable `NPM_NO_BUILD=true`. -{% endnote %} +1. Detect the root `package.json`. +2. Resolve and install Node.js. +3. Install the selected package manager when required. +4. Restore a compatible build cache. +5. Run `scalingo-prebuild`, when defined. +6. Install dependencies, including development dependencies by default. +7. Run `scalingo-postbuild` or `build`. +8. Cache build dependencies and artifacts. +9. Prune development dependencies for a production runtime, unless pruning is explicitly skipped. +10. Run `scalingo-cleanup`, when defined. +11. Prepare runtime environment variables and process metadata. -### Custom Cache Folder +See [Default Node.js Build and Runtime Behavior]({% post_url languages/nodejs/2000-01-01-default-behavior %}) for the full lifecycle and script precedence. -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. +## Starting the application -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: +For a normal Node.js application, the buildpack provides this default process: -```json -"cacheDirectories": ["client/node_modules", "server/node_modules"] +```text +web: npm start ``` -## 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]({% post_url -languages/meteorjs/2000-01-01-start %}) - -## 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: +Define a `start` script in `package.json`: ```json { - // … "scripts": { - "build": "", "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]({% -post_url platform/app/2000-01-01-static-files-hosting %}) to serve the file -generated during the build phase. - -## Buildpack - -More information at -[https://github.com/Scalingo/nodejs-buildpack](https://github.com/Scalingo/nodejs-buildpack). - -## Next.js - -Out of the box, Next.js is configured with a `package.json` which looks like: -```json -{ - "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]({% post_url languages/nodejs/2000-01-01-nextjs-standalone %}). - - -## Vite - -In `package.json`, you need -```json - "scripts": { - "start": "vite --port $PORT", - // others scripts - } - } -``` +An explicit root `Procfile` can define or override process types. A public web process must listen on the port supplied in the `PORT` environment variable. -In the `vite.config` (or `vite.config.ts`) file you need to add the following -```typescript - server: { - host: "0.0.0.0", - }, +```js +const port = Number.parseInt(process.env.PORT ?? "3000", 10); +server.listen(port, "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`. - -## Angular - -Please refer to the Angular [dedicated page]({% post_url languages/nodejs/2000-01-01-angular %}) for instructions on how to deploy such an application on Scalingo. - -## Yarn Known Issues +## Framework compatibility -### Catch `SIGTERM` In an Application Started With Yarn - -You may want to catch the `SIGTERM` signal in your Node.js application: - -```js -process.on('SIGTERM', () => { - log.notice('"SIGTERM" received'); - process.exit(0) -}); -``` +Most Node.js frameworks work through standard `package.json` scripts rather than framework-specific buildpack code. Documentation therefore distinguishes: -The good practice is to start the application by defining a `start` script in the `package.json`. For example: +- **Explicit buildpack support:** behavior implemented specifically in the buildpack. +- **Documented compatibility:** a Scalingo-tested deployment recipe. +- **Generic compatibility:** a framework can run because it produces a normal Node.js application. -```json -{ - "scripts": { - "start": "node server.js" - } -} -``` +See [Deploy Next.js]({% post_url languages/nodejs/frameworks/2000-01-01-nextjs %}) for a complete framework example. Additional framework pages should only claim the level of support backed by a maintained sample or automated deployment test. -Then define the `web` process in the Procfile. Example of Procfile content: +## Buildpack and changes -```yaml -web: yarn run start -``` +- [Scalingo Node.js buildpack][nodejs-buildpack] +- [Buildpack changelog][nodejs-buildpack-changelog] +- [Scalingo buildpacks overview]({% post_url platform/deployment/buildpacks/2000-01-01-intro %}) -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. +## Next steps -The solution is to change the content of the Procfile to directly start the Node.js process: +- [Deploy a Node.js Application]({% post_url languages/nodejs/2000-01-01-tutorial %}) +- [Select a Node.js Version]({% post_url languages/nodejs/2000-01-01-selecting-a-version %}) +- [Customize Node.js Builds]({% post_url languages/nodejs/2000-01-01-customizing %}) +- [Manage Native Modules and System Dependencies]({% post_url languages/nodejs/2000-01-01-extensions %}) +- [Troubleshoot Node.js Deployments]({% post_url languages/nodejs/2000-01-01-troubleshooting %}) -```yaml -web: node server.js -``` +[nodejs-buildpack]: https://github.com/Scalingo/nodejs-buildpack -[nodejs-memory-guide]: https://nodejs.org/learn/diagnostics/memory/understanding-and-tuning-memory -[EOL]: {% post_url platform/internals/stacks/2000-01-01-stacks %}#stack-end-of-life +[nodejs-buildpack-changelog]: https://github.com/Scalingo/nodejs-buildpack/blob/master/CHANGELOG.md diff --git a/src/_posts/languages/nodejs/2000-01-01-troubleshooting.md b/src/_posts/languages/nodejs/2000-01-01-troubleshooting.md new file mode 100644 index 000000000..01985351e --- /dev/null +++ b/src/_posts/languages/nodejs/2000-01-01-troubleshooting.md @@ -0,0 +1,371 @@ +--- +title: Troubleshoot Node.js Deployments +nav: Troubleshooting +modified_at: 2026-08-06 00:00:00 +tags: nodejs troubleshooting +index: 12 +--- + +Start with the first specific error in the deployment or application log. The final `Build failed` or boot-timeout message is often only a summary of an earlier problem. + +Follow logs: + +```bash +scalingo --app my-app logs --follow +``` + +For build failures, keep the complete deployment log from detection through the first classified error. + +## Quick triage + +| Failure stage | Typical cause | Start here | +| --- | --- | --- | +| Detection | Missing root `package.json` | [Application is not detected](#application-is-not-detected) | +| Runtime installation | Invalid or unavailable Node.js range | [Node.js version errors](#nodejs-version-errors) | +| Package-manager setup | Invalid Yarn or pnpm version | [Package-manager version errors](#package-manager-version-errors) | +| Dependency installation | Lockfile, registry, peer, native, or disk error | [Dependency installation fails](#dependency-installation-fails) | +| Build script | Compiler, framework, memory, or missing devDependency | [The build script fails](#the-build-script-fails) | +| Runtime boot | Missing start command, wrong port, crash | [The application does not boot](#the-application-does-not-boot) | +| Runtime after boot | Missing production dependency, memory, signal, or native library | [The application crashes at runtime](#the-application-crashes-at-runtime) | +| After a stack change | Native binary, system library, browser, or custom cache mismatch | [Identify the active stack](#identify-the-active-stack) | + +## Identify the active stack + +The stack is the Ubuntu base image, not the Node.js version. + +Each listed stack uses an Ubuntu long-term support (LTS) release. + +| Stack | Base operating system | Status | Lifecycle | +| --- | --- | --- | --- | +| `scalingo-22` | Ubuntu 22.04 LTS | Deprecated | Discontinued on 1 June 2027 | +| `scalingo-24` | Ubuntu 24.04 LTS | Supported | Supported through May 2029 | +| `scalingo-26` | Ubuntu 26.04 LTS | Supported and latest | Supported through May 2031 | + +Record the stack before comparing local and production behavior: + +```bash +scalingo --app my-app apps-info +``` + +If a failure began after a migration between `scalingo-22`, `scalingo-24`, and `scalingo-26`: + +1. confirm the application was redeployed after the stack setting changed; +2. verify the resolved Node.js and package-manager versions in the build log; +3. rebuild native dependencies instead of reusing committed modules; +4. temporarily disable the normal Node.js cache if necessary; +5. review custom `cacheDirectories` and APT packages; +6. reproduce against the target stack image when the error concerns a shared library or system binary. + +A stack migration can expose an old package that does not publish binaries for the newer Ubuntu base, a missing shared library, or a native module compiled for the previous stack. + +## Application is not detected + +### `package.json` is missing + +The Node.js buildpack requires `package.json` at the root of the deployed source. + +```bash +ls -la +git ls-files package.json +``` + +For a monorepo, configure a child application or deployment root. The buildpack does not search nested directories. + +### `package.json` is excluded + +The detection script emits a specific message when `.slugignore` or `.gitignore` excludes `package.json`. Remove the exclusion, commit the file, and redeploy. + +### `package.json` cannot be parsed + +Validate JSON locally: + +```bash +node -e 'JSON.parse(require("node:fs").readFileSync("package.json", "utf8"))' +``` + +Remove comments, trailing commas, unresolved merge markers, or invalid quoting. + +## Node.js version errors + +### Invalid semantic-version requirement + +Use a valid semver requirement: + +```json +{ + "engines": { + "node": "24.x" + } +} +``` + +### No published version matches + +The requirement is valid but does not match a version in the buildpack inventory. Choose a currently available release line from [Select a Node.js Version]({% post_url languages/nodejs/2000-01-01-selecting-a-version %}). + +### End-of-life warning + +Upgrade immediately. End-of-life Node.js releases no longer receive upstream security updates and can become build errors in a later buildpack release. + +### Node.js download or checksum failure + +Retry once to rule out a transient network problem. If it persists, include the requested version and download URL in a support request. Do not disable checksum validation. + +## Package-manager selection errors + +### Multiple lockfiles found + +Only one package manager can install dependencies. Keep one of: + +```text +package-lock.json +npm-shrinkwrap.json +yarn.lock +pnpm-lock.yaml +``` + +Remove the others, commit, and redeploy. The buildpack does not silently choose a precedence. + +### `packageManager` conflicts with `engines` + +For Yarn or pnpm, `packageManager` takes precedence over the corresponding `engines` field. Remove the duplicate declaration and keep one version source. + +## Package-manager version errors + +### Yarn version cannot be installed + +Confirm that the version exists and supports the selected Node.js release. For Berry, verify `.yarnrc.yml` and any `yarnPath` file are committed. + +### pnpm version cannot be installed + +Confirm that `packageManager` contains an existing pnpm version and that the version supports the selected Node.js release. + +Without an explicit version, the buildpack uses `pnpm@latest` and warns. Pin the version to prevent an unexpected major upgrade. + +## Dependency installation fails + +### npm lockfile is out of sync + +```bash +npm install +npm test +git add package.json package-lock.json +git commit -m "Update npm lockfile" +``` + +### Yarn frozen or immutable install fails + +```bash +yarn install +yarn test +git add package.json yarn.lock .yarnrc.yml .yarn +git commit -m "Update Yarn project files" +``` + +Commit only the `.yarn` files required by the project’s chosen Yarn workflow. + +### pnpm frozen lockfile fails + +```bash +pnpm install +pnpm test +git add package.json pnpm-lock.yaml +git commit -m "Update pnpm lockfile" +``` + +### Registry returns 401 or 403 + +Check: + +- the token exists in Scalingo environment variables; +- the token has read access to the package or scope; +- `.npmrc` or `.yarnrc.yml` references the correct variable name; +- the registry hostname and scope match; +- the token was not revoked or expired. + +Do not print the token while testing. + +### Registry returns 404 + +A private registry can return 404 when authentication is missing. Check both package spelling/version and credentials. + +### npm `ERESOLVE` + +Review the peer-dependency conflict named in the log. Update incompatible packages or align their required versions. Avoid permanent force or legacy-peer-dependency flags unless the resulting graph has been tested. + +### `EBADPLATFORM` or unsupported architecture + +The package or its prebuilt binary does not support the Scalingo stack. Update it or see [Manage Native Modules and System Dependencies]({% post_url languages/nodejs/2000-01-01-extensions %}). + +### Install script is blocked + +New package-manager versions can require explicit policy for dependency lifecycle scripts. Review the exact package and configure the manager’s allowlist only after confirming the script is trusted and required. + +### Build runs out of disk space + +Reduce dependency and artifact size, remove unnecessary cache paths, and inspect large generated files. A log-capture or `ENOSPC` error can indicate the build filesystem filled during installation or compilation. + +## The build script fails + +### Build command is not found + +The tool is probably absent from installed dependencies or development dependencies were disabled. + +Check: + +- the tool is declared in `devDependencies` or `dependencies`; +- `NPM_CONFIG_PRODUCTION=true` or `YARN_PRODUCTION=true` is not preventing installation; +- the script uses the local executable through the package manager rather than requiring a global install. + +### Both `build` and `scalingo-postbuild` exist + +Only `scalingo-postbuild` runs. Put the complete Scalingo build command there, or remove it to use the normal `build` script. + +### `NODE_BUILD_FLAGS` has no effect + +The variable is forwarded only to `build`, not to `scalingo-prebuild`, `scalingo-postbuild`, or `scalingo-cleanup`. + +### Build runs out of memory + +Inspect the selected container/build limits, framework memory requirements, and `NODE_OPTIONS`. + +```bash +scalingo --app my-app env-set NODE_OPTIONS="--max-old-space-size=2048" +``` + +A higher heap limit does not increase the actual container limit. Reduce parallel build work or generated artifact size when possible. + +### Native module compilation fails + +Find the first compiler error, not only the final package-manager summary. Check Node.js compatibility, system libraries, compiler/Python requirements, and package versions. + +## The application does not boot + +### No start script + +Define: + +```json +{ + "scripts": { + "start": "node server.js" + } +} +``` + +The buildpack supplies `web: npm start` by default. + +### Boot timeout + +The web process must listen on the platform port: + +```js +const port = Number.parseInt(process.env.PORT, 10); +server.listen(port, "0.0.0.0"); +``` + +Check that: + +- the process reads `PORT`; +- it binds to `0.0.0.0` rather than only `127.0.0.1`; +- startup does not wait indefinitely for a database migration or external service; +- the `Procfile` command matches the built output; +- the application does not crash before opening the port. + +### A `Procfile` starts the wrong command + +An explicit `Procfile` overrides the default process metadata. Compare it with `scripts.start` and the files produced by the build. + +### Next.js times out + +Use: + +```json +{ + "scripts": { + "start": "next start -H 0.0.0.0 -p $PORT" + } +} +``` + +For standalone mode, start `.next/standalone/server.js` and copy required static/public assets. See [Deploy Next.js]({% post_url languages/nodejs/frameworks/2000-01-01-nextjs %}). + +## The application crashes at runtime + +### `module not found`, `ng: not found`, or `nest: not found` + +A runtime requirement was probably declared in `devDependencies` and pruned after the build. + +Move it to `dependencies`, reinstall, commit the lockfile, and redeploy. + +Use a skip-pruning variable only when the application architecture genuinely requires build dependencies at runtime. + +### Native library cannot be loaded + +The package may have been compiled for another Node.js version or operating system, or a runtime shared library is missing. Do not commit `node_modules`. Reinstall for the selected Node.js version and verify system packages remain in the runtime image. + +### Out-of-memory restart + +Check container memory metrics and the number of Node.js processes. `NODE_OPTIONS=--max-old-space-size=...` applies per process and does not include all native memory. + +Reduce worker count, reduce application memory, or choose a larger container. See [Manage Node.js Web Concurrency]({% post_url languages/nodejs/2000-01-01-managing-web-concurrency %}). + +### The process does not shut down gracefully + +Ensure the Node.js process receives `SIGTERM`. Avoid unnecessary Yarn or shell wrappers in the `Procfile` when signal forwarding is uncertain. + +```text +web: node server.js +``` + +Add a termination handler and stop accepting new work before exiting. + +## Cache-related problems + +Symptoms can include an unexpected old artifact, a native binary mismatch, or a package-manager cache that is not restored. + +Disable caching for one build: + +```bash +scalingo --app my-app env-set NODE_MODULES_CACHE=false +``` + +After a successful clean build, re-enable it: + +```bash +scalingo --app my-app env-set NODE_MODULES_CACHE=true +``` + +Also review custom `cacheDirectories`. A custom cache can preserve outputs the buildpack does not know how to invalidate. + +Do not use cache clearing as a substitute for committing a synchronized lockfile. + +## Private Git dependency fails + +For public repositories, use an HTTPS URL pinned to a tag or commit. For private SSH dependencies, configure the SSH Private Key Buildpack and verify host-key configuration. + +Never place a private key in `package.json`, `.npmrc`, or repository files. + +## Collect information before contacting support + +Include: + +- the application name and region; +- the failed deployment date and approximate time; +- the Scalingo stack; +- the requested and resolved Node.js versions; +- package manager, version, and lockfile; +- the first specific error and surrounding log lines; +- whether the failure occurs during build, boot, or runtime; +- recent changes to Node.js, package manager, lockfile, buildpacks, or environment variables; +- whether a clean-cache build changes the result. + +Remove tokens, private URLs containing credentials, environment values, and other secrets before sharing logs. + +## Related documentation + +- [Node.js on Scalingo]({% post_url languages/nodejs/2000-01-01-start %}) +- [Select a Node.js Version]({% post_url languages/nodejs/2000-01-01-selecting-a-version %}) +- [Default Node.js Build and Runtime Behavior]({% post_url languages/nodejs/2000-01-01-default-behavior %}) +- [Customize Node.js Builds]({% post_url languages/nodejs/2000-01-01-customizing %}) +- [Manage Native Modules and System Dependencies]({% post_url languages/nodejs/2000-01-01-extensions %}) diff --git a/src/_posts/languages/nodejs/2000-01-01-tutorial.md b/src/_posts/languages/nodejs/2000-01-01-tutorial.md index 35e8142d0..db7de9945 100644 --- a/src/_posts/languages/nodejs/2000-01-01-tutorial.md +++ b/src/_posts/languages/nodejs/2000-01-01-tutorial.md @@ -1,92 +1,228 @@ --- -title: Get Started with Node.js on Scalingo +title: Deploy a Node.js Application nav: Get Started -modified_at: 2023-12-22 00:00:00 +modified_at: 2026-08-06 00:00:00 tags: nodejs express tutorial getting-started-tutorial -index: 2 +index: 4 --- -{% include info_tutorial_requirements.md %} +This tutorial deploys a minimal Express application with npm. The same buildpack also supports Yarn and pnpm. -## Initialize Your Application +## Prerequisites + +Before starting, install and configure: + +- Node.js and npm locally; +- Git; +- the [Scalingo command-line interface (CLI)]({% post_url tools/cli/2000-01-01-start %}); +- a Scalingo account with SSH authentication configured. + +{% note %} +This tutorial is suitable for `scalingo-24` and `scalingo-26`. `scalingo-22` is deprecated and should only be treated as a migration source, not the target for a new application. +{% endnote %} + +## Create the application ```bash -$ mkdir my-app -$ cd my-app -$ npm init +mkdir my-app +cd my-app +npm init -y +npm install express +``` + +The installation creates `package-lock.json`. Commit this lockfile so Scalingo uses reproducible npm installation. -# -# You need to fill the different info field for your project -# +Create `.gitignore`: -$ npm install express --save -$ echo "node_modules" > .gitignore +```text +node_modules/ +.env ``` -## Write a Base Server File +## Add the web server -The main file for this sample project is `server.js`: +Create `server.js`: ```js -// Node.js - Express sample application +const express = require("express"); + +const app = express(); +const port = Number.parseInt(process.env.PORT ?? "3000", 10); + +app.get("/", (_request, response) => { + response.send("Hello from Scalingo!"); +}); + +const server = app.listen(port, "0.0.0.0", () => { + console.log(`Listening on port ${port}`); +}); + +function shutdown(signal) { + console.log(`${signal} received, shutting down`); + server.close((error) => { + if (error) { + console.error(error); + process.exitCode = 1; + } + }); +} + +process.on("SIGTERM", () => shutdown("SIGTERM")); +process.on("SIGINT", () => shutdown("SIGINT")); +``` + +Scalingo supplies the public web port through `PORT`. The server must listen on that value and should accept connections on `0.0.0.0`. + +## Define the runtime and start command + +Update `package.json`: + +```json +{ + "name": "my-app", + "version": "1.0.0", + "private": true, + "engines": { + "node": "24.x" + }, + "scripts": { + "start": "node server.js" + }, + "dependencies": { + "express": "^5.1.0" + } +} +``` -var express = require('express') -var app = express() +Use the actual Express version recorded by npm in your generated file; the version above is only an example. -app.get('/', function (req, res) { - res.send('Hello World!') -}) +The Node.js buildpack provides `web: npm start` by default, so this application does not need a `Procfile`. -var server = app.listen(process.env.PORT || 3000, function () { - var host = server.address().address - var port = server.address().port - console.log('App listening at https://%s:%s', host, port) -}) +An explicit `Procfile` is useful when you need several process types: + +```text +web: node server.js +worker: node worker.js ``` -{% note %} - The `process.env.PORT` will read the environment variable PORT dynamically provided by our container manager. -{% endnote %} +## Run locally -## Define How to Start Your Application +```bash +npm start +``` -The `Procfile` (with a capital 'P') is the file defining how your application -is supposed to start ([more info about Procfile]({% post_url -platform/app/2000-01-01-procfile %})). This file must be at the root of your project. -Here is the content you have to write in the `Procfile` file for this project: +Open `http://localhost:3000`. Stop the process with `Ctrl+C`. -```yaml -web: node server.js +## Commit the application + +```bash +git init +git add package.json package-lock.json server.js .gitignore +git commit -m "Create Node.js application" ``` -## Commit Your Application +Confirm that `node_modules` is not tracked: ```bash -$ git init -$ git add . -$ git commit -m "Base Node.js application" +git status ``` -## Create Your Application on Scalingo and Deploy +## Create the Scalingo application -{% note %} - This operation has to be done in the directory of your project. -{% endnote %} +From the project directory: + +```bash +scalingo create my-app +``` + +The CLI creates the application and adds a `scalingo` Git remote when a repository is detected. + +Deploy the current branch: + +```bash +git push scalingo main +``` + +Use the actual local branch name when it is not `main`. + +During deployment, the log should show: + +- Node.js detection; +- the requested Node.js version; +- npm installation with `package-lock.json`; +- dependency installation; +- creation of the runtime image; +- the application boot check. + +## Check or choose the Scalingo stack + +A stack is the Ubuntu operating-system image used to build and run the application. It is independent from the Node.js version declared in `package.json`. + +Check the stack selected for the new application: + +```bash +scalingo --app my-app apps-info +``` + +New applications currently use `scalingo-26` by default. To explicitly select the latest stack for an existing or test application: ```bash -$ scalingo create my-app -Git repository detected: remote scalingo added -→ 'git push scalingo master' to deploy your app +scalingo --app my-app stacks-set scalingo-26 +git commit --allow-empty --message="Rebuild on scalingo-26" +git push scalingo main +``` + +The change takes effect on the next deployment. Test a stack migration before applying it to production, especially when the application uses native modules such as image-processing, database, or cryptography packages. -$ git push scalingo master +## Open and inspect the application + +Open the application from the dashboard or use the URL shown at the end of deployment. + +Inspect logs when the application does not start: + +```bash +scalingo --app my-app logs --follow ``` -## Access Your Application +A successful request returns: ```text -… -Waiting for your application to boot... -<-- https://my-app.osc-fr1.scalingo.io --> +Hello from Scalingo! ``` -Now develop your project and build something amazing! +## Make a change + +Edit the response in `server.js`, then redeploy: + +```bash +git add server.js +git commit -m "Update greeting" +git push scalingo main +``` + +The next build can reuse compatible dependency cache content. + +## Common first-deployment problems + +### The buildpack cannot detect the application + +Confirm that `package.json` is committed at the root of the deployed source. + +### The build fails because several lockfiles are present + +Keep only the lockfile for the package manager used by the project. For this tutorial, keep `package-lock.json` and remove `yarn.lock` or `pnpm-lock.yaml` if either was added accidentally. + +### The deployment times out while booting + +Confirm that the server reads `process.env.PORT` and listens on `0.0.0.0`. + +### A package is missing at runtime + +A runtime package must be in `dependencies`. Development dependencies are normally removed before the runtime image is started. + +## Next steps + +- [Default Node.js Build and Runtime Behavior]({% post_url languages/nodejs/2000-01-01-default-behavior %}) +- [Use npm on Scalingo]({% post_url languages/nodejs/2000-01-01-npm %}) +- [Manage Node.js Web Concurrency]({% post_url languages/nodejs/2000-01-01-managing-web-concurrency %}) +- [Troubleshoot Node.js Deployments]({% post_url languages/nodejs/2000-01-01-troubleshooting %}) diff --git a/src/_posts/languages/nodejs/2000-01-01-websocket-web-same-port.md b/src/_posts/languages/nodejs/2000-01-01-websocket-web-same-port.md deleted file mode 100644 index 8e36adda0..000000000 --- a/src/_posts/languages/nodejs/2000-01-01-websocket-web-same-port.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -title: Socket.IO and Express server listening on the same port -nav: Socket.IO and Express on the same port -modified_at: 2023-12-22 00:00:00 -tags: nodejs -index: 100 ---- - -On Scalingo, your application must listen to the port defined in the `PORT` environment variable dynamically defined by the platform. - -If your application uses both a HTTP server and a WebSocket, you can configure it to use the same port. A complete sample is deployed [here](https://node-socketio.is-easy-on-scalingo.com) with the code being publicly available in this [GitHub repository](https://github.com/Scalingo/sample-node-socketio). Here is a snippet to do that with an Express server and Socket.IO for the WebSocket part: - -```js -var express = require('express') -var app = express() -var http = require('http').createServer(app); -var io = require('socket.io')(http); - -app.get('/', function (req, res) { - res.sendFile(__dirname + '/index.html'); -}); - -http.listen(process.env.PORT || 3000, function() { - var host = http.address().address - var port = http.address().port - console.log('App listening at https://%s:%s', host, port) -}); - -io.on('connection', function(socket) { - console.log('Client connected to the WebSocket'); - - socket.on('disconnect', () => { - console.log('Client disconnected'); - }); - - socket.on('chat message', function(msg) { - console.log("Received a chat message"); - io.emit('chat message', msg); - }); -}) -``` diff --git a/src/_posts/languages/nodejs/2000-01-01-yarn-2.md b/src/_posts/languages/nodejs/2000-01-01-yarn-2.md deleted file mode 100644 index 61f3ea488..000000000 --- a/src/_posts/languages/nodejs/2000-01-01-yarn-2.md +++ /dev/null @@ -1,132 +0,0 @@ ---- -title: Yarn 2 and Yarn 3 Compatibility -modified_at: 2023-03-22 00:00:00 -tags: nodejs ---- - -## What's new in new Yarn major version - -Yarn was developed as an alternative way to handle Node.js dependencies to NPM -but was fully compatible with it. They were both manipulating the -`node_modules` directory and switching to one or the other tool was -straightforward. - -Yarn 2 and Yarn 3 have evolved to use another approach, aiming at making -dependency management for Node.js application more efficient, especially during -its deployment. - -{% warning %} -This article only covers application using the Node.js buildpack and not other -buildpacks which include installation of a Node.js stack like Ruby or PHP. If -Yarn 2 or 3 is used alongside a Ruby or PHP application, the -[multi-buildpacks]({% post_url platform/deployment/buildpacks/2000-01-01-multi -%}) should be used. -{% endwarning %} - -You are not forced to migrate to Yarn 2 or 3, compatibility with Yarn 1 will be -kept as long as possible. But to enjoy fastest deployments and last patches, -you are encouraged to upgrade your project or get back to NPM. - -New versions of Yarn have 2 ways to work: - -* With Plug'n Play: it is expected to checkout the application dependencies - `.yarn/cache` in your git repository. It will accelerate deployment since it - won't be necessary to download dependencies that are already in your repository. - Don't worry Yarn is optimizing and compressing them to prevent using too much space. - No `node_modules` directory will be present at the end of the build. - -* Without Plug'n Play: Dependencies will be downloaded normally during the - deployment and linked into the `node_modules` directory, it's - retrocompatible with most tools you have been using. - -More details in the [Yarn official documentation](https://yarnpkg.com/getting-started/migration). - -## Setting up your project - -### 1. Switch to the last stable Yarn version - -Configure Yarn to use its more recent ≥ v2.0.0 release - -``` -yarn set version berry -yarn install -``` - -The file `yarn.lock` is updated and new files are added to the `.yarn` directory. - -### 2a. Configure with Plug'n Play enabeld - -#### Update your `.gitignore` file - -Modify your `.gitignore` to ensure only required files are committed into -your repository, add the following: - -``` -.yarn/* -!.yarn/cache -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/sdks -!.yarn/versions -``` - -#### Disable dependency caching in your app - -``` -scalingo --app my-app env-set NODE_MODULES_CACHE=false -``` - -#### Add checkout config, metadata and cache files - -``` -git add yarn.lock .yarn .pnp.* -git commit -m "Deploy with Yarn 3 with Plug'n Play mode" -``` - -### 2b. OR - Configure without Plug'n Play enabled (retrocompatibily mode) - -#### Update your `.gitignore` file - -Modify your `.gitignore` to ensure only required files are committed into -your repository, add the following: - -``` -.pnp.* -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/sdks -!.yarn/versions -node_modules -``` - -#### Update your `.yarnrc.yaml` file - -Modify or add the line: - -``` -nodeLinker: "node-modules" -``` - -#### Add checkout config, metadata files - -``` -git add yarn.lock .yarn -git commit -m "Deploy with Yarn 3 without Plug'n Play mode" -``` - -### 3. Reset your deployment cache - -Since it may create conflict with the new dependencies management system. - -``` -scalingo --app my-app deployment-delete-cache -``` - -### 4. Deploy your application - -``` -git push scalingo master -``` diff --git a/src/_posts/languages/nodejs/2000-01-01-yarn.md b/src/_posts/languages/nodejs/2000-01-01-yarn.md new file mode 100644 index 000000000..06262b859 --- /dev/null +++ b/src/_posts/languages/nodejs/2000-01-01-yarn.md @@ -0,0 +1,237 @@ +--- +title: Use Yarn on Scalingo +nav: Yarn +modified_at: 2026-08-06 00:00:00 +tags: nodejs yarn +index: 8 +--- + +Yarn is selected when a `yarn.lock` file is committed at the root of the deployed source. The Node.js buildpack supports Yarn Classic and modern Yarn Berry releases, but their configuration, install modes, and pruning controls differ. + +## Select Yarn + +Commit: + +```text +package.json +yarn.lock +``` + +Remove `package-lock.json`, `npm-shrinkwrap.json`, and `pnpm-lock.yaml`. A deployment fails when several package-manager lockfiles are present. + +## Choose a Yarn generation + +| Yarn generation | Typical configuration | Install mode on Scalingo | +| --- | --- | --- | +| Yarn Classic 1.x | `engines.yarn` or default 1.22.x | Frozen lockfile | +| Yarn Berry 2+ | `packageManager`, `.yarnrc.yml`, optional vendored `yarnPath` | Immutable lockfile | + +Do not apply Yarn Classic environment variables to Berry projects. + +## Select a Yarn version + +For a modern Yarn project, prefer `packageManager`: + +```json +{ + "packageManager": "yarn@4.9.2" +} +``` + +Yarn Classic can use `engines.yarn`: + +```json +{ + "engines": { + "node": "24.x", + "yarn": "1.22.x" + } +} +``` + +When `packageManager` and `engines.yarn` are both present, `packageManager` takes precedence and the build emits a warning. + +A Berry project can also configure a vendored Yarn release with `yarnPath` in `.yarnrc.yml`. Do not configure both `packageManager` and an unrelated vendored release; the installed binary and executed binary can differ. + +## Yarn Classic installation + +The buildpack runs a frozen installation with offline-cache preference and installs development dependencies by default. + +A simplified representation is: + +```bash +yarn install --production=false --frozen-lockfile --prefer-offline +``` + +The buildpack also applies compatibility options. The exact command is shown in deployment logs. + +If `package.json` and `yarn.lock` disagree, the build fails. Repair the lockfile locally: + +```bash +yarn install +yarn test +git add package.json yarn.lock +git commit -m "Synchronize Yarn lockfile" +``` + +## Yarn Berry installation + +Berry projects use an immutable install: + +```bash +yarn install --immutable +``` + +Commit `.yarnrc.yml` and the files required by the selected Yarn workflow. + +Example using the `node-modules` linker: + +```yaml +nodeLinker: node-modules +``` + +Example repository files: + +```text +.yarnrc.yml +.yarn/ +yarn.lock +package.json +``` + +The buildpack treats `.yarnrc.yml` as the Berry configuration source. A root `.npmrc` or legacy `.yarnrc` is not used for Berry configuration in the inspected path and can trigger a warning. + +## Plug'n'Play and zero-install + +Yarn Berry can use Plug'n'Play or a checked-in compressed cache. Commit only the files required by the project’s documented Yarn workflow. + +A typical zero-install `.gitignore` policy is: + +```text +.yarn/* +!.yarn/cache +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions +``` + +When the repository includes the Yarn cache, the buildpack can verify that the cache remains immutable. Test zero-install deployments after changing Yarn versions, linker mode, or plugins. + +## Development and production dependencies + +Development dependencies are installed for the build by default. + +### Yarn Classic + +`YARN_PRODUCTION=true` can prevent development dependencies from being installed. Do not enable it when the build script needs development tools. + +### Yarn Berry + +Do not use `YARN_PRODUCTION`. To keep development dependencies in the runtime image, use: + +```bash +scalingo --app my-app env-set YARN2_SKIP_PRUNING=true +``` + +Prefer moving runtime requirements to `dependencies` instead. + +{% warning %} +The variable name `YARN2_SKIP_PRUNING` is retained for compatibility even when the project uses a Yarn major newer than 2. +{% endwarning %} + +## Private registries with Yarn Berry + +Store tokens in Scalingo environment variables and reference them from `.yarnrc.yml`. + +Example for a scoped registry: + +```yaml +npmScopes: + my-company: + npmRegistryServer: "https://registry.example.com" + npmAlwaysAuth: true + npmAuthToken: "${NPM_TOKEN}" +``` + +Set the token: + +```bash +scalingo --app my-app env-set NPM_TOKEN=replace-with-token +``` + +Validate the exact `.yarnrc.yml` syntax against the Yarn version used by the project. Never commit the resolved token. + +For Yarn Classic, use the registry configuration supported by that Yarn release and test it with the same Node.js and Yarn versions locally or in continuous integration (CI). + +## Stack considerations + +Yarn selection and lockfile behavior are the same on `scalingo-22`, `scalingo-24`, and `scalingo-26`. The stack becomes relevant when dependency installation runs native lifecycle scripts or downloads an operating-system-specific binary. + +After a stack migration: + +- redeploy so dependencies are installed for the new Ubuntu base; +- do not reuse committed `node_modules`; +- verify packages with native bindings or shared-library requirements; +- review custom cache paths if a clean build behaves differently. + +`scalingo-22` is deprecated. Prefer `scalingo-24` or `scalingo-26`, and use `scalingo-26` for new compatibility testing. + +## Caching + +Yarn uses a Yarn-specific cache. Berry and zero-install projects receive additional handling so runtime dependency files are kept in the application image when required. + +`USE_YARN_CACHE` defaults to enabled for Yarn builds. Disable all Node.js build caching temporarily with: + +```bash +scalingo --app my-app env-set NODE_MODULES_CACHE=false +``` + +Re-enable it after diagnosis. + +## Start commands and signal forwarding + +A normal start script is: + +```json +{ + "scripts": { + "start": "node server.js" + } +} +``` + +The buildpack default process runs `npm start`, which resolves the same `scripts.start` entry without requiring the project to start through Yarn. + +When an explicit `Procfile` uses a Yarn wrapper, verify that termination signals reach the Node.js process. For the simplest signal path, start Node.js directly: + +```text +web: node server.js +``` + +This is especially important for graceful shutdown during deployments and scaling operations. + +## Common Yarn errors + +### The lockfile would be modified + +Classic reports an outdated frozen lockfile; Berry commonly reports an immutable-install error such as `YN0028`. Run the project’s Yarn install locally and commit the updated files. + +### `.yarnrc.yml` or `yarnPath` is missing + +Commit the project configuration and the referenced vendored Yarn release, or remove `yarnPath` and use a version selected through `packageManager`. + +### `YARN_PRODUCTION` is rejected + +The project uses Berry. Remove `YARN_PRODUCTION`; use normal installation and `YARN2_SKIP_PRUNING` only when development dependencies must remain after the build. + +### The application does not receive `SIGTERM` + +Avoid a shell or Yarn wrapper that does not forward the signal as expected. Define the process command to execute Node.js directly. + +## Related documentation + +- [Default Node.js Build and Runtime Behavior]({% post_url languages/nodejs/2000-01-01-default-behavior %}) +- [Customize Node.js Builds]({% post_url languages/nodejs/2000-01-01-customizing %}) +- [Troubleshoot Node.js Deployments]({% post_url languages/nodejs/2000-01-01-troubleshooting %}) diff --git a/src/_posts/languages/nodejs/frameworks/2000-01-01-nextjs.md b/src/_posts/languages/nodejs/frameworks/2000-01-01-nextjs.md new file mode 100644 index 000000000..410fa55d7 --- /dev/null +++ b/src/_posts/languages/nodejs/frameworks/2000-01-01-nextjs.md @@ -0,0 +1,280 @@ +--- +title: Deploy Next.js +nav: Next.js +modified_at: 2026-08-06 00:00:00 +tags: nodejs nextjs +index: 11 +--- + +Next.js applications deploy through the normal Scalingo Node.js buildpack. The buildpack installs Node.js and dependencies, runs the project’s build script, and starts the command declared in `scripts.start` or the `Procfile`. + +This page covers two deployment modes: + +- **Standard server mode:** run `next start` after `next build`. +- **Standalone mode:** use Next.js output file tracing and start `.next/standalone/server.js` to reduce the runtime application size. + +Choose a Node.js version supported by the Next.js version used by the project. + +## Stack context + +Next.js uses the normal Node.js buildpack on all currently documented stacks. + +Each listed stack uses an Ubuntu long-term support (LTS) release. + +| Stack | Base operating system | Status | Lifecycle | +| --- | --- | --- | --- | +| `scalingo-22` | Ubuntu 22.04 LTS | Deprecated | Discontinued on 1 June 2027 | +| `scalingo-24` | Ubuntu 24.04 LTS | Supported | Supported through May 2029 | +| `scalingo-26` | Ubuntu 26.04 LTS | Supported and latest | Supported through May 2031 | + +The stack and Node.js version are separate choices. Select Node.js with `engines.node`; inspect or change the stack through the application settings. + +Most framework code is portable JavaScript, but a Next.js project can include native dependencies. The maintained Scalingo standalone sample, for example, includes `sharp`. After a stack migration, redeploy so these packages are installed or compiled for the target Ubuntu image. + +Use `scalingo-24` or `scalingo-26` for maintained deployments. Treat `scalingo-22` as a deprecated migration source. + +## Required project files + +A standard project contains: + +```text +package.json +package-lock.json, yarn.lock, or pnpm-lock.yaml +next.config.js, next.config.mjs, or next.config.ts +app/ or pages/ +public/ +``` + +The root `package.json` and exactly one supported lockfile must be committed. + +## Standard server mode + +Define build and start scripts: + +```json +{ + "private": true, + "engines": { + "node": "24.x" + }, + "scripts": { + "build": "next build", + "start": "next start -H 0.0.0.0 -p $PORT" + }, + "dependencies": { + "next": "", + "react": "", + "react-dom": "" + } +} +``` + +Use the versions already selected and tested by the project. + +During deployment: + +1. the selected package manager installs production and development dependencies; +2. the buildpack runs `next build`; +3. production pruning removes development dependencies when safe; +4. the runtime starts `next start` through the buildpack’s default `npm start` process. + +`-p $PORT` binds Next.js to the port supplied by Scalingo. `-H 0.0.0.0` makes the server accept external container traffic. + +{% warning %} +A fixed port such as `3000` can cause a Scalingo boot timeout. Always use the `PORT` environment variable in production. +{% endwarning %} + +No `Procfile` is required for the standard configuration. To make the command explicit: + +```text +web: npm start +``` + +## Environment variables + +Next.js uses environment variables at different times: + +- variables read by `next build` affect the generated build; +- variables read by server-side runtime code can be supplied when the container starts; +- variables prefixed with `NEXT_PUBLIC_` can be embedded into browser bundles during the build. + +Set Scalingo environment variables before deploying when the build needs them: + +```bash +scalingo --app my-app env-set API_BASE_URL=https://api.example.com +``` + +{% warning %} +Do not place secrets in `NEXT_PUBLIC_` variables. Values exposed to client-side code are visible to application users. +{% endwarning %} + +When an environment value must change without rebuilding, ensure it is read only from server-side runtime code rather than inlined into the build output. + +## Cache the Next.js build cache + +Next.js can reuse `.next/cache` between builds. Add it to `cacheDirectories` only after confirming that it improves build time and does not preserve invalid project output: + +```json +{ + "cacheDirectories": [ + ".next/cache" + ] +} +``` + +When diagnosing a stale build, disable the Node.js deployment cache for one build: + +```bash +scalingo --app my-app env-set NODE_MODULES_CACHE=false +``` + +Re-enable it afterward. + +## Standalone mode + +Standalone output uses Next.js output file tracing to create a smaller server bundle containing the files required at runtime. + +Configure `next.config.mjs`: + +```js +/** @type {import("next").NextConfig} */ +const nextConfig = { + output: "standalone", +}; + +export default nextConfig; +``` + +After `next build`, Next.js creates: + +```text +.next/standalone/ +``` + +The standalone server does not automatically include all static and public assets. Copy them into the standalone tree before the runtime image is finalized. + +A build and start configuration is: + +```json +{ + "scripts": { + "build": "next build && node copy-assets.js", + "start": "node .next/standalone/server.js" + } +} +``` + +Create `copy-assets.js`: + +```js +const fs = require("node:fs/promises"); +const path = require("node:path"); + +async function copyIfPresent(source, destination) { + try { + await fs.access(source); + } catch { + return; + } + + await fs.mkdir(path.dirname(destination), { recursive: true }); + await fs.cp(source, destination, { recursive: true }); +} + +async function main() { + await copyIfPresent( + path.join(__dirname, ".next", "static"), + path.join(__dirname, ".next", "standalone", ".next", "static"), + ); + + await copyIfPresent( + path.join(__dirname, "public"), + path.join(__dirname, ".next", "standalone", "public"), + ); +} + +main().catch((error) => { + console.error(error); + process.exitCode = 1; +}); +``` + +The standalone server reads `PORT` in the maintained Scalingo sample. Keep the start command direct so termination signals reach Node.js cleanly. + +Reference implementation: + +- [Scalingo sample Next.js standalone application][nextjs-standalone-sample] + +The sample uses `output: "standalone"`, copies `.next/static` and `public`, and starts `.next/standalone/server.js`. + +## Monorepos + +The Node.js buildpack expects a root `package.json`. For a Next.js project inside a monorepo, configure the deployed source root or child application so that the relevant workspace root is presented to the buildpack. + +If standalone tracing must include files outside the Next.js project directory, configure the appropriate Next.js tracing root and test the resulting runtime bundle. This is Next.js behavior, not automatic buildpack monorepo discovery. + +## Static exports + +A fully static Next.js export does not require a Node.js server at runtime. Use the platform’s static-application guidance or a documented static web-server buildpack pattern rather than starting the Next.js development server. + +Do not use `next dev` in production. + +## Image size + +Standard Next.js applications can produce large runtime images because they include framework dependencies, build output, source files, and caches. Standalone mode can reduce the required runtime file set, but it is not a substitute for inspecting large dependencies and generated assets. + +Check: + +- `.next/cache` is cached rather than shipped unnecessarily; +- source maps and test artifacts are included only when needed; +- `scalingo-cleanup` does not delete required standalone files; +- native dependencies such as image-processing libraries support the selected Node.js and Scalingo stack. + +## Graceful shutdown + +Scalingo sends termination signals during deployments and scaling operations. Next.js should be started through a command that allows the Node.js process to receive those signals. + +Prefer: + +```text +web: node .next/standalone/server.js +``` + +or the direct `next start` process provided by `npm start`. Avoid unnecessary shell or package-manager wrappers when signal behavior is uncertain. + +## Troubleshooting + +### Boot timeout + +Confirm that the start command uses `PORT` and binds to `0.0.0.0`. + +### Static assets return 404 in standalone mode + +Copy `.next/static` into `.next/standalone/.next/static` and `public` into `.next/standalone/public` after the build. + +### `next: not found` at runtime + +Ensure `next`, `react`, and `react-dom` are in `dependencies`. Alternatively, use the standalone server command. + +### Build-time environment variable is missing + +Set the variable before deployment. A variable required by `next build` cannot be added only after the build has completed. + +### Native image dependency fails + +Update the package, confirm Node.js compatibility, and see [Manage Native Modules and System Dependencies]({% post_url languages/nodejs/2000-01-01-extensions %}). + +### Runtime image is too large + +Try standalone mode, remove unnecessary generated files, inspect dependency size, and avoid shipping build caches as runtime content. + +## Related documentation + +- [Select a Node.js Version]({% post_url languages/nodejs/2000-01-01-selecting-a-version %}) +- [Default Node.js Build and Runtime Behavior]({% post_url languages/nodejs/2000-01-01-default-behavior %}) +- [Use npm]({% post_url languages/nodejs/2000-01-01-npm %}) +- [Use Yarn]({% post_url languages/nodejs/2000-01-01-yarn %}) +- [Use pnpm]({% post_url languages/nodejs/2000-01-01-pnpm %}) +- [Troubleshoot Node.js Deployments]({% post_url languages/nodejs/2000-01-01-troubleshooting %}) + +[nextjs-standalone-sample]: https://github.com/Scalingo/sample-nextjs-standalone diff --git a/src/_posts/platform/app/2000-01-01-slugignore.md b/src/_posts/platform/app/2000-01-01-slugignore.md index 41671bb91..711d74ac0 100644 --- a/src/_posts/platform/app/2000-01-01-slugignore.md +++ b/src/_posts/platform/app/2000-01-01-slugignore.md @@ -111,4 +111,4 @@ Godeps You're deploying a Next.js application but the image size is too big. You can try to run Next.js in standalone mode. -More information here: [Next.js in standalone mode]({% post_url languages/nodejs/2000-01-01-nextjs-standalone %}). +More information here: [Deploy Next.js]({% post_url languages/nodejs/frameworks/2000-01-01-nextjs %}#standalone-mode). diff --git a/src/_posts/platform/deployment/buildpacks/2000-01-01-wkhtmltopdf.md b/src/_posts/platform/deployment/buildpacks/2000-01-01-wkhtmltopdf.md index f431ce502..059506da0 100644 --- a/src/_posts/platform/deployment/buildpacks/2000-01-01-wkhtmltopdf.md +++ b/src/_posts/platform/deployment/buildpacks/2000-01-01-wkhtmltopdf.md @@ -5,7 +5,7 @@ tags: buildpacks build wkhtmltopdf --- {% warning %} -Wkhtmltopdf repository is deprecated since January 2023. You should rather use [Puppeteer]({% post_url languages/nodejs/2000-01-01-puppeteer %}) and the [`pdf`](https://pptr.dev/api/puppeteer.page.pdf/) method. +Wkhtmltopdf repository is deprecated since January 2023. You should rather use [Puppeteer with the required system dependencies]({% post_url languages/nodejs/2000-01-01-extensions %}#use-puppeteer-or-another-headless-browser) and the [`pdf`](https://pptr.dev/api/puppeteer.page.pdf/) method. {% endwarning %} ## Purpose of This Buildpack