CLI tool
josdejong/mathjs avatar
josdejong/mathjs

mathjs: mixed-type arithmetic and an expression parser for JavaScript

An extensive math library for JavaScript and Node.js

15,079 stars1,321 forksJavaScriptApache-2.0

At a glance

What is it?
mathjs is an Apache-2.0 math library for JavaScript and Node.js that unifies numbers, BigNumbers, complex numbers, fractions, units and matrices behind typed functions and an expression parser. It is the right tool when you need to evaluate user-supplied formulas or mix numeric types, and the wrong tool when a few lines of plain Math calls would do.
Who is it for?
Adopt mathjs when you need an expression parser, unit arithmetic, or arithmetic across BigNumber, complex, fraction and matrix types in one call site, and install it with npm install mathjs. Do not adopt it for a handful of scalar calculations, where the built-in Math object is smaller and faster to ship.
Can I use it commercially?
Yes. Apache-2.0 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 last received commits 17 days ago.
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

The problem mathjs solves: one arithmetic layer across incompatible numeric types

JavaScript has one numeric type, the double, plus the newer bigint. That is enough for a shopping cart and not enough for anything that needs exact decimal arithmetic, complex roots, or a value carrying a unit. The usual workaround is to pull in decimal.js for money, complex.js for complex numbers, fraction.js for rationals, and then write conversion code at every boundary where two of them meet. mathjs is the project that already did that assembly work: those three libraries appear in its dependency list, alongside typed-function, seedrandom and tiny-emitter. The target reader is a developer building a calculator, a spreadsheet formula engine, a physics or engineering tool, or any product where the user types a formula rather than picking from a fixed set of operations. The README states the library supports numbers, bignumbers, bigints, complex numbers, fractions, units, strings, arrays and matrices, and that it is compatible with JavaScript's built-in Math library, so the migration path from Math.round to mathjs is not a rewrite.

Typed functions and dependency injection: the mechanism behind mixed-type calls

The architecture section of the README describes two ingredients. The first is typed functions: every function is created with typed-function, which lets a single function name carry implementations for several input types and apply automatic conversions. The README gives the concrete case: define multiply for two numbers, extend it with a MyDecimal type, and if you also define a conversion from MyDecimal to number, typed-function will allow MyDecimal multiplied by number without you writing that overload. The second ingredient is dependency injection. Functions are built from factory functions, and higher-level functions receive lower-level ones as arguments, so prod picks up whatever multiply it was given. That has a practical consequence the README spells out: if you do not need the heavyweight multiply that handles BigNumbers and matrices, you can inject a number-only multiply into prod and the rest of the chain follows. At the bottom, math.create(...) builds an instance from a chosen set of factories, and math.import adds functions that the expression parser can then resolve. This is why mathjs is extensible without forking it, and also why the full build is heavy: the default instance carries every data type and every function, whether or not your application touches them.

Installing mathjs and evaluating a first expression

The README gives one install command and one CDN route. From npm:

bash
npm install mathjs

For the browser, the README points to the downloads page at mathjs.org/download.html rather than naming a specific CDN URL, so treat that page as the source of truth for bundle URLs. Once installed, the README's usage example imports named functions and constants, and the same block shows the expression parser. A minimal first run that exercises both the function API and the parser looks like this:

js
import { evaluate, round, e, sqrt, derivative } from 'mathjs'

round(e, 3)                 // 2.718
sqrt(-4)                    // 2i
evaluate('12 / (2.3 + 0.7)') // 4
evaluate('12.7 cm to inch')  // 5 inch
derivative('x^2 + x', 'x')   // 2 * x + 1

The comments are the outputs the README documents, so if your run prints something else, the difference is in your input rather than in the example. Two details are worth noticing on the first pass. sqrt(-4) returns a complex value rather than NaN, which means mathjs changes the meaning of an operation you may have relied on from Math. And the unit expression returns a value with a unit attached, not a bare number, so any downstream code that expects a double needs to convert explicitly. For chained operations, the README shows chain(3).add(4).multiply(2).done() evaluating to 14.

Where mathjs is the wrong tool

The case against mathjs is bundle size and surface area. The default entry point pulls in the whole library, including BigNumber support built on decimal.js, complex.js, fraction.js and the expression parser, and that is a lot of code to ship for a page that adds two numbers. The README does not document a tree-shaking guarantee for the main import; what it does document is the factory and dependency-injection mechanism, which is the supported route to a smaller instance rather than something the bundler does for you. If your arithmetic is a fixed set of scalar operations on doubles, plain Math is smaller and has no parser to reason about. A second boundary is the expression parser itself. Evaluating a string is convenient and it is also an execution surface: anything you feed it comes from somewhere, and the README does not describe a sandbox or a resource limit for evaluate. If the formula text is user-supplied and untrusted, that is a design question to settle before the library choice. Finally, note that mathjs changes semantics you may not expect: sqrt of a negative number yields a complex value, and a value with a unit is not a number. Code that assumed NaN or a double will need adjusting.

mathjs compared with decimal.js and other single-purpose libraries

The most common alternative is to compose narrow libraries: decimal.js for exact decimals, complex.js for complex arithmetic, fraction.js for rationals. That approach gives you a smaller bundle per concern and full control over how the pieces meet, at the cost of writing the glue yourself, including the conversions between a Decimal and a Complex and the dispatch logic that decides which type an operation returns. mathjs takes the opposite position: it depends on those same libraries and puts a typed-function dispatch layer and a parser on top, so a single call site handles any supported type. The trade is explicit. You get one API, automatic conversions, unit arithmetic, and an expression parser that can be handed to end users; you give up the ability to ship only the arithmetic you use without going through the factory mechanism. A second alternative is to keep the built-in Math object and accept floating-point error where it does not matter, which is the correct answer for a large share of front-end code. The decision point is whether your inputs are typed by a person or by your own source code. If a person types them, the parser earns its weight. If your source code types them, it usually does not.

Maintenance, licence and upgrade cost

The repository is not archived, and the last push was on 2026-09-13, so the project is being worked on. The package.json in the repository lists version 15.2.0 and the default branch is develop, which means the published npm version and the branch head are not the same thing; pin a published version rather than a commit if you want reproducible installs. The licence is Apache-2.0, which permits commercial and closed-source use and requires you to preserve the licence and notice files; the repository ships both LICENSE and NOTICE, and the NOTICE file is the one people forget to carry into a distributed build. This is a description of what the licence files say, not legal advice; if your product embeds the library in a way you are unsure about, that is a question for your own counsel. Upgrade cost is the part the README does not settle. The project maintains HISTORY.md at the repository root, and the contributing notes ask that new functions document a History section naming the version they land in, which suggests the changelog is the intended place to look before bumping. The README does not document a deprecation policy or a supported-version window, so the practical check before an upgrade is to read HISTORY.md for the versions between your pin and the target, then run your own tests. If you rely on the expression parser, treat parser behaviour as the thing most likely to shift and test it directly rather than assuming your function calls cover it.

Editorial conclusion

Adopt mathjs when you need an expression parser, unit arithmetic, or arithmetic across BigNumber, complex, fraction and matrix types in one call site, and install it with npm install mathjs. Do not adopt it for a handful of scalar calculations, where the built-in Math object is smaller and faster to ship. Before committing, check the size of the full bundle against your budget, confirm that the functions you rely on are covered by the project's own tests, and read the HISTORY.md entry for the release you pin.

Frequently asked questions

How do I install mathjs?

Install it from npm with npm install mathjs, or download a bundle from the downloads page at mathjs.org/download.html. The README gives both routes and notes the library runs in Node.js and in the browser.

How do I use mathjs to evaluate an expression?

Import evaluate and pass it a string, as in evaluate('12 / (2.3 + 0.7)'), which the README documents as returning 4. The same function handles unit expressions such as evaluate('12.7 cm to inch'), which returns 5 inch.

What is mathjs?

It is an Apache-2.0 math library for JavaScript and Node.js with a large set of built-in functions and constants, an expression parser with symbolic computation, and support for numbers, bignumbers, bigints, complex numbers, fractions, units and matrices.

How does mathjs differ from decimal.js?

decimal.js is one of mathjs's own dependencies, so it is not a competing implementation but a component. mathjs adds a typed-function dispatch layer, a parser and other numeric types on top, which means a larger default bundle in exchange for handling mixed types at one call site.

Official sources

  1. Issues
  2. josdejong/mathjs on GitHub
  3. License: Apache-2.0
  4. Project website
  5. README
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/josdejong-mathjs.svg)](https://hysenlabs.com/projects/josdejong-mathjs)