Claude Code Plugins

Community-maintained marketplace

Feedback

Configure MongoDB connection and test infrastructure. Use when adding MongoDB support to the project. Triggers on "setup mongodb", "add mongodb", "configure database", "mongodb connection".

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name setup-mongodb
description Configure MongoDB connection and test infrastructure. Use when adding MongoDB support to the project. Triggers on "setup mongodb", "add mongodb", "configure database", "mongodb connection".

Setup MongoDB

Configures MongoDB connection with the native driver (not Mongoose), including graceful shutdown and test infrastructure.

Quick Reference

Files created:

  • src/config/mongodb.setup.ts - Connection management
  • tests/config/mongodb.global.ts - Test server lifecycle
  • tests/config/mongodb.setup.ts - Test mocks and helpers

When to use: Before creating MongoDB repository implementations

Prerequisites

  • Project bootstrapped with base structure
  • Node.js 18+ with pnpm

Instructions

Phase 1: Install Dependencies

Step 1: Install MongoDB Driver

pnpm add mongodb

Step 2: Install Test Dependencies

pnpm add -D mongodb-memory-server

Phase 2: Environment Configuration

Step 3: Add Environment Variables

Update src/env.ts:

const envSchema = z.object({
  // ... existing variables ...

  // MongoDB Configuration
  MONGODB_URI: z.string().url().optional(),
  MONGODB_DATABASE: z.string().default("my-app-db"),
});

const mappedEnv = {
  // ... existing mappings ...
  MONGODB_URI: process.env.MONGODB_URI,
  MONGODB_DATABASE: process.env.MONGODB_DATABASE,
};

Update .env.example:

# MongoDB Configuration
MONGODB_URI=mongodb://localhost:27017
MONGODB_DATABASE=my-app-db

Update .env:

MONGODB_URI=mongodb://localhost:27017
MONGODB_DATABASE=my-app-db

Phase 3: Connection Setup

Step 4: Create Connection Manager

Create src/config/mongodb.setup.ts:

import { MongoClient, type Db } from "mongodb";
import { env } from "@/env";

let client: MongoClient | null = null;
let db: Db | null = null;

export async function connectToDatabase(): Promise<Db> {
  if (db) {
    return db;
  }

  const uri = env.MONGODB_URI;
  if (!uri) {
    throw new Error("MONGODB_URI environment variable is not set");
  }

  try {
    client = new MongoClient(uri);
    await client.connect();
    db = client.db(env.MONGODB_DATABASE);
    console.log(`Connected to MongoDB database: ${env.MONGODB_DATABASE}`);
    return db;
  } catch (error) {
    console.error("Failed to connect to MongoDB:", error);
    throw error;
  }
}

export async function disconnectFromDatabase(): Promise<void> {
  if (client) {
    await client.close();
    client = null;
    db = null;
    console.log("Disconnected from MongoDB");
  }
}

export async function getDatabase(): Promise<Db> {
  if (!db) {
    return connectToDatabase();
  }
  return db;
}

// Graceful shutdown handlers
process.on("SIGINT", async () => {
  await disconnectFromDatabase();
  process.exit(0);
});

process.on("SIGTERM", async () => {
  await disconnectFromDatabase();
  process.exit(0);
});

Phase 4: Test Infrastructure

Step 5: Update Vitest Config

Update vitest.config.ts:

import { defineConfig } from "vitest/config";
import path from "path";

export default defineConfig({
  test: {
    include: ["tests/**/*.test.ts"],
    globals: false,
    environment: "node",
    // MongoDB test configuration
    globalSetup: ["./tests/config/mongodb.global.ts"],
    setupFiles: ["./tests/config/mongodb.setup.ts"],
    pool: "forks", // Prevents database conflicts between tests
    coverage: {
      provider: "v8",
      reporter: ["text", "html"],
      exclude: ["node_modules/", "tests/", "dist/"],
    },
  },
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
});

Step 6: Create Global Setup

Create tests/config/mongodb.global.ts:

import { MongoMemoryServer } from "mongodb-memory-server";

let mongoServer: MongoMemoryServer | null = null;

export async function setup() {
  console.log("\nšŸš€ Starting MongoDB Memory Server...");

  mongoServer = await MongoMemoryServer.create({
    instance: {
      dbName: "test-db",
    },
  });

  const uri = mongoServer.getUri();
  process.env.MONGODB_URI = uri;
  process.env.MONGODB_DATABASE = "test-db";

  console.log(`āœ… MongoDB Memory Server started at: ${uri}`);
}

export async function teardown() {
  console.log("\nšŸ›‘ Stopping MongoDB Memory Server...");

  if (mongoServer) {
    await mongoServer.stop();
    mongoServer = null;
  }

  console.log("āœ… MongoDB Memory Server stopped");
}

Step 7: Create Test Setup

Create tests/config/mongodb.setup.ts:

import { vi, beforeAll, afterAll } from "vitest";
import { MongoClient, type Db } from "mongodb";

// Store test database connection
let testClient: MongoClient | null = null;
let testDb: Db | null = null;

// Mock the mongodb.setup module
vi.mock("@/config/mongodb.setup", () => ({
  getDatabase: vi.fn(async () => {
    if (!testDb) {
      const uri = process.env.MONGODB_URI;
      if (!uri) {
        throw new Error("MONGODB_URI not set by global setup");
      }
      testClient = new MongoClient(uri);
      await testClient.connect();
      testDb = testClient.db(process.env.MONGODB_DATABASE || "test-db");
    }
    return testDb;
  }),
  connectToDatabase: vi.fn(async () => {
    const { getDatabase } = await import("@/config/mongodb.setup");
    return getDatabase();
  }),
  disconnectFromDatabase: vi.fn(async () => {
    if (testClient) {
      await testClient.close();
      testClient = null;
      testDb = null;
    }
  }),
}));

// Global test helpers
declare global {
  function setupTestDatabase(): Promise<{ db: Db; client: MongoClient }>;
  function cleanupTestDatabase(client: MongoClient): Promise<void>;
}

globalThis.setupTestDatabase = async () => {
  const uri = process.env.MONGODB_URI;
  if (!uri) {
    throw new Error("MONGODB_URI not set");
  }
  const client = new MongoClient(uri);
  await client.connect();
  const db = client.db(process.env.MONGODB_DATABASE || "test-db");
  return { db, client };
};

globalThis.cleanupTestDatabase = async (client: MongoClient) => {
  if (client) {
    await client.close();
  }
};

// Cleanup after all tests
afterAll(async () => {
  if (testClient) {
    await testClient.close();
    testClient = null;
    testDb = null;
  }
});

Phase 5: Server Integration (Optional)

Step 8: Connect on Server Start

If you want to connect to MongoDB when the server starts, update src/server.ts:

import { serve } from "@hono/node-server";
import { app } from "./app";
import { env } from "./env";
import { connectToDatabase } from "./config/mongodb.setup";

const port = env.PORT;

async function startServer() {
  // Connect to MongoDB if URI is configured
  if (env.MONGODB_URI) {
    try {
      await connectToDatabase();
      console.log("MongoDB connection established");
    } catch (error) {
      console.error("Failed to connect to MongoDB:", error);
      // Decide: exit or continue with MockDB fallback
      // process.exit(1);
    }
  }

  console.log(`Server starting on port ${port}...`);

  serve({
    fetch: app.fetch,
    port,
  });

  console.log(`Server running at http://localhost:${port}`);
}

startServer();

Phase 6: Verification

Step 9: Test MongoDB Setup

Create a simple test to verify the setup works:

Create tests/config/mongodb.connection.test.ts:

import { describe, it, expect, beforeAll, afterAll } from "vitest";
import type { MongoClient, Db } from "mongodb";

describe("MongoDB Connection", () => {
  let testClient: MongoClient;
  let testDb: Db;

  beforeAll(async () => {
    const { db, client } = await setupTestDatabase();
    testDb = db;
    testClient = client;
  });

  afterAll(async () => {
    await cleanupTestDatabase(testClient);
  });

  it("connects to test database", async () => {
    expect(testDb).toBeDefined();
    expect(testDb.databaseName).toBe("test-db");
  });

  it("can perform basic operations", async () => {
    const collection = testDb.collection("test-collection");

    // Insert
    const insertResult = await collection.insertOne({ test: "data" });
    expect(insertResult.insertedId).toBeDefined();

    // Find
    const doc = await collection.findOne({ test: "data" });
    expect(doc).not.toBeNull();
    expect(doc?.test).toBe("data");

    // Cleanup
    await collection.deleteMany({});
  });
});

Run the test:

pnpm test -- tests/config/mongodb.connection.test.ts

Connection Patterns

Lazy Connection (Default)

Connection is established on first database access:

// In repository
private async getCollection() {
  if (!this.collection) {
    const db = await getDatabase(); // Connects if needed
    this.collection = db.collection("entities");
  }
  return this.collection;
}

Eager Connection

Connect explicitly at startup:

// In server.ts
await connectToDatabase();

Connection Pooling

The MongoDB driver handles connection pooling automatically. Default pool size is 100 connections.

To customize:

const client = new MongoClient(uri, {
  maxPoolSize: 50,
  minPoolSize: 5,
});

Files Created Summary

src/
└── config/
    └── mongodb.setup.ts      # Connection manager

tests/
└── config/
    ā”œā”€ā”€ mongodb.global.ts     # Memory server lifecycle
    ā”œā”€ā”€ mongodb.setup.ts      # Test mocks and helpers
    └── mongodb.connection.test.ts  # Verification test

Troubleshooting

"MONGODB_URI not set" Error

  • Check .env file has the variable
  • Verify env.ts includes the mapping
  • For tests, ensure globalSetup runs before tests

Memory Server Fails to Start

  • Check available memory (needs ~500MB)
  • Try specifying a version: MongoMemoryServer.create({ binary: { version: '6.0.0' } })
  • On M1 Macs, ensure Rosetta is installed

Tests Hang

  • Ensure pool: "forks" is set in vitest.config.ts
  • Check for unclosed connections in afterAll hooks
  • Verify global teardown runs

What NOT to Do

  • Do NOT use Mongoose (use native driver for transparency)
  • Do NOT connect in module scope (use async initialization)
  • Do NOT forget graceful shutdown handlers
  • Do NOT skip the pool: "forks" setting for tests
  • Do NOT hardcode connection strings (use env variables)

See Also

  • create-mongodb-repository - Create MongoDB repository implementation
  • test-mongodb-repository - Test MongoDB repository
  • add-env-variable - Add more environment variables