todo-sqlite

April 9, 2026 · View on GitHub

This project was generated by meshc init --template todo-api --db sqlite.

It is the honest local starter: a single-node SQLite Todo API, a process-backed write rate limiter, generated package tests, and a Dockerfile that packages the binary produced by meshc build .. It does not claim clustered placement, continuity, or operator surfaces.

Project layout

todo-sqlite/
  mesh.toml
  main.mpl
  config.mpl
  README.md
  Dockerfile
  .dockerignore
  api/
    health.mpl
    router.mpl
    todos.mpl
  runtime/
    registry.mpl
  services/
    rate_limiter.mpl
  storage/
    todos.mpl
  tests/
    config.test.mpl
    storage.test.mpl
  types/
    todo.mpl

Local contract

  • mesh.toml stays package-only and intentionally omits [cluster]
  • main.mpl validates local config, creates the SQLite schema, and starts the HTTP server directly
  • generated tests under tests/ prove the local config and storage contract with meshc test .
  • /health reports local SQLite state and rate-limit configuration
  • all routes run locally; there is no work.mpl, HTTP.clustered(...), or meshc cluster story in this starter

HTTP routes

  • GET /health — local SQLite + rate-limit configuration snapshot
  • GET /todos — list todos locally
  • GET /todos/:id — fetch one todo locally
  • POST /todos — create from {"title":"Buy milk"}
  • PUT /todos/:id — toggle completion
  • DELETE /todos/:id — delete a todo

Mutating routes (POST, PUT, DELETE) stay local and go through the actor-backed limiter in services/rate_limiter.mpl.

Environment

  • PORT — HTTP port (8080 by default)
  • TODO_DB_PATH — SQLite database path (todo.sqlite3 by default)
  • TODO_RATE_LIMIT_WINDOW_SECONDS — limiter window length (60 by default)
  • TODO_RATE_LIMIT_MAX_REQUESTS — allowed mutating requests per window (5 by default)

Use :memory: only for tests or intentionally ephemeral runs. If you set TODO_DB_PATH, it must be a non-empty path.

Local verification

meshc test .
meshc build .
PORT=8080 \
TODO_DB_PATH=./todo.sqlite3 \
TODO_RATE_LIMIT_WINDOW_SECONDS=60 \
TODO_RATE_LIMIT_MAX_REQUESTS=5 \
./todo-sqlite

Clustered and deployable paths

When you need clustered/runtime-owned execution or a shared-database starter, use one of the explicit paths instead of stretching this SQLite template past its contract:

meshc init --template todo-api --db postgres my-shared-todo
meshc init --clustered my-clustered-app

Docker

Build the Linux binary you want to ship, then package that ./output artifact into the image:

meshc build .
docker build -t todo-sqlite .

Re-run meshc build . before rebuilding the image, and build on the Linux target you plan to run because the Dockerfile copies the already-compiled ./output binary into the container. If you're driving Docker from macOS or Windows, emit ./output from a Linux builder host, CI job, or container first.

Run it with a persisted SQLite volume:

docker run --rm \
  -p 8080:8080 \
  -e PORT=8080 \
  -e TODO_DB_PATH=/var/lib/todo/todo.sqlite3 \
  -v todo-data:/var/lib/todo \
  todo-sqlite