Monday, 24 November 2025

How to run Node, npm, Prettier, Yarn and Serverless via Docker

 

We sometimes don't want to pollute our local machine by installing Node if we don't use it often. In this scenario we can run a desired version of Node via Docker container:

docker run --rm \
  node:16-alpine \
  sh -c "node --version"

Output:

v16.20.2


Running npm

The above also means that we can use Node tools against our local Node application repository, without the need to install Node locally:

docker run --rm \
  -v "$PWD":/app \
  -w /app \
  node:16-alpine \
  sh -c "npm install && npm audit"


We can run npm audit fix to fix critical issues and npm audit fix --force to address all issues (including breaking changes).


The above command should be run from the project's root directory.

If package.json lists some dependencies from a private package hosted on GitHub Packages e.g.:

  "dependencies": {
    ...
    "@foo/bar": "^0.5.4",
    ...
  } 

...and inside Docker there is no GitHub token, npm install might throw this error if npm can't be authenticated against GitHub:

npm ERR! 401 Unauthorized - GET https://npm.pkg.github.com/download/@foo/bar/0.5.4/db46279e9b10a74cec83b15ac06422c479e4d193fd3c8366c839ace085244c9b - authentication token not provided

This token is GitHub Personal Access Token (PAT) and it should have a permission to read our private npm package.

If our local machine is authenticating via GitHub CLI (gh) we can run:

gh auth token

Output is PAT that npm can use and it will be in this format:

ghp_xxx...

We can store this value in the local env variable:

export NODE_AUTH_TOKEN=$(gh auth token)

We now need to create a local .npmrc file which contains authentication 

echo "@foo:registry=https://npm.pkg.github.com/" > .npmrc
echo "//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}" >> .npmrc

...so .npmrc file will look like this:

@foo:registry=https://npm.pkg.github.com/
//npm.pkg.github.com/:_authToken=ghp_aAT3B3N...iiOO

If we try to execute npm install again, the issue with missing token should be resolved now.


Running Prettier

If prettier is added as devDependency in NodeJS project and .prettierrc config file is provided we can run prettier from Node Docker container, with no need to install Node on the local machine:

To find style errors:

docker run --rm \     
  -v "$PWD":/app \
  -w /app \
  node:18-alpine \
  sh -c "npm install && npx prettier --ignore-path .gitignore --check '**/*.+(ts|js|json|yml)'"

To fix the reported style errors:

docker run --rm \     
  -v "$PWD":/app \
  -w /app \
  node:18-alpine \
  sh -c "npm install && npx prettier --ignore-path .gitignore --write '**/*.+(ts|js|json|yml)'"


Running yarn

Node Docker image comes with yarn installed so we can use it just as we used npm:

docker run --rm \
  -v "$PWD":/app \
  -w /app \
  node:18-alpine \
  sh -c "yarn install --frozen-lockfile && yarn audit --audit-level=critical"


To remove some dependency:

docker run --rm \
  -v "$PWD":/app \
  -w /app \
  node:20-alpine \
  sh -c "yarn remove serverless-esbuild" 

Running Serverless


If we have Node-based Serverless project, we can run Serverless deployment from Node Docker container: 

docker run --rm \
  -v "$PWD":/app \
  -w /app \
  -e SERVERLESS_ACCESS_KEY=xxxx \
  node:18-alpine \
  sh -c "npm install -g serverless && yarn install --frozen-lockfile && yarn sls deploy --stage development"


Or like here:

docker run --rm \                              
  -v "$PWD":/app \
  -w /app -e SERVERLESS_ACCESS_KEY=xxxx \
  node:22-alpine \
  sh -c "npm install -g serverless && npm ci && sls deploy --stage development" 


Running tsc


docker run --rm \
  -v "$PWD":/app \
  -w /app -e SERVERLESS_ACCESS_KEY=xxx \
  node:22-alpine \
  sh -c "npm install -g serverless && npm ci && npx tsc -p ./tsconfig.json --noEmit --skipLibCheck"

---

How to run TypeScript compiler (tsc) via Docker

 

TypeScript compiler, often referred to as tsc , is responsible for compiling TypeScript code into JavaScript. It takes TypeScript source files as input and generates equivalent JavaScript files that can run in any JavaScript environment, ensuring compatibility with browsers.

If for any reason we don't want to install TypeScript compiler on our machine but want to use it to check the TypeScript syntax in the project, we can run in from a Docker container.

Let's first formulate a command which only checks the syntax:

tsc \
   --project ./tsconfig.json \
   --noEmit \
   --skipLibCheck

--project ./tsconfig.json - specifies the project configuration file (we can also use the short version of --project which is -p). tsc will compile only files included by that config.

--noEmit - TypeScript performs type-checking only, but does not output any .js, .d.ts, or build artifacts. Useful for: CI validation, pre-commit checks, linting purely for types, speeding up checks when we don’t care about compiled output.

--skipLibCheck - Tells TS not to check types inside node_modules or .d.ts libraries. This makes type checking much faster and avoids irrelevant type errors from dependencies. It skips: DefinitelyTyped typings, node_modules/*/*.d.ts, any imported library declaration file.


Before running TypeScript compiler, we need to install project's dependencies by running:

npm install

This is because:
  • This installs tsc (if package.json lists typescript among devDependencies, which it should in our case)
  • tsc must load types from our dependencies (@types/..., or any .d.ts shipped by packages).
  • Without node_modules, TypeScript cannot resolve imports like:
                import express from "express";

          and type-checking will fail.


If we have Node installed locally, we can run npm install before running Docker but otherwise, we can just invoke npm from the Docker image (npm install will install tsc):

docker run --rm \
  -v "$PWD":/app \
  -w /app \
  node:20-alpine \
  sh -c "npm install && npx tsc -p ./tsconfig.json --noEmit --skipLibCheck --listFiles --diagnostics"

-v "$PWD":/app - mounts our current directory to the container
-w /app - sets the working directory
node:20-alpine - lightweight Node image
npm install && npx tsc ... - installs project dependencies and runs TypeScript from our local node_modules


I also added --listFiles and --diagnostics flags, so tsc outputs something even if checks of all files pass as otherwise it will not emit any message.


If we are using Yarn instead of npm, we can call tsc directly from yarn:

docker run --rm \
  -v "$PWD":/app \
  -w /app \
  node:20-alpine \
  sh -c "yarn && yarn tsc -p ./tsconfig.json --noEmit --skipLibCheck"


---