Reduce Existing Javascript Lambda Package by 49%? Yes please!

I'm a Consulting Software Engineer, Software Architect, and AWS Solutions Architect with over 34 years of experience. My specializations include AWS serverless application development, IoT, and webapps.
I performed too well growing with the Cloud Native application development practice of a Premier AWS Consulting Partner, and got myself promoted to management. π
Now I'm returning to my true self as a full spectrum software engineer and cloud technologist; from discovery to delivery and everything between.
Photo by Markus Spiske on Unsplash
I was reading about the new aws-sdk for Javascript version 3 (aws-sdk-js-v3), and part of the advancement is the modularization of the SDK to reduce the resulting deployment package sizeβββand by extension cold-start time.
You can read about the new v3 SDK, including the modular architecture, here.
What if you are working on a project though that is stabilizing for release, or you just arenβt ready to make the jump to v3 yet? Thatβs where I was, but out of curiosity I read the migration guide and learned that the first step is to convert the existing aws-sdk-js v2 imports away from things like:
import AWS from βaws-sdkβ;
const dynamoDB = new AWS.DynamoDB();
into:
import DynamoDB from "aws-sdk/clients/dynamodb";
const dynamoDB = new DynamoDB();
Iβm already using Webpack and Tree Shaking!
This would supposedly reduce the amount of code imported, even with v2. So maybe I could make this simple change, preparing the code base for v3 later and safely improve performance now? I wasnβt sure how much such a change would help, since the project was already tree-shaking with webpack. I was aware though that webpack doesnβt work well on aws-sdk-jsβ¦ so maybe?
To try it out, I first added a new rule to tslint.json (Iβm using Typescript):
"import-blacklist": [true, "aws-sdk"]
With that, tslint highlights all the places that need to be changed and bans anyone from unwittingly doing a top-level import later and undoing any benefits. Cool. π
Because the code base uses hexagonal architecture, tslint only found twelve files that needed to be updated. π I made a few changes such as:
- import {ApiGatewayManagementApi} from "aws-sdk";
+ import ApiGatewayManagementApi from "aws-sdk/clients/apigatewaymanagementapi";
and
- import * as AWS from 'aws-sdk';
+ import Iot from 'aws-sdk/clients/iot';
+ import IotData from 'aws-sdk/clients/iotdata';
+ import {AWSError} from 'aws-sdk/lib/error';
A quick deploy and into the AWS Console I go to look in the stack deployment buckets in AWS S3 and compare the new and previous packages. What I found sealed the deal! Here area few of the results:
ββββββββββββββ¦ββββββββββββββββ¦βββββββββββ¦ββββββββββββ
β Stack Name β Previous Size β New Size β Reduction β
β βββββββββββββ¬ββββββββββββββββ¬βββββββββββ¬ββββββββββββ£
β ingest β 9.0 MB β 7.4 MB β 18% β
β provision β 4.2 MB β 1.8 MB β 57% β
β device-api β 14.3 MB β 6.5 MB β 55% β
β general-apiβ 1.4 MB β 0.6 MB β 57% β
β account-apiβ 5.6 MB β 2.4 MB β 57% β
ββββββββββββββ©ββββββββββββββββ©βββββββββββ©ββββββββββββ
Overall average reduction in size: 49%
It was an easy change that took mere minutes to forever speed up cold starts.
Yes, bundle your AWS SDK!
One last note, as Iβm sure someone will point out that you can reduce sizes even more by using the SDK already within the Lambda execution environment instead of bundling it with your code.
Donβt fall for that trap!
That goes against Best practices for working with AWS Lambda functions, which includes controlling your dependencies. The SDK in the execution environment is there for quick little functions with no other dependenciesβββoften made from within the AWS Console. Relying on this ever-changing version of the SDK in your production environment means that you never know when your system will change from under you and mysteriously break. It isnβt worth it! Bundle your dependencies, but only what you need.




