Skip to Content
Delmare Digital

MongoDB

Run payload-better-auth on Payload's MongoDB adapter. The adapter detects MongoDB itself; three settings change from the Postgres setup.

The adapter detects MongoDB from Payload's database adapter and configures itself, so payloadAdapter() needs no extra options. IDs are always text (ObjectId strings) on MongoDB.

Differences from Postgres

Postgres (default)MongoDB
ID type'number' (SERIAL)'text' (ObjectId strings)
advanced.database.generateIdSet to 'serial'Do not set
betterAuthStrategy()DefaultidType: 'text'

Payload config

Install the MongoDB adapter instead of the Postgres adapter:

npm i @payloadcms/db-mongodb

Keep the secrets and app origin from Installation, and replace DATABASE_URL with:

.env
DATABASE_URI=mongodb://127.0.0.1:27017/my-app
src/payload.config.ts
import { buildConfig } from 'payload'
import { mongooseAdapter } from '@payloadcms/db-mongodb'
import { betterAuth } from 'better-auth'
import {
  betterAuthCollections,
  createBetterAuthPlugin,
  payloadAdapter,
} from '@delmaredigital/payload-better-auth'
import { betterAuthOptions } from './lib/auth/config'
import { Users } from './collections/Users'
import { getBaseUrl } from './lib/auth/getBaseUrl'

const baseUrl = getBaseUrl()

export default buildConfig({
  secret: process.env.PAYLOAD_SECRET!,
  collections: [Users],
  plugins: [
    betterAuthCollections({ betterAuthOptions, skipCollections: ['user'] }),
    createBetterAuthPlugin({
      createAuth: (payload) =>
        betterAuth({
          ...betterAuthOptions,
          database: payloadAdapter({ payloadClient: payload }),
          // Do NOT set advanced.database.generateId
          secret: process.env.BETTER_AUTH_SECRET,
          baseURL: baseUrl,
          trustedOrigins: [baseUrl],
        }),
    }),
  ],
  db: mongooseAdapter({ url: process.env.DATABASE_URI! }),
})

Users collection and session helpers

src/collections/Users/index.ts
import type { CollectionConfig } from 'payload'
import { betterAuthStrategy } from '@delmaredigital/payload-better-auth'

export const Users: CollectionConfig = {
  slug: 'users',
  auth: {
    disableLocalStrategy: true,
    strategies: [betterAuthStrategy({ idType: 'text' })],
  },
  access: {
    read: ({ req }) => {
      if (!req.user) return false
      if (req.user.role === 'admin') return true
      return { id: { equals: req.user.id } }
    },
    admin: ({ req }) => req.user?.role === 'admin',
  },
  fields: [
    { name: 'email', type: 'email', required: true, unique: true },
    { name: 'emailVerified', type: 'checkbox', defaultValue: false },
    { name: 'name', type: 'text' },
    { name: 'image', type: 'text' },
    {
      name: 'role',
      type: 'select',
      defaultValue: 'user',
      options: [
        { label: 'User', value: 'user' },
        { label: 'Admin', value: 'admin' },
      ],
    },
  ],
}
src/lib/auth.ts
import { createSessionHelpers } from '@delmaredigital/payload-better-auth'
import type { User } from '@/payload-types'

export const { getServerSession, getServerUser } = createSessionHelpers<User>({
  idType: 'text',
})

Migrating from Postgres to MongoDB

Remove generateId: 'serial' from your Better Auth config.
Change betterAuthStrategy() to betterAuthStrategy({ idType: 'text' }).
Set idType: 'text' on createSessionHelpers.
Remove any explicit idType: 'number' from payloadAdapter's adapterConfig.
Switch Payload's database adapter to mongooseAdapter.

The atomic SQL path described in Atomic operations is Postgres-only. On MongoDB, consumeOne and incrementOne use the Local API.

Edit this page on GitHub

On this page