# Use Cases
URL: /docs/use-cases
LLM index: /llms.txt
Description: Where the generator-first approach fits best.

# Use Cases

The strongest fit is anything that needs one storage-facing design while giving
consuming applications room to choose their own persistence stack.

## Sections

- [Framework authors](/docs/use-cases/framework-authors)
- [Multi-storage walkthrough](/docs/use-cases/multi-storage-walkthrough)
- [Auth libraries](/docs/use-cases/auth-libraries)
- [Adapter ecosystem](/docs/use-cases/auth-adapter-ecosystem)
- [Billing modules](/docs/use-cases/billing-modules)
- [Full-stack frameworks](/docs/use-cases/fullstack-frameworks)
- [Internal platforms](/docs/use-cases/internal-platforms)

If you want one concrete end-to-end example instead of a category page, start
with the [multi-storage walkthrough](/docs/use-cases/multi-storage-walkthrough).

## 1. Auth-like libraries

This is one of the clearest use cases.

### The usual problem

Auth libraries often end up maintaining:

- Prisma adapter logic
- Drizzle adapter logic
- app-specific schema examples
- migration examples
- docs for every storage story

### What Farming Labs ORM changes

The auth package can define its schema once:

```ts
export const authSchema = defineSchema({
  user: model({
    table: "users",
    fields: {
      id: id(),
      email: string().unique(),
      name: string(),
      createdAt: datetime().defaultNow(),
    },
    relations: {
      sessions: hasMany("session", { foreignKey: "userId" }),
      accounts: hasMany("account", { foreignKey: "userId" }),
    },
  }),
  session: model({
    table: "sessions",
    fields: {
      id: id(),
      userId: string().references("user.id"),
      token: string().unique(),
    },
    relations: {
      user: belongsTo("user", { foreignKey: "userId" }),
    },
  }),
  account: model({
    table: "accounts",
    fields: {
      id: id(),
      userId: string().references("user.id"),
      provider: string(),
      accountId: string(),
    },
    relations: {
      user: belongsTo("user", { foreignKey: "userId" }),
    },
  }),
});
```

Then the consuming app decides how to generate it:

```ts
export default defineConfig({
  schemas: [authSchema],
  targets: {
    prisma: { out: "./generated/prisma/schema.prisma", provider: "postgresql" },
  },
});
```

The package also gets one runtime-facing contract for storage helpers:

```ts
export async function findUserByEmail(
  orm: ReturnType<typeof createOrm<typeof authSchema>>,
  email: string,
) {
  return orm.user.findFirst({
    where: { email },
    select: {
      id: true,
      email: true,
      sessions: {
        select: {
          token: true,
        },
      },
    },
  });
}
```

## 2. Billing and organization kits

Billing modules often need reusable data definitions for:

- plans
- subscriptions
- invoices
- credits
- seats
- organizations
- memberships

Instead of hand-writing those tables and examples for every consumer stack, the
package can ship one schema contract and let apps generate their preferred
output.

### Example structure

```ts
export const billingSchema = defineSchema({
  plan: model({
    table: "plans",
    fields: {
      id: id(),
      slug: string().unique(),
      name: string(),
    },
  }),
  subscription: model({
    table: "subscriptions",
    fields: {
      id: id(),
      userId: string(),
      planId: string().references("plan.id"),
      status: string(),
      createdAt: datetime().defaultNow(),
    },
  }),
});
```

This is especially nice in a monorepo where many products need the same
commercial model but not the same ORM choice.

## 3. Internal platform modules

Platform teams often own cross-cutting packages for:

- organizations
- roles and permissions
- audit logs
- feature flags
- provisioning state

The cost of drift grows fast when every app re-implements that schema
individually.

With Farming Labs ORM, the platform team can:

1. own the shared schema package
2. publish docs and examples from the same contract
3. generate stack-specific output for each consumer app

## 4. Greenfield apps that want a safe starting point

A greenfield app does not have to adopt a future runtime driver immediately.

It can start with:

- schema DSL
- safe SQL generation
- memory runtime for early tests and docs

Then later add richer drivers without replacing the source of truth.

## 5. Multi-package monorepos

The CLI supports multiple schema packages:

```ts
import { defineConfig } from "@farming-labs/orm-cli";
import { authSchema } from "@acme/auth";
import { billingSchema } from "@acme/billing";
import { orgSchema } from "@acme/org";

export default defineConfig({
  schemas: [authSchema, billingSchema, orgSchema],
  targets: {
    prisma: {
      out: "./generated/prisma/schema.prisma",
      provider: "postgresql",
    },
  },
});
```

That is one of the highest-leverage workflows in the project because it lets
several reusable packages contribute models into one generated application
surface.

## 6. When this approach is not the best fit

Farming Labs ORM is probably overkill when:

- you only have one app and one storage layer forever
- your team is already happy with one ORM-specific schema as the sole source of truth
- you do not need package-level reuse
- you are not trying to publish or share a storage-facing contract

## Practical decision rule

This approach becomes more valuable as these increase:

- number of consumer apps
- number of package boundaries
- number of supported stacks
- amount of duplicated storage docs and adapter work

If your biggest pain is “we keep rewriting the same storage story for every
consumer,” this project is aimed directly at that pain.