Lotus Formula
The functional, list-oriented @function language that Ray Ozzie built for Lotus Notes in 1989 by borrowing the formula compiler from the Lotus 1-2-3 spreadsheet - a spreadsheet language transplanted into documents, views, and groupware
Created by Ray Ozzie at Iris Associates, under contract to Lotus Development Corporation
Lotus Formula is the name under which programming-language catalogs record the @function-based formula language of Lotus Notes: a small, functional, list-oriented expression language that Ray Ozzie created at Iris Associates and that shipped with Notes Release 1.0 on December 7, 1989. It is a spreadsheet language by ancestry - Ozzie borrowed the formula compiler and decompiler from Lotus 1-2-3 - but a document language by purpose. Where a 1-2-3 formula computes a number in a cell, a Notes formula decides which documents appear in a view, what a field defaults to, whether a paragraph is hidden from a given user, or which records an agent should modify.
The language is known by several names. Lotus and IBM manuals call it simply the “formula language”; developers call it “@Formula” (pronounced “at-formula”) because nearly every construct begins with an @ sign; catalogs that index it as a Lotus product call it Lotus Formula. This encyclopedia has separate entries under two of those names - Notes @Formula and Formula Language - that cover the language as it is used inside Notes today. This page takes the catalog’s framing as its subject: the language as a Lotus language, born from the 1-2-3 spreadsheet, shaped by the company’s formula tradition, and belonging to an era that ended when IBM retired the Lotus name in 2013. The catalog’s classification of it as a functional language in the spreadsheet category, and its status as dormant, are all explained by that framing, and this page examines each.
History & Origins
Lotus and the @function tradition
Lotus 1-2-3, released in January 1983, made the @function the signature of the Lotus house style. Where VisiCalc had a small set of functions written as @SUM, 1-2-3 expanded the library and made formulas the center of the product; by 1989, the year Notes appeared, 1-2-3 was on Release 2.2 and Release 3, and the 1-2-3 macro language was among the most widely used end-user programming facilities of its day. Any product that came out of Lotus in that decade carried the expectation that users would write @IF(...), @LEFT(...), and @SUM(...).
Ray Ozzie was inside that culture. After working at Software Arts, the company behind VisiCalc and TK!Solver, he was recruited to Lotus in 1983 by Mitch Kapor to lead the team building Symphony, Lotus’s integrated word processor, spreadsheet, database, and graphing package. He left the following year with a different product in mind - a networked collaboration system modeled on the PLATO Notes discussion system he had used as a student at the University of Illinois - and founded Iris Associates on December 7, 1984. Lotus funded the work under a development contract in exchange for the option to buy the rights to the product.
Building the language for Notes
Notes needed a way for application designers - not C programmers - to express the logic of a document database: which documents belong in a view, how a computed field gets its value, how a field’s input should be validated. Ozzie’s solution was to reuse what Lotus already had. According to the language’s own documentation and its Wikipedia history, he took the formula compiler and decompiler from 1-2-3 and repurposed them. Formulas were compiled to a compact binary form stored inside the design element (a view, form, or field) and decompiled back to text for editing, exactly as 1-2-3 stored a formula in a cell.
What he changed was the language’s center of gravity. A spreadsheet formula language is about numbers; Notes had to process the contents of documents, which meant text, names, dates, and - above all - lists. Reportedly drawing on his earlier use of Icon and Lisp, Ozzie made the list the language’s fundamental data structure. Every value in the language is, in effect, a list: a text field with one value is a one-element text list, and the operators and functions are defined so that they apply element-wise across lists without loops. That design is what makes the language functional in character, and it is why catalogs classify it that way even though it also has side-effecting @commands.
Notes 1.0 shipped on December 7, 1989, with the formula language as its only built-in programming language. For its first seven years, every Notes application - the discussion databases, document libraries, and approval workflows that defined early groupware - was programmed entirely in formulas.
Lotus, IBM, HCL
The corporate history of the language is the history of its owners. Lotus bought Iris outright in 1994 for approximately US$84 million. IBM bought Lotus in 1995 for approximately US$3.5 billion, a purchase widely reported as being principally about Notes. Notes Release 4, in January 1996, added LotusScript as a second language, and Release 4.5 (December 1996) began adding Java support; from then on formulas were one language among several rather than the only one. In 2013 IBM dropped the Lotus name, and Release 9 shipped as IBM Notes. In December 2018 IBM announced the sale of Notes and Domino to HCL Technologies in a US$1.8 billion deal that closed in July 2019, and the product has since shipped as HCL Notes and HCL Domino, most recently version 14.5 on June 17, 2025.
Design Philosophy
The language’s design follows from three decisions.
Formulas belong to design elements, not to a program. In a spreadsheet, a formula belongs to a cell. Ozzie generalized the idea: in Notes, a formula belongs to a view (its selection formula), a column (its value formula), a field (its default-value, input-translation, and input-validation formulas), a paragraph (its hide-when formula), a button, or an agent. There is no main program. The application is the set of design elements, each carrying the formulas that govern it, and the Notes runtime evaluates the right formula at the right moment. A developer building a Notes application writes hundreds of small formulas rather than one large program.
Everything is a list. Because Notes documents are collections of multi-valued fields, the language treats a scalar as a one-element list and defines its operators over lists. "A" : "B" : "C" is a three-element text list; adding a number to a list adds it to each element; comparing two lists compares them pairwise. Most tasks that would need a loop in a procedural language become a single expression over a list - the same philosophy that drives array languages and the higher-order functions of Lisp, applied to office documents.
Expressions, not statements. A formula is a sequence of expressions separated by semicolons, and its value is the value of the last one. Conditional logic is an expression (@If), assignment is an expression (:=), and even the keywords that break the pattern - SELECT, FIELD, DEFAULT, ENVIRONMENT, REM - are only five in number. The language had no loops at all until 2002, and its designers regarded that as a feature: a formula was meant to be short, declarative, and evaluated in a bounded amount of time.
Key Features
@Functions and @Commands
The vocabulary divides in two. @Functions compute values: @Left, @Right, @Middle, @Trim, and @ProperCase for text; @Sum, @Round, and @Abs for numbers; @Now, @Today, @Adjust, and @Date for time; @UserName, @Name, and @UserRoles for identity; @DbLookup and @DbColumn for reading other databases. @Commands perform user-interface actions - @Command([FileSave]), @Command([EditDocument]), @Command([ViewRefreshFields]) - and can appear only in formulas that run in the client.
REM "Compute a display name from separate fields";
first := @Trim(FirstName);
last := @Trim(LastName);
@If(first = ""; last; last + ", " + first)
List processing
The list operators are the language’s most distinctive feature. : builds a list. Ordinary operators act pairwise; the same operators prefixed with * act on every combination (a “permuted” operation).
REM "Pairwise addition gives the two-element list A1 : B2";
pairwise := ("A" : "B") + ("1" : "2");
REM "Permuted addition gives every combination A1 : A2 : B1 : B2";
permuted := ("A" : "B") *+ ("1" : "2");
REM "@Elements returns 3; @Member returns 2, the position of y in the list";
count := @Elements("x" : "y" : "z");
position := @Member("y"; "x" : "y" : "z");
REM "@Implode joins a list into text: a, b, c (@Sort is a Release 6 addition)";
@Implode(@Sort("c" : "a" : "b"); ", ")
@Explode splits text into a list, @Implode joins a list into text, @Unique removes duplicates, @Subset takes a prefix or suffix, and @Replace performs list-wise substitution. Before 2002 these functions and the permuted operators were the only way to iterate, which pushed Notes developers into a functional, whole-collection style of thinking.
View selection and the SELECT keyword
The single most-written formula in Notes is a view selection formula:
SELECT Form = "Invoice" & Status = "Open" & @Adjust(DueDate; 0; 0; 30; 0; 0; 0) < @Today
Every document in the database is tested against it, and the ones that return true appear in the view. Because selection formulas are evaluated by the server’s indexer over potentially millions of documents, the bounded, loop-free nature of the original language was a practical virtue rather than an abstract one.
Comparison with the 1-2-3 formula language
| Aspect | Lotus 1-2-3 formulas | Lotus/Notes formula language |
|---|---|---|
| Home | A cell in a worksheet | A design element: view, form, field, agent, button |
| Central data type | Number | Text list |
| Argument separator | Comma: @IF(A1>0,"yes","no") | Semicolon: @If(Total > 0; "yes"; "no") |
| References | Cell addresses (A1, B2..B9) | Field names (Total, Status) |
| Iteration | Implicit over ranges | Implicit over lists; explicit loops only from Release 6 |
| Side effects | None (macros are separate) | FIELD assignment and @Commands |
| Compilation | Compiled per cell, decompiled for display | Compiled per design element, decompiled for editing - the same compiler lineage |
Evolution
1989-2001: the original engine
For its first thirteen years the language changed only by accretion: new @functions arrived with each release, notably @DbLookup and @DbColumn for cross-database access, and web-oriented functions once the Domino server began serving Notes applications over HTTP in the Release 4.5 and 4.6 era (1996-1997). The compiler at the core remained the one derived from 1-2-3, and the language kept its original restrictions - temporary variables could be assigned once, lists could not be indexed, and there were no loops.
2002: the Release 6 rewrite
Notes/Domino 6, released in September 2002, replaced the engine. Damien Katz, then a developer on the Notes team at Lotus/IBM, rewrote the formula evaluator and used the opportunity to extend the language. IBM’s 2002 developer article “Enhancements to the formula language in Domino 6” catalogs the changes:
- Loops:
@For,@While, and@DoWhile, with@Nothingto suppress a loop’s result - Runtime evaluation:
@Evalexecutes a formula held in a text string, and@CheckFormulaSyntaxvalidates one - List functions:
@Sort(with custom comparison),@Transform(apply a formula to every element),@Compare,@Count, and list subscripting withCategories[n] - Portable field code:
@GetField,@ThisName, and@ThisValue - Error handling:
@IfError - Web support:
@WebDbName,@URLEncode,@URLDecode - Language rules: temporary variables may be reassigned, assignments may nest, braces delimit
REMcomments and constants
REM {Release 6 style: a loop and a transform};
total := 0;
@For(n := 1; n <= @Elements(Amounts); n := n + 1;
total := total + Amounts[n]);
doubled := @Transform(Amounts; "x"; x * 2);
@Text(total) + " / " + @Implode(@Text(doubled); ",")
Katz later wrote about the project in a 2005 blog post, “Formula Engine Rewrite”, remembered less for its technical detail than for its account of the anxiety of replacing a component that every Notes application in the world depended on. The IBM article states that performance improved with the new engine; no published benchmark accompanies that claim, so the size of the improvement should not be quoted. What can be said is that the rewrite preserved backward compatibility with formulas written since 1989 while adding the constructs the language had lacked.
2002-present: stability
Since Release 6 the language has been stable. Later releases added @functions for new platform features but did not change the syntax or semantics. HCL’s Domino Designer documentation for version 12 through 14.5 still documents the language in full, including the note on each Release 6 function that it was “new with Release 6” - a small sign of how little has changed since.
Current Relevance
The formula language is, as of 2025, a supported and documented part of HCL Notes/Domino 14.5. Any organization still running Domino applications - and many large enterprises, government bodies, and financial institutions reportedly built decades of workflow on it - is running formula code every time a view is opened. The language has no life outside that platform: there is no open-source implementation, no standalone interpreter, and no Docker image, and its compiled form has never been publicly specified.
The catalog status of dormant is therefore a statement about the language as a Lotus language. The Lotus brand was retired in 2013, the Lotus 1-2-3 spreadsheet from which the compiler came was discontinued in 2013 with support ending in 2014, and the Notes platform itself, while maintained, has been in long decline against web and cloud collaboration tools since the mid-2000s. The language is not dead - it ships, it is documented, and it is used - but it is no longer evolving, and the community that once produced conference sessions and books about @formula tricks has largely dispersed. Its practical future is bound to the maintenance life of Domino.
Why It Matters
Lotus Formula is worth studying for three reasons.
It is a rare case of a spreadsheet language transplanted into a different domain. The formula compiler that drove 1-2-3’s cells was re-aimed at documents, and the result showed that the spreadsheet model - small formulas attached to things, evaluated on demand, written by end users rather than programmers - could organize an entire application platform. Notes applications were built by administrators and power users in the same way 1-2-3 models were built by accountants, and that low barrier was a large part of why Notes spread.
It was an early mainstream functional language. From 1989 onward, when most business software was programmed in COBOL, C, or BASIC, the growing population of Notes application designers was writing list-comprehension-style expressions with implicit iteration, first-class lists, and no assignment - not because they had read about functional programming, but because the language made that the natural way to work. Damien Katz’s Release 6 additions, @Transform in particular, are recognizably map.
And it is a link in a chain that runs from VisiCalc to CouchDB. Ozzie carried the @function from Software Arts and Lotus into Notes; Katz carried the Notes model of replicated, schema-free documents into CouchDB in 2005, and from there into the document-database movement. The formula language sits in the middle of that lineage - the piece of 1-2-3 that lived on inside groupware for more than three decades.
Timeline
Notable Uses & Legacy
Notes view selection and column formulas
Every view in a Notes/Domino database is defined by a SELECT formula that decides which documents it contains and by column formulas that compute what is displayed. Since 1989 there has been essentially no way to build a Notes view without writing in this language
Domino agents and workflow automation
Scheduled and triggered agents written in formula language select and modify batches of documents - routing approvals, archiving, and cleaning data - in the corporate workflow applications that made Notes a fixture of enterprise IT through the 1990s and 2000s
Domino web applications
When Domino became a web server in the late 1990s, formulas were extended for HTTP-facing work; Domino 6 added @WebDbName, @URLEncode, and @URLDecode specifically so formula code could generate and parse web URLs
Apache CouchDB's design lineage
Damien Katz, who rewrote the formula engine for Notes/Domino 6, went on to create CouchDB in 2005, a document database he described as inspired by his work on Notes - carrying the Notes model of replicated, schema-free documents into open source