Pick BASIC,
compiled to native code.
mvx is a MultiValue system built with today's tools. An LLVM compiler turns your BASIC into real machine code with a real debugger. It ships as containers, and it keeps your data in PostgreSQL, MongoDB or a local store, whichever your team already runs.
Or try it now, with nothing to install but Docker:
docker run --rm -it ghcr.io/mvx-lang/mvx-demo Your records, in the database you already run.
Every file in an account is bound to a storage driver, and one account can mix them. The dictionary you already have becomes the schema. Programs keep reading and writing records, while reporting tools read the same live data as rows or documents. There is no export and no nightly copy.
Acme CorpþWidgetýGadgetþ2ý1þ999ý450 In the account
One record. þ separates attributes, ý separates values.
001 Acme Corp 002 WidgetýGadget 003 2ý1 004 999ý450
PRICE is MD2, so 999 is $9.99.
On PostgreSQL
The record is a jsonb document. Mapping adds typed columns, and the line items go in a child table.
| id | doc | CUSTOMER |
|---|---|---|
| 10042 | {"1": "Acme Corp", …} | Acme Corp |
| id | seq | PRODUCT | QTY | PRICE |
|---|---|---|---|---|
| 10042 | 1 | Widget | 2 | 9.99 |
| 10042 | 2 | Gadget | 1 | 4.50 |
PRICE is a real numeric column, so sum("PRICE") works.
On MongoDB
One document. The mapped fields sit beside the record, and the line items become an array.
{
_id: '10042',
doc: { '1': 'Acme Corp', '2': [ … ], … },
CUSTOMER: 'Acme Corp',
ORDERITEMS: [
{ PRODUCT: 'Widget', QTY: '2', PRICE: 9.99 },
{ PRODUCT: 'Gadget', QTY: '1', PRICE: 4.50 }
]
} _id is the record id itself — only a byte the character set cannot carry is escaped.
Three commands to put a file on PostgreSQL.
Define a connection once and bind files to it by name. The host and password live outside the account, so the account can go under version control and a container can supply its target through environment variables.
CREATE-MAP names the fields you want as columns. From then on every
WRITE keeps them up to date, changing only what moved.
> SET-CONNECTION pgmain driver=postgres address=db:5432 dbname=mvx user=app namespace=sales
> CREATE-FILE ORDERS USING @pgmain
> CREATE-MAP ORDERS CUSTOMER PRODUCT QTY PRICE SELECT id, doc->>'1' AS customer, doc->'2' AS products
FROM sales."ORDERS";
id | customer | products
--------+-----------+----------------------
10042 | Acme Corp | ["Widget", "Gadget"] SELECT o."CUSTOMER", sum(i."QTY"::numeric * i."PRICE") AS total
FROM sales."ORDERS" o
JOIN sales."ORDERS_ORDERITEMS" i USING (id)
GROUP BY o."CUSTOMER";
CUSTOMER | total
-----------+-------
Acme Corp | 24.48 use sales
db.ORDERS.aggregate([
{ $unwind: '$ORDERITEMS' },
{ $group: {
_id: '$CUSTOMER',
total: { $sum: { $multiply: [
{ $toInt: '$ORDERITEMS.QTY' }, '$ORDERITEMS.PRICE' ] } }
} }
])
[ { _id: 'Acme Corp', total: 24.48 } ] Pick a backend per file.
- SQLite
- The default for a new account. One file, nothing to run.
- PostgreSQL
- Records as jsonb, typed columns from your dictionaries, native indexes, and record locks shared across processes.
- MongoDB
- A document per record, mapped fields beside it, and associations as embedded arrays.
- MySQL and MariaDB
- The same document shape, on the database many shops already run.
- LMDB
- Embedded and very fast, for a single host.
- mvx-lmdbd
- LMDB behind a network daemon, so many hosts share one set of files.
- Directory files
- Each record is a plain OS file, so source code sits where git and your editor can see it.
Queries are pushed down to the database where it can answer them, so a LIST with a
WITH clause returns only the matching records rather than the whole table.
How the drivers work.
Compiled, not interpreted.
mvx compiles BASIC straight to machine code through LLVM, the compiler toolkit behind clang and Swift. It does not translate to C first. Numeric variables become real integers and doubles, so arithmetic runs close to the speed of C.
It is also designed for today's hardware. The classic MultiValue systems were built when memory was measured in megabytes, and saved every byte. mvx trades some of today's gigabytes for speed: it keeps an index into each dynamic array, so reading or writing any element takes a few nanoseconds, however long the array is.
The compiler also writes standard debug information mapped to your BASIC line numbers. gdb and lldb step through the program you wrote, and profilers such as perf and Instruments report time against your own source lines.
- mvx LLVM, native code 97% of C
- jBASE 6.2.1 with -O4 compiled through C 1.6% of C
- UniData 8.3 interpreted 0.5% of C
- OpenQM (ScarletDME) interpreted 0.3% of C
Each system is measured against C on its own machine, in September 2026 (jBASE in August). How these were measured.
Made to run in containers.
A session is an ordinary process, and a file can live on another machine. So an account can keep its programs local while its data sits on a shared database, and you add capacity by adding containers instead of buying a bigger server.
- Published images for
linux/amd64andlinux/arm64:ghcr.io/mvx-lang/mvx,mvx-lmdbdandmvx-demo. - Relocatable tarballs that find their own runtime and drivers. No environment variables to set.
- Connections from the environment. Set
MVXCONN_SALESDB_ADDRESSand the account follows, with no file to edit. - Operations you already know. Backups, replication and monitoring are handled by PostgreSQL or MongoDB, with the tools your team uses today.
Message another port, without breaking their screen.
Sessions have a port again. WHO and LISTU answer from a real
registry, and MSG takes the classic forms — a port, a range, an account,
a user, or every port at once.
Nothing is pushed at a running program. A message waits until the program asks for it, so a full-screen form keeps its shape; at the prompt it appears as it arrives and the line you were typing comes back underneath it.
One small daemon carries it on a host. Point that at MQTT and the roster spans machines, so ports in different containers can reach each other.
> WHO
3 jane SALES
> MSG !7 WITH ORDERS O1234 have a look at this
sent to 1 port, with ORDERS O1234 sales> LIST ORD
[3] jane: have a look at this
attached: ORDERS O1234 — on the stack as "CT ORDERS O1234" (.1 to recall)
sales> LIST ORD SEND "Backup starting at 18:00" TO 7 THEN
PRINT "told them"
END ELSE
PRINT "port 7 is not logged on"
END A complete MultiValue system.
- TCL shell
- The classic command line, with its verbs written in BASIC and cataloged like any program.
- Dictionaries and queries
LIST,SELECTandSORTdriven by your dictionaries, with conversions, formats and select lists.- Secondary indexes
- Built on the backend itself where it has them.
- Packages
MVPKGinstalls libraries from packages.mvx-lang.org, with dependencies resolved for you.- Version control
- Records, dictionaries and VOC under git, from the
GITverb or the shell. - Permissions in the runtime
- Restricted, developer and unrestricted sessions, enforced where a program cannot get around them.
Latest release
Relocatable builds for Linux. Installing mvx also installs MVPKG and git, and asks which version of each you want. Other packages are on packages.mvx-lang.org.
Released 6 October 2026
- Download for Linux x86-64 mvx-lang-0.8.0-linux-amd64.tar.gz, 31 MB
- Download for Linux ARM64 mvx-lang-0.8.0-linux-arm64.tar.gz, 30 MB
Read from GitHub when this page loads.
tar xzf mvx-lang-0.8.0-linux-amd64.tar.gz # or -arm64
./mvx-lang/bin/mvx -a myaccount Documentation
- Getting started Build, install and open your first account.
- The language MVX BASIC, statements and intrinsic functions.
- TCL The command shell and its verbs.
- Files and dictionaries Records, dictionaries, queries, indexes, and mapping to SQL and JSON.
- Deployment Storage drivers, named connections, PostgreSQL and MongoDB.
- Containers The published images and how to run them.
- Packages Installing and publishing with MVPKG.
- Version control Hash-file records under git.
Have a Pick application?
mvx gets better by running real software. If you have a UniVerse, UniData, jBASE, D3 or Reality application, or a framework such as SB+ or CueBic, that you would let me test against, I would like to hear from you. I'm happy to sign an NDA.