# MongoDB
URL: /docs/integrations/mongodb
LLM index: /llms.txt
Description: How MongoDB fits into Farming Labs ORM through the native MongoDB and Mongoose runtime packages.

# MongoDB

MongoDB support is live through two runtime packages:

- `@farming-labs/orm-mongo`
  Use this if your app uses the native `mongodb` client
- `@farming-labs/orm-mongoose`
  Use this if your app already has Mongoose models

## Native MongoDB example

```ts title="mongo-runtime.ts"
import { createOrm } from "@farming-labs/orm";
import { createMongoDriver } from "@farming-labs/orm-mongo";
import { MongoClient } from "mongodb";
import { authSchema } from "./schema";

const client = new MongoClient(process.env.MONGODB_URL!);
await client.connect();

const orm = createOrm({
  schema: authSchema,
  driver: createMongoDriver({
    db: client.db("app"),
    client,
  }),
});
```

## Mongoose example

```ts title="mongoose-runtime.ts"
import { createOrm } from "@farming-labs/orm";
import { createMongooseDriver } from "@farming-labs/orm-mongoose";
import { authSchema } from "./schema";

const orm = createOrm({
  schema: authSchema,
  driver: createMongooseDriver<typeof authSchema>({
    models: {
      user: UserModel,
      profile: ProfileModel,
      session: SessionModel,
      account: AccountModel,
    },
    connection: mongoose.connection,
  }),
});
```

## Field mapping

MongoDB support still uses the schema as the source of truth, including mapped
field names.

```ts title="mongo-mapped-schema.ts"
const authSchema = defineSchema({
  user: model({
    table: "users",
    fields: {
      id: id().map("_id"),
      email: string(),
      emailVerified: boolean().map("email_verified"),
      createdAt: datetime().map("created_at"),
    },
  }),
});
```

Library code keeps using logical names like `id` and `emailVerified`. The
runtime handles `_id`, `email_verified`, and other mapped fields.

## Relations

Both Mongo runtimes support:

- `belongsTo`
- `hasOne`
- `hasMany`
- `manyToMany`

They load related documents through follow-up queries and return the same typed
result shape as the other runtimes.

That does not mean MongoDB is missing native join-like features forever. A
future Mongo-native aggregation / `$lookup` path can still be added later. The
current fallback behavior just means this repo has not translated those richer
native plans yet.

The live MongoDB suites also verify:

- `integer()` fields
- `json()` fields
- compound-unique lookups and upserts
- JSON update and reload behavior

## Transactions

- `@farming-labs/orm-mongo` uses MongoDB sessions when `client` or `startSession` is provided
- `@farming-labs/orm-mongoose` uses Mongoose sessions when `connection` or `startSession` is provided
- if no session source is configured, transactions fall back to non-transactional execution

Helpful references:

<HoverLink
  href="https://www.mongodb.com/docs/drivers/node/current/fundamentals/transactions/"
  title="MongoDB Node.js transactions"
  description="Learn how MongoDB sessions and multi-operation transactions work in the official Node.js driver, including session boundaries and transaction lifecycles."
  linkLabel="Open MongoDB docs"
>
  MongoDB transaction guide
</HoverLink>
<br />
<HoverLink
  href="https://mongoosejs.com/docs/transactions.html"
  title="Mongoose transactions"
  description="See how Mongoose layers transaction support on top of MongoDB sessions and how document operations participate in a transaction."
  linkLabel="Open Mongoose docs"
>
  Mongoose transaction guide
</HoverLink>

## Why there are two Mongo packages

MongoDB is not a SQL backend with different syntax. It has its own query,
relation, and transaction model.

That is why the repo ships:

- one native Mongo runtime
- one Mongoose runtime

Both use the same schema contract and typed API, but they plug into different
MongoDB application stacks.

## Local verification

The repo verifies both Mongo runtimes locally:

- native MongoDB runtime: `pnpm --filter @farming-labs/orm-mongo test:local`
- Mongoose runtime: `pnpm --filter @farming-labs/orm-mongoose test:local`

Or run both with:

```bash title="terminal"
pnpm test:local:mongodb
```