ShipKit docs
Guides

Generators

One command scaffolds a whole vertical slice, from the Drizzle table to the react-query hook.

Adding a resource by hand means touching a table, a model, a service, a controller, the route registration, shared schemas, hooks and the OpenAPI spec — eight places, in a fixed order, every time. The generator does that pass deterministically.

bun run generate resource projects
bun run generate job send-digest
bun run generate webhook-event project.completed

apps/web/app/[locale]/dashboard/projects in the running demo is what a generated resource looks like once it has a screen.

What resource writes

schema.ts (table appended)
model.ts
service.ts
service.test.ts
controller.ts
schemas.ts
types.ts
hooks.ts
index.ts

It also registers the controller in the v1 router and refreshes apps/api/openapi.json, which means the new routes appear in the Scalar reference and as MCP tools without another step.

The generated service.test.ts is a guard test, not a placeholder: it asserts the ownership scoping that keeps one user's rows away from another's.

Flags

FlagEffect
--entitlement=<feature>Gates the routes on a feature from the entitlements catalogue
--auditWrites changes through the audit-log helper
--singular=<word>When the plural is irregular and the derived singular would be wrong
--forceOverwrite existing files instead of skipping them
--jsonEmit the manifest as JSON

It is safe to re-run

Existing files are skipped, not clobbered, and in-place registrations are applied once. Running the same command twice is a no-op rather than a mess, which is what makes it usable from a script.

Every run prints a manifest of what it created, updated and skipped. With --json that manifest is machine-readable, so an agent can generate a slice and then act on exactly the files it touched instead of guessing.

The generator does not run db:push. It appends the table to the schema and stops, so you can read the diff before it reaches a database. Push or generate a migration yourself — see database for which of those you want.

After generating

The scaffold is correct and generic. What it cannot know is your domain: the columns beyond id, ownerId and timestamps, the validation that matters, and whether a list endpoint should paginate. Open model.ts first — the schemas there drive both the API validation and the OpenAPI spec, so tightening them is the highest-leverage edit.

On this page