How to Secure Your NestJS App with SecureNow — TypeScript-Native Tracing and Threat Detection

End-to-end guide to adding security monitoring to your NestJS application using the securenow npm package. Covers instrument.js setup, TypeScript compatibility, PM2, Docker, and dashboard verification.

Lhoussine
Mar 26, 2026·9 min read
getting started securenow nestjs

How to Secure Your NestJS App with SecureNow — TypeScript-Native Tracing and Threat Detection

NestJS gives you a structured, TypeScript-first framework for building scalable server-side applications. But structure alone does not tell you who is calling your API, whether those requests are malicious, or what attack patterns are emerging across your endpoints.

SecureNow captures every HTTP request flowing through your NestJS app as an OpenTelemetry trace. Those traces feed a security analysis engine that detects SQL injection, credential stuffing, API abuse, and anomalous traffic — without modifying your controllers, guards, interceptors, or module definitions.

Because NestJS is TypeScript-based, the instrumentation approach differs slightly from plain JavaScript frameworks: you create a small instrument.js file and preload it before your app starts. This guide covers the full setup, from installation to production deployment.

...

Prerequisites

  • Node.js 18+ installed
  • An existing NestJS project (generated via @nestjs/cli or equivalent)
  • ts-node available (included with @nestjs/cli projects by default)
  • A terminal and a browser

No SecureNow account yet? The CLI handles signup for you.

...

Step 1: Install the Package

From your project directory:

npm install securenow

This single package includes the OpenTelemetry SDK, auto-instrumentations for Node.js, an OTLP exporter, the SecureNow CLI, and optional console-log forwarding. Your NestJS dependencies (@nestjs/core, @nestjs/common, etc.) should already be in your project.

...

Step 2: Log In via the CLI

Authenticate with SecureNow:

npx securenow login

A browser tab opens at app.securenow.ai where you can sign up or log in. The token is saved to ~/.securenow/credentials.json and authorizes all subsequent CLI commands.

Prefer a non-interactive flow? Generate a CLI token from your dashboard at Settings → CLI Token, then run:

npx securenow login --token YOUR_TOKEN

Verify you are logged in:

npx securenow whoami
...

Step 3: Create an Application (Free Trial)

Every monitored application gets a unique identifier (the app key). Create one:

npx securenow apps create my-nestjs-api

When prompted to pick a ClickHouse instance, choose Free Trial — this gives you a managed OTLP collector at https://freetrial.securenow.ai:4318 at no cost and with no credit card.

After creation:

✔ Application created

  SECURENOW_APPID=e5f6a7b8-c9d0-1234-5678-9abcdef01234
  SECURENOW_INSTANCE=https://freetrial.securenow.ai:4318

Add these to your .env file.

Set the new app as your default:

npx securenow config set defaultApp e5f6a7b8-c9d0-1234-5678-9abcdef01234
...

Step 4: Configure Environment Variables

Create (or update) a .env file in your project root:

SECURENOW_APPID=e5f6a7b8-c9d0-1234-5678-9abcdef01234
SECURENOW_INSTANCE=https://freetrial.securenow.ai:4318
SECURENOW_LOGGING_ENABLED=1
SECURENOW_CAPTURE_BODY=1
VariablePurpose
SECURENOW_APPIDIdentifies your app in the dashboard. Use the key from Step 3.
SECURENOW_INSTANCEOTLP collector URL. Free trial default shown above.
SECURENOW_LOGGING_ENABLEDSet to 1 to forward console.log/warn/error as OTel logs.
SECURENOW_CAPTURE_BODYSet to 1 to attach request bodies to trace spans. NestJS supports body capture fully. Sensitive fields are automatically redacted.
...

Step 5: Create the Instrumentation File

This is the key step that differs from plain JavaScript frameworks. Create a file called instrument.js in your project root (the same directory as package.json and tsconfig.json):

// instrument.js
require('securenow/register');
require('securenow/console-instrumentation');

That is the entire file — two lines. It must be plain JavaScript (not TypeScript) because it is loaded before ts-node or the compiled output.

Important: Do not modify src/main.ts. Your NestJS entry file stays exactly as-is. The instrument.js file is preloaded via the -r flag, so the OpenTelemetry SDK initializes before NestFactory.create() runs.

...

Step 6: Update Your Package Scripts

Update your package.json scripts to preload instrument.js in both development and production modes:

{
  "scripts": {
    "start:dev": "node -r ./instrument.js -r ts-node/register src/main.ts",
    "start": "node -r ./instrument.js dist/main.js",
    "build": "nest build"
  }
}
ScriptWhat It Does
start:devLoads instrument.js, then ts-node/register for TypeScript compilation, then your NestJS entry file. Used during development.
startLoads instrument.js, then runs the compiled JavaScript output. Used in production after nest build.
buildStandard NestJS build — compiles TypeScript to dist/. No changes needed.

Your src/main.ts remains untouched. Here is a typical NestJS entry file for reference:

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(process.env.PORT || 3000);
}
bootstrap();
...

Step 7: Example NestJS Application

Here is a minimal controller and module to illustrate what gets traced:

// src/app.controller.ts
import { Controller, Get, Post, Body, HttpCode } from '@nestjs/common';

interface CreateTaskDto {
  title: string;
  description?: string;
  priority?: 'low' | 'medium' | 'high';
}

@Controller()
export class AppController {
  @Get('health')
  getHealth() {
    return { status: 'ok', timestamp: new Date().toISOString() };
  }

  @Post('tasks')
  @HttpCode(201)
  createTask(@Body() body: CreateTaskDto) {
    return {
      id: Date.now(),
      ...body,
      createdAt: new Date().toISOString(),
    };
  }
}
// src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';

@Module({
  controllers: [AppController],
})
export class AppModule {}

SecureNow auto-instruments every route registered through NestJS controllers. The @Get, @Post, @Put, @Delete decorators all produce properly named trace spans.

...

Step 8: Start and Verify

Run in development mode:

npm run start:dev

You should see confirmation in your terminal:

[securenow] OTel SDK started → https://freetrial.securenow.ai:4318/v1/traces
[securenow] 📋 Logging: ENABLED → https://freetrial.securenow.ai:4318/v1/logs
[securenow] Console instrumentation installed
[Nest] LOG [NestFactory] Starting Nest application...
[Nest] LOG [NestApplication] Nest application successfully started

Generate some traffic:

curl http://localhost:3000/health
curl -X POST http://localhost:3000/tasks -H "Content-Type: application/json" -d '{"title":"Deploy to staging","priority":"high"}'

Then check your dashboard:

npx securenow status

Your app should appear as protected. Browse traces from the terminal:

npx securenow traces

Or open app.securenow.ai to explore traces, logs, security issues, and analytics.

...

Bonus: Useful CLI Commands

Once your app is instrumented, the CLI becomes your terminal-based control plane:

CommandWhat It Does
securenow tracesList recent traces
securenow traces show <traceId>Inspect a single trace
securenow traces analyze <traceId>AI-powered trace analysis
securenow logsList recent logs
securenow issuesView detected security issues
securenow analyticsTraffic and performance analytics
securenow ip <address>Look up an IP address
securenow blocklist add <ip>Block a malicious IP
securenow alerts rulesManage alert rules
securenow forensicsRun natural-language forensic queries
...

Production Deployment with PM2

Build your NestJS project first, then deploy with PM2:

npm run build
// ecosystem.config.js
module.exports = {
  apps: [{
    name: 'my-nestjs-api',
    script: 'dist/main.js',
    instances: 4,
    exec_mode: 'cluster',
    node_args: '-r ./instrument.js',
    env: {
      SECURENOW_APPID: 'e5f6a7b8-c9d0-1234-5678-9abcdef01234',
      SECURENOW_INSTANCE: 'https://freetrial.securenow.ai:4318',
      SECURENOW_LOGGING_ENABLED: '1',
      SECURENOW_CAPTURE_BODY: '1',
      SECURENOW_NO_UUID: '1',
      NODE_ENV: 'production',
    }
  }]
};
pm2 start ecosystem.config.js

The PM2 config points script to dist/main.js (the compiled output) and uses node_args to preload instrument.js. Setting SECURENOW_NO_UUID=1 ensures all cluster workers report under the same service name.

...

Docker Deployment

FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
ENV SECURENOW_APPID=my-nestjs-api
ENV SECURENOW_INSTANCE=https://freetrial.securenow.ai:4318
ENV SECURENOW_LOGGING_ENABLED=1
ENV SECURENOW_CAPTURE_BODY=1
ENV NODE_ENV=production
EXPOSE 3000
CMD ["node", "-r", "./instrument.js", "dist/main.js"]

The CMD preloads instrument.js before running the compiled NestJS output. Make sure instrument.js is in the Docker build context (it lives at the project root alongside package.json).

...

What SecureNow Detects Automatically

Once traces are flowing, SecureNow watches for:

  • SQL injection — malicious patterns in query parameters and request bodies
  • XSS attempts — script injection in user input
  • Credential stuffing — high-velocity failed authentication attempts
  • API abuse — unusual request patterns, rate-limit evasion, unauthorized endpoint access
  • Anomalous traffic — AI-powered detection of behavioral outliers
  • Supply-chain signals — unexpected outbound calls from your service
  • Performance degradation — slow queries, high error rates, latency spikes

NestJS guards that reject requests still generate traces, so SecureNow can detect patterns like repeated 403 Forbidden responses from a single IP — a strong signal for brute-force or enumeration attacks.

...

Recap

StepCommand / ActionTime
Installnpm install securenow10 s
Loginnpx securenow login20 s
Create appnpx securenow apps create my-nestjs-api15 s
ConfigureAdd env vars to .env30 s
Create instrument.jsTwo-line file at project root15 s
Update scriptsAdd -r ./instrument.js to start commands30 s
Verifynpm run start:devnpx securenow status20 s

Seven steps, under five minutes, zero changes to your NestJS source code. Your application is now observable and protected.

...

Next Steps

Happy shipping — and happy securing.

Frequently Asked Questions

Why do I need a separate instrument.js file for NestJS?

NestJS uses TypeScript and compiles via ts-node (dev) or tsc (production). OpenTelemetry instrumentation must be loaded before any application code is imported. A plain JavaScript instrument.js file preloaded with -r ./instrument.js ensures the SDK initializes before TypeScript compilation and NestJS bootstrap begin.

Does SecureNow work with NestJS guards, interceptors, and pipes?

Yes. SecureNow instruments at the HTTP transport layer, so guards, interceptors, pipes, and exception filters all execute normally. Requests blocked by guards still generate traces — useful for detecting unauthorized access attempts.

Can I use the same setup for development and production?

The instrument.js file is identical for both. In development you run node -r ./instrument.js -r ts-node/register src/main.ts. In production, after running nest build, you run node -r ./instrument.js dist/main.js. The preload flag is the same — only the entry file changes.

Do I need to modify src/main.ts at all?

No. Your src/main.ts stays completely unchanged. The instrument.js file is loaded before main.ts via the -r flag, so the OpenTelemetry SDK is initialized before NestFactory.create() is called. No imports, decorators, or module changes are needed in your NestJS source code.

Recommended reading

Getting Started with SecureNow and Nuxt 3 — Add Security Monitoring in Under 2 Minutes

A hands-on walkthrough for adding security observability to a Nuxt 3 app using the securenow npm package and official Nuxt module. Covers installation, nuxt.config.ts setup, environment variables, optional tuning, deployment targets, CLI verification, and troubleshooting.

Apr 2
One Flag to Trace Them All — `-r securenow/register` Now Works for ESM and CJS

Stop juggling --require and --import flags. securenow/register now auto-registers the ESM loader hook via module.register() on Node >=20.6, so a single -r flag is all you need for both CommonJS and ESM apps.

Apr 2
Add Security Monitoring to a Next.js App with SecureNow — Traces, Logs, and Body Capture on AWS

Step-by-step guide to integrating SecureNow into a self-hosted Next.js application on AWS EC2. Covers installation, instrumentation, environment configuration, verifying traces and logs, enabling request body capture, and creating alert rules.

Mar 29
deploy nextjs hacker news aws securenow