DEV Community

Cover image for AWS Lambda Self-Managed S3 Code Storage: `COPY` vs. `REFERENCE`

AWS Lambda Self-Managed S3 Code Storage: `COPY` vs. `REFERENCE`

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 .zip file 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.

Architecture diagram showing AWS Lambda writing to Amazon DynamoDB within an AWS account

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 .zip file 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 to COPY.

  • The S3 bucket policy must allow the Lambda service principal, lambda.amazonaws.com, to perform s3:GetObject and s3: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"
        }
      }
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode
  • The built-in Lambda console code editor was not available for the function using REFERENCE mode.

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.

Sources

Top comments (0)