Meet Mimlet
Test data, with character. Build typed fixtures, keep scenarios connected, and reproduce failures with explicit seeds and compatible replay records.
Mimlet's core has no runtime dependencies. Schema adapters, generation engines, protocols, code generation and the local playground are independently installable packages. Choose an adapter for the capabilities you need.
Install the alpha
The coordinated alpha is available on npm's next channel: @mimlet/* packages at 0.1.0-alpha.2, alongside hey-api-builders@3.0.0-alpha.2. Pin matching versions when reproducing fixtures or generated clients. The existing Hey API latest tag remains on v2.
For the TypeBox example below, use Node 22.18 or newer and install:
npm install --save-dev @mimlet/core@0.1.0-alpha.2 @mimlet/typebox@0.1.0-alpha.2 typebox@1.3.34For a plain factory, only @mimlet/core is needed. The mimlet executable comes from @mimlet/codegen; the core package does not install a CLI. See compatibility for tested runtime and schema-library versions.
Your first fixture
This example uses modern typebox@1.3.34 and @mimlet/typebox. It is the same source compiled and executed by pnpm test:examples and shown on the home page.
import Type from 'typebox';
import { fluent } from '@mimlet/core';
import { fromTypeBox } from '@mimlet/typebox';
const User = Type.Object({
id: Type.String({ default: 'user-1' }),
role: Type.Union([
Type.Literal('reader'),
Type.Literal('admin'),
]),
});
const users = fluent(fromTypeBox(User), ['id', 'role']);
export const admin = users.withRole('admin').buildValidated();The original builder remains unchanged when you call .with(). .build() creates schema input; .buildValidated() validates that input and returns decoded output. Those types can differ when your schema has a codec or transform. Use the async methods when validation or the factory is asynchronous.
Named fluent helpers
Use fluent() to add selected named setters directly to a schema builder. Declare it once beside the test, then create the variations you need. No builder file or code-generation step is required:
npm install --save-dev @mimlet/core@0.1.0-alpha.2 @mimlet/zod@0.1.0-alpha.2 zod@4.6.5import { fluent } from '@mimlet/core';
import { fromZod } from '@mimlet/zod';
import { z } from 'zod';
const User = z.object({ name: z.string(), age: z.string().transform(Number) });
const users = fluent(fromZod(User), ['name', 'age']);
export const input = users.withName('Ada').withAge('42').build();
export const output = users.withName('Ada').withAge('42').buildValidated();
// input.age is a string; output.age is a number. No builder file is generated.
// Async transitions retain setters and remove synchronous build methods.
export const asynchronous = await users
.transformAsync(async (value) => value)
.withName('Grace')
.withAge('24')
.buildValidatedAsync();The field tuple is checked against the schema's input. Generic .with() remains available. For finite ordinary records, named setters retain native validation, immutable branches and async capabilities. Existing generated classes and the Hey API plugin remain optional alternatives.
Build from source
Use the repository's pinned pnpm toolchain:
git clone https://github.com/JeffreyNijs/mimlet.git
cd mimlet
corepack pnpm install --frozen-lockfile
corepack pnpm build
corepack pnpm test:examples
corepack pnpm docs:devThe example command installs toolkit tarballs in a temporary consumer, compiles the recipes, and runs them. If Corepack is unavailable, use pnpm 10.34.5 directly.
Try an isolated source consumer
From a clean, committed Mimlet checkout, pnpm release:prepare creates the verified tarballs and their digest manifest in release/. The command requires a clean tree and refuses to overwrite an existing release directory.
In a separate test project, install the core and TypeBox adapter tarballs together:
npm init -y
npm pkg set type=module
npm install /absolute/path/to/checkout/release/mimlet-core-0.1.0-alpha.2.tgz /absolute/path/to/checkout/release/mimlet-typebox-0.1.0-alpha.2.tgz typebox@1.3.34Replace the absolute paths with the checkout you built. Add only the adapters you need, using the matching release train. This local workflow lets you test source changes before publishing a new version.
When generation needs your help
Automatic generation has a supported capability set. A native refinement, custom format or callback may need an explicit factory:
import Type from 'typebox';
import { fromTypeBoxFactory } from '@mimlet/typebox';
const Code = Type.String({ pattern: '^APP-[0-9]+$' });
const codes = fromTypeBoxFactory(Code, (index: number) => `APP-${index}`);
export const code = codes.buildValidated(42); // 'APP-42'Use a factory to express meaningful domain data while retaining native validation. A generation failure does not prove that a schema has no valid values.
Continue with scenarios, replay, or the coding-agent recipes. Existing Hey API users should read the migration guide.