Mako is a compiled language. You write .mko files; the compiler turns them into
native binaries. There is no garbage collector or VM in the Mako runtime.
Speed matters here: release builds use -O3 -flto, and concurrency is built in
(crew / kick / join / fan, channels, actors). Memory is handled with
ownership, shares, arenas, and explicit resource APIs. The standard library
covers backend areas without requiring a framework for every service.
This is version 0.2.1. It runs. The surface is still early — expect change, rough edges, and missing pieces.
0.2.1 highlights: match exhaustiveness checking, match guards
(pattern if cond =>), use-after-move detection for hold values, and
compile-time rejection of unsynchronized mutable closure captures at every
kick boundary. fan mappers must be capture-free; explicit Sync handles are
the safe shared-state escape hatch. Plus everything from 0.2.0:
generics, mut self, stdlib in Mako, speed optimizations.
Next (roadmap): 0.2.2 — tooling (LSP, debugger, package registry).
mako-lang.com · Status · Roadmap · Guide · Book
Mako is built with cargo on our CI. You download the finished binary bundle (CLI + runtime + std). You never install Rust or run cargo yourself.
Linux
curl -fsSL https://github.com/loreste/mako/releases/latest/download/install-linux.sh | bash
source "$HOME/.local/share/mako/env.sh"
mako version
macOS
curl -fsSL https://github.com/loreste/mako/releases/latest/download/install-release.sh | bash
source "$HOME/.local/share/mako/env.sh"
That single command:
.mko files can compile)mako binary package for your CPUenv.sh, updates shell RC when possiblemako init hello && cd hello && mako run main.mko
Or grab the raw binary only (still needs headers via the tarball/installer for compiles):
https://github.com/loreste/mako/releases/latest/download/mako-x86_64-unknown-linux-gnu.tar.gz
Options:
curl -fsSL …/install-linux.sh | bash -s -- --prefix /opt/mako --yes
curl -fsSL …/install-linux.sh | bash -s -- --no-deps # skip clang install
curl -fsSL …/install-linux.sh | bash -s -- --version v0.2.1
You do not need Rust or cargo on the machine that runs Mako.
make install
mako version
Prefer the .zip from Releases, or build from source with LLVM clang on PATH.
mako init hello && cd hello
mako run main.mko
fn main() {
print("hello from mako")
print(fib(10))
}
fn fib(n: int) -> int {
if n <= 1 { return n }
return fib(n - 1) + fib(n - 2)
}
Real work, low ceremony: infer locals, one print, ? for errors, match for
routes, power (hold / crew / arena) only when you need it.
Ergonomics.
Native binaries, no GC, release -O3 -flto. Concurrent and parallel
work is first-class (crew, fan) — not a slow afterthought.
Speed · Performance.
The repository’s claim boundaries and current evidence are tracked in STATUS.md, SECURITY.md, and the release/cross-target guide. “No GC” means there is no tracing collector or mandatory collector mode; explicit MVCC version reclamation is a storage operation, not runtime garbage collection.
The compiler tracks who owns what. hold bindings move when you use them —
try to use a value after it's moved and the compiler stops you. For
request-scoped work, arenas let you allocate a bunch of things and free them
all at once when the scope ends:
arena a {
let msg = arena_text(a, "hello arena")
let xs = arena_ints(a, 1000)
}
// everything in `a` is gone — one free, zero bookkeeping
crew blocks own jobs started with kick. When the block ends, those jobs are
cancelled and joined. Explicit detach is a process-scoped escape and must be
followed by detached_join_all():
fn main() {
let ch = chan_new(4)
crew t {
let p = t.kick(producer(ch, 5))
let c = t.kick(consumer(ch))
let _ = p.join()
print_int(c.join())
}
// everything joined and done here
}
If a function returns a Result, you have to deal with it. The compiler
won't let you ignore one:
fn load() -> Result[int, string] {
let fd = open_cfg("config.toml")?
Ok(fd)
}
HTTP, TLS, WebSocket, JSON, SQLite, Postgres, crypto, compression, regex, file I/O, event loops, binary buffers, rate limiters, circuit breakers, consistent hashing, game networking, and session management are covered by the stdlib/runtime surface. Optional integrations still depend on their platform libraries; see STDLIB and Release.
fn main() {
let fd = http_bind(8080)
while true {
let c = http_accept(fd)
let path = http_path(c)
if str_eq(path, "/health") {
let _ = http_respond_json(c, 200, "{\"ok\":true}")
}
let _ = http_close(c)
}
}
Incremental by default. Release builds use -O3 -flto.
Benchmarks.
// Defer — runs on exit, last-in first-out
defer print("cleanup")
// Enums with methods
enum Shape {
Circle(int),
Rect(int, int),
}
fn Shape_area(self: Shape) -> int {
match self {
Circle(r) => r * r,
Rect(w, h) => w * h,
}
}
// Interfaces
interface Writer {
fn write(string) -> int
}
// Derive macros
#[derive(json)]
struct Person {
name: string
age: int
}
// Actors
actor Session {
receive Invite { print("invite") }
receive Bye { print("bye") }
}
// Memory-mapped files
let m = mmap_create("data.bin", 4096)
let _ = mmap_write(m, 0, "hello")
// Binary protocols
let b = buf_pack_new(64)
buf_write_u32be(b, 1024)
// Concurrent hashmaps
let m = cmap_new()
cmap_set(m, "key", "value")
// FFI
extern "C" fn my_c_function(n: int) -> int
Putting it all together — struct, database, error handling, arenas, and concurrency in one program (examples/showcase.mko):
#[derive(json)]
struct Task {
id: int
title: string
done: int
}
fn insert_task(db: SqlDB, title: string) -> Result[int, string] {
let rc = sql_exec_str4(db, "INSERT INTO tasks (title, done) VALUES ($1, $2)", title, "0", "", "")
if rc != 0 { return error("insert failed") }
Ok(0)
}
fn worker(ch: chan[int], id: int, results: CMap) -> int {
arena a {
let label = arena_text(a, format_int(id))
while true {
let task_id = ch.recv()
if task_id == 0 { break }
cmap_set(results, format_int(task_id), "worker " + label + " done")
}
}
return id
}
fn main() {
let db = sql_open_sqlite("/tmp/showcase.db")
let _ = sql_exec_plain(db, "CREATE TABLE IF NOT EXISTS tasks (id INTEGER PRIMARY KEY, title TEXT, done INTEGER)")
match insert_task(db, "write tests") {
Ok(_) => print("inserted"),
Err(e) => print("error: " + e),
}
let results = cmap_new()
let ch = chan_new(10)
crew t {
let w1 = t.kick(worker(ch, 1, results))
let w2 = t.kick(worker(ch, 2, results))
for i in 5 { let _ = ch.send(i + 1) }
let _ = ch.send(0)
let _ = ch.send(0)
let _ = w1.join()
let _ = w2.join()
}
for i in 5 { print(cmap_get(results, format_int(i + 1))) }
let _ = sql_close(db)
}
More in examples/ and The Mako Book.
mako init myapp # new project
mako run main.mko # compile and run
mako build main.mko # compile
mako build --release main.mko # optimized
mako test examples/testing # test suite
mako fmt -w # format
mako lint # lint
mako check main.mko # type-check only
mako build --target wasm32-wasip1 main.mko # WebAssembly
Split your code across files, import what you need:
// main.mko
import "./db.mko"
import "./routes.mko"
fn main() {
let _ = db_init()
let fd = http_bind(8080)
while true {
let c = http_accept(fd)
handle(c)
let _ = http_close(c)
}
}
Grouped and aliased imports work too:
import (
"./db.mko"
"./routes.mko"
"strings"
)
import "./helpers.mko" as h
For separate packages, use mako.toml:
[dependencies]
helper = { path = "../helper" }
| The Mako Book | Start here |
| Identity | Our syntax + identity checklist |
| Dual-form inventory | Optional sugar (not preferred) |
| How-to Guides | Practical walkthroughs |
| Language Guide | Current syntax reference (Mako-native) |
| Compat | Dual forms / what won't break |
| Standard Library | What's included |
| Built-in Functions | Documented built-ins and signatures |
| Language Spec | Formal specification |
| CLI Reference | Current commands, flags, and workflows |
| Tutorials | Backend, game networking, databases, FFI, concurrency, cloud |
| Examples | Runnable programs |
| Debugging | dbg(), lldb, sanitizers, error messages |
| Security | Safety model |
| Performance | Benchmarks |
| Status | What works, what doesn't |
| Roadmap | What's next |
| Changelog | What changed |
VS Code extension with syntax highlighting, LSP, format-on-save, launch configurations, and a custom dark theme. Debugging uses host adapters where available. See editors/vscode/.
The language server (mako lsp) speaks stdio JSON-RPC and supports the
implemented features in LSP-compatible editors.
mako test examples/testing
mako test -r TestAdd -v
mako test --coverage
Unit, property, fuzz, snapshot, fixture, and mock tests. The default suite is designed to run without external services; network-bound tests still require local socket permissions, and optional-service tests skip or soft-fail when the service/library is absent.
Mako is its own language with its own syntax. We take simplicity and control as goals, and we design the surface around the problems backend engineers actually hit — GC pauses, null, error-handling noise, leaked tasks, and lifetime ceremony — solving them with Mako's own tools rather than borrowing another look.
Keywords: fn, on, pack, pull, hold, share, arena, crew, kick,
match, export.
Identity · Pain points.
export struct Point {
x: int
y: int
}
on Point {
fn distance(self) -> int {
return self.x + self.y
}
}
fn divmod(a: int, b: int) -> (int, int) {
return (a / b, a % b)
}
fn main() {
let p = Point { x: 3, y: 4 }
print(p.distance())
let q, r = divmod(17, 5)
print(q)
print(r)
// Structured concurrency (ordinary kicked tasks are joined)
crew t {
let j = t.kick(work())
print(j.join())
}
}
Identity: docs/IDENTITY.md.
Sample: examples/mako_style.mko.
Dual spellings (func, :=, …) still parse for compatibility.
Full list in STATUS.md.
See CONTRIBUTING.md.
MIT