NGINX njs Scripting Prompt
Write a small, reviewable njs (NGINX JavaScript) module for request/response manipulation — header rewriting, JWT inspection, custom routing — instead of contorting the config language or reaching for Lua you don't need.
- Target user
- Engineers extending NGINX with njs for logic the config language can't express
- Difficulty
- Advanced
- Tools
- Claude, ChatGPT, Cursor
The prompt
You are a senior infrastructure engineer who uses njs sparingly and on purpose. You know njs is a restricted, non-blocking JavaScript subset — not Node — and you keep modules small, side-effect-light, and easy to review. I will provide: - What I'm trying to do that plain config can't: [DESCRIBE — e.g. transform a header, inspect a JWT claim, build a routing key] - The input available (headers, args, body, variables): [DESCRIBE] - Where it hooks in: [js_set variable / js_content handler / header/body filter] - Any hard constraints (no external calls, latency budget): [DESCRIBE] Build the solution: 1. **Confirm njs is the right tool** — first tell me if a `map`, `return`, or `add_header` would do this without scripting. Only proceed to njs if config genuinely can't express it. 2. **The module** — write a small `.js` file using the `r` request object (`r.headersIn`, `r.headersOut`, `r.args`, `r.variables`, `r.return()`). Respect njs limits: no `require` of arbitrary Node modules, non-blocking only, ES5/limited-ES6 subset. Comment every njs-specific idiom. 3. **The config wiring** — show the `js_path`, `js_import`, and the `js_set`/`js_content`/`js_header_filter` directives that connect the module, and which phase it runs in. 4. **Failure handling** — what happens if input is missing or malformed; never throw uncaught (it 500s the request). Return a safe default. Output: (a) the complete `.js` module, (b) the config snippet that loads and invokes it, (c) a curl test exercising a normal and a malformed input, and the `nginx -t` line. Keep the module under ~40 lines and easy to read. Validate with `nginx -t` and reload — do not deploy njs to prod without testing the malformed-input path.
Why this prompt works
njs is the right tool surprisingly rarely, and the biggest win this prompt delivers is the first step: making the model prove that a map, return, or add_header can’t do the job before it writes any JavaScript. Scripting in the request path is something you have to maintain, review, and reason about under load, so the cheapest njs module is the one you didn’t write. Engineers reach for it because the config language frustrated them, not because they checked whether the frustration was avoidable.
When njs genuinely is warranted, the failure modes are unforgiving. It runs inside the NGINX worker, it’s non-blocking by design, and an uncaught exception turns into a 500 for a real user. By demanding guarded input handling and a malformed-input test, the prompt steers away from the demo-quality script that works in the happy path and explodes the first time a header is absent.
The wiring step matters because njs’s phase model — js_set for variables, js_content for full handlers, header/body filters for response rewriting — is unintuitive, and the same module behaves differently depending on which directive invokes it. Forcing the model to name the phase and keep the module small produces something a reviewer can actually read and you can actually debug, rather than a clever black box wedged into the hot path.
Related prompts
-
NGINX Config Security Audit Prompt
Audit an NGINX config for the classic misconfigurations — version leakage, missing security headers, open proxy, path traversal, exposed dotfiles — and get a prioritized fix list with exact directives, not a generic checklist.
-
NGINX map & geo Conditional Routing Prompt
Replace a brittle pile of nested if blocks with clean map and geo directives — for feature flags, country routing, or per-host variables — so your config is fast, readable, and free of the 'if is evil' traps.