How to Use Assert in Node.js: A Practical Guide

Learn the Node.js built-in assert module: strictEqual, deepStrictEqual, throws, rejects, and more, with real code examples for testing API responses.

INEZA Felin-Michel

INEZA Felin-Michel

22 May 2026

How to Use Assert in Node.js: A Practical Guide

Apidog for Enterprise

On-Premises Deploy

SSO & RBAC

SOC 2 Compliant

Explore Apidog Enterprise

Every test framework you have used, whether Jest, Mocha, or node:test, sits on top of a simple idea: state what you expect, then throw an error if reality disagrees. Node.js ships that idea as a built-in module called assert. No install, no dependency, just require it and start checking assumptions.

The assert module is worth knowing on its own. It powers quick sanity checks in scripts, it underpins many test runners, and it teaches you what an assertion actually is before any framework dresses it up. This guide covers the methods that matter, the strict-versus-legacy distinction that trips people up, how to assert on errors and async code, and how the same module helps you validate API responses.

What the assert module does

An assertion is a statement that must be true for your program to be considered correct. When you write assert.strictEqual(total, 100), you are declaring that total should equal 100. If it does, nothing happens and execution continues. If it does not, assert throws an AssertionError that stops execution and tells you what went wrong.

Import the module. The modern, recommended form is the strict version:

const assert = require('node:assert/strict');
// or with ES modules:
// import assert from 'node:assert/strict';

The simplest assertion checks that a value is truthy:

const user = getUser(42);
assert(user, 'getUser should return a user object');

The first argument is the value under test. The second, optional, is a message shown when the assertion fails. Always write that message. A failure that says “getUser should return a user object” is far more useful than a bare AssertionError. Understanding assertions also helps when you move to dedicated API assertions in a testing tool.

Strict mode versus legacy mode

This is the single most important thing to get right. The assert module has two modes.

Legacy mode, which you get from require('node:assert'), uses loose equality (==) for assert.equal and assert.deepEqual. That means assert.equal(1, '1') passes, because 1 == '1' is true in JavaScript. Loose equality is a well-known source of bugs.

Strict mode, which you get from require('node:assert/strict'), uses strict equality (===) for everything. assert.equal(1, '1') fails, as it should, because the types differ.

const looseAssert = require('node:assert');
looseAssert.equal(1, '1');        // passes, surprising and dangerous

const strict = require('node:assert/strict');
strict.equal(1, '1');             // throws AssertionError, correct

Use strict mode. There is no good reason to accept loose equality in tests. The rest of this guide assumes node:assert/strict, where assert.equal behaves like assert.strictEqual.

Comparing values: equal and strictEqual

assert.strictEqual(actual, expected) checks that two values are identical with ===. It is the workhorse for primitives like numbers, strings, and booleans.

const assert = require('node:assert/strict');

function priceWithTax(price, rate) {
  return price + price * rate;
}

assert.strictEqual(priceWithTax(100, 0.08), 108, 'tax calc should add 8 percent');
assert.strictEqual(typeof priceWithTax(100, 0.08), 'number', 'result should be a number');

There is also assert.notStrictEqual, which passes when the two values are not identical. Use it to confirm a value changed:

const before = getCacheKey();
refreshCache();
const after = getCacheKey();
assert.notStrictEqual(before, after, 'cache key should change after refresh');

For objects and arrays, strictEqual will not help. Two object literals with the same contents are different references, so === returns false. That is what deep equality is for.

Comparing objects: deepStrictEqual

assert.deepStrictEqual(actual, expected) compares structure and values recursively. Two objects pass if every key holds a strictly equal value, all the way down.

const assert = require('node:assert/strict');

function buildOrder(id, items) {
  return { id, items, status: 'pending' };
}

assert.deepStrictEqual(
  buildOrder(7, ['keyboard', 'mouse']),
  { id: 7, items: ['keyboard', 'mouse'], status: 'pending' },
  'order object should match expected shape'
);

This is the method you will use most when testing functions that return objects, and especially when testing API responses, since JSON bodies are objects. Its counterpart assert.notDeepStrictEqual passes when the structures differ.

One caveat: deepStrictEqual checks types too. A property holding the number 7 will not match a property holding the string '7'. That strictness is a feature; it catches type drift in your data. If you are testing functions with many input combinations, our guide to data-driven testing with CSV and JSON shows how to scale assertions across datasets.

When deepStrictEqual fails, Node prints a diff that highlights exactly which properties disagree. That diff is one of the most useful things about the module. Instead of staring at two large objects trying to spot the difference, you read a few highlighted lines. For nested data, that alone justifies reaching for deepStrictEqual over manually checking each field with strictEqual.

Partial matching with assert.match and assert.ok

Not every check needs full equality. Sometimes you only care that a value looks roughly right. assert.ok(value) passes whenever the value is truthy, which is the right tool for “this should exist” checks: a non-empty string, a defined object, a non-zero count.

assert.match(string, regexp) checks that a string matches a regular expression, and assert.doesNotMatch checks the opposite. These are useful for values whose exact content varies but whose shape is fixed.

const assert = require('node:assert/strict');

function generateOrderId() {
  return 'ORD-' + Date.now();
}

const id = generateOrderId();

// the exact timestamp changes, so assert the format, not the value
assert.match(id, /^ORD-\d+$/, 'order id should be ORD- followed by digits');
assert.ok(id.length > 4, 'order id should not be empty');

This pattern matters for API testing especially, where responses contain timestamps, generated IDs, and tokens you cannot predict. You assert the format with match and the existence with ok, and you reserve strictEqual for the values you actually control.

Asserting that code throws

Sometimes correct behavior means throwing an error. assert.throws(fn, expectedError) runs a function and passes only if it throws.

const assert = require('node:assert/strict');

function parsePort(value) {
  const port = Number(value);
  if (!Number.isInteger(port) || port < 1 || port > 65535) {
    throw new RangeError('port must be an integer between 1 and 65535');
  }
  return port;
}

// passes: invalid input should throw a RangeError
assert.throws(
  () => parsePort('70000'),
  RangeError,
  'out-of-range port should throw RangeError'
);

// you can also match the error message with a regex
assert.throws(
  () => parsePort('abc'),
  /must be an integer/,
  'non-numeric port should throw a descriptive error'
);

// passes: valid input should not throw
assert.doesNotThrow(
  () => parsePort('8080'),
  'a valid port should not throw'
);

Note that you pass a function, not a call. assert.throws(parsePort('70000')) would execute parsePort before assert ever sees it, and the error would escape uncaught. Always wrap it: () => parsePort('70000').

Asserting on async code: rejects

Modern Node.js code is full of promises, and a rejected promise is the async equivalent of a thrown error. assert.rejects and assert.doesNotReject handle that case. Both return promises, so you await them.

const assert = require('node:assert/strict');

async function fetchUser(id) {
  if (typeof id !== 'number') {
    throw new TypeError('id must be a number');
  }
  // ... real lookup would go here
  return { id, name: 'Dana Lee' };
}

async function runTests() {
  // passes: bad input rejects with a TypeError
  await assert.rejects(
    fetchUser('not-a-number'),
    TypeError,
    'string id should reject'
  );

  // passes: good input resolves without rejecting
  await assert.doesNotReject(
    fetchUser(101),
    'valid id should resolve cleanly'
  );
}

runTests();

Forgetting to await an assert.rejects call is a common mistake. Without await, the test function finishes before the assertion settles, and a failure becomes an unhandled rejection instead of a clear test error.

Using assert to test API responses

The assert module is genuinely useful for checking the output of an HTTP request. After you fetch an endpoint, you have a status code and a JSON body, and both are things to assert on.

const assert = require('node:assert/strict');

async function testGetUser() {
  const res = await fetch('https://api.example.com/users/101');

  // check the status code
  assert.strictEqual(res.status, 200, 'GET /users/101 should return 200');

  const body = await res.json();

  // check the shape and types of the response
  assert.strictEqual(typeof body.id, 'number', 'id should be a number');
  assert.strictEqual(body.id, 101, 'id should match the requested user');
  assert.ok(body.name, 'response should include a name');
  assert.ok(Array.isArray(body.roles), 'roles should be an array');
}

testGetUser().then(
  () => console.log('API test passed'),
  (err) => { console.error('API test failed:', err.message); process.exitCode = 1; }
);

This pattern works, and it teaches the fundamentals. But for a real API test suite you will want structured runs, retries, environment handling, and reporting that raw assert does not provide. Our guides on how to write automated test scripts and the pytest API automation framework cover that next step.

If you would rather not hand-build a test harness, Apidog lets you define API requests and attach visual assertions on status codes, headers, and JSON fields without writing assertion code at all. You can chain requests into automated test scenarios, run them in CI/CD, and still drop into custom scripts when you need the control that assert gives you. It is a faster path from “I have an endpoint” to “I have a test suite,” and you can download Apidog and use it for free. Together with Apidog, the Node.js assert module covers both quick checks and full suites.

Frequently asked questions

Do I need to install the assert module?

No. assert is built into Node.js. Import it with require('node:assert/strict') or require('node:assert'). There is no npm package to install and no dependency to manage. The node: prefix makes it explicit that you are loading a core module.

What is the difference between assert.equal and assert.strictEqual?

In legacy mode, assert.equal uses loose equality (==) and assert.strictEqual uses strict equality (===). In strict mode, loaded via node:assert/strict, assert.equal behaves identically to assert.strictEqual. Always use strict mode so type coercion never silently passes a test.

When should I use deepStrictEqual instead of strictEqual?

Use strictEqual for primitives: numbers, strings, booleans. Use deepStrictEqual for objects and arrays, because strictEqual compares references and two separate objects are never reference-equal. Any time you assert on a JSON body or a returned object, reach for deepStrictEqual.

Should I use the assert module or a test framework like Jest?

For quick scripts and learning, raw assert is fine. For a real test suite, use a framework. Node.js also ships a built-in test runner, node:test, that pairs naturally with assert and gives you test organization, reporting, and parallelism without an external dependency.

How do I assert that an async function rejects?

Use assert.rejects, and remember to await it. Pass the promise or an async function call, optionally with an expected error type or message regex. assert.rejects(somePromise, TypeError) passes only if the promise rejects with a TypeError. Without await, a failure becomes an unhandled rejection rather than a clear assertion error.

Practice API Design-first in Apidog

Discover an easier way to build and use APIs

How to Use Assert in Node.js: A Practical Guide