Manage Connections with AWS Lambda
On this page
Use the following best practices to properly manage connections between AWS Lambda and Atlas:
Define the client to the MongoDB server outside the AWS Lambda handler function.
Don't define a new MongoClient object each time you invoke your function. Doing so causes the driver to create a new database connection with each function call. This can be expensive and can result in your application exceeding database connection limits. As an alternative, do the following:
- Create the MongoClient object once.
- Store the object so your function can reuse the MongoClient across function invocations.
The Connection Example reuses existing database connections to speed up communication with the database and keep connection counts to the database at a reasonable level with respect to application traffic.
If your handler takes a callback as its last argument, set the
callbackWaitsForEmptyEventLoop
property on the AWS Lambda Context object to false.context.callbackWaitsForEmptyEventLoop = false; This allows a Lambda function to return its result to the caller without requiring that the MongoDB database connection be closed. Setting this property is not applicable for async handlers.
Restrict network access to your Atlas cluster.
Connect to your Atlas cluster over private networking using a Network Peering connection between your Atlas cluster and your AWS Lambda function, or, alternatively, a private endpoint, so that you can allow only private IP addresses to your IP access list.
If private networking is not an option, consider connecting to your Atlas cluster via a NAT gateway with a mapped Elastic IP address. Otherwise, you must allow all IP addresses (0.0.0.0/0) to access your service cluster.
Set Up Unified AWS Access and use AWS IAM authentication where possible.
You can connect to your Atlas clusters using AWS IAM roles instead of hardcoding your credentials in Lambda. Hardcoded credentials are viewable by anyone who accesses your AWS Lambda environment, which can pose a security risk. With AWS IAM authentication, Atlas accesses AWS Lambda through an assumed IAM role, so you don't need credentials in your connection strings.
Atlas supports AWS IAM authentication for clusters running MongoDB version 4.4 or higher. We strongly advise using AWS IAM authentication for Lambda connections if your cluster meets the requirements.
To use AWS IAM authentication, Set Up Unified AWS Access.
NoteFor the connection examples on this page, you can use AWS IAM authentication instead of hardcoded credentials by doing the following:
- Set Up Unified AWS Access
In the first Node.js example, replace
const { MongoClient } = require('mongodb');
with the following lines of code:index.js1 const MONGODB_CONNECTION_STRING = new URL(process.env.MONGODB_URI); 2 MONGODB_CONNECTION_STRING.username = process.env.AWS_ACCESS_KEY_ID; 3 MONGODB_CONNECTION_STRING.password = encodeURIComponent(process.env.AWS_SECRET_ACCESS_KEY); 4 MONGODB_CONNECTION_STRING.searchParams.set('authSource', '$external'); 5 MONGODB_CONNECTION_STRING.searchParams.set('authMechanism', 'AWS_SESSION_TOKEN:' + encodeURIComponent(process.env.AWS_SESSION_TOKEN)); - In the first Node.js example, replace
process.env.MONGODB_URI
withMONGODB_CONNECTION_STRING.toString()
Connection Examples
This section includes examples for two approaches:
- In the first Node.js example, the
index.js
file shows how to reuseMongoclient.connect
across function invocations. - In the second Node.js example, the
index.js
andmongodb-client.js
files show how to isolate the call toMongoClient.connect
into its own module so that the connections can be reused across functions. Use this approach if you package multiple logical functions together in a single Lambda handler function.
The following example shows the best practice of defining the
MongoClient.connect
function in your application's Node.js code
outside the handler so it can be reused across function invocations.
1 ;2 3 // Import the dependency. 4 const { MongoClient } = require('mongodb'); 5 6 // Create a module-scoped MongoClient promise. 7 // CRITICAL: You must call connect() outside the handler so that the client 8 // can be reused across function invocations. 9 let client = new MongoClient(process.env.MONGODB_URI, 10 { useNewUrlParser: true, useUnifiedTopology: true }); 11 const clientPromise = client.connect(); 12 13 // Handler 14 module.exports.handler = async function(event, context) { 15 16 // Get the MongoClient by calling await on the promise. 17 // Because this is a promise, it will only resolve once. 18 client = await clientPromise; 19 20 // Use the client to return the name of the connected database. 21 return client.db().databaseName; 22 }
Some serverless frameworks that run on top of Lambda allow for
multiple logical functions to be packaged together in a single
Lambda handler function. If your application runs multiple functions
within the same Lambda process, we recommend isolating the call to
the MongoClient.connect
function into its own module so that
the connections can be reused across functions.
In the following code examples:
mongo-client.js
organizes theMongoClient.connect
function into its own module (mongo-client).index.js
imports that module and uses it to connect.
1 ;2 3 // Import the dependency. 4 const { MongoClient } = require('mongodb'); 5 6 // Export a module-scoped MongoClient promise. By doing this in a separate 7 // module, the client can be shared across functions. 8 const client = new MongoClient(process.env.MONGODB_URI, 9 { useNewUrlParser: true, useUnifiedTopology: true }); 10 module.exports = client.connect();
1 ;2 3 // Import the dependency. 4 const clientPromise = require('./mongodb-client'); 5 6 // Handler 7 module.exports.handler = async function(event, context) { 8 9 // Get the MongoClient by calling await on the connection promise. Because 10 // this is a promise, it will only resolve once. 11 const client = await clientPromise; 12 13 // Use the connection to return the name of the connected database. 14 return client.db().databaseName; 15 }