
MongoDB attachDatabasePool Vercel - Docs Only Show Postgres.
Skilldham
Engineering deep-dives for developers who want real understanding.
Last updated: July 2026
TL;DR
Vercel's attachDatabasePool works with MongoDB. The docs just never show it. Use the native driver as normal. Call attachDatabasePool(client) right after you create it. For Mongoose, call getClient() first. That gives you the raw client underneath. Pass that into attachDatabasePool. Payload's MongoDB adapter does not expose that client yet. This pattern will not work there until it does.
You provision MongoDB Atlas on Vercel. You enable Fluid Compute for the faster cold starts. Traffic goes up. Then Atlas throws a connection limit error.
You check the docs. Every example uses pg. You check Prisma's guide. Pg again. You check Neon's guide. Also pg.
You find one GitHub issue that even mentions Mongo here. It is a bug report, not a tutorial.
Here is the part nobody wrote down. A working MongoDB attachDatabasePool Vercel setup exists today. You just have to know where to put it.
Why every example uses Postgres
Vercel's own API reference lists Mongo as a supported client. So are pg, MySQL2, MariaDB, ioredis, and cassandra-driver. That part is not in doubt.
But check the worked examples. Vercel's two guides on pooling both use pg. Prisma's deployment guide uses pg too. Neon's guide uses pg as well. Neon is Postgres.
Atlas has its own Vercel Marketplace integration. Even that snippet uses the raw driver directly. It skips the ORM layer entirely. No walkthrough exists for Mongoose.
That gap is why a payloadcms/payload GitHub issue exists at all. A developer hit Atlas's 500 connection limit on Fluid Compute. They found no way to wrap Payload's internal client. The issue is still open.
Ask an AI coding assistant how to do this. It will likely copy the pg pattern. It may invent a Mongo pool option that does not exist. Or it may quietly swap mongo into Postgres code.
Native driver setup
This is the simplest working MongoDB attachDatabasePool Vercel setup. It is what Vercel's own Atlas Marketplace page ships. The native driver already runs its own pool internally. The helper just tells Fluid Compute to clean that pool up.
javascript
// lib/mongo.ts
import { MongoClient, MongoClientOptions } from 'mongodb';
import { attachDatabasePool } from '@vercel/functions';
const options: MongoClientOptions = {
appName: 'my-app.vercel',
maxIdleTimeMS: 5000,
};
const client = new MongoClient(process.env.MONGODB_URI!, options);
// Attach the client so Fluid Compute closes idle connections on suspend
attachDatabasePool(client);
// Export a module-scoped client so every function invocation reuses it
export default client;Two details matter here. Both get skipped in copy-paste versions.
First, the client has to sit at module scope. Create it fresh inside a route handler, and you lose the whole benefit. Every request opens a new connection instead of reusing one.
Second, the helper runs once, at load time. Not inside a request handler. It hooks into the function's own lifecycle. Call it per request, and it does nothing extra.
To use the client in a route:
javascript
// app/api/users/route.ts
import client from '@/lib/mongo';
export async function GET() {
const db = client.db('myapp');
const users = await db.collection('users').find().limit(20).toArray();
return Response.json(users);
}No connect() call is needed per request. The driver connects lazily on its own. It keeps that connection alive across calls on the same instance.
Mongoose setup via getClient()
Most production apps skip the native driver. They use Mongoose instead. The pool helper needs an object with a close() method. A Mongoose connection does not have that shape directly. The client underneath it does.
Mongoose has offered getClient() since version 5.10. It hands back the exact client Mongoose uses inside.
javascript
// lib/mongoose.ts
import mongoose from 'mongoose';
import { attachDatabasePool } from '@vercel/functions';
declare global {
var mongooseConn: typeof mongoose | undefined;
}
async function connect() {
if (global.mongooseConn) return global.mongooseConn;
const conn = await mongoose.connect(process.env.MONGODB_URI!, {
maxPoolSize: 10,
minPoolSize: 1,
maxIdleTimeMS: 5000,
});
// Pull the underlying MongoClient and attach it
const client = conn.connection.getClient();
attachDatabasePool(client);
global.mongooseConn = conn;
return conn;
}
export default connect;Global caching is not optional here. Skip it, and hot reload keeps reconnecting. You would attach the pool over and over.
Call connect() at the top of every route. Do this before you touch a model:
javascript
// app/api/orders/route.ts
import connect from '@/lib/mongoose';
import Order from '@/models/Order';
export async function GET() {
await connect();
const orders = await Order.find().limit(20).lean();
return Response.json(orders);
}connect() returns instantly after the first call. The global variable is already set. The helper itself only runs once, at first connection.
Pool sizing, translated from Postgres
The official guide gives Postgres-shaped advice. Set a low idle timeout. Keep min at 1. Avoid max at 1. That advice still applies, but the option names change.
pg calls it idleTimeoutMillis. Mongo calls it maxIdleTimeMS instead. pg calls it max. Mongo splits that into two options.
Here is the direct mapping:
Postgres guidanceMongo equivalentSuggested valueLow idle timeoutmaxIdleTimeMS5000min: 1minPoolSize1avoid max: 1maxPoolSize5-10 for most API routesappName for debuggingappNameyour project name
I run maxPoolSize at 10 on a Munshi API route. It handles finance-app spikes without much warning. Atlas Flex's ceiling is 500 connections total. That number is shared across your whole cluster. A lower pool size per function keeps you further from that shared number.
minPoolSize at 1 keeps one warm connection alive per instance. That beats dropping to zero every time. Then paying a fresh handshake on the next request. A short idle timeout is what actually does the real work here. It tells the driver to release idle connections fast. The pool helper then makes sure that happens before your function suspends.

What framework layers don't support yet
Say you use Payload, Keystone, or something similar. These frameworks own the Mongo connection internally. The pool helper will not help you today.
The GitHub issue linked above states this directly. There is no supported way to reach in. Payload's adapter builds its own client and keeps it private. You cannot wrap what you cannot access.
Some frameworks build their own client with no escape hatch at all. If yours does, this pattern stays blocked. It stays that way until the framework adds support. Check your framework's connection code first. Look for where it calls new MongoClient(. See if that client gets exported anywhere.
How to confirm it actually worked
Do not just ship this and assume it works. Confirm it for real.
Deploy to a preview environment first. Turn Fluid Compute on. Hit your API route several times, fast. Then let it sit idle for 30 seconds.
Open Atlas next. Go to Metrics, then Connections. Watch the count rise during the burst. It should drop back down after the idle period. If it stays flat, something is wrong.
Check one thing if the count never drops. Confirm the helper runs once, at module scope. Not inside your handler. That is the most common reason this silently fails.
Key Takeaways
A working MongoDB attachDatabasePool Vercel setup is officially supported - the docs just never show it
For the native driver, call attachDatabasePool(client) once, at module scope, right after creating the client
For Mongoose, call getClient() first to get the raw client, then pass that to attachDatabasePool
Cache your Mongoose connection globally, or you risk attaching the pool more than once
Translate Postgres pool options to Mongo's own names: maxIdleTimeMS, maxPoolSize, minPoolSize
Framework-owned clients, like Payload's adapter, do not expose a way to attach the pool yet
Confirm it worked - watch the Atlas connection count drop after an idle spell, don't just assume
FAQ
Does attachDatabasePool actually support MongoDB, or is that undocumented?
It is documented. Vercel's API reference lists Mongo right alongside pg. What is missing is a worked example, not official support.
Can I use this with Mongoose, or only the native driver?
Both work. The native client goes straight into the helper. For Mongoose, call getClient() first to get that same underlying client. Attach that instead.
Why does Payload CMS not support this?
Payload's adapter builds its own client internally. It does not expose that client today. There is no supported way to intercept it. This is tracked in an open GitHub issue on payloadcms/payload.
Do I need Fluid Compute enabled for this to matter?
Yes. The helper exists for a Fluid Compute problem specifically. Functions stay warm across calls. Their idle connections need cleanup before suspension. Without Fluid Compute, instances are short-lived anyway.
What connection limit does MongoDB Atlas actually enforce?
It depends on your tier. Atlas Flex caps you at 500 concurrent connections. That cap covers your whole cluster, not one instance. Every Fluid Compute instance shares that same number. That is why unpooled connections spike so fast.
Will this work with Prisma's MongoDB connector?
Not directly today. Prisma's Mongo connector hides the raw client. Mongoose exposes it through getClient(); Prisma does not, currently. If you run Prisma with Mongo, watch Prisma's GitHub issues for driver adapter support.
Is maxPoolSize: 10 the right number for every app?
No. Ten is a reasonable starting point. Not a universal answer. Size it against your Atlas tier's ceiling. Factor in how many instances you expect at peak. Then adjust based on what Atlas shows you.
Does this replace Mongoose's own connection pooling?
No, it works alongside it. Mongoose already pools connections through its client. The helper does not replace that pool. It just closes idle connections before your instance suspends. Mongoose has no way to know about that suspension on its own.
Conclusion
MongoDB already works with attachDatabasePool. The only missing piece was a real example. Get the client - directly for the native driver, through getClient() for Mongoose. Attach it once, at module scope.
Get this wrong, and you find out the hard way. Atlas throws connection errors under real traffic. That is a bad way to learn. If you run Mongoose in production on Vercel, check your connection code now. Confirm it calls the helper before your next spike finds out for you.
The Mongoose buffering timed out in production post covers a related failure. It explains what happens when a connection is not ready yet. The same lifecycle applies here. Weighing Prisma against a raw driver for a new project? The Prisma 7 and NeonDB driver adapter setup post covers that side, on Postgres.
Want the next pooling breakdown before it hits the blog? Subscribe to the SkillDham newsletter.