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.
Prerequisites
Section titled “Prerequisites”- Bun
- Wrangler on your
PATH - A Cloudflare D1 database only if you plan to run remote migrations or deploy
Start the example API
Section titled “Start the example API”From the repository root:
bun installbun run codegenbun run devWhat those commands do:
bun installinstalls workspace dependencies, including the docs app.bun run codegengenerates the Semitra manifest and Worker bootstrap forapps/example-api.bun run devruns the example API locally through the Semitra CLI.
Key entry points
Section titled “Key entry points”apps/example-api/src/index.tsis the Worker entrypoint.apps/example-api/.semitra/generated/app.tsis the generated bootstrap.apps/example-api/config/application.tsconfigures tenancy.apps/example-api/config/routes.tsdefines the route DSL.
If you edit routes, controllers, records, resources, policies, jobs, mailers, mailboxes, or channels, rerun code generation before restarting the worker:
bun run codegenCreate a full-stack starter
Section titled “Create a full-stack starter”Use the CLI when you want a new Semitra app instead of the repository example:
semitra new support-portalcd support-portalbun installbun run devThe 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/apifor the Cloudflare Worker JSON backend.apps/webfor the React Router 7, Vite, and Tailwind frontend.apps/web/app/lib/api.tsfor typed API endpoints.apps/web/app/modelsfor 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.
Run migrations
Section titled “Run migrations”The example app uses the DB D1 binding declared in
apps/example-api/wrangler.toml.
Run local migrations:
bun run migrate:localRun remote migrations:
bun run migrate:remoteHit the API
Section titled “Hit the API”Once bun run dev is running:
curl http://127.0.0.1:8787/healthcurl http://127.0.0.1:8787/api/v1/healthCreate a post through the versioned API:
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-tenantparticipates in tenant resolution.x-semitra-roleis used byApplicationControllerto hydratecurrentUser.x-semitra-user-idcan optionally set the demonstration user id.
Generate framework files
Section titled “Generate framework files”Semitra scaffolds the conventional layers:
semitra generate model postsemitra generate controller postssemitra generate policy postsemitra generate resource postsemitra generate job welcome_emailsemitra generate channel notificationssemitra generate mailer welcomesemitra generate mailbox inboundGenerated files land in the standard app/ tree and extend the Semitra
base-class model through application-specific base classes.