Run npm Packages Without Installing Node.js
Want to use an npm package without installing Node.js? Learn how to use a simple shell alias with Podman or Docker to run any tool in an isolated container. This keeps your host system clean while giving you on-demand access to any package. Here’s how to set it up.

Ever needed to run a single command-line tool from npm but didn't want to install Node.js and its whole ecosystem on your machine? Maybe you want to keep your development environment clean or avoid potential version conflicts. It turns out there’s a clean and simple way to do this using containers.
This approach lets you use any npm package on-demand without it ever touching your host system's configuration. Here’s how to do it.
The Goal: Running pyright-langserver
As a practical example, let's say we want to run pyright-langserver
, the language server for Python from Microsoft. The goal is to run it directly from the command line as if it were installed locally, but have it execute inside a container instead.
The Solution: A Handy Shell Alias
The magic lies in a single, powerful shell alias. You can add this to your .bashrc
, .zshrc
, or equivalent shell configuration file.
alias pyright-langserver='podman run --rm -it -v "$(pwd):$(pwd):Z" -w "$(pwd)" --user "${UID}:${UID}" docker.io/node:lts-alpine npx --yes --loglevel=silent --logs-max=0 --package=pyright pyright-langserver'
Let's break down what each part of this command does:
alias pyright-langserver='...'
: This creates a new command (an alias),pyright-langserver
, in our shell.podman run
: This is the command to run a container using Podman (this works similarly with Docker).--rm
: This flag automatically removes the container after it stops. This is great for one-off commands, as it prevents cluttering your system with stopped containers.-it
: This allocates an interactive terminal, which is necessary for using a command-line tool.-v "$(pwd):$(pwd):Z"
: This is a critical step. It mounts the current working directory (pwd) on your host machine to the exact same path inside the container. Now the container can see and operate on your project files. The:Z
at the end is an SELinux label that ensures the container has the correct permissions to read/write to the mounted volume.-w "$(pwd)"
: This sets the working directory inside the container to the path we just mounted. This ensures that when the command runs, it runs from your current project folder.--user "${UID}:${UID}"
: This runs the command inside the container with your current user and group ID. This is crucial for avoiding permission errors. Any files the container creates will be owned by you, not root.docker.io/node:lts-alpine
: This is the container image we are using. It's a minimal, lightweight official image with the Long-Term Support (LTS) version of Node.js.npx --yes ... pyright-langserver
: This is the command that gets executed inside the container.npx
is the Node Package Runner. It downloads the specified package to a temporary cache, runs the command, and then cleans up.--yes
automatically accepts any prompts fromnpx
.--package=pyright
tellsnpx
which package to download and use.pyright-langserver
is the actual executable from thepyright
package that we want to run. This might be different to the package name.
How to Use It
After adding the alias to your shell configuration and reloading your shell (e.g., by running source ~/.bashrc
or opening a new terminal), you can now use the command as if it were installed natively.
For example, start the language server to see the output.
pyright-langserver --stdio
Content-Length: 119
{"jsonrpc":"2.0","method":"window/logMessage","params":{"type":3,"message":"Pyright language server 1.1.403 starting"}}Content-Length: 172
{"jsonrpc":"2.0","method":"window/logMessage","params":{"type":3,"message":"Server root directory: file:///home/node/.npm/_npx/110e52990071af13/node_modules/pyright/dist"}}
And that's it! You've successfully run an npm package without installing Node.js on your host machine. This pattern is incredibly versatile and can be adapted for almost any command-line tool available on npm.
Potential Drawbacks
While this method is great for isolation and cleanliness, it's important to be aware of the trade-offs:
- Slower Startup Time: There is a noticeable overhead compared to a native installation. The first time you run the command,
podman
has to download thedocker.io/node:lts-alpine
image. On subsequent runs, it still has to create a new container and download the npm package, which takes a moment. For frequently used, quick-running tools, this delay might be inconvenient. - OS Integration Issues: This approach is best for self-contained command-line tools. Certain packages that need to interact closely with the host operating system, manage system services, access specific hardware, or launch a GUI may not work seamlessly or at all without complex container configuration.