Getting Started
OverviewLanguage GuideFull Reference
Book
Table of ContentsIntroductionPrefaceGetting StartedLanguage TourOwnershipErrorsConcurrencyStdlibNetworkingDataPackagesSpeed & SafetyCross-PlatformToolingCookbookAppendix
Reference
Standard LibraryKeywordsPerformanceSecurityBuilt-in FunctionsStatusDebuggingABI
How-To
Getting StartedHTTP APIsErrorsPackagesConcurrencyMemoryWASITestingRelease Builds
Project
RoadmapVisionChangelogContributing

Documentation

Mako

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


Install

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:

  1. Installs clang if missing (so .mko files can compile)
  2. Downloads the cargo-built mako binary package for your CPU
  3. Installs runtime headers + standard library beside it
  4. Verifies SHA-256, writes env.sh, updates shell RC when possible
mako 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.

From source (large — installs Rust toolchain + crates)

make install
mako version

Windows

Prefer the .zip from Releases, or build from source with LLVM clang on PATH.


Write something

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.


How it works

Speed first

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.

Ownership instead of 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

Concurrency that cleans up

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
}

Errors the compiler enforces

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)
}

Standard library

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)
    }
}

Builds

Incremental by default. Release builds use -O3 -flto. Benchmarks.


Syntax tour

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


Commands

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

Multi-file projects

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" }

Docs

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

Editor support

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.

Testing

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.

Our syntax — its own

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.

What's not done yet

Full list in STATUS.md.

Contributing

See CONTRIBUTING.md.

License

MIT

Edit this page on GitHub Report an issue