All Integrations
Languages@tigerops/node npm package

Express.js Integration

Auto-instrument Express.js with one npm install. Route handler spans, middleware timing, database query traces, and error capture — all with zero code changes to your routes.

Setup

How It Works

01

Install the SDK

Run npm install @tigerops/node. The SDK auto-instruments Express via the OpenTelemetry express-instrumentation plugin, which patches app.use() to track middleware registration and wrap route handlers.

02

Require Before Express

Add require("@tigerops/node/register") as the very first line of your entry point — before require("express"). This order is critical for the middleware and route instrumentation patches to apply correctly.

03

Set Environment Variables

Export TIGEROPS_API_KEY, TIGEROPS_SERVICE_NAME, and TIGEROPS_ENVIRONMENT. The SDK reads these at startup and configures the OTLP exporter. dotenv is supported for local development.

04

Routes, Middleware & DB Span

Within seconds TigerOps receives Express route spans with express.route.path and handler.name, individual middleware timing, database query child spans, and outbound HTTP spans from axios and node-fetch.

Capabilities

What You Get Out of the Box

Route Handler Tracing

Every Express route handler (GET, POST, PUT, DELETE) creates a root span with the route pattern (e.g. /users/:id), HTTP method, status code, and response time. Named middleware functions appear as child spans.

Middleware Timing

Each middleware function in the chain is individually timed and reported as a span event. Slow authentication, validation, or body parsing middleware are immediately visible in the request trace waterfall.

Router & Sub-App Nesting

Express.Router and mounted sub-apps are fully instrumented. Nested route spans correctly show the full path (e.g. /api/v1/orders/:id) including the router prefix, even when using express.Router() mounting.

Error Middleware Capture

Express error handling middleware (4-argument functions) is auto-instrumented. Errors passed via next(err) are captured with the error message, stack trace, and the route that triggered the error.

Database Query Spans

Automatic instrumentation for pg, mysql2, mongodb, ioredis, and Prisma ORM. Every database call from within an Express handler creates a child span with the normalized query and execution time.

Outbound HTTP Tracing

Calls made via axios, node-fetch, got, and the native http/https modules become child spans with the target URL, method, and status code. W3C TraceContext headers are injected for service-to-service tracing.

Configuration

Install & Initialize

One npm install. One require. Full Express.js observability.

terminal + app.js
# Install the TigerOps Node.js SDK
npm install @tigerops/node

# Set environment variables
export TIGEROPS_API_KEY="your-api-key"
export TIGEROPS_SERVICE_NAME="my-express-api"
export TIGEROPS_ENVIRONMENT="production"

# app.js — IMPORTANT: require register BEFORE express
require('@tigerops/node/register')

const express = require('express')
const { Pool } = require('pg')

const app = express()
const db = new Pool({ connectionString: process.env.DATABASE_URL })

app.use(express.json())

// This route is automatically traced
// Span: GET /orders/:id
app.get('/orders/:id', async (req, res, next) => {
  try {
    // pg query is automatically a child span
    const { rows } = await db.query(
      'SELECT * FROM orders WHERE id = $1',
      [req.params.id]
    )
    if (!rows[0]) return res.status(404).json({ error: 'Not found' })
    res.json(rows[0])
  } catch (err) {
    next(err)
  }
})

// Error middleware — errors passed to next() are auto-captured
app.use((err, req, res, next) => {
  // TigerOps already recorded this error on the active span
  res.status(500).json({ error: err.message })
})

app.listen(3000)

// Custom span for business logic
const { trace } = require('@tigerops/node')
const tracer = trace.getTracer('order-service')

async function applyDiscount(orderId, couponCode) {
  return tracer.startActiveSpan('discount.apply', async (span) => {
    span.setAttribute('order.id', orderId)
    span.setAttribute('coupon.code', couponCode)
    try {
      const discount = await lookupCoupon(couponCode)
      await applyToOrder(orderId, discount.percent)
      span.setAttribute('discount.percent', discount.percent)
      return discount
    } finally {
      span.end()
    }
  })
}
FAQ

Common Questions

Does @tigerops/node work with both Express 4 and Express 5?

Yes. Express 4.x is fully supported. Express 5.x (beta/RC) is supported on a best-effort basis. The instrumentation patches router.Layer and Route prototypes, which are stable across both major versions.

My Express app uses a custom error handler — will errors still be traced?

Yes. TigerOps patches the error middleware dispatch mechanism, not specific error handler functions. Any error passed to next(err) is captured regardless of how many custom error handlers are registered.

Can I use TigerOps with Express-based frameworks like LoopBack or Sails.js?

LoopBack 4 is based on Express and is fully supported. Sails.js uses Express under the hood and is also supported. NestJS (which wraps Express by default) has dedicated instrumentation via the @tigerops/nestjs package.

How does TigerOps handle streaming responses in Express?

For streaming responses (res.write() followed by res.end()), the span ends when res.end() is called. Stream duration, bytes written, and any errors during streaming are captured as span events.

Does TigerOps work with express-validator and Joi validation middleware?

Yes. Validation middleware is instrumented as part of the middleware chain. Validation errors returned via next(err) are captured automatically. You can also add custom span attributes in your validators using the TigerOps API.

Get Started

Full Express.js Observability in One npm Install

Route spans, middleware timing, database query traces, and error capture — no code changes to your routes.