How to Secure Your Hono App with SecureNow — ESM-Ready Tracing for Modern Node.js

Complete walkthrough for adding security monitoring to a Hono application with SecureNow. Covers the ESM preload pattern, body capture limitations, and production deployment.

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

How to Secure Your Hono App with SecureNow — ESM-Ready Tracing for Modern Node.js

Hono is one of the fastest-growing web frameworks in the Node.js ecosystem — lightweight, multi-runtime, and built on Web Standard APIs. If you have picked Hono for your next API, adding security observability takes just one npm package and a single CLI flag.

There are two things to know upfront: Hono uses ESM, so you need the -r preload flag instead of a require() call; and body capture must be disabled because Hono uses ReadableStream bodies that conflict with Node.js stream hooks. This guide covers both caveats in detail, along with every other step from install to production deployment.

...

Prerequisites

  • Node.js 18+ installed
  • An existing Hono project using @hono/node-server (or willingness to scaffold one)
  • A terminal and a browser

No SecureNow account yet? The CLI will open a browser-based signup/login flow for you.

...

Step 1: Install the Package

npm install securenow

Your project should already have hono and @hono/node-server installed. SecureNow does not require any Hono-specific adapter — it instruments the underlying Node.js http module that @hono/node-server uses internally.

...

Step 2: Log In via the CLI

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.

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)

npx securenow apps create my-hono-api

Choose Free Trial when prompted. Output:

✔ Application created

  SECURENOW_APPID=a1b2c3d4-e5f6-7890-abcd-ef1234567890
  SECURENOW_INSTANCE=https://freetrial.securenow.ai:4318

Add these to your .env file.

Optionally set it as your default:

npx securenow config set defaultApp a1b2c3d4-e5f6-7890-abcd-ef1234567890
...

Step 4: Configure Environment Variables

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

SECURENOW_APPID=a1b2c3d4-e5f6-7890-abcd-ef1234567890
SECURENOW_INSTANCE=https://freetrial.securenow.ai:4318
SECURENOW_LOGGING_ENABLED=1
SECURENOW_CAPTURE_BODY=0
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_BODYMust be 0 for Hono. Hono uses ReadableStream bodies that conflict with Node.js stream-based capture. URL parameters, headers, and trace metadata are still fully captured.
...

Step 5: Instrument Your Hono App

Hono uses ES modules — your entry file is .mjs (or your package.json has "type": "module"). You cannot use require() inside ESM. Instead, preload SecureNow using the -r flag when starting Node.js.

Here is a complete Hono server in app.mjs:

import { serve } from '@hono/node-server';
import { Hono } from 'hono';

const app = new Hono();

app.get('/api/health', (c) => {
  return c.json({ status: 'ok' });
});

app.get('/api/users', (c) => {
  console.log('Fetching users', { query: c.req.query() });
  return c.json([
    { id: 1, name: 'Alice' },
    { id: 2, name: 'Bob' },
  ]);
});

app.post('/api/users', async (c) => {
  const body = await c.req.json();
  console.info('Creating user', { email: body.email });
  return c.json({ id: 3, ...body }, 201);
});

app.get('/api/users/:id', (c) => {
  const id = c.req.param('id');
  return c.json({ id: Number(id), name: 'Alice' });
});

app.onError((err, c) => {
  console.error('Unhandled error', err);
  return c.json({ error: 'Internal server error' }, 500);
});

const PORT = process.env.PORT || 3000;
serve({ fetch: app.fetch, port: Number(PORT) }, (info) => {
  console.log(`Server running on port ${info.port}`);
});

Notice there is no SecureNow import in the file. The instrumentation is loaded externally via the -r flag.

The Critical Command

node -r securenow/register app.mjs

The -r flag tells Node.js to execute securenow/register (a CommonJS script) before the ESM loader processes app.mjs. This gives the OTel SDK time to monkey-patch the http module before Hono's node-server adapter creates the HTTP listener.

To also forward console logs:

node -r securenow/register -r securenow/console-instrumentation app.mjs

Adding to package.json

{
  "type": "module",
  "scripts": {
    "start": "node app.mjs",
    "start:observe": "node -r securenow/register -r securenow/console-instrumentation app.mjs"
  }
}
...

Step 6: Start and Verify

node -r securenow/register -r securenow/console-instrumentation app.mjs

You should see:

[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
Server running on port 3000

Generate some traffic:

curl http://localhost:3000/api/health
curl http://localhost:3000/api/users
curl http://localhost:3000/api/users/1
curl -X POST http://localhost:3000/api/users -H "Content-Type: application/json" -d '{"name":"Charlie","email":"charlie@example.com"}'

Check your dashboard:

npx securenow status

You should see your app listed as protected. Browse traces:

npx securenow traces

Or open the full dashboard at app.securenow.ai.

...

Bonus: Useful CLI Commands

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

For production, use PM2 with an ecosystem config. The key difference for Hono is passing the preload via node_args and pointing script to the .mjs file:

// ecosystem.config.cjs
module.exports = {
  apps: [{
    name: 'my-hono-api',
    script: './app.mjs',
    instances: 4,
    exec_mode: 'cluster',
    node_args: '-r securenow/register -r securenow/console-instrumentation',
    env: {
      SECURENOW_APPID: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
      SECURENOW_INSTANCE: 'https://freetrial.securenow.ai:4318',
      SECURENOW_LOGGING_ENABLED: '1',
      SECURENOW_CAPTURE_BODY: '0',
      SECURENOW_NO_UUID: '1',
      NODE_ENV: 'production',
    }
  }]
};
pm2 start ecosystem.config.cjs

Setting SECURENOW_NO_UUID=1 ensures all cluster workers report under the same service name. The ecosystem file uses .cjs because PM2 config must be CommonJS even when your app is ESM.

...

Docker Deployment

FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
ENV SECURENOW_APPID=my-hono-api
ENV SECURENOW_INSTANCE=https://freetrial.securenow.ai:4318
ENV SECURENOW_LOGGING_ENABLED=1
ENV SECURENOW_CAPTURE_BODY=0
ENV NODE_ENV=production
EXPOSE 3000
CMD ["node", "-r", "securenow/register", "-r", "securenow/console-instrumentation", "app.mjs"]
...

What SecureNow Detects Automatically

Once traces are flowing, SecureNow watches for:

  • SQL injection — malicious patterns in query parameters and URL paths
  • 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

All detection works from URL, headers, and trace metadata — body capture is not required. Issues surface in the dashboard and can trigger alerts via email, Slack, or custom webhooks.

...

Recap

StepCommand / ActionTime
Installnpm install securenow10 s
Loginnpx securenow login20 s
Create appnpx securenow apps create my-hono-api15 s
ConfigureAdd env vars to .env (body capture OFF)30 s
InstrumentUse -r securenow/register flag10 s
Verifynpx securenow status10 s

One flag, one package, zero code changes. Your Hono API is now observable and protected.

...

Next Steps

Happy shipping — and happy securing.

Frequently Asked Questions

Why can't I use require('securenow/register') in my Hono app?

Hono applications use ES modules (.mjs files or 'type': 'module' in package.json). ESM does not support require(). Instead, use the -r flag to preload the module: node -r securenow/register app.mjs. The -r flag runs CommonJS preload scripts before the ESM loader kicks in.

Why doesn't body capture work with Hono?

Hono uses web-standard ReadableStream bodies via the Fetch API rather than Node.js Readable streams. SecureNow's body capture hooks into Node.js streams, which conflicts with Hono's stream handling. Set SECURENOW_CAPTURE_BODY=0 to avoid issues. Request metadata, headers, and URL parameters are still fully captured.

Can I use SecureNow with Hono running on Bun or Deno?

SecureNow is built on the Node.js OpenTelemetry SDK and requires a Node.js runtime. For Hono apps running on @hono/node-server, it works perfectly. Bun and Deno runtimes are not currently supported.

Does SecureNow detect attacks even without body capture?

Yes. Most attack detection — SQL injection in query strings, path traversal, anomalous traffic patterns, credential stuffing, and IP reputation — works from URL, headers, and trace metadata alone. Body capture adds coverage for POST-body injection patterns but is not required.

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