A formula engine for Java and JavaScript

Excel-like formulas, checked before they run

fxEngine is a statically typed formula engine you build into your own software. Your users write the formulas they know from spreadsheets. fxEngine works out the type of every one and refuses a mistake the moment it is typed, with a message that says what is wrong.

Hear when it ships

The shell runs in your browser. There is nothing to install.

fxEngine Shell
  1. Price = 49.5Price = 49,5
    49.549,5 Number
  2. Quantity = 120Quantity = 120
    120120 Number
  3. Total = Price * QuantityTotal = Price * Quantity
    59405940 Number
  4. Threshold = "5000"Threshold = "5000"
    "5000""5000" Text
  5. Total > ThresholdTotal > Threshold

    Das ist eine Textzeichenfolge, aber die andere Seite von > ist eine Zahl

    This is a text string, but the other side of > is a number

    Esto es una cadena de texto, pero el otro lado de > es un número

    C'est une chaîne de texte, mais l'autre côté de > est un nombre

    Qui c'è una stringa di testo, ma dall'altro lato di > c'è un numero

    Dit is een tekenreeks, maar de andere kant van > is een getal

    Isto é uma cadeia de texto, mas o outro lado de > é um número

    Det här är en textsträng, men den andra sidan av > är ett tal

    Das ist eine Textzeichenfolge, aber die andere Seite von > ist eine Zahl

    This is a text string, but the other side of > is a number

    Esto es una cadena de texto, pero el otro lado de > es un número

    C'est une chaîne de texte, mais l'autre côté de > est un nombre

    Qui c'è una stringa di testo, ma dall'altro lato di > c'è un numero

    Dit is een tekenreeks, maar de andere kant van > is een getal

    Isto é uma cadeia de texto, mas o outro lado de > é um número

    Det här är en textsträng, men den andra sidan av > är ett tal

Why static typing

Formulas are written once and run for years

In a spreadsheet, a bad formula shows #VALUE! the moment it is typed, and its author fixes it. In your software, a formula is written once and runs weeks or months later, on someone else's data, far from whoever wrote it. fxEngine moves every check it can to the moment the formula is written.

Total is 5940, Threshold is the text "5000", as read from a CSV file, and Due is March 31, 2026.

Formula A spreadsheet answers fxEngine answers
Total + ThresholdTotal + Threshold A spreadsheet answers 10940 The text is quietly converted to a number. fxEngine answers
Type mismatch. The type of the operand "Threshold" is expected to be Number, but it is Text.Type mismatch. The type of the operand "Threshold" is expected to be Number, but it is Text.
Total > ThresholdTotal > Threshold A spreadsheet answers FALSE All text is ordered after all numbers. fxEngine answers
Type mismatch. The operand "Threshold" must have the same type as the other operands of ">": it is expected to be Number, but it is Text.Type mismatch. The operand "Threshold" must have the same type as the other operands of ">": it is expected to be Number, but it is Text.
Due / 2Due / 2 A spreadsheet answers 23056 A date is a number of days since 1900. fxEngine answers
Type mismatch. The type of the operand "Due" is expected to be Number, but it is Temporal.Type mismatch. The type of the operand "Due" is expected to be Number, but it is Temporal.
  • Caught as it is typed

    A formula is checked as a whole before it runs, so a mistake in a branch that rarely runs is caught too.

  • Messages for people

    A message names what is wrong, what was expected and what was found, and can be worded for spreadsheet users rather than programmers.

  • The whole model at once

    Names that no longer exist and circular references are caught across every formula of a model, not one formula at a time.

The type system

A real type system, made for formulas

Numbers, text, logical values, dates, colors, arrays, records and types of your own, inferred rather than declared. The language has been designed around its type system since 2008, and it reads like the formulas your users already write.

  • Type inference

    Nothing is declared. Adding days to a date gives a date, and subtracting two dates gives a number of days.

    DATE(2026, 3, 31) + 30DATE(2026; 3; 31) + 30
    DATE(2026, 4, 30)DATE(2026; 4; 30) Temporal
  • Arrays and lifting

    A function taking a number also takes an array of numbers, and returns an array.

    ABS({ -4, 4 })ABS({ -4; 4 })
    { 4, 4 }{ 4; 4 } Array<Number>
  • Lambdas

    FILTER, SUMIF and their kin take a condition written as a formula, with a name of your choosing for each element.

    FILTER({ 5, 11, 13, 20 }, P -> (P > 10) && ISODD(P))FILTER({ 5; 11; 13; 20 }; P -> (P > 10) && ISODD(P))
    { 11, 13 }{ 11; 13 } Array<Number>
  • Enumerated values

    Where Excel takes a magic number, fxEngine also takes a named value, checked like any other.

    XMATCH(12, { 5, 13, 20 }, MatchMode.ExactOrNextLargest)XMATCH(12; { 5; 13; 20 }; MatchMode,ExactOrNextLargest)
    22 Number
  • Union types

    A parameter may accept more than one type, here an enumerated value or one of Excel's numbers, and nothing else.

    XMATCH(12, { 5, 13, 20 }, Color.Red)XMATCH(12; { 5; 13; 20 }; Color,Red)
    Type mismatch. The type of a function parameter, Color.Red, is expected to be MatchMode or Number, but it is Color.Type mismatch. The type of a function parameter, Color,Red, is expected to be MatchMode or Number, but it is Color.
  • Named parameters

    Every parameter of every function can be given by name, so optional ones can be skipped.

    SEQUENCE(3, StepValue: 2)SEQUENCE(3; StepValue: 2)
    { 1, 3, 5 }{ 1; 3; 5 } Array<Number>
  • Decimal commas

    Formulas can also be written with decimal commas and semicolons, and converted from one convention to the other.

    ROUND(2,567; 2)
    2,57 Number
  • Decimal points

    Formulas can also be written with decimal points and commas, and converted from one convention to the other.

    ROUND(2.567, 2)
    2.57 Number
  • Imperative mode

    Formulas run by buttons and rules may assign values and call functions with side effects. Other formulas never do.

    Total := Price * Quantity; RESET(Notes)Total := Price * Quantity;; RESET(Notes)

Domain models

Your business objects, reachable from formulas

Every name in a formula is checked against a model. Describe a few named values in a couple of lines, or expose your own classes as a domain model, with fields that can be visible, valid or enabled, and let formulas decide which.

  • Typed properties

    Amount.ValidAmount,Valid and Notes.VisibleNotes,Visible are properties of your containers, with types of their own. Properties are reached with ., and children with !, as in Form.StartupParameters!DailyLimitForm,StartupParameters!DailyLimit.

  • Implicit casts

    A number field stands in for its value, so users write Amount > 100 rather than Amount.Value > 100Amount,Value > 100. The compiler inserts the cast.

  • Ranges

    Containers that know their neighbors support ranges, such as SUM(Field1:Field10), or A1:D10 in a grid.

  • Built for live editing

    Values are added, renamed and removed as the author types, several changes can be made as one, and only what a change affects is checked again.

ExpenseEntry Form screen
  • ExpenseDate Date field .Value,Value .Valid,Valid .Visible,Visible .Enabled,Enabled
  • Reimbursable Switch .Value,Value .Valid,Valid .Visible,Visible .Enabled,Enabled
  • Amount Number field .Value,Value .Valid,Valid .Visible,Visible .Enabled,Enabled
  • Notes Text field .Value,Value .Valid,Valid .Visible,Visible .Enabled,Enabled
  • Amount.ValidAmount,Valid Amount <= Form.StartupParameters!DailyLimitAmount <= Form,StartupParameters!DailyLimit
  • Amount.EnabledAmount,Enabled ReimbursableReimbursable
  • Notes.VisibleNotes,Visible Reimbursable && (Amount > 100)Reimbursable && (Amount > 100)
  • ExpenseDate.ValidExpenseDate,Valid ExpenseDate <= TODAY()ExpenseDate <= TODAY()
  • Notes.VisibleNotes,Visible Reimbursable && (Amount > Notes)Reimbursable && (Amount > Notes) Type mismatch. The operand "Notes" must have the same type as the other operands of ">": it is expected to be Number, but it is Text.

The form builder example of fxEngine Compiler, with the formulas above.

The function library

410 functions, and room for yours

The functions spreadsheet users rely on, from XLOOKUP and FILTER to LET and SUMIFS, with blanks and errors handled as in Excel. Where an Excel signature is awkward, fxEngine adds an overload alongside it. Add functions, operators and types of your own without forking anything.

AI agents

Exact answers, and errors an agent can act on

A language model estimates. A formula calculates: the same formula on the same data gives the same answer, every time. Have an agent write the formula rather than the answer, and the compiler checks its work before anything runs.

  1. 1

    The agent writes a formula

    Total > ThresholdTotal > Threshold
  2. 2

    The compiler refuses it

    Type mismatch. The operand "Threshold" must have the same type as the other operands of ">": it is expected to be Number, but it is Text.Type mismatch. The operand "Threshold" must have the same type as the other operands of ">": it is expected to be Number, but it is Text.
  3. 3

    The agent corrects it

    Total > TONUMBER(Threshold)Total > TONUMBER(Threshold)
    TRUETRUE Logical
  • Deterministic

    No sampling and no drift. A result can be reproduced, tested and audited.

  • Checkable

    The model tells an agent which names exist and what type each one has, and an error names exactly what to fix.

  • Reviewable

    A formula is short enough for a person to read and approve before it is stored.

  • Ready for coding agents

    fxEngine Shell comes with a skill for coding agents, which runs every formula through the shell before the agent offers it.

Platforms

Runs where your code runs

Compile formulas in Java or in the browser, and calculate them in any modern JavaScript environment or inside the JVM. A REST API, for every other language, is planned.

  1. fxEngine Compiler

    Parses, type-checks and compiles formulas to JavaScript.

    • Java 11+
    • JavaScript
    • WebAssembly
  2. A model, as JSON

    Values, compiled formulas and which values depend on which.

  3. fxEngine Runtime

    Calculates, and recalculates only what a change affects.

    • Browsers
    • Node
    • Bun
    • Java, through GraalVM
Describing and calculating a model from Java
ContainerHandle root =
  RuntimeFormulas.liveModel(builder -> builder
    .number("UnitPrice", 10)
    .number("Quantity", 3)
    .numberFormula("Total", "UnitPrice * Quantity"));

root.value("Total").asNumber();   // 30.0

root.writeNumber("Quantity", 4);
root.value("Total").asNumber();   // 40.0
  • 2008 The year work on fxEngine began. It powers Calcapp, an app designer where people who don't program build apps out of formulas.
  • 1,594 Worked examples in the function reference, every one checked by the compiler whenever the reference is generated.
  • 8 Languages error messages can be shown in: Dutch, English, French, German, Italian, Portuguese, Spanish and Swedish.

The ecosystem

One engine, and the tools around it

The compiler and the runtime have been in production for years and are being prepared for release. The shell is here today.

  • fxEngine Compiler

    Coming

    Parses, type-checks and compiles formulas, and validates whole models, circular references included.

    Runs on
    Java 11+, JavaScript, WebAssembly
    License
    Source-available
  • fxEngine Runtime

    Coming

    Calculates compiled models and recalculates only what a change affects.

    Runs on
    TypeScript, Java through GraalVM
    License
    Source-available
  • fxEngine Shell

    Available now

    The language at a prompt, with tutorials and the documentation built in, and CSV files imported and exported.

    Runs on
    Web, terminal
    License
    Free to use
    Open the shell full screen →
  • fxEngine Editor

    Coming

    A formula editor for the web, with completion and the signature of the function being typed.

    Runs on
    TypeScript, CodeMirror 6
    License
    MIT
  • fxEngine Validator

    Coming

    Constraint-driven validation of Java object graphs, generated at build time, with no reflection.

    Runs on
    Java
    License
    Apache 2.0
  • fxEngine API

    Planned

    Compiles, validates and calculates formulas over HTTP, from any language.

    Runs on
    REST
    License
    Hosted service

The compiler and the runtime are source-available: free for study, evaluation and personal use, with a commercial license for production. The shell is free to use for any purpose, and the editor and the validator are open source.

Get in touch

Talk to us

Want early access to the compiler and the runtime, or to talk about fitting fxEngine into your product? Questions about licensing are welcome too. Write to us, and you'll hear back from the people building it.

fxEngine Shell Want this in your own terminal? A standalone version is coming. Get notified.
Loading fxEngine Shell