mongoose.connect() creates one MongoClient, one pool, and stores it on the default connection that mongoose.model() uses. Call it once at startup and let every model share it. Driver options pass straight through, so maxPoolSize and serverSelectionTimeoutMS mean what Connection Pooling said they mean.
mongoose.connection.on('connected', () => console.log('event connected'));
console.log('readyState ', mongoose.connection.readyState); // 0 disconnected, 2 connecting,
// 1 connected, 3 disconnecting
const connecting = mongoose.connect(process.env.MONGO_URI,
{ serverSelectionTimeoutMS: 5000, maxPoolSize: 10 });
console.log('while connecting ->', mongoose.connection.readyState);
await connecting;
console.log('after connect ->', mongoose.connection.readyState, '| host',
mongoose.connection.host + ':' + mongoose.connection.port, '| db',
mongoose.connection.name);
await mongoose.disconnect();
console.log('after disconnect ->', mongoose.connection.readyState);readyState 0 while connecting -> 2 event connected after connect -> 1 | host 127.0.0.1:28112 | db bookshelf after disconnect -> 0
connect() returns a promise but need not be awaited before you use a model, because Mongoose 243,355 buffers operations issued while readyState is 0 or 2 and replays them once the connection is up. That convenience is the most confusing failure mode in the library: if the connection never arrives, the query fails on a timer rather than with a network error. Query a model with no connection at all, after setting mongoose.set('bufferTimeoutMS', 2000) — the default is 10000 — and you get exactly this:
MongooseError: Operation `books.findOne()` buffering timed out after 2000ms
That means "no connection", not "slow query". After an explicit disconnect() buffering is off and the driver's own MongoNotConnectedError comes back instead.
For a second database, or a request-scoped connection in tests, mongoose.createConnection(uri) returns a Connection rather than touching the global one; it is not a promise, so call .asPromise(). Models then come from conn.model(...), which is why the Bookshelf store of Queries and the Query Builder takes a connection as an argument: each test gets its own database, with no global state to reset.