Skip to main content
The @feathersjs/mongodb adapter provides native MongoDB integration for Feathers services, supporting all MongoDB features including aggregation pipelines, GridFS, and transactions.

Installation

1

Install dependencies

Install the MongoDB adapter and the MongoDB driver:
npm install @feathersjs/mongodb mongodb
2

Connect to MongoDB

Create a MongoDB connection:
import { MongoClient } from 'mongodb'

const client = new MongoClient('mongodb://localhost:27017/mydb')
await client.connect()

const db = client.db()
3

Create a service

Create a service using the MongoDB adapter:
import { MongoDBService } from '@feathersjs/mongodb'

class UserService extends MongoDBService {
  // Custom methods here
}

app.use('users', new UserService({
  Model: db.collection('users'),
  paginate: {
    default: 10,
    max: 50
  }
}))

Configuration

Service Options

The MongoDB adapter accepts these options:
interface MongoDBAdapterOptions {
  Model: Collection | Promise<Collection>  // MongoDB collection
  id?: string                              // Primary key field (default: '_id')
  disableObjectify?: boolean               // Don't convert IDs to ObjectId
  useEstimatedDocumentCount?: boolean      // Use estimated count for performance
  paginate?: PaginationOptions             // Pagination settings
  multi?: boolean | string[]               // Allow multi operations
  events?: string[]                        // Custom events
}

Example Configuration

import { MongoDBService } from '@feathersjs/mongodb'

app.use('messages', new MongoDBService({
  Model: db.collection('messages')
}))

Querying

Basic Queries

The MongoDB adapter supports all standard Feathers query operators:
// Find all users
const users = await app.service('users').find({
  query: {}
})

// Find with filters
const activeUsers = await app.service('users').find({
  query: {
    status: 'active',
    age: { $gte: 18 }
  }
})

MongoDB-Specific Options

Pass native MongoDB options through params.mongodb:
// Find with MongoDB options
const users = await app.service('users').find({
  query: { status: 'active' },
  mongodb: {
    hint: { status: 1 },
    maxTimeMS: 5000,
    readPreference: 'secondary'
  }
})

// Create with write concern
const user = await app.service('users').create(
  { name: 'John', email: '[email protected]' },
  {
    mongodb: {
      writeConcern: { w: 'majority', wtimeout: 5000 }
    }
  }
)

Aggregation Pipelines

Use MongoDB’s powerful aggregation framework with the pipeline parameter:
// Use aggregation pipeline
const results = await app.service('orders').find({
  pipeline: [
    { $match: { status: 'completed' } },
    {
      $group: {
        _id: '$customerId',
        totalSpent: { $sum: '$amount' },
        orderCount: { $sum: 1 }
      }
    },
    { $sort: { totalSpent: -1 } },
    { $limit: 10 }
  ]
})

Data Manipulation

Create

const user = await app.service('users').create({
  name: 'Alice',
  email: '[email protected]',
  age: 25
})

Update

// Replace entire document (except _id)
const updated = await app.service('users').update(
  '507f1f77bcf86cd799439011',
  {
    name: 'Alice Updated',
    email: '[email protected]',
    age: 26
  }
)

Patch

// Partial update
const patched = await app.service('users').patch(
  '507f1f77bcf86cd799439011',
  { status: 'verified' }
)

Remove

const removed = await app.service('users').remove(
  '507f1f77bcf86cd799439011'
)

ObjectId Handling

The adapter automatically handles ObjectId conversion:
import { ObjectId } from 'mongodb'

// These all work the same
await app.service('users').get('507f1f77bcf86cd799439011')
await app.service('users').get(new ObjectId('507f1f77bcf86cd799439011'))

// Query by ObjectId
const users = await app.service('users').find({
  query: {
    _id: { $in: [
      '507f1f77bcf86cd799439011',
      '507f1f77bcf86cd799439012'
    ]}
  }
})

// Disable automatic ObjectId conversion
app.use('users', new MongoDBService({
  Model: db.collection('users'),
  disableObjectify: true  // Keep IDs as strings
}))

Performance Optimization

Estimated Document Count

For large collections, use estimated count for better performance:
app.use('logs', new MongoDBService({
  Model: db.collection('logs'),
  useEstimatedDocumentCount: true,
  paginate: { default: 50, max: 100 }
}))

// Pagination will use estimatedDocumentCount()
// instead of countDocuments() - much faster but approximate
const logs = await app.service('logs').find({
  query: { $limit: 50 }
})

Field Projection

// Only select needed fields
const users = await app.service('users').find({
  query: {
    $select: ['name', 'email']  // Exclude large fields
  }
})

Indexes

Create indexes on your collections:
// Create indexes for better query performance
await db.collection('users').createIndex({ email: 1 }, { unique: true })
await db.collection('users').createIndex({ status: 1, createdAt: -1 })
await db.collection('posts').createIndex({ userId: 1, publishedAt: -1 })

Type Safety

Full TypeScript support with generics:
import { ObjectId } from 'mongodb'
import { MongoDBService, MongoDBAdapterParams } from '@feathersjs/mongodb'
import type { Params } from '@feathersjs/feathers'

interface User {
  _id: ObjectId
  email: string
  name: string
  age: number
  roles: string[]
  createdAt: Date
}

interface UserData {
  email: string
  name: string
  age: number
  roles?: string[]
}

interface UserParams extends MongoDBAdapterParams {
  user?: User
}

class UserService extends MongoDBService<User, UserData, UserParams> {
  async find(params?: UserParams) {
    // Fully typed
    return super.find(params)
  }
}

app.use('users', new UserService({
  Model: db.collection<User>('users')
}))

// Type-safe usage
const users: User[] = await app.service('users').find()
const user: User = await app.service('users').get(userId)

Error Handling

The adapter provides specific error handling:
import { errorHandler } from '@feathersjs/mongodb'

try {
  await app.service('users').create({
    email: '[email protected]'
  })
} catch (error) {
  // MongoDB errors are converted to Feathers errors
  // Duplicate key -> Conflict (409)
  // Invalid operation -> BadRequest (400)
  // Not found -> NotFound (404)
}

Next Steps

Knex Adapter

Learn about the SQL adapter

Common Patterns

Explore adapter patterns

Hooks

Add hooks to your services

Validation

Validate your data with schemas

Build docs developers (and LLMs) love