nginx njs examples: pairing nginx configs with njs scripts
NGINX JavaScript examples
At a glance
- What is it?
- nginx/njs-examples is a cookbook of runnable njs samples, each one an nginx config fragment plus a JavaScript file. It is a reading and copy starting point for people who already run nginx, not a library with a release cycle.
- Who is it for?
- Adopt this repository as a reference and a source of copyable configurations if you already operate nginx and want to see njs handlers in a real request path. Do not treat it as a dependency, since it publishes no releases and issues are handled in the separate nginx/njs mirror.
- Can I use it commercially?
- Yes. BSD-2-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 120 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A cookbook of njs samples, not a library with a release
nginx/njs-examples is a set of runnable examples for the njs scripting module rather than a library you bolt onto an application. The repository description is a single line, NGINX JavaScript examples, and the top level holds LICENSE, README.rst, conf/ and njs/. Every sample is a pair: an nginx configuration fragment under conf/ and one or more JavaScript files under njs/.
The README is explicit about the audience. It says the document and the njs documentation expect some familiarity with and understanding of nginx, and it points beginners to the official admin guide. So the readers this repository is written for are operators and backend engineers who already run nginx in production and want to see what the JavaScript layer can do inside a request path. Someone looking for a published npm package or a library with semantic versioning will find nothing of the sort here, because the repository has no GitHub releases at all.
One docker run command is the entire test loop
Running a sample does not require installing njs anywhere. The README states that njs is available as a part of the official nginx docker image as well as an officially supported package for major Linux distributions, and it then gives a single command that mounts one config file and the whole njs/ directory into a container. The EXAMPLE variable selects which conf/ file gets mounted as nginx.conf, so switching between samples is a matter of changing that one value.
The sequence to run is the following, with the container named so it can be stopped later:
git clone https://github.com/nginx/njs-examples
cd njs-examples
EXAMPLE='http/hello'
docker run --rm --name njs_example -v $(pwd)/conf/$EXAMPLE.conf:/etc/nginx/nginx.conf:ro -v $(pwd)/njs/:/etc/nginx/njs/:ro -p 80:80 -p 443:443 -d nginxStopping is done with a plain container stop, and the README notes that the public nginx image contains the open source version of nginx, so NGINX-PLUS examples require building your own image.
js_path and js_import decide where the script is found
The mechanics are visible in the hello world sample. The config loads the module, points js_path at a directory inside the container, and imports two units: a bare utils.js and a named default export from http/hello.js. Each location then binds to a function name with js_content, so the routing table and the JavaScript file are linked by string rather than by a build step.
load_module modules/ngx_http_js_module.so;
events {}
http {
js_path "/etc/nginx/njs/";
js_import utils.js;
js_import main from http/hello.js;The matching script is deliberately small, and it exports a default object so that js_content can address the handler by property name:
function hello(r) {
r.return(200, "Hello world!\n");
}
export default {hello}Checking the result takes two requests, one to the root path and one to the version path handled by utils.version:
curl http://localhost/
Hello world!
curl http://localhost/version
1.0.0There is no compilation and no package resolution. The paths inside js_path must line up with the container mounts, which is why the run command mounts both the conf/ file and the whole njs/ tree.
The access phase handler inspects the body before proxy_pass
Several examples go beyond returning a string. The access phase section covers the js_access directive, which registers a JavaScript handler that runs after the built in access checkers such as allow, deny, auth_basic and auth_request, and before the content phase. The README marks this group as requiring njs 0.9.9 or later, and it calls out support for asynchronous work (ngx.fetch(), r.subrequest(), setTimeout()) and for the request body readers r.readRequestText(), r.readRequestJSON(), r.readRequestArrayBuffer() and r.readRequestForm().
The signed request sample is the most interesting one because it drops an earlier pattern. Instead of reading the body in a named location and issuing an internal redirect, the handler reads the body in the access phase and proxy_pass forwards the unmodified body to the backend. The configuration binds the handler and the upstream side by side:
js_import main from http/access/auth_signature_body.js;
upstream backend {
server 127.0.0.1:8081;
}The script computes an HMAC over the URI, plus either the query arguments or the body, using a secret passed in through the environment:
let h = crypto.createHmac('sha1', process.env.SECRET_KEY);
h.update(r.uri);Signature failures return 401 with the computed digest in the body, which is a debugging convenience but also means the expected signature is echoed to the client. The README shows the digest being generated on the command line:
SIG=$(printf '%s' '/secure/Ba=1' | openssl dgst -sha1 -hmac foo -binary | base64)Two engines are available and the directive picks one
njs can run on top of two JavaScript engines: the built in njs engine and QuickJS. The choice is made with the js_engine directive, written as js_engine njs; or js_engine qjs;. According to the README, QuickJS offers broader ECMAScript compatibility and is the recommended engine for new deployments.
The repository does not fork into a separate tree for the two engines. The README says the examples work with both engines unless noted otherwise, so the risk is not that a sample fails outright but that a sample silently depends on behaviour that only one engine provides. That is worth checking before you copy a handler into production, since an example can be valid under the default engine and fail after you switch js_engine to qjs.
The repository also notes that njs is a native nginx module, which is why its nginx compatibility is high even though it is developed as a separate project, and that it is routinely tested against recent nginx versions across platforms and architectures.
Version floors and the absence of releases shape the upgrade cost
The most practical constraints are version numbers. Most examples in the repository work with njs 0.7.0 or later, and the ones that rely on newer features state their own minimum version, with the access phase group requiring 0.9.9 or later. To see which version an image ships, the README tells you to run the njs binary from the image directly:
`docker run -i -t nginx:latest /usr/bin/njs -V`
There are no GitHub releases, so there is no changelog to read and no upgrade path published here. The repository is also not where you file problems: the README asks that questions, issues and patches go through the official GitHub mirror at github.com/nginx/njs, because njs itself is the project under development and this repository only demonstrates it.
Licensing is simple. The repository carries a BSD-2-Clause license, so the configuration and JavaScript text can be reused with attribution and without a copyleft obligation. That matters more than usual here, because the intended use of this code is to be copied into a configuration you own. On maintenance status, the last push was on 2026-06-25, and the README describes njs itself as being in active development while production ready, with reliability backed by test coverage and customer use.
Editorial conclusion
Adopt this repository as a reference and a source of copyable configurations if you already operate nginx and want to see njs handlers in a real request path. Do not treat it as a dependency, since it publishes no releases and issues are handled in the separate nginx/njs mirror. Before you copy anything, check the njs version shipped by the image you plan to run, because most samples assume 0.7.0 or later and the access phase samples require 0.9.9 or later.
Frequently asked questions
How do I run the nginx njs examples with Docker?
Clone the repository, set the EXAMPLE variable to the conf/ file you want, and run the docker run command from the README, which mounts that config as nginx.conf and the njs/ directory into the official nginx image. Stop the container with docker stop njs_example.
Which JavaScript engine do the njs examples use, the built in engine or QuickJS?
Both are supported, and the engine is selected with the js_engine directive, either js_engine njs; or js_engine qjs;. The README says QuickJS offers broader ECMAScript compatibility and is the recommended engine for new deployments, and that the examples work with both unless noted otherwise.
How do I check which njs version the nginx Docker image ships?
The README points to running the njs binary from the image: docker run -i -t nginx:latest /usr/bin/njs -V. The version matters because most examples require njs 0.7.0 or later, and the access phase examples require 0.9.9 or later.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/nginx-njs-examples)Was this useful?