Speed up deployment of Lambda functions by creating dependency layers in AWS instead of locally.
- ⛓️ Easily separate dependency deployment from Lambda code deployment
- 🔁 Never re-package dependencies just because of a small code change
- ☁️ Never download another single dependency package locally again
- 🏋️ Never upload oversized code packages again
- 🌎 Edit your code in the browser -- no more "deployment package too large to enable inline code editing"
- ❌ Uninstall Docker from your laptop and extend your battery life
- ☕ Take shorter coffee breaks when deploying
Supported Lambda runtimes:
- 🐍 Python
- 📜 Node.js
- 💎 Ruby
- ☕ Java
Below are synth and deploy times for a simple Python function with PythonFunction
compared to Turbo Layers. The benchmark ran three times and the best time were taken for each step.
💤 PythonFunction | 🚀 Turbo Layers | 💤 5x PythonFunction | 🚀 5x Functions w/ Shared Turbo Layer | |
---|---|---|---|---|
Initial Synth | 1:21 | 0:06 | 2:43 | 0:06 |
Initial Deploy | 1:18 | 2:05 | 2:10 | 2:06 |
Code Change Synth | 0:31 | 0:06 | 1:21 | 0:06 |
Code Change Deploy | 0:49 | 0:29 | 1:19 | 0:36 |
New Dependency Synth | 0:33 | 0:06 | 1:30 | 0:06 |
New Dependency Deploy | 0:52 | 1:50 | 1:31 | 1:50 |
As you can see, code changes synth much faster and deploy a bit faster too. Dependency changes take longer to deploy, but are assumed to be way less frequent than code changes. The more dependencies your function uses, the better the results will be.
To run the benchmark yourself use:
npm run bundle && npm run benchmark
The best way to browse API documentation is on Constructs Hub. It is available in all supported programming languages.
- Confirm you're using CDK v2
- Install the appropriate package
- Python
pip install cloudsnorkel.cdk-turbo-layers
- TypeScript or JavaScript
npm i @cloudsnorkel/cdk-turbo-layers
- Java
<dependency> <groupId>com.cloudsnorkel</groupId> <artifactId>cdk.turbo-layers</artifactId> </dependency>
- Go
go get github.com/CloudSnorkel/cdk-turbo-layers-go/cloudsnorkelcdkturbolayers
- .NET
dotnet add package CloudSnorkel.Cdk.TurboLayers
- Python
const packager = new PythonDependencyPackager(this, 'Packager', {
runtime: lambda.Runtime.PYTHON_3_9,
type: DependencyPackagerType.LAMBDA,
});
new Function(this, 'Function with inline requirements', {
handler: 'index.handler',
code: lambda.Code.fromInline('def handler(event, context):\n import requests'),
runtime: lambda.Runtime.PYTHON_3_9,
// this will create a layer from with requests and Scrapy in a Lambda function instead of locally
layers: [packager.layerFromInline('inline requirements', ['requests', 'Scrapy'])],
});
new Function(this, 'Function with external source and requirements', {
handler: 'index.handler',
code: lambda.Code.fromAsset('lambda-src'),
runtime: lambda.Runtime.PYTHON_3_9,
// this will read pyproject.toml and poetry.lock and create a layer from the requirements in a Lambda function instead of locally
layers: [packager.layerFromPoetry('poetry requirements', 'lambda-src')],
});
- lovage: standalone Python framework that uses the same trick to deploy decorated functions to AWS
- serverless-pydeps: plugin for Serverless Framework that speeds up deployment
- Implements: aws-cdk-lib.aws_iam.IGrantable, aws-cdk-lib.aws_ec2.IConnectable
Packager for creating Lambda layers for Java dependencies in AWS.
Nothing is done locally so this doesn't require Docker and doesn't upload huge files to S3.
import { JavaDependencyPackager } from '@cloudsnorkel/cdk-turbo-layers'
new JavaDependencyPackager(scope: Construct, id: string, props?: DependencyPackagerProps)
Name | Type | Description |
---|---|---|
scope |
constructs.Construct |
No description. |
id |
string |
No description. |
props |
DependencyPackagerProps |
No description. |
- Type: constructs.Construct
- Type: string
- Type: DependencyPackagerProps
Name | Description |
---|---|
toString |
Returns a string representation of this construct. |
layerFromMaven |
Create a layer for dependencies defined in pom.xml installed with Maven. |
public toString(): string
Returns a string representation of this construct.
public layerFromMaven(id: string, path: string, props?: LayerProps): LayerVersion
Create a layer for dependencies defined in pom.xml installed with Maven.
- Type: string
- Type: string
- Type: LayerProps
Name | Description |
---|---|
isConstruct |
Checks if x is a construct. |
import { JavaDependencyPackager } from '@cloudsnorkel/cdk-turbo-layers'
JavaDependencyPackager.isConstruct(x: any)
Checks if x
is a construct.
- Type: any
Any object.
Name | Type | Description |
---|---|---|
node |
constructs.Node |
The tree node. |
connections |
aws-cdk-lib.aws_ec2.Connections |
The network connections associated with this resource. |
grantPrincipal |
aws-cdk-lib.aws_iam.IPrincipal |
The principal to grant permissions to. |
public readonly node: Node;
- Type: constructs.Node
The tree node.
public readonly connections: Connections;
- Type: aws-cdk-lib.aws_ec2.Connections
The network connections associated with this resource.
public readonly grantPrincipal: IPrincipal;
- Type: aws-cdk-lib.aws_iam.IPrincipal
The principal to grant permissions to.
- Implements: aws-cdk-lib.aws_iam.IGrantable, aws-cdk-lib.aws_ec2.IConnectable
Packager for creating Lambda layers for Node.js dependencies in AWS. Nothing is done locally so this doesn't require Docker, doesn't download any packages and doesn't upload huge files to S3.
import { NodejsDependencyPackager } from '@cloudsnorkel/cdk-turbo-layers'
new NodejsDependencyPackager(scope: Construct, id: string, props?: DependencyPackagerProps)
Name | Type | Description |
---|---|---|
scope |
constructs.Construct |
No description. |
id |
string |
No description. |
props |
DependencyPackagerProps |
No description. |
- Type: constructs.Construct
- Type: string
- Type: DependencyPackagerProps
Name | Description |
---|---|
toString |
Returns a string representation of this construct. |
layerFromInline |
Create a layer for dependencies passed as an argument and installed with npm. |
layerFromPackageJson |
Create a layer for dependencies defined in package.json and (optionally) package-lock.json and installed with npm. |
layerFromYarn |
Create a layer for dependencies defined in package.json and yarn.lock and installed with yarn. |
public toString(): string
Returns a string representation of this construct.
public layerFromInline(id: string, libraries: string[], props?: LayerProps): LayerVersion
Create a layer for dependencies passed as an argument and installed with npm.
- Type: string
- Type: string[]
- Type: LayerProps
public layerFromPackageJson(id: string, path: string, props?: LayerProps): LayerVersion
Create a layer for dependencies defined in package.json and (optionally) package-lock.json and installed with npm.
- Type: string
- Type: string
- Type: LayerProps
public layerFromYarn(id: string, path: string, props?: LayerProps): LayerVersion
Create a layer for dependencies defined in package.json and yarn.lock and installed with yarn.
- Type: string
- Type: string
- Type: LayerProps
Name | Description |
---|---|
isConstruct |
Checks if x is a construct. |
import { NodejsDependencyPackager } from '@cloudsnorkel/cdk-turbo-layers'
NodejsDependencyPackager.isConstruct(x: any)
Checks if x
is a construct.
- Type: any
Any object.
Name | Type | Description |
---|---|---|
node |
constructs.Node |
The tree node. |
connections |
aws-cdk-lib.aws_ec2.Connections |
The network connections associated with this resource. |
grantPrincipal |
aws-cdk-lib.aws_iam.IPrincipal |
The principal to grant permissions to. |
public readonly node: Node;
- Type: constructs.Node
The tree node.
public readonly connections: Connections;
- Type: aws-cdk-lib.aws_ec2.Connections
The network connections associated with this resource.
public readonly grantPrincipal: IPrincipal;
- Type: aws-cdk-lib.aws_iam.IPrincipal
The principal to grant permissions to.
- Implements: aws-cdk-lib.aws_iam.IGrantable, aws-cdk-lib.aws_ec2.IConnectable
Packager for creating Lambda layers for Python dependencies in AWS.
Nothing is done locally so this doesn't require Docker, doesn't download any packages and doesn't upload huge files to S3.
import { PythonDependencyPackager } from '@cloudsnorkel/cdk-turbo-layers'
new PythonDependencyPackager(scope: Construct, id: string, props?: DependencyPackagerProps)
Name | Type | Description |
---|---|---|
scope |
constructs.Construct |
No description. |
id |
string |
No description. |
props |
DependencyPackagerProps |
No description. |
- Type: constructs.Construct
- Type: string
- Type: DependencyPackagerProps
Name | Description |
---|---|
toString |
Returns a string representation of this construct. |
layerFromInline |
Create a layer for dependencies passed as an argument and installed with pip. |
layerFromPipenv |
Create a layer for dependencies defined in Pipfile and (optionally) Pipfile.lock and installed with pipenv. |
layerFromPoetry |
Create a layer for dependencies defined in pyproject.toml and (optionally) poetry.lock and installed with poetry. |
layerFromRequirementsTxt |
Create a layer for dependencies defined in requirements.txt and installed with pip. |
public toString(): string
Returns a string representation of this construct.
public layerFromInline(id: string, requirements: string[], props?: LayerProps): LayerVersion
Create a layer for dependencies passed as an argument and installed with pip.
- Type: string
- Type: string[]
- Type: LayerProps
public layerFromPipenv(id: string, path: string, props?: LayerProps): LayerVersion
Create a layer for dependencies defined in Pipfile and (optionally) Pipfile.lock and installed with pipenv.
- Type: string
- Type: string
- Type: LayerProps
public layerFromPoetry(id: string, path: string, props?: LayerProps): LayerVersion
Create a layer for dependencies defined in pyproject.toml and (optionally) poetry.lock and installed with poetry.
- Type: string
- Type: string
- Type: LayerProps
public layerFromRequirementsTxt(id: string, path: string, props?: LayerProps): LayerVersion
Create a layer for dependencies defined in requirements.txt and installed with pip.
- Type: string
- Type: string
- Type: LayerProps
Name | Description |
---|---|
isConstruct |
Checks if x is a construct. |
import { PythonDependencyPackager } from '@cloudsnorkel/cdk-turbo-layers'
PythonDependencyPackager.isConstruct(x: any)
Checks if x
is a construct.
- Type: any
Any object.
Name | Type | Description |
---|---|---|
node |
constructs.Node |
The tree node. |
connections |
aws-cdk-lib.aws_ec2.Connections |
The network connections associated with this resource. |
grantPrincipal |
aws-cdk-lib.aws_iam.IPrincipal |
The principal to grant permissions to. |
public readonly node: Node;
- Type: constructs.Node
The tree node.
public readonly connections: Connections;
- Type: aws-cdk-lib.aws_ec2.Connections
The network connections associated with this resource.
public readonly grantPrincipal: IPrincipal;
- Type: aws-cdk-lib.aws_iam.IPrincipal
The principal to grant permissions to.
- Implements: aws-cdk-lib.aws_iam.IGrantable, aws-cdk-lib.aws_ec2.IConnectable
Packager for creating Lambda layers for Ruby dependencies in AWS.
Nothing is done locally so this doesn't require Docker, doesn't download any packages and doesn't upload huge files to S3.
import { RubyDependencyPackager } from '@cloudsnorkel/cdk-turbo-layers'
new RubyDependencyPackager(scope: Construct, id: string, props?: DependencyPackagerProps)
Name | Type | Description |
---|---|---|
scope |
constructs.Construct |
No description. |
id |
string |
No description. |
props |
DependencyPackagerProps |
No description. |
- Type: constructs.Construct
- Type: string
- Type: DependencyPackagerProps
Name | Description |
---|---|
toString |
Returns a string representation of this construct. |
layerFromBundler |
Create a layer for dependencies defined in Gemfile and (optionally) Gemfile.lock and installed with Bundler. |
public toString(): string
Returns a string representation of this construct.
public layerFromBundler(id: string, path: string, props?: LayerProps): LayerVersion
Create a layer for dependencies defined in Gemfile and (optionally) Gemfile.lock and installed with Bundler.
- Type: string
- Type: string
- Type: LayerProps
Name | Description |
---|---|
isConstruct |
Checks if x is a construct. |
import { RubyDependencyPackager } from '@cloudsnorkel/cdk-turbo-layers'
RubyDependencyPackager.isConstruct(x: any)
Checks if x
is a construct.
- Type: any
Any object.
Name | Type | Description |
---|---|---|
node |
constructs.Node |
The tree node. |
connections |
aws-cdk-lib.aws_ec2.Connections |
The network connections associated with this resource. |
grantPrincipal |
aws-cdk-lib.aws_iam.IPrincipal |
The principal to grant permissions to. |
public readonly node: Node;
- Type: constructs.Node
The tree node.
public readonly connections: Connections;
- Type: aws-cdk-lib.aws_ec2.Connections
The network connections associated with this resource.
public readonly grantPrincipal: IPrincipal;
- Type: aws-cdk-lib.aws_iam.IPrincipal
The principal to grant permissions to.
import { DependencyPackagerProps } from '@cloudsnorkel/cdk-turbo-layers'
const dependencyPackagerProps: DependencyPackagerProps = { ... }
Name | Type | Description |
---|---|---|
architecture |
aws-cdk-lib.aws_lambda.Architecture |
Target Lambda architecture. |
logRemovalPolicy |
aws-cdk-lib.RemovalPolicy |
Removal policy for logs of image builds. |
logRetention |
aws-cdk-lib.aws_logs.RetentionDays |
The number of days log events are kept in CloudWatch Logs. |
preinstallCommands |
string[] |
Additional commands to run before installing packages. |
runtime |
aws-cdk-lib.aws_lambda.Runtime |
Target Lambda runtime. |
subnetSelection |
aws-cdk-lib.aws_ec2.SubnetSelection |
VPC subnets used for packager. |
type |
DependencyPackagerType |
Type of dependency packager. |
vpc |
aws-cdk-lib.aws_ec2.IVpc |
VPC used for packager. |
public readonly architecture: Architecture;
- Type: aws-cdk-lib.aws_lambda.Architecture
Target Lambda architecture.
Packages will be installed for this architecture so make sure it fits your Lambda functions.
public readonly logRemovalPolicy: RemovalPolicy;
- Type: aws-cdk-lib.RemovalPolicy
- Default: RemovalPolicy.DESTROY
Removal policy for logs of image builds.
If deployment fails on the custom resource, try setting this to RemovalPolicy.RETAIN
. This way the CodeBuild logs can still be viewed, and you can see why the build failed.
We try to not leave anything behind when removed. But sometimes a log staying behind is useful.
public readonly logRetention: RetentionDays;
- Type: aws-cdk-lib.aws_logs.RetentionDays
- Default: logs.RetentionDays.ONE_MONTH
The number of days log events are kept in CloudWatch Logs.
When updating
this property, unsetting it doesn't remove the log retention policy. To
remove the retention policy, set the value to INFINITE
.
public readonly preinstallCommands: string[];
- Type: string[]
- Default: []
Additional commands to run before installing packages.
Use this to authenticate your package repositories like CodeArtifact.
public readonly runtime: Runtime;
- Type: aws-cdk-lib.aws_lambda.Runtime
Target Lambda runtime.
Packages will be installed for this runtime so make sure it fits your Lambda functions.
public readonly subnetSelection: SubnetSelection;
- Type: aws-cdk-lib.aws_ec2.SubnetSelection
- Default: default subnets, if VPC is used
VPC subnets used for packager.
public readonly type: DependencyPackagerType;
- Type: DependencyPackagerType
- Default: {@link DependencyPackagerType.LAMBDA}
Type of dependency packager.
Use Lambda for speed and CodeBuild for complex dependencies that require building native extensions.
public readonly vpc: IVpc;
- Type: aws-cdk-lib.aws_ec2.IVpc
- Default: no VPC
VPC used for packager.
Use this if your package repositories are only available from within a VPC.
import { LayerProps } from '@cloudsnorkel/cdk-turbo-layers'
const layerProps: LayerProps = { ... }
Name | Type | Description |
---|---|---|
alwaysRebuild |
boolean |
Always rebuild the layer, even when the dependencies definition files haven't changed. |
public readonly alwaysRebuild: boolean;
- Type: boolean
- Default: false
Always rebuild the layer, even when the dependencies definition files haven't changed.
Type of dependency packager.
This affects timeouts and capabilities of the packager.
Name | Description |
---|---|
LAMBDA |
Use Lambda function to package dependencies. |
CODEBUILD |
Use CodeBuild to package dependencies. |
Use Lambda function to package dependencies.
It is much faster than the alternative, but limited to 15 minutes and can't build native extensions.
Use CodeBuild to package dependencies.
It is capable of everything your local machine can do, but takes a little longer to startup.