Aws Lambda Best Practices For Performant & Scalable Serverless Functions

Serverless functions help you build powerful systems quickly and at a low initial cost.
They are versatile in that they can fit small MVP workloads and large scalable enterprise systems.
However, like any other tool, they must be used properly and with best practices.
I’ve been building backend systems, for large and small companies, for over 6 years now and I’ll share with you some best practices and tips I’ve learned along the way.
Use this article as a guide for every time you create a new Lambda function, to make sure it follows the best practices in this list.
1. Memory & Timeout
The first thing you should be configuring as soon as you create a new Lambda function is the memory and timeout settings.
These settings can be found in the General Configuration tab under the main Conguration tab.
99.9% of your functions should have at least 500MB of memory. Anything lower than that will usually take longer than needed to run or timeout.
The sweet spot for most functions is between 500MB and 1GB. If you have longer running workloads you can bring that up to 2–3GB.
For the timeout, set a default of 3–5 seconds, depending on how long your functions tend to run. Monitor the timeout for your functions in CloudWatch and determine the best timeout for each function.
That will optimize costs and performance.
2. Permissions
Your Lambda function should respect the least privilege principle. In other words, it should be overly permissive yet have access to the services it communicates with.
Rather than having an IAM role like “admin” (read/write any AWS service), or a role which has access to several different services, each function should have a role for the one thing it performs.
For example, if your function is responsible for fetching items from DynamoDB, it should possess only a DynamoDB query role. Not a DynamoDB full access, read or read+write.
The tighter the permissions control is on your Lambdas, the less room there is for error.
3. Concurrency
Concurrency dictates how many times your Lambda function can be invoked at the same time.
For higher traffic usage, you may need a higher amount.
In the Configurations settings under concurrency and recursion detection you can set the concurrency for each function individually.
The way it works is your account has a total quota of concurrency for all the Lambdas in it.
Think of it as a pool of concurrency. If you need a certain amount of concurrency for a popular function, you can reserve 100 concurrency units for it.
This will guarantee the function can always support no less and no more than 100 concurrent executions.
This is what reserved concurrency means.
If you leave the default (unreserved concurrency) this lets the function take as much concurrency as it needs without regards to other functions.
So imagine you have a total of 100 account concurrency and you have 1 function using up 100 invocations at the same time, your other functions won’t be able to run as they will have no concurrency available to them to run.
Setting reserved concurrency will guarantee that the function to never be starved of concurrency.
4. Versions
Lambda versions let you publish immutable “snapshots” of your function code and configurations.
This is particularly useful when you need to perform rollbacks or AB testing of your function.
A best practice with versions is to publish a new version after every stable code change and use aliases like dev, satging, prod, to manage deployment stages safely.
5. Triggers
Triggers come in handy when working with other AWS services like DynamoDB or S3.
If you need to react to changes in S3 or DynamoDB and execute code with your Lambda function in response, triggers is what you need to use.
For example, you can setup a DynamoDB or S3 trigger on your Lambda to do things like:
calculate data in one table and write it to another DynamoDB table
update an external search index whenever new data is written to my DynamoDB table
Write a new item to my DynamoDB table every time a file is uploaded to S3
The process is simple: add a trigger on the Lambda function, configure the trigger, write your Lambda code to capture the upstream data and finally push that data to a downstream service.
6. Environment Variables
Environment variables are useful and important to set for hidden values and configuration variables.
Typically, they are used to store values such as:
- S3 bucket names
- DynamoDB table names
- API base URLs
- Config keys & non-sensitive credentials
- feature toggles
In the screenshot above, you can see I use them specifically for a Algolia integration. I store my app id as an environment variable as well as the index name which is a configuration value.
To add environment variables, select the Configuration tab and select environment variables in the left sidebar. From there you can add your variables.
It is important to note not to use environment variables for secret keys or sensitive values. Those should be securely stored using AWS Secrets Manager.
Conclusion
In this article we went through several best practices of using AWS Lambda. These include configuring memory and timeout, concurrency, working with permissions and versions as well as setting triggers and environment variables.
By following these best practices you can make sure your Lambda functions are secure, efficient and production-ready.
Keep this guide as a checklist whenever you build or update your serverless functions.
???? My name is Uriel Bitton and I’m committed to helping you master AWS, serverless and DynamoDB.
???? Build the database your business needs with DynamoDB — subscribe to my email newsletter The Serverless Spotlight.
Thanks for reading and see you in the next one!