# Quickstart (Mojo)
> uvx m0 new to a served page, tests, rebuild on save and a deploy image. CI runs every tagged command on the page.
A web application written in Mojo: a server-rendered list that htmx 4 swaps
in place, compiled to one binary with no interpreter in it. `m0` writes the
project, builds it against the framework's source, tests it, rebuilds it on
save and builds its deploy image.
macOS arm64 and glibc Linux (x86-64, aarch64). It needs
[uv](https://docs.astral.sh/uv/) and a C compiler named `cc` (Xcode's
command line tools, or `build-essential`); `uv sync` installs the Mojo
toolchain into the project. CI extracts the tagged commands below and runs
them on every pull request (`poe smoke-quickstart-mojo`).
## 1. A project
```bash setup
uvx m0 new shop
cd shop
uv sync
```
`m0 new` writes `./shop` and needs neither a toolchain nor a network.
`uv sync` installs the two packages `pyproject.toml` pins exactly: `m0`, and
the one `mojo` that `m0` release was tested on. The toolchain is a few
hundred megabytes the first time and comes from uv's cache after that.
```text
shop/
src/server.mojo main: hands the views table to the host
src/views.mojo the state, the views, the URL table
src/pages.mojo the routes as constants, the fragment, the document
test/ test_*.mojo
smoke.sh build, serve, probe the wire, stop
deploy/ Dockerfile, fly.toml
AGENTS.md the rules that are not obvious from the code
```
`--template live` writes the other template: a producer thread that pushes
its whole state to every open tab over Server-Sent Events, with Datastar.
## 2. Build and serve
```bash setup
uv run m0 build
```
`src/server.mojo` compiles to `bin/server`.
The first build takes 13–15 s, a build after an edit 10–13 s, and
`uv run m0 test` 2–4 s, so put logic where a test can reach it.
```bash serve
bin/server --port 8080
```
Open . Add an item, open it, delete it: each is one
request whose answer replaces the `` element. Stop the
server with Ctrl-C.
From a second terminal, in `shop/`:
```bash verify
curl -sf --retry 20 --retry-delay 1 --retry-all-errors http://127.0.0.1:8080/health
echo
# A navigation gets a document. An htmx 4 swap says `HX-Request-Type: partial`
# and gets the fragment alone.
curl -s http://127.0.0.1:8080/items | grep -q ''
curl -s -H 'HX-Request-Type: partial' http://127.0.0.1:8080/items | grep -q '^ /dev/null
curl -s http://127.0.0.1:8080/items | grep -q 'nothing yet'
sed -i.bak 's/nothing yet/the shelf is empty/' src/pages.mojo && rm src/pages.mojo.bak
# The old server answers until the new build has succeeded.
for i in $(seq 1 90); do
curl -s --max-time 2 http://127.0.0.1:8080/items | grep -q 'the shelf is empty' && break
sleep 1
done
curl -s http://127.0.0.1:8080/items | grep -q 'the shelf is empty'
echo "rebuilt and swapped"
```
## 6. An image
```bash
uv run m0 image
docker run --rm -p 8080:8080 shop
```
`m0 image` is `docker build -f deploy/Dockerfile` from the project root,
then the image's own `/app/about.json` as the last line of output. The
compiler runs in the builder stage, so this step needs docker, a committed
`uv.lock`, and no local toolchain. The image holds the binary and the Mojo
runtime libraries and no Python. CI builds this image from a scaffolded
project on x86-64 Linux on every pull request (`poe smoke-scaffold-image`);
the commands above are not among the ones this page's gate runs, because
half of its runners have no docker. [Deploy](https://m0serve.dev/mojo/deploy.md) has
the rest, Fly.io included.
## Next
- [The host](https://m0serve.dev/mojo/host.md): workers, threads, a handler pool,
flags and the doctor, every refusal.
- [Views and fragments](https://m0serve.dev/mojo/views.md): the views table,
`Fragment`, the htmx and Datastar vocabularies, pages and fragments from
one view, URLs, sessions.
- `AGENTS.md` in the project is the short form of both, written for a coding
agent. `uv run m0 include` prints where the framework's source is
installed; it is there to be read.