╦ ╦ ╦╦ ╦ ║ ║ ║╔╣ ╩═╝╚═╝╩ ╩
The Language That
Changes Everything
Algebraic effects. Behavioral types. Schema evolution.
Compile to native C or JavaScript. One language, every platform.
Not Just Another Functional Language
Lux solves problems other languages can't even express
ALGEBRAIC EFFECTS
Side effects in the type signature. Swap handlers for testing. No dependency injection frameworks.
BEHAVIORAL TYPES
Prove functions are pure, total, deterministic, or idempotent. The compiler verifies it.
SCHEMA EVOLUTION
Built-in type versioning with automatic migrations. Change your data types safely.
DUAL COMPILATION
Same code compiles to native C (via GCC) or JavaScript. Server and browser from one source.
NATIVE PERFORMANCE
Beats Rust and Zig on recursive benchmarks. Zero-cost effect abstraction via evidence passing.
BATTERIES INCLUDED
Package manager, LSP, REPL, debugger, formatter, test runner. All built in.
Effects: The Core Innovation
Every side effect is tracked in the type signature
fn processOrder(
order: Order
): Receipt
with {Sql, Http, Console} =
{
let saved = Sql.execute(db,
"INSERT INTO orders...")
Http.post(webhook, order)
Console.print("Order {order.id} saved")
Receipt(saved.id)
}
The signature tells you everything:
- Sql — Touches the database
- Http — Makes network calls
- Console — Prints output
No surprises. No hidden side effects. Ever.
Testing Without Mocks or DI Frameworks
Swap effect handlers at test time. Same code, different behavior.
// Production: real database, real HTTP
run processOrder(order) with {
Sql -> postgresHandler,
Http -> realHttpClient,
Console -> stdoutHandler
}
// Test: in-memory DB, captured calls
run processOrder(order) with {
Sql -> inMemoryDb,
Http -> captureRequests,
Console -> devNull
}
No Mockito. No dependency injection. Just swap the handlers.
Behavioral Types: Compile-Time Guarantees
Prove properties about your functions. The compiler enforces them.
// The compiler verifies these properties
fn add(a: Int, b: Int): Int
is pure is commutative = a + b
fn factorial(n: Int): Int
is total = if n <= 1 then 1 else n * factorial(n - 1)
fn processPayment(p: Payment): Result
is idempotent = // Safe to retry on failure
...
fn hash(data: Bytes): Hash
is deterministic = // Same input = same output
...
is pure
No side effects. Safe to memoize.
is total
Always terminates. No infinite loops.
is idempotent
Run twice = run once. Safe for retries.
Schema Evolution: Safe Data Migrations
Built-in type versioning. No more migration headaches.
type User @v1 { name: String }
type User @v2 {
name: String,
email: String,
from @v1 = {
name: old.name,
email: "unknown@example.com"
}
}
type User @v3 {
firstName: String,
lastName: String,
email: String,
from @v2 = {
firstName: String.split(old.name, " ").head,
lastName: String.split(old.name, " ").tail,
email: old.email
}
}
Load old data with new code. The compiler ensures migration paths exist.
One Language, Every Platform
Compile to native C or JavaScript from the same source
# Compile to native binary (via GCC)
lux compile server.lux
./server # Runs natively
# Compile to JavaScript
lux compile client.lux --target js
node client.js # Runs in Node/browser
Same code, different targets:
- Native C — Maximum performance, deployable anywhere
- JavaScript — Browser apps, Node.js servers
- Shared code — Validation, types, business logic
Native Performance
fib(35) benchmark — verified with hyperfine
Zero-cost effects via evidence passing — O(1) handler lookup
Built-in Effects
Everything you need, ready to use
Console
print, readLine, readInt
File
read, write, exists, listDir
Http
get, post, put, delete
HttpServer
listen, respond, routing
Sql
query, execute, transactions
Process
exec, env, args, exit
Random
int, float, bool
Time
now, sleep
Developer Experience
Modern tooling, built-in
# Package manager
lux pkg init myproject
lux pkg add json-parser
lux pkg install
# Development tools
lux fmt # Format code
lux check # Type check
lux test # Run tests
lux watch app.lux # Hot reload
# LSP for your editor
lux lsp # Start language server
Everything included:
- Package Manager — Git repos, local paths, registry
- LSP — VS Code, Neovim, Emacs, Helix
- REPL — Interactive exploration
- Debugger — Step through code
- Formatter — Consistent style
- Test Runner — Built-in test effect
Get Started
# Install via Nix (recommended)
nix run github:luxlang/lux
# Or build from source
git clone https://github.com/luxlang/lux
cd lux && nix develop
cargo build --release
# Start the REPL
./target/release/lux
# Run a file
./target/release/lux hello.lux
# Compile to native binary
./target/release/lux compile app.lux --run
// hello.lux
fn main(): Unit with {Console} = {
Console.print("Hello, Lux!")
}
run main() with {}
Why Lux?
vs Haskell
Algebraic effects instead of monads. Same power, clearer code. Weeks to learn, not months.
vs Rust
No borrow checker to fight. Automatic memory management. Still native performance.
vs Go
Real type safety. Pattern matching. No nil panics. Effects track what code does.
vs TypeScript
Sound type system. Native compilation. Effects are tracked, not invisible.
vs Elm
Compiles to native, not just JS. Server-side, CLI apps, anywhere.
vs Zig
Higher-level abstractions. Algebraic types. Still fast.