API model
Beignet APIs follow a small grammar. Once you know the grammar, new packages should feel predictable.
Naming
Use define* for static declarations that describe application-owned shape.
defineErrors(...)
definePorts(...)
defineConfig(...)
Use create* for runtime factories, adapters, servers, clients, providers, and
test helpers.
createContractGroup()
createEnv(...)
createNextServer(...)
createClient(...)
createReactQuery(client)
createReactHookForm()
createNuqs()
createProvider(...)
createUseCase(...)
createUseCaseTester(...)
Definition helpers use domain language when the helper creates a reusable application primitive or runtime declaration.
defineEntity("Post")
defineEvent("PostPublished")
defineValueObject("Email")
defineJob("SendEmail")
Declaration builders use .build() when they need an explicit finalization
step.
defineEntity("Post").props(postSchema).build()
defineValueObject("Email").schema(emailSchema).build()
Builders
Builders are immutable. Chained methods refine the definition and return the next builder.
const posts = createContractGroup()
.namespace("posts")
.prefix("/api/posts")
.headers(writerHeadersSchema);
export const createPost = posts
.post("/")
.body(createPostSchema)
.errors({ Unauthorized: errors.Unauthorized })
.responses({ 201: postSchema });
The same shape appears in application code.
export const createPostUseCase = useCase
.command("posts.create")
.input(createPostSchema)
.output(postSchema)
.run(async ({ ctx, input }) => {
return ctx.ports.posts.create(input);
});
Contract-aware adapters
Contract-aware adapters accept the contract builder you already exported. You
do not need to manually extract .config for normal usage.
const endpoint = client.endpoint(createPost);
const mutation = rq(createPost).mutationOptions();
const form = rhf(createPost).useForm();
const filters = nq(listPosts).query({ parsers });
This is the main transfer rule: define the contract once, then bind it to the runtime surface you need.
Normal path and escape hatches
The normal path is contract-first and builder-driven:
contract -> server route -> client endpoint -> React adapter
Properties such as .config, .schema, .metadata, .responseSchemas, and
.endpoint are escape hatches for integration code, generators, tests, and
advanced introspection. Application code should usually pass the contract
builder directly.
App vocabulary
Beignet apps keep the same concepts in predictable folders.
features/ feature-owned contracts, routes, use cases, policies, and UI
server/ runtime wiring
ports/ app-wide dependency interfaces
infra/ concrete adapters
client/ browser/core/server client adapters
lib/ shared app helpers such as env, auth, and use-case builder
The CLI follows this vocabulary when it inspects an app, generates resources, and reports drift.