Run JavaScript Inside Nginx with njs: A Hands‑On Guide

This article introduces njs, the JavaScript engine for Nginx, explains its basic "Hello world" example and walks through advanced features such as filesystem APIs, asynchronous I/O, shared memory, response handling, logging, and the global namespace, all with concrete code snippets.

Full-Stack Cultivation Path
Full-Stack Cultivation Path
Full-Stack Cultivation Path
Run JavaScript Inside Nginx with njs: A Hands‑On Guide

Introduction

JavaScript is known for flexibility across front‑end, back‑end, desktop and mobile. The article explores using JavaScript inside Nginx via the njs engine.

What is njs?

njs is a subset of JavaScript that runs directly in Nginx. It implements ECMAScript 5.1 strict mode and supports many ES6+ features, allowing familiar syntax to write Nginx modules for access control, security checks, and response‑header manipulation.

Typical Use Cases

Fine‑grained access control and security checks before upstream requests.

Response‑header manipulation to meet business requirements.

Asynchronous content handlers and filters to boost processing capacity.

Basic HTTP Example

A minimal njs script returns “Hello world!” and the corresponding Nginx configuration.

njs script (http.js)

function hello(r) {
    r.return(200, "Hello world!");
}
export default {hello};

Nginx configuration

load_module modules/ngx_http_js_module.so;

events {}

http {
    js_import http.js;

    server {
        listen 8000;

        location / {
            js_content http.hello;
        }
    }
}

Visiting the root URL triggers the script and returns “Hello world!”.

Advanced njs Features

Beyond basic request handling, njs provides filesystem APIs, asynchronous operations, shared memory, response handling, logging, and a global namespace.

Filesystem API

Common functions include: access() – check file permissions. open() – open files (sync/async). readdir() – read directory contents. realpath() – resolve absolute path. rename() – rename files or directories. unlink() – delete files. rmdir() – delete directories (recursive). stat() – get file status. symlink() – create symbolic links.

Asynchronous Processing

njs supports promises, enabling non‑blocking I/O. Example reads a file and returns different status codes based on accessibility.

function asyncExample(r) {
    // Asynchronous file check
    fs.promises.access('/path/to/file', fs.constants.R_OK).then(() => {
        r.return(200, 'File is accessible');
    }).catch(() => {
        r.return(403, 'File is not accessible');
    });
}
export default { asyncExample };

Shared Memory

Shared memory zones let multiple worker processes exchange data.

// Set shared data
function setSharedData(r) {
    const shared = ngx.shared.my_shared_zone;
    shared.set('key', 'value');
    r.return(200, 'Data set in shared memory');
}

// Get shared data
function getSharedData(r) {
    const shared = ngx.shared.my_shared_zone;
    const value = shared.get('key');
    r.return(200, value || 'No data found');
}
export default { setSharedData, getSharedData };

Responding to Clients

njs can send headers, body chunks, and finish the response.

function respondExample(r) {
    r.sendHeader();
    r.send('Hello, ');
    r.send('world!');
    r.finish();
}
export default { respondExample };

Logging

Different log levels are available via ngx.log.

function logExample(r) {
    ngx.log(ngx.INFO, 'This is an info message.');
    ngx.log(ngx.WARN, 'This is a warning message.');
    ngx.log(ngx.ERR, 'This is an error message.');
    r.return(200, 'Logged messages');
}
export default { logExample };

Global Namespace

Both njs and ngx expose global functions and variables.

function globalNamespaceExample(r) {
    // Get njs version, e.g., '0.4.7'
    njs.version;
    ngx.log(ngx.INFO, 'Using njs version: ' + njs.version);
    const shared = ngx.shared.my_shared_zone;
    shared.set('key', 'value');
    r.return(200, 'Global namespace example');
}
export default { globalNamespaceExample };

Conclusion

The examples demonstrate how njs enables asynchronous processing, shared memory, client responses, logging, and global‑namespace usage, extending Nginx with the flexibility of JavaScript while retaining high performance.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaScriptNginxshared memoryasynchronous processingnjsfilesystem APIserver scripting
Full-Stack Cultivation Path
Written by

Full-Stack Cultivation Path

Focused on sharing practical tech content about TypeScript, Vue 3, front-end architecture, and source code analysis.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.