# chrome-aws-lambda-layer, Chromium in an AWS Lambda layer

> shelfio/chrome-aws-lambda-layer republishes the Sparticuz/chromium build of Google Chrome as an AWS Lambda layer, compressed with Brotli so the browser fits inside Lambda's size limits at 68 MB for x64 and 66 MB for arm64, with layer versions published in sixteen regions for both architectures.

**shelfio/chrome-aws-lambda-layer** — 58 MB Google Chrome to fit inside AWS Lambda Layer compressed with Brotli

- Repository: https://github.com/shelfio/chrome-aws-lambda-layer
- Stars: 745 · Forks: 50
- Language: Unknown
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/shelfio-chrome-aws-lambda-layer

## What the layer contains and why it exists

This repository publishes Google Chrome for AWS Lambda as a layer, described as a 58 MB Google Chrome compressed with Brotli to fit inside an AWS Lambda layer. The README's own header line gives the sizes as 68 MB for x64 and 66 MB for arm64, which is the compressed layer size, and the repository description rounds that to 58 MB.

The underlying artifact is Sparticuz/chromium, a project that produces a Chromium build trimmed for serverless use, so that Puppeteer or Playwright can drive a real browser inside a Lambda function. The layer here is a distribution mechanism for that artifact, not a different build.

The reason a layer rather than a dependency is size. Lambda has a hard limit on the size of a deployment package, and a full Chromium build is around 120 MB uncompressed, which does not fit. Splitting it out into a layer moves the browser out of your function's package, and Brotli compression is what makes the remaining size acceptable. The tradeoff is that the layer is a separate deployment artefact that has to be versioned and kept in step with your function, and the README's list of layer ARNs is really a version manifest.

The layer carries Chromium version 153.0.0 at the time of the README, and it is tested with Node.js 16x, 18x, 20x and 22x, and with both x86_64 and arm64 architectures.

The project is MIT licensed, the default branch is master, and the last push was on 2026-09-12.

## How to wire it into a function

Adding the layer is done in the Lambda console or through infrastructure code, and the README covers both.

In the console you go to Layers, choose Add a layer, choose Provide a layer version ARN, and paste the ARN for your architecture. The x86_64 ARN is in us-east-1 and the arm64 ARN is in the same region under a different layer name.

In CDK, the layer is referenced with LayerVersion.fromLayerVersionArn:

```ts
layers: [LayerVersion.fromLayerVersionArn(this, 'chromium-lambda-layer',
  'arn:aws:lambda:us-east-1:764866452798:layer:chrome-aws-lambda:117'
)]
```

and the arm64 version uses the chrome-aws-lambda-arm64 layer name and its own version number. The README notes this is CDK code and that you can convert it to SAM or whatever you prefer.

The container settings matter and the README lists them: an x86_64 or arm64 architecture matching the layer, at least 1024 MB of memory, and @sparticuz/chromium marked as an externalModule in the bundling settings. The memory floor is not incidental, because Chromium is a heavy process and a Lambda with 512 MB will struggle to start one.

Then there is the detail that trips people up. The README says to import @sparticuz/chromium rather than chrome-aws-lambda when importing the module inside the function. The layer delivers the browser binary, but the package that knows how to launch it and where to find it is still the npm one, so the import stays the same in your code.

In the package.json, @sparticuz/chromium and puppeteer-core are both marked as dependencies. The reason puppeteer-core rather than full puppeteer is that puppeteer downloads its own browser, which defeats the entire point of shipping the browser separately.

In the deployed function you use a regular ES6 or CommonJS import of @sparticuz/chromium, exactly as the README indicates.

## The settings that decide whether it works

The memory floor is the setting most likely to cause a bad first run.

1024 MB is the minimum the README gives, and Chromium is a memory-hungry process even when it is only loading a single page. Lambda bills by memory, so raising it costs money, which makes it tempting to run lower. The failure when you do is not a clean error; it is the browser failing to start, or being killed partway through a navigation, and the resulting error in the function log is often a timeout rather than an out of memory message. If you need more than the minimum, for example because the page under test is heavy, you raise it, and the README's floor becomes a starting point rather than a target.

The external module setting is the other one. Because the browser binary arrives in the layer rather than in the deployment package, the npm package that knows where to find it has to be present at runtime, and marking it as an externalModule is what tells the bundler to leave it out of the package rather than trying to include it. If you get that wrong, the usual symptom is a function that deploys successfully and then fails on the first call to launch the browser, because the package was bundled but the binary it points at is not on disk.

The architecture match is the third. The x64 and arm64 layers contain different builds, and referencing the arm64 ARN from an x86_64 function, or the other way round, produces a function that cannot find a usable browser. The layer version numbers make the mistake easy because they differ between the two series, but the failure is at launch rather than at deploy.

One more practical note. The layer contains a browser, and the browser contains a version of Chrome. If the page under test behaves differently from your local Chrome, the layer's version is the reason, and the fix is to point at a newer layer version rather than to debug the page.

## The region list and the question of layer versions

The README publishes layer ARNs for sixteen regions for each architecture, and reading that list is instructive because the versions are not all the same.

For x86_64, most regions are on version 117: ap-northeast-1, ap-southeast-1, ap-southeast-2, ca-central-1, eu-central-1, eu-west-1, eu-west-2, eu-west-3, sa-east-1, us-east-1, us-west-1 and us-west-2. Two regions are behind at version 116: ap-northeast-2, and us-east-2 also appears at 117 in the list. ap-south-1 and us-east-2 are listed at 117.

For arm64, the versions are lower, at 11, and they are consistent across every listed region.

The practical reading is that the layer is rebuilt periodically and published to a set of regions, and the version numbers differ between architectures because the x64 and arm64 builds are packaged separately. The regions that lag are the ones that have not received the newest build.

That leads to the operational advice, which the README does not spell out but which the format makes obvious. A layer version is immutable in Lambda, so if you want a newer Chromium you reference a newer version number, and the function deployment has to be updated to point at it. There is no way to say use the latest. The layer ARN in your infrastructure code is a version pin, and the maintenance task is bumping it.

This is worth weighing against the alternative, which is bundling the browser into the function package directly. The Sparticuz/chromium project is distributed as a compressed npm package precisely so that it can be installed as a dependency, and many teams do exactly that. The layer approach wins when the function package is already near the size limit, or when the same browser is shared by many functions and you would rather deploy it once. The npm approach wins when you want the function to be self-contained and the deployment to carry its own browser version.

Neither is free. A layer is a version pin that has to be maintained and a deployment artefact that has to be published in every region you use. A bundled browser is 120 MB in your deployment package on every function, which affects cold start and your storage bill.

The two architectures also have separate version series, which is the concrete reminder that the Chromium version you get on Graviton is not the same as the one you get on Intel. If you test on one and deploy on the other, that is a difference worth watching.

## Conclusion

Adopt this layer if you run Puppeteer or Playwright in a Lambda and want a current Chromium without bundling one into your function package. Skip it if you can use the Sparticuz/chromium package directly, since the layer only changes how the binary is delivered. Verify first by checking the layer version against the Chromium release you need, since the layer lags the browser by however long the publisher takes to rebuild, and by confirming your function has at least 1024 MB of memory and the external module configured.

## FAQ

### What does shelfio/chrome-aws-lambda-layer provide?

It publishes the Sparticuz/chromium build of Google Chrome as an AWS Lambda layer, compressed with Brotli, at 68 MB for x64 and 66 MB for arm64, so a browser fits in Lambda where a full Chromium would not.

### How do I add the Chrome layer to a Lambda function?

In the console, add a layer and provide a layer version ARN for your architecture, or in CDK use LayerVersion.fromLayerVersionArn with the ARN. The function needs the matching architecture, at least 1024 MB of memory, and @sparticuz/chromium marked as an externalModule in the bundling settings.

### Which package do I import in the function code?

@sparticuz/chromium, not chrome-aws-lambda. The layer delivers the browser binary, but the npm package that knows how to launch it and where to find it is still required, and a regular ES6 or CommonJS import is used.

### Which dependencies does the Lambda function need?

In the package.json, @sparticuz/chromium marked as a dependency and puppeteer-core marked as a dependency. The README notes it is tested with Node.js 16x, 18x, 20x and 22x, and it has Chromium v153.0.0.

### How are the layer versions maintained across regions?

The README publishes an ARN per region for both architectures, and the x86_64 versions are mostly 117 while the arm64 ones are at 11, with the two series packaged separately. A Lambda layer version is immutable, so upgrading Chromium means referencing a new version number and redeploying the function.

## Sources

- [Issues](https://github.com/shelfio/chrome-aws-lambda-layer/issues)
- [License: MIT](https://github.com/shelfio/chrome-aws-lambda-layer/blob/master/LICENSE)
- [README](https://github.com/shelfio/chrome-aws-lambda-layer/blob/master/README.md)
- [shelfio/chrome-aws-lambda-layer on GitHub](https://github.com/shelfio/chrome-aws-lambda-layer)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/shelfio-chrome-aws-lambda-layer
