Skip to content
All guides

learn

The ledger becomes an app

You started with println("Ledger ready"). You now have types, a list, functions, structs, and errors. This chapter is the last mile of that same program:

  1. Split it into modules (the files you just learned)
  2. Serve it as a Keel API with a page
  3. Pack a ship

That is the 1.0 loop. Not a rewrite in another language. Not a framework migration.

1. Split the CLI

From the ledger project:

ledger/
  buraaq.pkg
  src/main.bq
  src/tx.bq
  src/account.bq

src/tx.bq:

pub struct Tx {
    amount: int
    note: text
}

pub fn deposit(cents: int, note: text) -> Tx {
    Tx { amount: cents, note: note }
}

pub fn withdraw(cents: int, note: text) -> Tx {
    Tx { amount: 0 - cents, note: note }
}

src/account.bq:

use tx.Tx

pub struct Account {
    owner: text
    balance: int
}

pub fn open(owner: text) -> Account {
    Account { owner: owner, balance: 0 }
}

pub fn apply(a: Account, t: Tx) -> Account {
    Account { owner: a.owner, balance: a.balance + t.amount }
}

src/main.bq:

use tx.{deposit, withdraw}
use account.{open, apply}

fn main() {
    mut a = open("Ada")
    a = apply(a, deposit(5000, "payroll"))
    a = apply(a, withdraw(1200, "rent"))
    println(a.owner)
    println(a.balance)
}
buraaq run

You should see Ada and 3800. Unique std.io names still import themselves. The use lines are only for your modules.

2. Serve the same idea

A CLI proves the language. A service proves the stack. Keep the project. Change main to declare a hull:

fn main() {
    page("/", "public/index.html")
    api("accounts", "name, note")
    api("ledger", "account, cents, memo")
    run()
}

page, api, and run auto-import from std.keel. Put a page in public/index.html (or run buraaq new ledger in a fresh folder if you want the scaffold).

Set Postgres on the host, not in source:

$env:BURAAQ_DATABASE_URL = "host=127.0.0.1 port=5432 dbname=ledger user=postgres"
buraaq run

Keel creates the tables, serves /api/accounts and /api/ledger, and /api/health is SELECT 1. If a Neon pooler drops an idle socket, Keel reconnects on the next query.

Do not put JSON in a Buraaq "..." string ({ interpolates). POST from curl or from the page.

curl http://127.0.0.1:8080/api/health

Open http://127.0.0.1:8080. TLS is on 8443.

This is the same ledger: accounts, amounts in cents, a memo. The difference is the OS can exec it as a service.

3. Pack it

buraaq up

That packs a hashed .bur, starts a local Dock if needed, and runs the process. On a VM you own:

buraaq land --cloud hetzner
buraaq ship HOST

Put BURAAQ_DATABASE_URL in ~/.buraaq/dock/env (or an env file next to the binary). Never in git. A Windows .bur will not run on Linux: pack on the host OS.

This chapter is the full arc in public docs: modules, ownership, spawn, a Keel ledger, Postgres, Land. Private demos may go further; your ledger here is the version you can ship from the public tree.

What you just beat

StepWhat you did not need
Two filesheaders, mod.rs, a bundler
Auto-importa use list for println / page / run
The APIExpress, Axum, a Dockerfile
The databasean ORM, a migration DSL for api() tables
The deployKubernetes, a guest Linux

You wrote Buraaq the whole way. Native LLVM the whole way. Next: stdlib if you want Stream, Gfx, Hold, and Grid, or Servers for REST depth, or Ship for the hash and the dock.