---
title: "Development Seeding"
url: "https://effect-auth.itsbroly.com/guides/development-seeding/"
description: "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 [#generate-the-integration]

Use the [Schema Generator API](/infrastructure/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 [#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 [#compose-the-service]

The generated file uses the focused account composition for the requested runtime. The core API remains small:

```ts
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 [#run-safely]

Apply the generated migration before running the seed. Standalone generated files refuse `NODE_ENV=production` and require an explicit gate:

```sh
EFFECT_AUTH_DEVELOPMENT_SEED=true bun run seed-auth.ts
```

PostgreSQL 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.

<CalloutContainer type="error">
  <CalloutTitle>
    Development only
  </CalloutTitle>

  <CalloutDescription>
    The credentials are deliberately public and memorable. Never invoke the seed against production data or expose it through an HTTP route.
  </CalloutDescription>
</CalloutContainer>

