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:
Shared.marexists. 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.Main.maris the only module that sees both halves. It hands the list of services and the list of pages toApp.fullstack. Everything else is either backend, frontend, or shared.mar.jsonis 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.