Skip to content

Getting Started

The quickest way to understand Semitra is to run the example API in this repository and follow one request from route to response.

If you are starting a new app rather than exploring this repository, Semitra also generates a full-stack workspace with apps/api and apps/web.

  • Bun
  • Wrangler on your PATH
  • A Cloudflare D1 database only if you plan to run remote migrations or deploy

From the repository root:

Terminal window
bun install
bun run codegen
bun run dev

What those commands do:

  • bun install installs workspace dependencies, including the docs app.
  • bun run codegen generates the Semitra manifest and Worker bootstrap for apps/example-api.
  • bun run dev runs the example API locally through the Semitra CLI.
  • apps/example-api/src/index.ts is the Worker entrypoint.
  • apps/example-api/.semitra/generated/app.ts is the generated bootstrap.
  • apps/example-api/config/application.ts configures tenancy.
  • apps/example-api/config/routes.ts defines the route DSL.

If you edit routes, controllers, records, resources, policies, jobs, mailers, mailboxes, or channels, rerun code generation before restarting the worker:

Terminal window
bun run codegen

Use the CLI when you want a new Semitra app instead of the repository example:

Terminal window
semitra new support-portal
cd support-portal
bun install
bun run dev

The generated root dev script calls semitra dev, which runs apps/api and apps/web together. Use bun run dev:api or bun run dev:web only when you want to run one side by itself.

The generated workspace contains:

  • apps/api for the Cloudflare Worker JSON backend.
  • apps/web for the React Router 7, Vite, and Tailwind frontend.
  • apps/web/app/lib/api.ts for typed API endpoints.
  • apps/web/app/models for frontend response models.

The generated backend defaults to a versioned API under /api/v1. The local dev server proxies /api requests to the Worker; use VITE_API_BASE_URL only when the browser should call a separate API origin directly.

The example app uses the DB D1 binding declared in apps/example-api/wrangler.toml.

Run local migrations:

Terminal window
bun run migrate:local

Run remote migrations:

Terminal window
bun run migrate:remote

Once bun run dev is running:

Terminal window
curl http://127.0.0.1:8787/health
curl http://127.0.0.1:8787/api/v1/health

Create a post through the versioned API:

Terminal window
curl \
-X POST http://127.0.0.1:8787/api/v1/posts \
-H 'content-type: application/json' \
-H 'x-semitra-tenant: public' \
-H 'x-semitra-role: admin' \
-d '{"post":{"title":"Hello Semitra","content":"Cloudflare-native"}}'

In the example app:

  • x-semitra-tenant participates in tenant resolution.
  • x-semitra-role is used by ApplicationController to hydrate currentUser.
  • x-semitra-user-id can optionally set the demonstration user id.

Semitra scaffolds the conventional layers:

Terminal window
semitra generate model post
semitra generate controller posts
semitra generate policy post
semitra generate resource post
semitra generate job welcome_email
semitra generate channel notifications
semitra generate mailer welcome
semitra generate mailbox inbound

Generated files land in the standard app/ tree and extend the Semitra base-class model through application-specific base classes.