Development Seeding
Add deterministic demo identities and credentials through an app-owned Effect boundary.
Effect Auth provides a fixed development dataset through @effect-auth/core/DevelopmentSeed. Use it for local login flows, UI states, adapter tests, and repeatable demos. It is not a production bootstrap or a general-purpose data factory.
Generate the integration
Use the Schema Generator API or its workbench and enable Include development seed, then choose a supported focused runtime target:
| Database | Targets |
|---|---|
| SQLite | bun-sqlite, node-sqlite |
| PostgreSQL | postgres |
| D1 | alchemy-d1 |
Keep complexity: "medium" unless the seed should be a standalone executable. Medium output exports an app-owned AppDevelopmentSeedLive and runDevelopmentSeed Effect without running it at module load time. Low output runs the Effect at the top level for standalone SQLite or PostgreSQL.
The D1 target builds an Effect Drizzle database from the queried binding and provides D1SqliteAccountAuthStorageLive, the focused nine-port account composition. Invoke it explicitly from alchemy.run.ts after migrations and pass AlchemyContext.dev as the development gate.
Dataset
Every run targets the same 100 identities, user1@example.test through user100@example.test. When the selected features include password, every account uses the public password password.
| Account | State |
|---|---|
user1@example.test | Active and verified |
user2@example.test | Unverified email |
user3@example.test | Disabled user |
user4@example.test | Revoked identity |
user5@example.test | Revoked password credential |
The complete distribution is 85 active verified users, 8 unverified users, 4 disabled users, 2 revoked identities, and 1 revoked password credential. Permissions are deliberately absent so the application remains responsible for its own authorization model.
Without the password feature, the seed calls seedUsers and needs no CredentialStore, PasswordHasher, or crypto layer. The revoked-password definition becomes an ordinary active verified identity because no password credential exists to revoke.
Compose the service
The generated file uses the focused account composition for the requested runtime. The core API remains small:
import {
DevelopmentSeed,
DevelopmentSeedLive,
} from "@effect-auth/core/DevelopmentSeed";
import { Effect } from "effect";
const seedProgram = Effect.gen(function* () {
const seed = yield* DevelopmentSeed;
return yield* seed.seedPasswordUsers;
});
export const runDevelopmentSeed = seedProgram.pipe(
Effect.provide(DevelopmentSeedLive)
);DevelopmentSeedLive itself requires the user, identity, and registration stores plus IdentityKindRegistry. seedPasswordUsers additionally requires CredentialStore and PasswordHasher; the generated Layer supplies those requirements with a focused direct account composition, default identity registry, PBKDF2 hasher, and Web Crypto. seedUsers leaves the password-only services out of the graph.
Run safely
Apply the generated migration before running the seed. Standalone generated files refuse NODE_ENV=production and require an explicit gate:
EFFECT_AUTH_DEVELOPMENT_SEED=true bun run seed-auth.tsPostgreSQL also requires DATABASE_URL. Bun and Node SQLite use EFFECT_AUTH_SQLITE_FILE, defaulting to ./data/auth.sqlite.
The operation is idempotent only for its owned deterministic namespace. A second unchanged run reports 100 existing users. It validates owned IDs, metadata, state, normalized identities, and the documented password rather than overwriting drift or taking over a colliding email. Treat a DevelopmentSeedError as a signal to inspect development data instead of silently repairing unrelated records.
Development only
The credentials are deliberately public and memorable. Never invoke the seed against production data or expose it through an HTTP route.