Varian v1.0 is live

One language.
The entire stack.

A fast, memory-safe language with native actors and channels, a batteries-included web framework (Zenith), a server-driven UI framework (Lumen), a build tool (Kiln), and a package registry (Constellation). Aurora is all of it, together.

147/147
Tests passing
~10.5k
Req/s single-process
1
Language, whole stack
v1.0
Shipped
main.vn
let name = "Varian"
print("Hello, " + name)

Why Varian?

Three pillars that make Varian different

bolt

Fast

Compiled bytecode VM with computed-goto dispatch. ~10,500 req/s single-process Zenith, ~35k multi-worker. No hidden allocation tax.

hub

Concurrent by default

Green-thread actors + channels, cooperative scheduler, no locks. Spawn thousands of lightweight tasks in a single process.

shield

Safe

Memory-safe core, escape-by-default HTML templating, friendly errors with line numbers, and built-in security middleware.

Tour

Language tour

Real Varian code, every snippet runs. Comparisons to languages you already know.

code Hello / values

Varian uses type inference — you write let x = 5, not int x = 5. This works like Python or modern JavaScript: the compiler infers the type from the value. Strings are fully UTF-8 encoded and concatenate with +. Numbers are 64-bit floating point by default — there's no int vs float distinction at the value level.

Unlike Java, C++, or Go, Varian has no concept of "primitives" vs "objects". Every value — numbers, strings, booleans, structs — lives on the GC-managed heap and is a first-class citizen. This means you can pass a number to a function that expects a generic value, store it in an array, or return it from a function, all without boxing or special syntax.

hello.vn
let name = "Varian"
print("Hello, " + name)

function Functions

Functions in Varian are first-class values — you can store them in variables, pass them as arguments to other functions, return them from other functions, and put them in data structures. This is the same model as JavaScript, Python, or Lua. A function is defined with fn name(args) { body } and called with name(args).

Where Varian differs from JS and Lua is closure semantics: closures capture their enclosing scope by value, not by reference. The captured variables are snapshotted at the moment the closure is created. This eliminates the classic "loop variable capture" bug — you know, the one where every closure in a for loop sees the final iteration value because they all share the same mutable variable. In Varian, each closure gets its own copy, frozen at creation time.

functions.vn
fn add(a, b) {
  return a + b
}
print(add(2, 3))

category Structs

Structs are named collections of typed fields — like C structs, Rust structs, or Go structs. They bundle related data together into a single value that can be passed around, stored in arrays, or nested inside other structs. Fields are accessed with dot notation: point.x.

Varian structs don't have methods attached to them. Instead, you write functions that take the struct as the first parameter (conventionally named self), similar to Python. There's no inheritance, no vtables, no virtual dispatch, no diamond problem — just plain data on the GC heap, always passed by reference. If you've used Go or Rust, this will feel familiar. If you're coming from Java or C++, it takes some getting used to — but the simplicity pays off: no fragile class hierarchies, no super() calls to get wrong.

structs.vn
struct Point { x: int, y: int }
let p = Point { x: 10, y: 20 }
print(p.x)

alt_route Control flow

Varian has all the control flow constructs you'd expect from a C-family language: if/else, for over ranges, while, and loop/break. But there's a key difference: if is an expression, not a statement. It returns a value. This means there's no need for a ternary operator — just write let x = if cond { a } else { b }. Rust and Kotlin work the same way.

Range syntax uses 0..n (exclusive end), the same as Rust. The for loop iterates over each value in the range, binding it to the loop variable. You can also use while cond { } for condition-based looping and loop { break } for infinite loops with explicit exit. No switch statement — use match instead (see Enums & match below).

control.vn
if x > 10 {
  print("Big")
} else {
  print("Small")
}
let y = if ok { 10 } else { 20 }
for i in 0..5 { print(i) }

diversity_3 Actors

Actors are Varian's primary concurrency primitive — inspired by Erlang and Elixir. An actor is an isolated unit of computation with its own private state and a message mailbox. Actors communicate by sending messages to each other, never by sharing memory. Each actor processes one message at a time, so there are no locks, no mutexes, no data races.

Define an actor with actor Name { fields, fn methods }. Call Name.spawn() to create an instance. Each method on the actor is a message handler — calling it sends a message to the actor's mailbox, and the actor processes it asynchronously. If you've used Akka (Scala/Java), Elixir agents, or Pony actors, this will feel familiar. Unlike threads, actors are lightweight green threads (a few KB each), so you can spawn thousands in a single process.

actors.vn
actor Greeter {
    name: string,
    fn greet(self) {
        print("Hello from actor!")
    }
}
let a = Greeter.spawn()
a.greet()

swap_horiz Channels

Channels are the other concurrency primitive in Varian, modeled after Go channels. A channel is a typed pipe that connects concurrent tasks: one task sends a value into the pipe, another task receives it out the other end. Channels are buffered — you specify the buffer capacity when creating one with task.channel(size).

Send to a channel with ch <- value and receive with <- ch. If the buffer is full, the sender blocks until space frees up — automatic backpressure. Unlike Go, Varian channels are always buffered (there's no unbuffered equivalent). This eliminates a whole category of accidental deadlocks where both sides block waiting for each other. If you want the equivalent of a rendezvous, use a channel with buffer size 1.

channels.vn
fn sender(ch) {
    ch <- 42
    print("sent")
}
let ch = task.channel(10)
task.spawn(sender, [ch])
print(<- ch)

error Errors

Varian uses try/catch for error handling, similar to Java, JavaScript, or Python. throw("message") raises an error, and catch e { } catches it with the error value bound to e. There are no checked exceptions, no throws declarations, no complex type gymnastics — just throw what you want and catch what you can handle.

For null safety, Varian provides the ?. (optional chaining) and ?? (null coalescing) operators, which work like Dart or TypeScript. For unrecoverable bugs — situations where the program cannot meaningfully continue — use fail("message"), which prints a stack trace and terminates. This is equivalent to Go's panic or Rust's panic!.

errors.vn
try {
    throw("error!")
} catch e {
    print("Caught: " + e)
}

globe Web server (6 lines)

Zenith is Varian's built-in web framework — it ships with the runtime, so there's no npm install express or pip install fastapi or Cargo.toml to edit. Create a server with new_app(), register routes with app.get(path, handler, summary), and start listening with app.listen(port). The handler is a closure that receives a request and returns a Response struct with status, body, and content type.

The summary parameter (third argument to app.get) is used for auto-generated OpenAPI documentation — describe what your route does in plain text, and the framework produces the spec for you. Beyond the router, Zenith ships with middleware chains, WebSocket support, server-sent events, JWT auth middleware, CORS middleware, rate limiting, and built-in database drivers for SQLite and Postgres. All of it is included — no imports needed.

server.vn
let app = new_app()
app.get("/", |req| {
    return Response { status: 200, body: "Hello, World!", content_type: "text/plain" }
}, "Root")
app.listen(8080)

category Enums & match

Enums are tagged unions — a type that can be one of several variants, each of which may carry its own data. This is the same concept as Rust's enum, TypeScript's discriminated unions, or Swift's enums. Unlike C/C++ enums, Varian enums are not integers — they are full types with optional payloads per variant.

The match expression performs exhaustive pattern matching: the compiler checks that every variant of the enum is handled, so you can never accidentally miss a case. Variant payloads are destructured directly in the match arm. No switch fallthrough bugs, no unhandled cases, no stringly-typed enums. If you've used Rust's match or Haskell's pattern matching, this is the same idea — safe, expressive, and checked at compile time.

enums.vn
enum Option {
    Some(int),
    None
}
let a = Option::Some(42)
match a {
    Option::Some(val) => print(val),
    Option::None => print(0)
}

shield Nil safety

Varian uses null to represent the absence of a value. But accessing a field or calling a method on null doesn't crash — instead, the optional chaining operator ?. short-circuits the entire expression and returns null. This works like Dart's ?. or TypeScript's optional chaining (the ?. operator from ES2020).

The null-coalescing operator ?? provides a default value when the expression on the left is null. Chain them naturally: user?.profile?.name ?? "anonymous". No more "Cannot read property of null" runtime errors — the language handles null propagation for you. If you need to distinguish between null and a value, use match with enums instead (see above).

nil.vn
let role = user?.profile?.role ?? "guest"
let len = my_string?.len() ?? 0

auto_awesome Traits

Traits define interfaces in Varian — a set of method signatures that a type must implement. But unlike Java's interface or Rust's trait, Varian uses structural typing (also called duck typing at compile time): if a struct has methods matching the trait's signature, it automatically satisfies the trait. There's no implements keyword, no explicit trait registration.

This works like Go's interfaces or TypeScript's structural type system. A function that accepts a trait parameter will accept any struct that has the right method shapes. If it walks like a duck and quacks like a duck, it's a Greeter. This gives you the flexibility of dynamic typing (write generic code that works with many types) with the safety of compile-time checking (the compiler verifies that the shape matches at the call site).

traits.vn
trait Greeter {
    fn greet(self)
}
struct Robot {}
impl Robot {
    fn greet(self) { print("Beep Boop") }
}
do_greet(Robot{})

neurology Comptime

Comptime (compile-time evaluation) runs arbitrary Varian code during compilation, similar to Zig's comptime blocks or C++ constexpr functions — but much more powerful. In C++, constexpr is heavily restricted (no allocations, no pointer casts, limited loops). In Varian, a comptime block can run arbitrary Varian code: allocate arrays, call functions, build strings, query databases at compile time (via the ORM), generate code — anything that doesn't require runtime input.

The result of a comptime block is a literal value baked directly into the bytecode. There is zero runtime cost — it's as if you had written the result by hand. Use comptime for precomputing lookup tables, validating configuration at build time, building optimized database queries, or generating repetitive boilerplate code. It's compile-time metaprogramming without macros or code generation tools — just plain Varian code that runs early.

comptime.vn
let table = comptime {
    return [100 * 200, 300 * 400]
}
// Comptime SQL query builder:
let query = comptime build_query("users")

code Python bridge

Varian can call any Python library directly — no FFI bindings, no PyO3, no C extension modules, no wrapper code. The python.run("module", "function", args) function imports a Python module, calls a function on it with the given arguments, and returns the result. This works like Julia's PyCall package: the Python runtime is embedded in the Varian process, and values are converted automatically between the two languages.

Need numpy arrays? python.run("numpy", "array", [[1,2],[3,4]]). Need S3 from boto3? python.run("boto3", "client", ["s3"]). Need scikit-learn, pandas, requests, OpenCV, PyTorch? It all works — the entire PyPI ecosystem is available from Varian without writing a single line of glue code. This is especially useful for data science, ML inference, and API integration where existing Python libraries are mature and well-tested.

python.vn
let np = python.run("numpy", "array", [[1, 2], [3, 4]])
let s3 = python.run("boto3", "client", ["s3"])

Built-in

Everything built in

No package manager, no imports, no npm install. Every feature ships with the runtime.

swap_horiz

Actors & channels

Green-thread concurrency with message-passing actors and buffered channels. No locks, no races. Spawn thousands of lightweight tasks in a single process — each one costs ~2 KB of memory, not megabytes. The cooperative scheduler multiplexes them across available CPU cores automatically.

verified

Memory safety

GC-managed heap with per-task bump arenas for allocation speed. The escape-promote write barrier detects short-lived objects and promotes them to a thread-local arena, which means many request paths never touch the global GC at all. No segfaults, no use-after-free, no manual memory management — but without the pause-the-world overhead of traditional tracing GCs.

package_2

Batteries-included stdlib

HTTP client and server, JSON parser and serializer, SQLite and Postgres drivers, Redis client, SMTP, JWT creation and verification, crypto (AES, SHA, HMAC, random), regex engine, file I/O, datetime, OS interaction. All built in, available globally — no imports, no require(), no Cargo.toml or package.json to maintain.

dns

Zenith web framework

Fast radix-trie router (O(n) where n is URL length, not route count), middleware chains, WebSocket and SSE support, built-in JWT auth middleware, CORS, rate limiting, request body validation, and auto-generated OpenAPI documentation from your route handler summaries. No Express, no FastAPI, no Actix — it ships with new_app().

web

Lumen frontend

Server-driven UI framework using HTML-over-WebSocket. Your UI lives entirely on the server — no client-side framework bundle to download, no hydration mismatches, no SEO problems. State changes send incremental DOM patches over a persistent WebSocket connection. Think Phoenix LiveView or Hotwire, but built into the language.

deployed_code

Kiln build + Constellation

vn build compiles to a single bytecode bundle; vn build --release produces a native binary with the runtime embedded. vn add fetches packages from Constellation, the built-in package registry. vn test runs tests. vn fmt formats code. The entire toolchain is a single vn binary — no separate build system, test runner, or package manager to install.

Ecosystem

The fullstack platform

Five products. One language. No glue code. Every tool designed together, from the same team, for the same runtime.

Aurora

Aurora is the reason Varian exists. It's everything together — your backend API in Zenith, your frontend UI in Lumen, compiled with Kiln, shipped through Constellation.

No microservices. No separate frontend build. No cross-language context switching. Write your entire application — from database migrations to CSS styles — in one language. Deploy as a single binary with the frontend rendered server-side over WebSocket. Zero client-side JavaScript framework required.

sh
# One command to scaffold the full stack
./vn new myapp && cd myapp && ./vn dev

# One command to build for production
./vn build --release
server.vn
let app = new_app()
app.get("/api/products", |req| {
    let products = db.query("SELECT * FROM products")
    return Response { status: 200, body: json_encode(products) }
})
app.listen(8080)
index.lumen
<template>
  <div class="product-list">
    <h1>Products</h1>
    <div @click="loadProducts">Load from API</div>
  </div>
</template>

Above: a Zenith API endpoint serving products, and a Lumen UI component calling it — same language, same project, zero glue code.

Learn more about Aurora arrow_forward

Zenith

A batteries-included web framework with a radix-trie router, middleware chains, WebSocket support, SSE, built-in JWT auth, CORS, rate limiting, and auto-generated OpenAPI documentation.

Database drivers for SQLite and Postgres are built into the runtime — no ORM dependency, no package.json, no Cargo.toml. Every route handler returns a Response struct. ~10,500 req/s single-process, ~35k with multiple workers. No async/await ceremony — Varian's green threads handle concurrency transparently.

server.vn
let app = new_app()
app.get("/hello", |req| {
    return Response { status: 200, body: "Hello!", content_type: "text/plain" }
}, "Says hello")
app.listen(8080)
middleware.vn
// Built-in JWT auth on a route group
let admin = app.group("/admin", { auth: "jwt", roles: ["admin"] })
admin.get("/dashboard", |req| {
    return Response { status: 200, body: "Admin dashboard" }
})
db.vn
let users = db.query("SELECT id, name FROM users WHERE active = ?", [true])
app.get("/users", |req| {
    return Response { status: 200, body: json_encode(users) }
})
Learn more about Zenith arrow_forward

Lumen

A server-driven UI framework that renders HTML on the server and sends incremental DOM patches over WebSocket. No client-side framework to download, no hydration mismatch, no SEO problems.

State lives in plain Varian data on the server. Write a state() function, bind it in templates with {{ variable }} and @click handlers. Think Phoenix LiveView or Rails Hotwire — but the UI framework ships with the language. Lumen UI provides a full Shadcn-inspired component registry.

counter.lumen
<template>
  <button @click="inc">{{ count }}</button>
</template>
<script>
fn state() { return { count: 0 } }
fn inc(s, v) { return s.set("count", s.get("count") + 1) }
</script>
sh
# Scaffold a Lumen project with hot-reload dev server
./vn lumen new my-app && cd my-app && ./vn dev

# Add a pre-built Lumen UI component
./vn lumen add card
UserCard.lumen
<template>
  <div class="card">
    <h3>{{ name }}</h3>
    <p>Likes: {{ likes }}</p>
    <button @click="like">Like</button>
  </div>
</template>
<script>
fn state() { return { likes: 0 } }
fn like(s, v) { s.likes = s.likes + 1; return s }
</script>
Learn more about Lumen arrow_forward

Kiln

The vn binary is everything: the language runtime, the compiler, the test runner, the formatter, the package manager — all in one binary.

vn build compiles to bytecode. vn build --release embeds the runtime into a single native binary for distribution. No separate build tool, no Makefile, no Docker layer for dependencies. vn dev for hot-reload, vn test for tests, vn fmt for formatting — the entire toolchain, one command.

sh
# Build for production
./vn build --release

# Development with hot reload
./vn dev pages/
sh
# Run tests
./vn test

# Format all source files
./vn fmt

# Lint for issues
./vn lint
Learn more about Kiln arrow_forward

Constellation

A decentralized package registry that just works. vn add pkg_name fetches a package and its transitive dependencies, vendored locally for reproducible offline builds.

No lockfile drama. No Python virtualenvs. No Go module proxy bureaucracy. Packages are hosted on any HTTP server that serves a constellation.json manifest. Specify a package name, and the toolchain handles resolution, download, and vendoring. No configuration file to edit.

sh
# Add a package
./vn add my-lib

# Use it — no import needed, globals auto-resolve
./vn run app.vn
sh
# Publish your own package (any HTTP server works)
./vn publish ./my-pkg https://my-server.com/packages
Learn more about Constellation arrow_forward

Performance

Benchmarks

Honest numbers for a young dynamic language. Varian prioritizes developer productivity over raw throughput — but it's no slouch.

FrameworkSingle-process8 workersMemory per requestProperty accessMethod dispatch
Zenith (Varian)12,053 req/s40,872 req/s~2 KB28.3M/s56.6M/s
Go (net/http)~20k req/s~85k req/s~4 KB
Rust (axum)~30k req/s~113k req/s~1 KB

Zenith benchmarks measured via wrk -t4 -c100 -d10s (plaintext). Single-process: 12,053 req/s. 8-worker cluster: 40,872 req/s. Property and method dispatch measured via bench/props.vn (1M iterations) and bench/dispatch.vn (2M iterations). Zenith is ~1.7-2.5x slower than statically compiled frameworks bar for bar, but the ergonomics win is enormous: one language for the whole stack, no async/await, no npm/node_modules, no FFI bindings. Varian is designed for teams that ship fast, not for maximum HTTP throughput.

Get started

Build from source and run in minutes

Build from source and run your first program in minutes.

bash
# Build from source
$ git clone https://github.com/Chidi09/VarianLang && cd VarianLang && make

# Your first program
$ echo 'print("Hello, World!")' > hello.vn
$ ./vn run hello.vn
Hello, World!

# A new fullstack app
$ ./vn new myapp && cd myapp && ./vn dev
terminal vn run <file> build vn build science vn test format_align_left vn fmt add_box vn add <pkg>

Community

Open-source, built by a thriving community