Nerdamer 2.0: a TypeScript rewrite of the JavaScript symbolic math library
a symbolic math expression evaluator for javascript
At a glance
- What is it?
- Nerdamer 2.0 replaces the string parsing internals of the long-standing JavaScript CAS with a TypeScript implementation, keeps the familiar string-based API, and adds typed entry points for the core, algebra, calculus, solve, structures, assumptions and parser modules. It is Apache-2.0 licensed and published on npm under the `latest` tag, but the last tagged release on the repository is still v1.1.12 from 2021.
- Who is it for?
- Nerdamer 2.0 suits a TypeScript codebase that needs symbolic algebra in the browser or in Node without shipping a WebAssembly runtime, and it suits a project willing to read BREAKING_CHANGES.md before upgrading from 1.x. It does not suit an application that expects every parser result to be an Expression, that relies on the removed `solveEquations` name, or that needs the 1.x release line, since the newest tag on the repository is v1.1.12 from 2021-07-06 and the 2.0 work sits on master.
- 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 1 day ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Nerdamer 2.0 is, and who reaches for it
Nerdamer is a symbolic mathematics library and computer algebra system for JavaScript and TypeScript. Nerdamer 2.0 is a TypeScript rewrite of Nerdamer, and the README is clear that the familiar string-based API remains available while the package also exposes typed modules for direct use of the symbolic engine, algebra, calculus, solving, structures, assumptions, parser APIs and advanced algorithms. The branch prepares 2.0.0.
The audience is a developer who needs computed algebra inside an application rather than a notebook. A product that shows the derivative of a user entered formula, a form that simplifies what the user typed, or a bot that answers an equation can call a CAS in the browser without a Python service or a WebAssembly runtime. That is the space Nerdamer occupies, and the 2.0 work is about making that usable from TypeScript with types rather than about adding new mathematics.
The core interaction is a callable. You pass a string and get back a symbolic entity, and you ask that entity for its text:
const nerdamer = require('nerdamer');
const expression = nerdamer('x^2+2*(cos(x)+x*x)');
console.log(expression.text());
// 2*cos(x)+3*x^2The same call in TypeScript, with an expansion and a sorted output:
import nerdamer from 'nerdamer';
const expression = nerdamer('(x+1)^3').expand();
console.log(expression.text({ sort: true }));
// x^3+3*x^2+3*x+1The output is a Nerdamer notation string, not a JavaScript number, which is the point. Nothing is evaluated until you ask for it.
Installing the package and wiring it into a TypeScript build
Installation is a single npm command, and the README states that Nerdamer 2.0 is published under npm's `latest` tag:
npm install nerdamerThat detail matters more than it looks. Publishing 2.0.0 under `latest` means an existing project that runs `npm install nerdamer` after a release will pull the rewrite rather than staying on the 1.x line, and the package version in the repository is 2.0.0 with a publishConfig tag of `latest`.
The TypeScript note in the README is short and easy to miss: TypeScript projects compiling to CommonJS should enable `esModuleInterop`. That is the setting that makes the default import in the example above resolve correctly, and a project that hits it without the flag gets an import error rather than a CAS failure.
The package manifest gives you the rest of the shape. The main entry is dist/bundle.js and the types entry is index.d.ts, and the files array ships dist, output, docs-data, index.d.ts, README.md, BREAKING_CHANGES.md, docs/MIGRATION_FROM_1X.md and docs/RELEASE_NOTES_2.md. So the migration documentation travels inside the package rather than only living on the site.
For a browser without a bundler, the README points at the two distribution bundles. dist/bundle.js is the complete Nerdamer package and dist/parser.js is a parser-focused browser bundle, and the markup to load the full one is:
<script src="./node_modules/nerdamer/dist/bundle.js"></script>
<script>
console.log(nerdamer('factor(x^2-1)').text());
</script>The parser bundle exposes `nerdamerParser` rather than the complete `nerdamer` API, so the two bundles are not interchangeable and the global name changes with it.
Splitting the CAS into typed module entry points
The structural change in 2.0 is that the monolithic library can be loaded in pieces. The normal `nerdamer` entry point assembles the complete CAS, registering the parser and core, the math functions, and the algebra, calculus and solving domains together.
The package exports the complete callable API plus typed module entry points:
import nerdamer from 'nerdamer';
import { Expression, Rational, type TextOptions } from 'nerdamer/core';
import { Polynomial, gcd, lcm, partfrac } from 'nerdamer/algebra';
import { diff, integrate, limit } from 'nerdamer/calculus';
import { solve, PolynomialSolver } from 'nerdamer/solve';
import { Matrix, Vector, ValuesSet } from 'nerdamer/structures';
import { assume, clearAssumptions } from 'nerdamer/assumptions';
import { Parser } from 'nerdamer/parser';Additional supported entry points are `nerdamer/advanced` and `nerdamer/debug`.
That list is the practical payoff of the rewrite. A tool that only needs to parse and print expressions does not need the solver, and a bundle that only needs the parser does not need the higher-level algebra, calculus and solver domains. The parser entry point is the clearest case:
import { Parser } from 'nerdamer/parser';
const expression = Parser.parse('sqrt(x^2+1)');
console.log(expression.text());The parser entry point contains the symbolic parser, scripting, assumptions, structures, complex and polynomial operations, and general math functions, but not the higher-level domains. The same split shows up in the browser builds, with a complete bundle and a parser-only bundle.
The `assumptions` module deserves a note, because it is a mechanism rather than a namespace. `assume` and `clearAssumptions` let you attach conditions to the symbolic session, which is how a CAS is told that a symbol is positive before it attempts a simplification, and since settings remain shared by the package instance, that state persists for the lifetime of the instance.
Parser results are typed entities, not one universal Expression
The most consequential breaking change is visible in the return type. `nerdamer(...)` returns the Nerdamer entity represented by the input. Scalar symbolic input normally returns an `Expression`, but equations and structured notation can return `Equation`, `Vector`, `Matrix`, `Collection`, `ValuesSet` or `Dictionary`.
const scalar = nerdamer('x^2+1');
const equation = nerdamer('x^2=1');
const vector = nerdamer('[x, y, 3]');The README is explicit that this is intentional: Nerdamer 2.0 does not wrap every parser result in a compatibility `Expression` object. Code written against 1.x that assumed `.text()` on everything still works for scalars, but code that assumed a uniform Expression type now has to branch, or use the typed classes exported from `nerdamer/structures`, which include `Matrix`, `Vector` and `ValuesSet`.
The structured values are first-class parser entities in their own right:
nerdamer('matrix([1,2],[3,4])').text();
nerdamer('[1,x,3]').text();
nerdamer('{1,2,x}').text();Set and vector notation that was a string convention in 1.x is now a data structure, and that is why the structures module exists as a separate entry point.
Substitution follows from the same design. Values supplied to `nerdamer(...)` are substitutions and they do not imply numerical evaluation:
const substituted = nerdamer('x^2+cos(x)', { x: 6 });
const evaluated = substituted.evaluate();The substitution is a symbolic replacement, and `.evaluate()` is the separate step that turns it into a number. Values can themselves be symbolic expressions, so `nerdamer('x^2+1', { x: 'y+1' })` substitutes one symbol for another rather than computing anything.
Output formatting, TeX and the deprecated conversion alias
Output is controlled per call, which matters when you are rendering results into a UI. `text()` returns Nerdamer notation and the term ordering can be requested per call:
const expression = nerdamer('x^2+2*x+1');
expression.text();
// 1+2*x+x^2
expression.text({ sort: true });
// x^2+2*x+1The full package also supplies `toText()` and TeX conversion:
expression.toText();
expression.toTeX();
nerdamer.convertToTeX('sqrt(x^2+1)');
nerdamer.convertFromLaTeX('\\frac{x^2+1}{2}');`convertToLaTeX()` remains as a deprecated compatibility alias, so a 1.x call site will keep working but is on notice, and `convertFromLaTeX` gives you a way to accept TeX from a user and get a symbolic entity back.
Scientific formatting is available without changing the underlying expression:
nerdamer('1200').text({ scientific: 4 });
// 1.200e3One caveat on the browser bundle: the TeX conversion helpers come from the full package, so a build that only loads dist/parser.js does not have them. The parser bundle gives you `nerdamerParser` and the parser domain, and the README does not claim the full conversion API is present there.
Algebra, calculus and the rewritten polynomial path
The mathematics is reached through a flat function API on the main entry point:
nerdamer.expand('(x+1)^4').text();
nerdamer.factor('x^4-1').text();
nerdamer.simplify('sin(x)^2+cos(x)^2').text();
nerdamer.gcd('x^2-1', 'x^2-2*x+1').text();
nerdamer.partfrac('1/(x^2-1)', 'x').text();The README states that the 2.0 algebra implementation includes the rewritten polynomial GCD and factorization path, partial fractions, polynomial solving support and direct polynomial APIs. The direct polynomial API is what the `Polynomial`, `gcd`, `lcm` and `partfrac` exports from `nerdamer/algebra` are for, and it is a different route to the same results than the string based calls.
Prime factorization has two explicit forms, a list and a map:
nerdamer.pfactor(100).text();
// [2,2,5,5]
nerdamer.pfactord(100).text();
// {2=>2,5=>2}Calculus works the same way:
nerdamer.diff('x^3+sin(x)', 'x').text();
nerdamer.integrate('x^2', 'x').text();
nerdamer.limit('sin(x)/x', 'x', '0').text();
nerdamer.laplace('t', 't', 's').text();and the same operations are available in Nerdamer notation inside a string, for example `nerdamer('diff(x^3,x)').text()`. That dual surface is deliberate and it is also the main compatibility trap, because the notation parser and the function API do not always grow in step.
Solving, the scripting layer and runtime functions
Single-variable solving returns a `SolutionSet`:
const roots = nerdamer.solve('x^2-1', 'x');
console.log(roots.text());System solving returns Nerdamer structures rather than legacy JavaScript arrays:
const solutions = nerdamer.solveSystem(
['x+y=3', 'x-y=1'],
['x', 'y']
);
console.log(solutions.text());The name change is the thing to note. The legacy `solveeqs` name is retained as the compatibility alias for system solving, and `solveEquations` is not part of the 2.0 public API. Code that was written against a 1.x `solveEquations` helper has to change, while code on `solveeqs` keeps working.
Nerdamer notation also includes a symbolic scripting layer with assignments, user functions, local bindings, conditionals, loops, blocks, logical operations, `return`, `break`, `continue` and error-handling helpers:
const result = nerdamer(`
f(x):=x^2+1;
f(12)
`);
console.log(result.text());Control-flow operations that intentionally produce no mathematical value use an internal null signal, and the README notes that this signal is distinct from legitimate values such as an empty vector and is not exposed as a normal parser entity. That distinction is a small but real design detail, because it means an empty result from a loop is not confused with an empty vector.
Finally, you can add your own runtime functions, constants and variables to the shared instance:
nerdamer.setFunction('line', ['x', 'm', 'b'], 'm*x+b');
nerdamer.setConstant('g', 9.81);
nerdamer.setVar('a', 5);Settings remain shared by the package instance, which is convenient and also means state can leak between requests in a server context, since the module is a singleton.
Where Nerdamer 2.0 is the wrong tool, and the licence and upgrade position
The first limit is the upgrade boundary itself. The README is explicit that Nerdamer 2.0 is a rewrite rather than an incremental release, and the package version, the typed entry points, the non-Expression parser results and the removed `solveEquations` name all point the same way. The repository ships BREAKING_CHANGES.md, docs/MIGRATION_FROM_1X.md and docs/RELEASE_NOTES_2.md for this, and a 1.x codebase with string handling around solver results will need work rather than a version bump.
The second limit is the release history. The recent releases listed for the repository are v1.1.12 from 2021-07-06, v1.1.11 from 2021-05-24 and v1.1.9 from 2021-03-26, and the last push was on 2026-10-17. So the 2.0 work is on master and published to npm under the `latest` tag, but the tagged release history on the repository still belongs to the 1.x line. If you pin a version from the git tags rather than from npm, you are pinning the old implementation.
The third limit is scope. The documentation describes a symbolic CAS for JavaScript and TypeScript and does not mention a numeric array library, a plotting system or a statistics package, and if you need dense numerical work rather than symbolic manipulation this is the wrong dependency.
The licence is Apache-2.0, with LICENSE.md in the repository root and a CITATION.cff file alongside it. Apache 2.0 is permissive, includes an express patent grant and requires you to keep the licence and notices when you redistribute, which matters if you ship a bundle into a product, and it is not legal advice, so read LICENSE.md yourself.
Compare this with a Python-hosted CAS such as SymPy reached over an API. The difference in approach is that Nerdamer runs in the same process and the same language as your application, so there is no service to run, no network hop and no serialization of expressions, and in exchange you are limited to what the JavaScript implementation covers and you accept a rewrite of the API in 2.0. Against a WebAssembly port of a desktop CAS, the trade goes the other way: you get a smaller runtime and a JavaScript-native API, and you give up the breadth of a system built for symbolic research.
Editorial conclusion
Nerdamer 2.0 suits a TypeScript codebase that needs symbolic algebra in the browser or in Node without shipping a WebAssembly runtime, and it suits a project willing to read BREAKING_CHANGES.md before upgrading from 1.x. It does not suit an application that expects every parser result to be an Expression, that relies on the removed `solveEquations` name, or that needs the 1.x release line, since the newest tag on the repository is v1.1.12 from 2021-07-06 and the 2.0 work sits on master. Before you adopt it, install with `npm install nerdamer`, check that your TypeScript build enables `esModuleInterop` if it compiles to CommonJS, and read docs/MIGRATING_FROM_1X.md to see which of your call sites change.
Frequently asked questions
What changed in Nerdamer 2.0 compared with 1.x?
Nerdamer 2.0 is a TypeScript rewrite. The string-based API remains, and the package adds typed module entry points for the core, algebra, calculus, solve, structures, assumptions and parser APIs. Parser results are no longer all wrapped in an Expression, and `solveEquations` is not part of the 2.0 public API, with `solveeqs` retained as the alias.
How do I install Nerdamer and use it in a TypeScript project?
Run `npm install nerdamer`, then import the default export and call it with an expression string. TypeScript projects compiling to CommonJS should enable `esModuleInterop`. Nerdamer 2.0 is published under npm's `latest` tag, and the package version in the repository is 2.0.0.
What is the difference between the nerdamer and nerdamer/parser entry points?
The normal `nerdamer` entry point assembles the complete CAS, registering the parser and core with the math functions and the algebra, calculus and solving domains. The `nerdamer/parser` entry point holds the symbolic parser, scripting, assumptions, structures, complex and polynomial operations and general math functions without the higher-level algebra, calculus and solver domains, and it is exposed in the browser as dist/parser.js under the global `nerdamerParser`.
Does nerdamer('x^2+1', { x: 6 }) evaluate the expression?
No. Values supplied to `nerdamer(...)` are substitutions and do not imply numerical evaluation, so you call `.evaluate()` on the result to get a number. The substituted value can also be symbolic, for example `{ x: 'y+1' }`.
Is the project actively maintained?
The repository is not archived and the last push was on 2026-10-17, and the README states that this branch prepares 2.0.0, with Nerdamer 2.0 published under npm's `latest` tag. The most recent tagged releases on the repository are from the 1.x line, with v1.1.12 dated 2021-07-06.
Official sources
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.
[](https://hysenlabs.com/projects/jiggzson-nerdamer)Was this useful?