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

Getting Started

Mar’s toolchain is one binary, mar. It is the compiler, the type checker, the dev server, the formatter, the test runner for your project’s shape, and the deploy tool. This chapter takes you from nothing to a running app, and names each moving part so later chapters can refer to them.

Install

Download the mar binary for your platform from the releases page and put it on your PATH. There is no package manager, virtual environment, or runtime to install; day-to-day development happens on macOS and Linux.

Check it works:

$ mar version

For syntax highlighting and completions, install the editor plugin: VS Code or Sublime Text.

Scaffold a project

$ mar init my-app

mar init asks which starter you want (a fullstack app with auth, a frontend-only app, and more) and writes a working project. The fullstack layout looks like this:

my-app/
  mar.json              manifest: name, server port, database path, mail, auth
  Main.mar              entry point: App.fullstack { services, pages }
  Shared.mar            types and Service contracts used by BOTH halves
  Backend/
    Users.mar           entities and service handlers
    Tasks.mar
  Frontend/
    Routes.mar          typed paths
    SignIn.mar          one MVU page per file
    Home.mar

Three things to notice, because they carry the philosophy:

  1. Shared.mar exists. Types and service contracts that both halves need live in one module both import. This file is the reason the frontend and backend cannot drift apart.
  2. Main.mar is the only module that sees both halves. It hands the list of services and the list of pages to App.fullstack. Everything else is either backend, frontend, or shared.
  3. mar.json is configuration, not code. Ports, database path, SMTP settings. Secrets must be environment references like "env:SMTP_PASSWORD"; a literal secret in the manifest is a compile error.

Run it

$ cd my-app
$ mar dev

mar dev boots a hot-reload development server. Edit any .mar file and the browser updates in place. Three details worth knowing already:

  • The compiler is watching. Save a file with a type error and the browser shows the error, nicely formatted, where your app was. Fix it and the app returns. You will spend real time reading these messages; they are written to be read.
  • The database is migrating. On startup, Mar compares your entity declarations to the actual SQLite schema and applies safe migrations automatically. Destructive changes refuse to run and tell you why. You never write migration files.
  • The admin panel is live at /_mar/admin: your entities, browsable and editable, with no code written.

There is also mar check (type-check without running) and mar build (produce the deployable artifacts).

Deploy it

$ mar deploy

One command, reading mar.json to decide what to ship:

  • A fullstack app compiles to a single self-contained binary (your code, the runtime, SQLite, static assets) and ships to a Fly.io VM.
  • A frontend-only app compiles to a folder of static files and ships to Cloudflare Pages.

Chapter 11 covers what is actually inside those artifacts and why the single-binary model was chosen.

The shape of every chapter ahead

You now have the pieces on the table: a manifest, a shared module, backend modules with entities and handlers, frontend modules with pages, and a runtime that turns them into a product. The rest of the book explains the ideas that make those pieces fit without glue, starting with the most fundamental one: values that never change.