mvx

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.

10042 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.

sales."ORDERS"
iddocCUSTOMER
\x3130303432{"1": "Acme Corp", …}Acme Corp
sales."ORDERS_ORDERITEMS"
idseqPRODUCTQTYPRICE
\x31303034321Widget29.99
\x31303034322Gadget14.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: Binary('MTAwNDI=', 0),
  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 10042, stored as bytes.

The same record, three ways. Programs read and write it as a record; SQL and Mongo tools read the rows and the document. The mapping comes from the dictionary you already have.

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.

At the mvx prompt
> 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
In psql, before any mapping: attributes by number
SELECT id, doc->>'1' AS customer, doc->'2' AS products
  FROM sales."ORDERS";

 id     | customer  | products
--------+-----------+----------------------
 \x3130303432 | Acme Corp | ["Widget", "Gadget"]
In psql, after mapping: names from the dictionary
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
In mongosh, the same file bound to MongoDB
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 at 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.

A prime sieve written in Pick BASIC, run for five seconds, as a share of a C version on the same machine.
  • mvx LLVM, native code 101% 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/amd64 and linux/arm64: ghcr.io/mvx-lang/mvx, mvx-lmdbd and mvx-demo.
  • Relocatable tarballs that find their own runtime and drivers. No environment variables to set.
  • Connections from the environment. Set MVXCONN_SALESDB_ADDRESS and 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.

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, SELECT and SORT driven by your dictionaries, with conversions, formats and select lists.
Secondary indexes
Built on the backend itself where it has them.
Packages
MVPKG installs libraries from packages.mvx-lang.org, with dependencies resolved for you.
Version control
Records, dictionaries and VOC under git, from the GIT verb 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.

mvx 0.2.2

Released 17 September 2026

Checked against GitHub on 17 September 2026. This page is rebuilt when a new release is published.

tar xzf mvx-lang-0.2.2-linux-amd64.tar.gz     # or -arm64
./mvx-lang/bin/mvx -a myaccount

Documentation

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.