Library / SDK
chaijs/chai avatar
chaijs/chai

chai: the assertion library that stays out of your test runner's way

BDD / TDD assertion framework for node.js and the browser that can be paired with any testing framework.

8,267 stars727 forksJavaScriptMIT

At a glance

What is it?
chai is a BDD/TDD assertion library for Node.js and the browser that pairs with any JavaScript testing framework. Three styles, a plugin API, and a Node 18 floor are the whole story.
Who is it for?
Adopt chai when you want one assertion vocabulary that survives a change of test runner, or when you need a plugin such as chai-as-promised or chai-http. Skip it if your runner already ships assertions you like, or if you cannot move to Node 18 or newer, since the package declares engines.node >=18.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What chai solves, and who ends up installing it

Node ships an assert module, and every test runner ships something. So why add a dependency? Because assertion style and test execution are two different decisions, and chai is the part that refuses to make the second one. The README describes it as a BDD / TDD assertion library for node and the browser that can be paired with any javascript testing framework. That pairing is the product. You can move from Mocha to another runner, or run the same spec files in Node and in a browser, and the assertions do not change.

The audience is therefore narrower than the download numbers suggest. If you are writing a handful of tests in a project that will never swap runners, Node's built-in assert is enough and costs nothing. chai earns its place in three situations: a suite large enough that readable failure output matters, a project where the same assertions must run under Node and in a real browser, and a codebase that needs an assertion type the standard library does not have, which is where the plugin ecosystem comes in.

Three interfaces over one assertion core

The repository layout tells you most of the architecture. There is a lib/ directory holding the implementation, and three thin entry files at the top level: register-assert.js, register-expect.js and register-should.js. package.json lists files as index.js and register-*.js, so the published tarball is a built bundle plus those three registration shims. The build script is a single esbuild invocation that bundles lib/chai.js into index.js with format=esm and target=es2021. There is no separate CommonJS build, and package.json sets type to module.

That explains the import syntax in the README. You import the style you want by name, or you import a register-* module for its side effect of putting the assertion function somewhere global. The three styles are not three libraries. They are three surfaces on the same chainable assertion object, which is why a plugin written against the core works regardless of which surface you chose. The should style is the odd one out: the README notes that calling should() modifies Object.prototype. That is the mechanism behind value.should.equal(3), and it is also the reason some teams ban it outright, since every object in the process gains a property.

Installing chai and writing a first assertion

The README gives one install command for Node. It is a development dependency, since nothing in production should import an assertion library.

bash
npm install --save-dev chai

After that, import the style you want. The README shows the three named imports side by side.

js
import { assert } from 'chai';  // Using Assert style
import { expect } from 'chai';  // Using Expect style
import { should } from 'chai';  // Using Should style

If you would rather not import in every file, the register modules install the style globally instead. With Mocha, the README passes them through --require, and the file extension is part of the path.

bash
mocha spec.js --require chai/register-expect.js  # Using Expect style

The browser path is different and worth reading carefully. The README instructs you to install via npm and then load the bundled index.js as a module from node_modules, which means a bundler or a dev server is doing the resolution rather than a script tag pointing at a CDN copy.

html
<script src="./node_modules/chai/index.js" type="module"></script>

Where chai is the wrong tool

The most common failure is not a bug, it is a mismatch. chai asserts; it does not discover tests, run them, report on them or watch files. If you install chai expecting a test framework, you will get a library with no CLI. The README's own Mocha examples make the division explicit: Mocha runs the file, chai supplies the assertions.

The second constraint is the runtime floor. package.json declares engines.node as >=18, and the build targets es2021 with ESM output and no CommonJS bundle. On an older Node, or in a toolchain that still resolves require('chai') against a CommonJS entry point, the import will not work the way older tutorials show. That is a hard boundary, not a configuration preference.

The third is the should style's global mutation. Modifying Object.prototype in a test process is survivable when the process only runs tests. It is a genuine hazard if the same process also loads application code, because any object can now collide with the added property. The README documents the behaviour plainly; it does not warn you off it. Treat that as a design decision you are opting into, not an accident.

Finally, coverage. The test script runs c8 with --99 --check-coverage, so the project holds itself to a 99 percent threshold on its own suite. That says nothing about whether your assertions are correct, and it is not a reason to trust chai over anything else. It only means the maintainers are strict about their own tests.

chai against Node's built-in assert

The honest alternative is the assert module already in Node. It has the same job, zero dependencies, and no version floor beyond the Node you are already running. The difference is in the output and the vocabulary. Node's assert gives you a function call and a thrown AssertionError; chai gives you a chainable expression where the failure message is built from the chain itself, which is why an expectation reads closer to the intent than the equivalent boolean check.

There is a second difference that matters more at scale: extensibility. chai documents a plugin architecture with a published API guide, and the README points at an official plugin list. Plugins are discovered through package.json keywords, specifically chai-plugin, with browser and browser-only as modifiers for plugins that do or do not work under Node. That keyword convention is how a plugin signals its runtime support before you install it. Node's assert has no equivalent, and adding a domain-specific assertion means writing and maintaining your own helper.

If your suite is small and your runner's assertions are already readable, the built-in module wins on dependency count. If you need assertions that do not exist yet, chai is the one with a documented place to put them.

Maintenance, licensing and the upgrade tax

The repository is not archived, and the last push was on 2026-09-21. Releases are frequent: v6.2.0 on 2025-09-27, v6.2.1 on 2025-11-11, v6.2.2 on 2025-12-22. That cadence is the practical measure of maintenance here, more than any single number.

The cost of adopting chai is not the library. It is the plugins. Each one is a separate package with its own release schedule, and each one has to be compatible with the chai major you are on. The README's keyword convention tells you whether a plugin claims browser support, but it does not tell you which chai versions it was tested against. Budget time for that check whenever you bump chai's major version.

Licensing is straightforward. package.json declares MIT, and the repository carries a LICENSE file at the top level. MIT permits commercial use and modification, and it requires that the copyright notice and permission notice be preserved in copies or substantial portions. That is a statement about the licence text, not advice about your situation; if your organisation has rules about third-party notices, route it through whoever owns that process.

One contribution detail is worth knowing if you plan to send patches. The README asks contributors not to commit changes to the chai.js build, because it is regenerated once per release, and to rebase commits before pushing. A pull request that edits the bundle will be asked to drop that change.

Editorial conclusion

Adopt chai when you want one assertion vocabulary that survives a change of test runner, or when you need a plugin such as chai-as-promised or chai-http. Skip it if your runner already ships assertions you like, or if you cannot move to Node 18 or newer, since the package declares engines.node >=18. Before committing, verify which of the three styles your codebase will standardize on, because should() modifies Object.prototype, and check that every plugin you depend on has a release compatible with chai 6.

Frequently asked questions

What is chai in JavaScript?

chai is an assertion library for Node.js and the browser, similar in purpose to Node's built-in assert. It provides many assertions you can run against your code and can be paired with any JavaScript testing framework.

Is chai a testing framework?

No. chai asserts; it does not run or discover tests. The README pairs it with Mocha in its examples, where Mocha executes the spec file and chai supplies the assertions.

How do I install chai?

Install it from npm as a development dependency with npm install --save-dev chai. For browser use, the README says to install via npm and load the index.js file from node_modules as a module.

Which assertion styles does chai offer?

Three: assert, expect and should. You can import any of them by name, or use the register-assert, register-expect and register-should modules to make a style available globally. The should style calls should() and modifies Object.prototype.

Does chai work with TypeScript?

The repository includes a tsconfig.json and a lint:types script that runs tsc, so the project type-checks its own code. The README does not document a TypeScript setup guide for consumers.

What Node version does chai require?

package.json declares engines.node as >=18, and the published entry point is an ESM bundle built with target es2021. Older Node versions and CommonJS require() setups are outside what the package declares.

Official sources

  1. chaijs/chai on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/chaijs-chai.svg)](https://hysenlabs.com/projects/chaijs-chai)