home / skills / toilahuongg / shopify-agents-kit / mongoose

mongoose skill

/.claude/skills/mongoose

This skill guides secure, TypeScript-first Mongoose usage with performance best practices for MongoDB, enabling faster, type-safe data access in modern apps.

npx playbooks add skill toilahuongg/shopify-agents-kit --skill mongoose

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
4.3 KB
---
name: mongoose
description: Guide for Mongoose ODM (2025-2026 Edition), covering Mongoose 8.x/9.x, TypeScript integration, and performance best practices.
---

# Mongoose Skill (2025-2026 Edition)

This skill provides modern guidelines for using Mongoose with MongoDB, focusing on Mongoose 8.x/9.x, strict TypeScript integration, and performance optimizations relevant to the 2025 ecosystem.

## 🚀 Key Trends & Features (2025/2026)

*   **TypeScript-First:** Mongoose 8+ has superior built-in type inference. `@types/mongoose` is obsolete.
*   **Performance:** Mongoose 9 introduces architectural changes for lower overhead. Native vector search support is now standard for AI features.
*   **Modern JavaScript:** Full support for `async/await` iterators and native Promises.

## 📐 TypeScript Integration (The Strict Way)

Do **NOT** extend `LengthyDocument` or standard `Document`. Use a plain interface and let Mongoose infer the rest.

### 1. Define the Interface (Raw Data)
Define what your data looks like in plain JavaScript objects.

```typescript
import { Types } from 'mongoose';

export interface IUser {
  name: string;
  email: string;
  role: 'admin' | 'user';
  tags: string[];
  organization?: Types.ObjectId; // Use specific type for ObjectIds
  createdAt?: Date;
}
```

### 2. Define the Schema & Model
Create the model with generic typing.

```typescript
import mongoose, { Schema, model } from 'mongoose';
import { IUser } from './interfaces';

const userSchema = new Schema<IUser>({
  name: { type: String, required: true },
  email: { type: String, required: true, unique: true },
  role: { type: String, enum: ['admin', 'user'], default: 'user' },
  tags: [String],
  organization: { type: Schema.Types.ObjectId, ref: 'Organization' }
}, {
  timestamps: true /* Automatically manages createdAt/updatedAt */
});

// ⚡ 2025 Best Practice: Avoid "extends Document" on the interface.
// Let 'model<IUser>' handle the HydratedDocument type automatically.
export const User = mongoose.models.User || model<IUser>('User', userSchema);
```

### 3. Usage (Type-Safe)

```typescript
// 'user' is typed as HydratedDocument<IUser> automatically
const user = await User.findOne({ email: '[email protected]' });

if (user) {
  console.log(user.name); // Typed string
  await user.save(); // Typed method
}
```

## ⚡ Performance Optimization

### 1. `.lean()` for Reads
Always use `.lean()` for read-only operations (e.g., GET requests). It skips Mongoose hydration, speeding up queries by 30-50%.

```typescript
// Returns plain JS object (IUser), NOT a Mongoose document
const users = await User.find({ role: 'admin' }).lean(); 
```

### 2. Indexes
Define compound indexes for common query patterns directly in the schema.

```typescript
// Schema definition
userSchema.index({ organization: 1, email: 1 }); // Optimized lookup
```

### 3. Projections
Fetch only what you need. Network I/O is often the bottleneck.

```typescript
const names = await User.find({}, { name: 1 }).lean();
```

## 🛠️ Connection Management (Serverless/Edge Friendly)

For modern serverless/edge environments (like Vercel, Next.js, Remix), use a singleton pattern with caching to prevent connection exhaustion.

```typescript
import mongoose from 'mongoose';

const MONGODB_URI = process.env.MONGODB_URI!;

if (!MONGODB_URI) {
  throw new Error('Please define the MONGODB_URI environment variable');
}

/**
 * Global is used here to maintain a cached connection across hot reloads
 * in development. This prevents connections growing exponentially
 * during API Route usage.
 */
let cached = (global as any).mongoose;

if (!cached) {
  cached = (global as any).mongoose = { conn: null, promise: null };
}

async function connectDb() {
  if (cached.conn) {
    return cached.conn;
  }

  if (!cached.promise) {
    const opts = {
      bufferCommands: false,
    };

    cached.promise = mongoose.connect(MONGODB_URI, opts).then((mongoose) => {
      return mongoose;
    });
  }
  
  try {
    cached.conn = await cached.promise;
  } catch (e) {
    cached.promise = null;
    throw e;
  }

  return cached.conn;
}

export default connectDb;
```

## 📚 References

*   [Mongoose Documentation (Latest)](https://mongoosejs.com/docs/)
*   [Mongoose TypeScript Guide](https://mongoosejs.com/docs/typescript.html)
*   [MongoDB Performance Best Practices](https://www.mongodb.com/docs/manual/administration/analyzing-mongodb-performance/)

Overview

This skill is a compact, modern guide for using Mongoose with MongoDB in 2025–2026, covering Mongoose 8.x and 9.x, strict TypeScript integration, and performance best practices. It focuses on TypeScript-first patterns, serverless-friendly connection handling, and query optimizations to reduce latency and resource usage. The advice reflects current engine improvements like native vector search and lower middleware overhead.

How this skill works

The guide explains how to define plain TypeScript interfaces for document shapes and let Mongoose infer hydrated document types via model generics instead of extending Document. It shows schema and model creation, recommended query patterns such as .lean() and projections, and how to add indexes and compound keys for common lookups. It also provides a serverless/edge-friendly singleton connection pattern that caches connections across hot reloads to avoid exhaustion.

When to use it

  • Building TypeScript-first Node.js apps with Mongoose 8.x or 9.x where strict typing is required
  • Implementing read-heavy endpoints where lean() and projections reduce latency
  • Deploying to serverless or edge platforms that can spawn many short-lived processes
  • Optimizing query performance with compound indexes and minimal projection fields
  • Adding AI features that leverage Mongoose-native vector search capabilities

Best practices

  • Define plain interfaces for your data shape and use model<IYourInterface>() — do not extend built-in Document types
  • Use .lean() for read-only operations to avoid hydration overhead and improve throughput
  • Create compound indexes aligned with your most common query patterns to speed lookups
  • Project only required fields to reduce network I/O and serialization costs
  • Cache connections in a global singleton for serverless/edge environments to prevent connection exhaustion

Example use cases

  • A TypeScript API that returns lists of users using User.find(...).lean() and lightweight projections
  • A multi-tenant app indexing organization + email for fast tenant-scoped user lookups
  • Serverless Next.js API routes that reuse a cached mongoose connection across cold starts
  • An AI feature using Mongoose-native vector search for similarity queries alongside typed document models

FAQ

Should I still install @types/mongoose?

No. Mongoose 8+ includes improved type inference; relying on the built-in types and using model generics is the recommended approach.

When must I avoid .lean()?

.lean() should be avoided when you need document methods, setters, virtuals, or middleware behavior that requires hydrated Mongoose documents.