flarisvm hello.fls
Fast, embeddable, and concurrent by design. Flaris combines fiber-based async/await with a compact bytecode VM written in C - familiar syntax, deterministic execution, and a 39-module standard library.
// A quick taste of Flaris import { Https, Status, ContentType, CookieJar, Multipart } from library("Https", "1.0"); fn async fetchData(url:string):object { var resp = await Https.GetAsync(url); return Json.Parse(resp.body); } fn async Main() { let data = await fetchData("https://api.example.com/data"); Console.WriteLine("Received: ", Json.Stringify(data)); // Fibers run concurrently on the cooperative scheduler let jobs = [ fetchData("https://api.example.com/a"), fetchData("https://api.example.com/b") ]; foreach (j in jobs) await j; return 0; }
Why Flaris
Flaris runs in the same tier as Lua - comfortably faster than CPython and
QuickJS on compute-heavy code, and ahead of Lua on array-intensive work.
Switch on the JIT with --jit and hot math and array loops run
within 2-3x of C and Go, matching or beating LuaJIT - no annotations, same
source. First-class fiber concurrency, mandatory static analysis, and native
C integration, with no external dependencies.
Compiles .fls source to compact .flx bytecode. Execute pre-compiled files for fast cold-start - compile once, deploy anywhere.
Lightweight fibers with async/await and cooperative scheduling. No threads, no data races - deterministic execution always.
A multi-pass analyzer (10 passes) catches type errors, unused variables, unreachable code, and flow issues before runtime.
Load native shared libraries at runtime and call C functions directly. Wrap performance-critical code in a thin C layer with full access to the VM API.
HTTP, JSON, Regex, Crypto, Graphics, File I/O, Networking, and more - batteries included without external dependencies.
Unsafe features (FFI, raw memory, eval) require the explicit --unsafe flag. Any module import can be pinned to a SHA-256 fingerprint - if the bytecode doesn't match, the VM halts before execution. Production deployments stay locked down.
Compile on macOS, run on Linux (ARM64 or x86-64) or Windows without recompiling. Portable .flx files run on any supported target.
Drop flarisvm into your C application. Script your game, tool, or server with a minimal surface area.
Fold your program and the runtime into one native executable with --embed - a Go-style single file to ship, ~1 MB total, no install on the target machine.
Borrows from JavaScript and C# - let/var, classes, lambdas, modules. Short adoption time from most modern languages.
Add --jit and every eligible function compiles to native ARM64 or x86-64 automatically - no annotations. Loop-heavy math and array work runs 6-11x faster than the interpreter, same source.
Breakpoints, stepping and variable inspection - in VS Code or from a terminal with --debug. The VM speaks the Debug Adapter Protocol itself, so there is no adapter to install.
SLAB allocator, SSO strings (≤15 chars inline), and compact bytecode keep heap pressure minimal. The full VM, compiler, and standard library weigh in around 1 MB - ideal for embedded targets and resource-constrained environments.
Annotate as much or as little as you want. The analyzer infers types where omitted and enforces them where declared. Null unions (string|nil) and null-coalescing (??) are built into the language.
flarispm installs packages from any git repository - no central registry needed. Written in Flaris itself. One command to add, compile, and import a library.
Code Examples
From classes to fibers, from HTTP to native FFI - a few patterns to get started.
class Animal { fn Constructor(n: string) { this.name = n; } fn Speak() { Console.WriteLine(this.name, " makes a sound."); } } class Dog : Animal { fn Constructor(n: string) { this.name = n; } fn Speak() { Console.WriteLine(this.name, " barks."); } } fn Main() { let d: instance = new Dog("Rex"); d.Speak(); // Rex barks. return; }
fn async fetch(id: int): int { Fiber.Sleep(id * 10); return id * id; } fn async Main() { // Spawn three fibers - they run cooperatively let a: fiber = fetch(3); let b: fiber = fetch(1); let c: fiber = fetch(2); // await collects each result Console.WriteLine(await a, await b, await c); // 9 1 4 return; }
import { Http, Status, ContentType, CookieJar, Multipart, HttpError, HttpUnsupportedError } from library("Http", "1.0"); fn Main() { // Simple HTTP GET let resp = Http.Get("http://httpbin.org/json"); Console.WriteLine("status: ", resp.status); let data = Json.Parse(resp.body); Console.WriteLine(data.slideshow.title); // POST with JSON body let payload = Json.Stringify({ name: "Flaris", version: 1 }); let post = Http.Post("http://httpbin.org/post", payload, { "Content-Type": "application/json" }); Console.WriteLine("posted, status: ", post.status); return; }
fn divide(a: int, b: int): int { if (b == 0) throw(1, "division by zero"); return a / b; } fn Main() { try { Console.WriteLine(divide(100, 10)); // 10 Console.WriteLine(divide(100, 0)); // throws } catch (e) { Console.WriteLine("caught: ", e.Error); } finally { Console.WriteLine("cleanup"); } // Null coalescing let raw: string|nil = nil; let val: string|nil = raw ?? "default"; Console.WriteLine(val); // default return; }
// Tight numeric loops can compile to native ARM64 or x86-64 at runtime. // Just run with --jit - eligible functions compile to native automatically: // flarisvm --jit compute.fls fn sum(n: int): int { var s: int = 0; for (var i: int = 0; i < n; i++) { s = s + i; } return s; } fn Main() { Console.WriteLine(sum(1000)); // 499500 return; } // Measured over 10 000 calls on Apple M-series: // interpreter 1502 ms // JIT 8 ms - ~180× faster // // The compiler analyzes type annotations to decide eligibility. // Only pure integer/float math with typed locals qualifies. // Everything else falls back to the interpreter transparently.
// Run: flarisvm --debug app.fls // Stops at the start of Main, then you drive it from the prompt. [Entry] Main (app.fls:40) [fiber 1] (fdb) b inspectOrder breakpoint 1 at app.fls:21 (inspectOrder) (fdb) c [Breakpoint 1] inspectOrder (app.fls:21) [fiber 1] (fdb) locals [0] order = (instance) Order {3 fields} [1] retries = (int) 2 (fdb) p order.label order.label = (string) "espresso" (fdb) n // step over; s steps in, finish runs to the return [Step] inspectOrder (app.fls:22) [fiber 1] (fdb) fibers // every fiber, and what each is waiting on -> #1 running frames=2 inspectOrder (app.fls:22) #2 yielded frames=1 producer (app.fls:9) #3 wait-fiber frames=1 consumer (app.fls:14) waiting on fiber 2 // Also: bt, up/down, list, dis (bytecode), stack, info, delete, help. // An uncaught exception drops you here too, at the throw site, // with every frame still standing.
// Run: flarisvm --check app.fls // The static analyzer runs 9 passes and reports early: fn Main() { let x: int = "hello"; // ← error: type mismatch let y: int = 42; return; Console.WriteLine("unreachable"); // ← warning: dead code } // app.fls:4:24: 1000: Type mismatch for 'x' (expected compatible with declared type). // app.fls:8:35: 2006: Unreachable code.
Runnable .fls files - each covering a distinct language feature or use case.
Debugging
Set breakpoints in VS Code and step through Flaris source with locals, object fields and array
elements in the Variables pane. The VM speaks the Debug Adapter Protocol itself
— there is no separate adapter process to install. The same debugger is available as a
terminal prompt with --debug, so a session over SSH needs nothing but the VM.
compute: locals with the Order instance
expanded, the call stack, and the Disassembly View showing the bytecode for the same line.
Gutter breakpoints, step in/over/out, and pause a running program. Breakpoints can be added or removed while it runs.
Fibers map exactly onto the editor's thread picker, so you can read any fiber's stack — and see what each one is waiting on.
Locals, class instances, nested objects and arrays — including flat [float] arrays, read straight from their backing store.
An uncaught exception stops at the throw site with every frame intact, so you can read the values that caused it instead of guessing from a trace.
The Disassembly View shows the instructions around any frame, and dis ir shows the typed IR a JIT-compiled function was built from.
Inspecting never allocates or changes a reference count, so attaching a debugger cannot perturb the behaviour you are trying to observe.
# In VS Code: install the extension and press F5 on any .fls file. # From a terminal - stops at the start of Main: $ flarisvm --debug app.fls # Serve the Debug Adapter Protocol on loopback for an editor: $ flarisvm --dap=4711 app.fls
Debugging turns the JIT off. A JIT-compiled function runs natively and never reports its source lines, so a breakpoint inside one could not be reached — running everything in the VM is what makes stopping reliable rather than silently skipped.
Standard Library
Everything from JSON and cryptography to regex and compression is built in. No package manager required for the essentials.
Libraries
Install a library once into your per-user libs folder — ~/.flaris/libs on macOS and Linux, %USERPROFILE%\.flaris\libs on Windows — and import it by name from any script, no --libs flag needed. (You can also just drop a .flx next to a script for one-off use.) Each library ships source and pre-compiled bytecode. Libraries marked --unsafe require the unsafe flag at runtime. Download the .fls source for inline documentation and usage examples.
Every library here is open source under the MIT licence and written in Flaris itself — so they double as a substantial worked example of the language. Source, tests, the FFI plugin shims and the documentation all live in github.com/flaris-lang/flaris. Contributions and new libraries are welcome.
Browse the open source on GitHub ↗
--unsafe flag needed.
--unsafe required.
pg_ffi.c and --unsafe flag.
redis_ffi.c and --unsafe flag.
--unsafe flag.
sqlite_ffi.c and --unsafe flag.
--unsafe flag.
Downloads
One command installs flarisvm and flarispm and adds them to your PATH.
$ curl -fsSL https://www.flaris-lang.org/install.sh | sh
PS> iwr -useb https://www.flaris-lang.org/install.ps1 | iex
# Run your first program $ flarisvm hello.fls # Compile to bytecode, then execute $ flarisvm --compile hello.fls hello.flx $ flarisvm --exec hello.flx # Ship it as one self-contained binary $ flarisvm --embed hello.fls hello
Installs to ~/.flaris/bin/ by default. Override with FLARIS_HOME=/your/path.
Or download individual binaries below. flarisvm is the full toolchain (compiler +
runtime); flaris is the compiler-free runtime — about half the size and the base
for self-contained binaries.
Runtime only (flaris) — the small, compiler-free VM used to run .flx
and as the stub for --embed.
Editor support and the full documentation live under For Developers below.
Ship it
Like Go, Flaris can fold your program and the runtime into a single native
executable — one file to copy, nothing to install on the target machine. The full
toolchain compiles your .fls, then appends the bytecode to the small
flaris runtime stub. The result is an ordinary executable that runs your program
when launched.
# Source in, self-contained executable out $ flarisvm --embed app.fls myapp $ ./myapp arg1 arg2 # runs standalone - no flaris on PATH, no --libs # Statically link your library dependencies in the same step $ flarisvm --embed app.fls myapp --bundle='./mylib.flx' # Already have bytecode? Embed the .flx directly $ flarisvm --embed app.flx myapp
How it works. The program is appended to the runtime after its native image, with a small trailer recording where the payload begins. On startup the binary reads that trailer out of its own file and runs the embedded program — falling back to a normal VM only when no payload is present. Because the payload rides after the executable image, the OS loader ignores it, so a plain copy of the file still works.
Add --bundle and your .flx dependencies are statically linked into the
payload — the shipped binary needs no ~/.flaris/libs and no --libs.
The stub is the runtime only (no compiler, no eval), so you ship exactly the bytecode
you built, with a smaller attack surface. A modest program lands around 1 MB total.
Self-contained binaries run on Linux, macOS (including Apple Silicon), and Windows — the payload rides in space every executable format already tolerates. Producing binaries that pass strict code-signing (macOS notarization, Windows Authenticode) is on the roadmap.
Security
Flaris bytecode (.flx) carries an embedded Ed25519 signature.
The official standard library is signed with the Flaris signing key, and the matching
public key is compiled into the runtime as a trust anchor - so signed code verifies with
nothing to download or configure. A tampered .flx fails to load; run with
--require-signed to refuse anything not signed by a trusted key.
flaris-official b6e2237413be79854985a1d4650ddefca8bc9c517964e6b9814b887bc6b779be
This is the canonical reference. Confirm your install matches it: the key shown when you inspect a library, the key compiled into your runtime, and the value above should all be identical. If they agree, the artifact was signed by the official Flaris key.
# Inspect any .flx - the signer and trust status are in the header $ flarisvm --disasm ~/.flaris/libs/Jwt.flx Signature : Ed25519 (valid, trusted signer) Signed by : b6e2237413be79854985a1d4650ddefca8bc9c517964e6b9814b887bc6b779be # Enforce signatures: refuse unsigned or untrusted bytecode $ flarisvm --require-signed --exec app.flx
valid, trusted signer means the embedded key matched a trusted key;
valid, untrusted signer means the signature is good but the key is not trusted
(add it to ~/.flaris/trusted_keys to trust a third-party publisher);
INVALID means the file was altered after signing.
Package Manager
flarispm is the official Flaris package manager - written entirely in Flaris itself.
Install libraries from any public or private git repository in one command.
No central registry. No build system. Just git, bytecode, and --libs.
flarispm ships as a single signed .flx - nothing else to download.
flarisvm verifies its flaris-lang.org signature on every run, so you can
trust it regardless of how it reached you. Run it with flarisvm --exec flarispm.flx, or
add a short alias.
# Verify the download is the official, untampered build $ flarisvm --sig-info flarispm.flx signed|trusted|b6e2…79be|flaris-lang.org # macOS / Linux - alias so 'flarispm' just works $ mkdir -p ~/.flaris/bin && cp flarispm.flx ~/.flaris/bin/ $ echo "alias flarispm='flarisvm --exec ~/.flaris/bin/flarispm.flx'" >> ~/.zshrc # Windows - doskey / a one-line .bat that calls: flarisvm --exec flarispm.flx %* C:\> copy flarispm.flx C:\tools\flaris\
# Initialise a project manifest $ flarispm init # Add any package from GitHub (or any git host) $ flarispm add https://github.com/stefansolid/flaris-test-package # Run with the installed packages in scope $ flarisvm --libs='./flaris_packages' myapp.fls
import { Greet } from library("Greet", "1.0"); fn Main() { Greet.Hello("John"); // Hello, John! Greet.Shout("it works"); // IT WORKS!!! }
| flarispm init | Create flaris.json in current directory |
| flarispm add <url> [version] | Clone, compile and register a package |
| flarispm install | Install all dependencies from flaris.json |
| flarispm remove <url> | Remove a package and its compiled files |
| flarispm list | Show installed packages and their status |
| flarispm update [url] | Pull latest and recompile (all or one) |
| flarispm version | Print flarispm version |
For Developers
Editor tooling and the full documentation - language specification, standard library reference, and FFI guide - all maintained alongside the source.
Syntax highlighting, inline analyzer errors, build/run tasks, and the debugger - breakpoints, stepping and variable inspection. Search for Flaris in the Extensions pane, or install from a terminal with code --install-extension flaris-lang.flaris.
The standard libraries, their tests, the examples, the FFI plugin sources and the docs - MIT licensed, and written in Flaris itself.
Read top-to-bottom introduction: variables, classes, fibers, async/await, and the module system.
Full CLI flags, type system spec, built-in functions, operator precedence, VM limits, and stdlib API tables.
Write C plugins, expose functions to Flaris, marshal types, and build high-performance native extensions.
Required header for building FFI plugins:
↓ ffi_object.hThe complete .flx ISA manual: container format, Ed25519 signing, string pool, all 173 opcodes with stack effects and traps, loader validation rules, and an annotated hex dump. Self-contained - everything needed to write your own compiler, VM or tooling, with a companion format diagram.
Contact
Bug reports, feature requests, collaborations, and questions are all welcome. For questions and general chat, the Discord server is the fastest way to reach us.
Join the Flaris Discord →For bug reports, please include the Flaris version and a minimal reproducing script.