Deep Dive Into Serverless

February 7, 2023
Ryan Jones
5 minutes to read

Cloudfront can be simply defined as a CDN (Content Delivery Network), caching your static assets in a datacenter nearer to your viewers. But Cloudfront is a lot more complex and versatile than this simple definition.
Cloudfront is a “pull” CDN, which means that you don’t push your content to the CDN. The content is pulled into the CDN Edge from the origin at the first request of any piece of content.

In addition to the traditional pull and cache usage, Cloudfront can also be used as:

  • A Networking Router
  • A Firewall
  • A Web Server
  • An Application Server

Why is using a CDN relevant?

The main reason is to improve the speed of delivery of static content. By caching the content on the CDN edge, you not only reduce the download time from a few seconds to a few milliseconds, but you also reduce the load and amount of requests on your backend (Network, IO, CPU, Memory, …).

Static content can be defined as content not changing between two identical requests done in the same time frame.

Identical can be as simple as the same URI, or as fine grained as down to the authentication header. The time frame can range between 1 second to 1 year.
The most common case is caching resources like Javascript or CSS and serving the same file to all users forever. But caching a JSON response tailored to a user (Authentication header) for a few seconds reduces the backend calls when the user has the well-known “frenetic browser reload syndrome”.

Edges, Mid-Tier Caches, and Origins

Cloudfront isn’t “just” some servers in datacenters around the world. The service is a layered network of Edge Locations and Regional Edge Caches (or Mid-Tier Caches).

Edge Locations are distributed around the globe with more than 400 points of presence in over 90 cities across 48 countries. Each Edge Location is connected to one of the 13 Regional Edge Caches.

Regional Edge Caches are transparent to you and your visitors, you can’t configure them or access them directly. Your visitors will interact with the nearest Edge Location, which will connect to the attached Regional Edge Cache and finally to your origin. Therefore, in this article, we will refer to Cloudfront as the combination of Edge Locations and Region Edge Caches.

What Have We Learned?

Cloudfront is more than just a simple “pull-cache-serve” service

  • You improve delivery speed to your visitors
  • You can increase resilience by always using a healthy backend
  • You improve overall speed to your backend by leveraging AWS’s backbone
  • You can modify any request to tailor the response to your visitor’s device or region
  • You don’t always need a backend
  • You protect your backend by reducing the number of calls reaching it

Access free book

More from Serverless Guru

Building Serverless REST APIs for a Meal Prep Service with CloudGTO

October 31, 2023
Learn More

How to build an AWS AppSync GraphQL API with multiple data sources

October 26, 2023
Learn More

Building a Secure Serverless API with Lambda Function URL and CloudFront — Part 1

October 17, 2023
Learn More

AWS Serverless Development: Coding Best Practices

Let's Talk


In this article, we will look at AWS Serverless Development (Serverless Framework + Node.js) Coding Best Practices that will help your team implement production applications code with better readability, maintenance, reusability, performance, code management, and security.

Coding best practices from the beginning of the project to production leads to a high quality application and easy maintenance far into the future.

What is Serverless on AWS?

Serverless means building and running applications without thinking about servers.

AWS offers technologies for running code, managing data, and integrating applications, all without managing servers. Serverless technologies feature automatic scaling, built-in high availability, and a pay-for-use billing model to increase agility and optimize costs. These technologies also eliminate infrastructure management tasks like capacity provisioning and patching, so you can focus on writing code that serves your customers. Serverless applications start with AWS Lambda, an event-driven compute service natively integrated with over 200 AWS services and software as a service (SaaS) applications. [1]

What Is Serverless Framework?

Serverless Framework is an open-source infrastructure-as-code (IaC) tool and development framework that allows you to build and deploy serverless applications.

What is NodeJs?

Here’s a formal definition as given on the official Node.js website:

Node.js is a JavaScript runtime built on Chrome’s V8 JavaScript engine

Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient.

Node.js’ package ecosystem, npm, is the largest ecosystem of open source libraries in the world.

AWS Serverless Development - Serverless Framework Coding Best Practices

Break large serverless.yml into multiple files

When serverless.yml gets too big, you can break it up into smaller files and reference them back in the main serverless.yml. This helps to keep the serverless.yml file easily manageable.

To reference properties in other YAML files use this syntax:


in this configuration file:


Category: Code management

Benefits: Keep code clean and well manageable


The example below shows how to break large serverless.yml into multiple files

  • serverless.yml
  • yml/custom.yml
  • yml/plugins.yml
  • yml/functions.yml

One IAM role per function

By default, the Serverless Framework uses a shared role for all the functions in the serverless.yml. This too violates the principle of least privilege as functions would gain unnecessary access through the shared role.

Instead, you should use the serverless-iam-roles-per-function plugin and define IAM roles for each function.

Category: Security

Benefits: Enhance security through the principle of least privilege


No wildcards in IAM role statements

Serverless applications can be more secure than their container and VM counterparts. But, we still need to do our part and make sure we don’t overprovision our functions with access.

We should follow the principle of least privilege and grant our functions the minimal amount of access they need. And that means granting permissions to perform specific operations against specific resources.

Category: Security

Benefits: Enhance security through the principle of least privilege granting permissions to perform specific operations against specific resources.




Setup a defaults file for serverless.yml imports

If there are configuration values that are specific to an environment (DEV, QA, PREPROD, PROD), consider creating a separate file that would act as a reference for injecting values into the serverless.yml file that performs the actual deployment.

Category: Code management

Benefits: Avoid code logic at the handler level to perform operations based on the environment.

Based on default values imported into the serverless.yml, you can utilize environment variables to hold only those values for that environment deployment.



Note: Place the defaults in the root directory, and manage the path reference for the defaults file from the serverless.yml accordingly

Configure stack tags

Tags help you find resources easier and you can even use them to track your AWS spending. By default, the Serverless Framework inserts the STAGE tag to the generated CloudFormation template.

However, you should consider adding other custom tags using the stackTags property. Common tags to consider include Author, Team, Feature, and Region.

Category: Resource Management

Benefits: Resource tagging helps to identify different resources on large projects & able to track AWS spending based on resource tagging.

Use webpack to improve cold start and reduce package size

For Node.js functions, the Initialization time is a big part of the cold start time and can vary greatly depending on how many dependencies you have. Webpack can help reduce Initialization time significantly. You should use the serverless-webpack plugin to run webpack automatically every time you deploy your code.

Category: Performance

Benefits: Deployments are much faster because package size is small

Reduce the number of AWS Lambda function versions using the prune plugin

Following deployment, the Serverless Framework does not purge previous versions of functions from AWS, so the number of deployed versions can grow out of hand rather quickly.

It is good practice to limit the number of Lambda versions to keep using serverless-prune-plugin.

Category: Resource Management


Store sensitive details in secrets manager/parameter store/SLS params

Hardcoding credentials, API keys, secrets as part of the environment variables in the IAC stack, leads to storing those details at the repository level. For security purposes, sensitive details can be stored in the Secrets manager (or Parameter store, depending on use case) or SLS params.

For SLS param case value show encrypted in the serverless pro dashboard but they come out plain text in the console when storing into Lambda environment variable, so that is not most secure way for sensitive information.

In the case of a secrets manager, the most secure way is to pull in using the AWS SDK inside the lambda function and not expose it at all as an environment variable as they get exposed in the lambda console.

Category: Security

Benefits: Better control since the rotation of secrets can be done by the admin from the console with no hard coding required in the repository.

AWS Serverless Development - NodeJS Coding Best Practices

Use Latest LTS versions of Node

Avoid using older versions of NodeJs as possible. AWS Lambda deprecated usage of older version before Node.js 12.x while ago, Recommended runtime version as of 01/21/2022 is Node.js 14.x.

Lambda functions running on Node.js 14 will have 2 full years of support.

Category: Performance, security, features

Benefits: Latest Node version always have more stability and new features.

Remove unused dependencies

Review carefully the dependencies file requires. Any unused dependencies should be removed.

Having too many dependencies opens you up to security risks as those packages could be exploited at some point on top of package size and cold starts.

We don't need aws-sdk in dependencies AWS Lambda already has this installed.

Category: Performance

Benefits:Reduce package size.Reduce cold start timing.

Import only what your code needs

When possible, instead of importing the whole dependency, we should require only what the code is going to use.

Category: Performance

Benefits: Reduce package size.Reduce cold start timing.


In this example, we only need the S3 client to upload an object to AWS S3. So instead of requiring the whole aws sdk, we can only require the S3 client.



Function code management

A typical lambda function should not be more than 200 lines in code length performing only one singular task.Split logic into separate functions, if possible. However, in scenarios when the logic cannot be separated, move those sub-functions that perform a singular task into separate files under a “helper” folder, and restructure your handler function with the appropriate imports.

Category: Performance, maintenance, readability

Benefits: Easier to maintain. Smaller functions promote better management and pose a lower risk of failing a system because the logic is decoupled into separate functions.

Module exports definition

Place the module.exports definition at the bottom of the file with all the functions/variables you want to export.

Category: Readability, Maintenance




Use async/await instead of callbacks

There are 3 ways to handle code that takes time, such as aws-sdk calls:

  • callbacks
  • promises
  • async await

In the context of serverless backend lambda functions, we find async await can greatly increase the readability of code and help us avoid what is known in the NodeJS community as 'the pyramid of doom'.

Category: Readability, Maintenance

Use parallel execution when possible

When need to await for some functions to be executed and they don’t depend on the other functions responses, you can run them in parallel.

Category: Performance




Remove unused functions

Functions that are not being used have to be removed to have a cleaner codebase.

Category: Readability, Maintenance

Use else block only if needed

Do not use unnecessary else blocks when possible.

Category: Readability, Maintenance




Move env variables to the top of the file

Move all process.env.MY_VAR references to the top of the file for better visibility on what env variables are required in the file.

Category: Readability, Maintenance




Move helper functions to a helper file

Any helper function that is used in multiple files, instead of redeclaring it on every function, we can create a helper file and export/require the function, removing code duplication.

Category: Reusability, Maintenance

Avoid using global variables in Lambda

Keeping track of the global state in a Lambda Function is undesirable because Lambda Functions executing one after the other will share the container originally spun up by the first Lambda execution. This means global variables will carry over to the next invocation.

If the global state is intended to keep track of state for 1 single invocation rather than multiple invocations, the behavior will be very unpredictable.

Category: Maintenance


Result global variable counter will have unpredictable results.

Use const/let instead of var

“const” and “let” provide more information about whether that variable can be reassigned or not.

  • “const” is used for variables that won’t change the value.
  • “let” is used for variables that will change the value

Category: Readability, Maintenance

Avoid nested checks as much as possible

Nested checks make the code more difficult to follow.

Category: Readability, Maintenance




Use strict equality operator when possible (=== | !==)

The most notable difference between this operator and the equality (==) operator is that if the operands are of different types, the == operator attempts to convert them to the same type before comparing. [2] It makes code more reliable and easier to troubleshoot.

Category: Readability, Maintenance

Remove “this” keyword

Don’t use “this” when declaring a new variable.

Category: Readability



Don’t use magic strings

Magic strings are rarely self-documenting. If you see one string, that tells you nothing of what else the string could / should be. You will probably have to look into the implementation to be sure you've picked the right string.When a magic string is used more than once and you have to refactor the code, you would have to update the value in several places which makes the process error-prone.

Category: Readability, Reusability, Maintenance




Utilize Object Destructuring to import only needful methods

Instead of importing the entire library, we can use object destructuring to only import the methods we need.

Category: Performance




The arrow function syntax is preferred

Arrow function syntax introduced in ES6 is preferred over regular function syntax for readability.

Category: Readability





Coding best practices always matter, When a small or big team works on a project and follows coding best practices then of course produced production application quality code will have better Readability, Maintenance, Reusability, Performance, Code Management, Security.

In this blog, Covered a few above-shared generic coding best practices but there are more possible practices as well.

Coding best practices from the beginning of the project to production leads to the high quality of your application and easy maintenance in the future going.




More from Serverless Guru

Join the Community

Gather, share, and learn about AWS and serverless with enthusiasts worldwide in our open and free community.