It is rarely a good idea. Installing packages into /tmp when a Lambda starts avoids package size limits, but it adds latency, needs outbound network access, and runs code that your build and scan never saw. Bundle dependencies at build time, or use a container image for large ones.
Why teams do it
The pattern appears when a dependency is too big for the zip. AWS lists 250 MB unzipped for a .zip package including layers, and the writable /tmp directory offers between 512 MB and 10,240 MB. The temptation is to run pip or npm during the init phase and keep the files in /tmp.
It works in a demo. The trouble shows up later.
What goes wrong
| Problem | Why it matters |
|---|---|
| Unreviewed code | The version installed at run time may differ from what you scanned at build time |
| Network dependency | The function needs a package index reachable on every cold start |
| Latency | AWS says initialization code outside the handler runs during the Init phase, and that phase has a 10 second limit for standard functions |
| Repeatability | Two cold starts a day apart can install different transitive versions |
| Inventory gap | An SBOM from the build does not list what was installed at run time |
AWS documents that the Init phase runs your static code outside the handler and is limited to 10 seconds. If it does not finish, Lambda retries at the first invocation using the function timeout. A big install in that window is a gamble.
There is also a permission angle. A function that can reach a package index and execute downloaded code has a wider network and trust footprint than one that does not.
Better options
- Bundle at build time. Install from a lockfile in CI, scan the result and ship the zip.
- Use a container image for big dependencies. AWS documents a 10 GB uncompressed limit for container image code packages. Read zip or container, which is easier to keep patched.
- Trim first. Many oversized packages shrink a lot once dev dependencies and unused files are removed. See what to trim.
- Fetch data, not code. Large models or datasets can live in object storage and be read at run time. Treat them as data inputs with integrity checks.
If you must download something at run time
Sometimes data or a binary has to be fetched. If so:
- Pin an exact version and verify a checksum that you store with the code, not next to the download.
- Fetch from a location you control.
- Log the version and checksum on every cold start.
- Add it to the inventory by hand, since scanners will not see it.
How to find the pattern in your estate
Search your handler repos for pip install, npm install and subprocess calls near start-up code, plus writes to /tmp followed by a path change. A quick grep catches most cases. Review each hit with its owner.
Try it yourself
The gate pull request demo shows how a build step can block a change that adds an unreviewed dependency. That is the control that run-time installs bypass.
Click through it at your own pace, or open it full screen.
Where Safeguard fits
Safeguard's policies and gates can block a pull request that adds a dependency with known problems, and its dependency scanning covers what is declared in the repo. It cannot see packages fetched at run time, which is one more reason to avoid the pattern. Free scan: gold.safeguard.sh/scan.
Quick check
Is /tmp big enough to hold installed packages?
AWS documents /tmp storage from 512 MB to 10,240 MB. Size is rarely the problem, the unreviewed code and latency are.
Will a scanner see packages installed at run time?
Not one that reads the repo or build output. Those packages are missing from the build SBOM.
Sources
- Lambda quotas, AWS documentation
- Understanding the Lambda execution environment lifecycle, AWS documentation
Last reviewed: 19 October 2026.