On July 15, 2026, AWS announced a new option for storing AWS Lambda deployment packages: self-managed Amazon S3 code storage.
How Lambda stored deployment packages before
Before this release, Lambda copied every .zip deployment package into Lambda-managed storage, even when the source file was already in Amazon S3.
This storage was limited to 75 GB per account and region, so teams with many functions, versions, and layers could eventually encounter a CodeStorageExceededException and need a quota increase.
With this release, AWS made the following changes:
- Default Lambda managed storage quota has been increased to 300 GB per account and region
- There are now 2 code storage modes for Lambda
-
COPY- Lambda copies the .zip file into its own storage (Will count against the 300 GB per region/account) -
REFERENCE- Lambda references the.zipfile directly from your S3 bucket without creating a Lambda-managed copy.
-
What this feature does not change
Self-managed S3 code storage changes where Lambda stores deployment packages, but the existing deployment limits still apply:
- Deployment package size: The unzipped package cannot exceed 250 MB.
-
Container images: Self-managed S3 code storage applies only to
.zip-based functions and layers.
Testing REFERENCE mode
To understand how REFERENCE mode works, I tested it using a simple Lambda function connected to Amazon DynamoDB.
During deployment, I found the following requirements and limitations:
The S3 bucket containing the deployment package must have versioning enabled. Lambda references a specific version of the
.zipfile rather than only using the object key. This ensures that the deployed package does not change when a new file is uploaded using the same key.When creating or updating the function, you must provide the S3 object version and set the storage mode to
REFERENCE. The mode must be specified on every code update; otherwise, Lambda defaults toCOPY.The S3 bucket policy must allow the Lambda service principal,
lambda.amazonaws.com, to performs3:GetObjectands3:GetObjectVersion.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "LambdaSelfManagedCodeAccess",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:GetObjectVersion"
],
"Resource": [
"arn:aws:s3:::my-bucket/my-function.zip"
],
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Condition": {
"ArnLike": {
"aws:SourceArn": "arn:aws:lambda:us-east-1:111122223333:function:my-function"
}
}
}
]
}
- The built-in Lambda console code editor was not available for the function using
REFERENCEmode.
Does REFERENCE mode affect Lambda performance?
To find out, I benchmarked two functionally identical Lambda functions that differed only in code storage mode.
Test setup
| Configuration | lambda-storagemode-copy |
lambda-storagemode-reference |
|---|---|---|
| Storage mode |
COPY (default) |
REFERENCE (self-managed S3) |
| Runtime | Python 3.14 | Python 3.14 |
| Architecture | x86_64 |
x86_64 |
| Application code | Identical | Identical |
| Workload | DynamoDB PutItem
|
DynamoDB PutItem
|
| Memory configurations tested | 128 MB–3008 MB | 128 MB–3008 MB |
Both functions were profiled with AWS Lambda Power Tuning using the same parameters to keep the test conditions as consistent as possible.
Cold-start performance
To isolate cold-start behavior, every invocation was forced to launch a new execution environment.
Configuration: 15 invocations per memory size · onlyColdStarts: true · parallelInvocation: false · discardTopBottom: 0
| Memory | COPY |
REFERENCE |
|---|---|---|
| 128 MB | 811.36 ms | 807.31 ms |
| 256 MB | 764.52 ms | 712.20 ms |
| 512 MB | 558.92 ms | 644.49 ms |
| 1024 MB | 629.97 ms | 549.06 ms |
| 1536 MB | 620.68 ms | 681.16 ms |
| 3008 MB | 760.22 ms | 605.82 ms |
AWS Lambda Power Tuning selected 512 MB as the balanced configuration for both functions.
Neither mode was consistently faster across the tested memory sizes. With only 15 invocations per memory size, these results should be treated as directional.
Standard Power Tuning performance
Next, I ran Power Tuning with forced cold starts disabled and the default outlier trimming enabled.
Configuration: 15 invocations per memory size · onlyColdStarts: false · parallelInvocation: true · discardTopBottom: 0.2
| Memory | COPY |
REFERENCE |
|---|---|---|
| 128 MB | 120.70 ms | 35.53 ms |
| 256 MB | 15.55 ms | 13.57 ms |
| 512 MB | 8.57 ms | 8.46 ms |
| 1024 MB | 8.71 ms | 8.11 ms |
| 1536 MB | 8.40 ms | 8.32 ms |
| 3008 MB | 8.04 ms | 11.75 ms |
Both functions again converged on 512 MB as the balanced configuration. I did not use the 128 MB row for a mode-to-mode comparison. At that memory allocation, a small number of slower invocations can disproportionately affect the average.
Takeaway
Across both tests, COPY and REFERENCE showed no consistent runtime performance advantage over one another.


Top comments (0)