Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

What Is Mar?

Mar is a language for building full-stack applications: the kind with a database, a server, signed-in users, and a user interface that runs in a browser and on a phone. You write the whole thing, backend and frontend, in one language, in one codebase, and it compiles into everything you need to ship.

one codebase  →  a web bundle
              →  a native iOS app
              →  a single server binary with SQLite, auth, and an admin panel inside

One codebase, three targets

The problem Mar is aimed at

Think about what a small, ordinary product is made of today: a frontend framework, a language for it, a bundler, a backend language, an HTTP framework, an ORM, a database, a migration tool, an auth provider, JSON schemas or an API-types package to keep the two halves agreeing, and a deployment story for each piece.

None of these pieces is bad. The trouble is the seams between them. The frontend believes the API returns dueDate; the backend renamed it to due_date last Tuesday. The ORM model drifted from the actual table. The auth middleware runs on every route except the one where it matters. Every seam is glue, every glue joint is invisible to the type checker, and every invisible joint fails at runtime, in production, at night.

Mar’s founding observation is that most of these seams are not essential. They exist because we build one product out of several languages and toolchains that cannot see each other. Put the whole application in one language, and the seams become ordinary function calls and shared types, which a compiler can check.

The Mar project describes this with a metaphor from Japanese woodworking: sashimono, joinery without nails or glue. Each piece is shaped to fit the others. There is no glue to fail because there is no glue.

What that looks like in practice

A few concrete consequences, each of which gets its own chapter later:

  • One definition of every type. The Task record your database stores, your server returns, and your page renders is the same declaration. Rename a field and the compiler walks you through every place that must change, across the entire stack.
  • API calls are typed function calls. A service is declared once, with its request and response types, and both halves import that declaration. There is no JSON handling in your code, and there is no way for the two sides to disagree and still compile.
  • The scaffolding is included. Authentication (passwordless email codes), authorization, database, migrations, backups, rate limiting, and an admin panel ship with the runtime. Day one of a Mar project is spent on your product, not on wiring.
  • The UI is written once. Pages are composed from a fixed vocabulary of elements. The web runtime renders them as careful HTML and CSS; the iOS runtime renders them as native SwiftUI. You do not write either.
  • Deployment is boring. A fullstack app compiles to one self-contained executable, assets and database engine included. A frontend-only app compiles to a folder of static files.

The kind of language Mar is

Mar belongs to the ML family of languages, with syntax and discipline closely modeled on Elm. If you have not met this family, here is the character sketch; Part I develops each point properly.

  • Purely functional. Programs are built from functions that compute values from values. Anything that touches the world (the database, the network, the clock) is described as data and executed by the runtime, never performed secretly inside your logic.
  • Immutable. A value, once created, never changes. “Change” means computing a new value.
  • Statically typed, with inference. Every expression has a type checked at compile time, but you rarely write type annotations; the compiler works them out (the technique is called Hindley-Milner inference). Union types and exhaustive pattern matching replace null checks and exception handling.
  • Interpreted by its runtime, by design. Mar programs are shipped as a compact program description that each platform’s runtime executes: JavaScript on the web, Swift on iOS, Go on the server. This is what makes one language on three platforms tractable, and it is fast enough that entire 60fps games are written in it.

What Mar is not

Honesty early saves disappointment later.

  • Mar is not a systems language. There is no manual memory management and no C interop. You will not write a database engine in it (Mar’s own engine is written in Go, underneath the language).
  • Mar is not a general-purpose UI toolkit. The view vocabulary is opinionated. If your product needs a bespoke design system with custom CSS on every pixel, Mar will feel like a straitjacket.
  • Mar is not runtime-dynamic. There is no eval, no monkey patching, no reflection. Everything is known at compile time. This is a feature, but it is fair to note it also closes doors.
  • Mar is young. The ecosystem is small, the language is evolving, and breaking changes still happen between versions.

The right mental model: Mar trades breadth for depth. It covers one shape of software, the typed application with a UI, a server, and a database, and it tries to cover it end to end, better than a pile of glued parts can.

The next chapter installs the toolchain and runs a real project, so the rest of the book has something concrete to point at.