Description
This is a performance follow-up to #634. That issue fixed correctness for Cargo-workspace projects (binaries are now found), but the underlying build strategy still compiles each function in isolation, so shared dependencies are recompiled once per function.
For a workspace with N Rust functions that share heavy dependencies (e.g. the AWS SDK), sam build compiles the shared dependency tree N times. In a real project with 16 functions sharing the AWS SDK, this makes sam build take over an hour.
Root cause
In cargo_lambda.py (v1.65.0):
if not os.getenv("CARGO_TARGET_DIR"):
# This results in the "target" dir being created under the member dir of a cargo workspace
os.environ["CARGO_TARGET_DIR"] = "target"
CARGO_TARGET_DIR is set to the relative path target, and the build runs with cwd=self._source_dir (each function's own member directory — actions.py#L97). So each function gets an isolated <member>/target/, and cargo cannot reuse any compiled dependency across functions. The dependency graph is rebuilt from scratch for every function.
Expected behavior
For a workspace, compile once and package many. A single cargo lambda build --release [--arm64] at the workspace root builds every member binary in one pass, compiling shared deps only once.
Local measurement on the same 16-function workspace:
- Current (per-function): > 1 hour
- Single workspace build: ~10m cold, ~2m19s warm
Possible fix
The builder already supports selecting a single binary — build_command appends --bin <handler> (actions.py#L90). A workspace-aware path could:
- Detect the Cargo workspace root and run one
cargo lambda build there (shared target/, deps compiled once).
- Resolve each function's binary from the shared
target/lambda/<name>/ output by package/bin name, and copy it into that function's ARTIFACTS_DIR — instead of shelling out per CodeUri.
This keeps BuildMethod: rust-cargolambda transparent to users: no per-function Makefiles and no manual binary distribution. (cargo-lambda-cdk already handles the workspace case, as noted in #634.)
Current workaround
Switch each function to BuildMethod: makefile and drive a single workspace cargo lambda build yourself, distributing each bootstrap into its function dir before sam build packages it. Works, but pushes SAM's build responsibility into user-maintained Makefiles.
Description
This is a performance follow-up to #634. That issue fixed correctness for Cargo-workspace projects (binaries are now found), but the underlying build strategy still compiles each function in isolation, so shared dependencies are recompiled once per function.
For a workspace with N Rust functions that share heavy dependencies (e.g. the AWS SDK),
sam buildcompiles the shared dependency tree N times. In a real project with 16 functions sharing the AWS SDK, this makessam buildtake over an hour.Root cause
In
cargo_lambda.py(v1.65.0):CARGO_TARGET_DIRis set to the relative pathtarget, and the build runs withcwd=self._source_dir(each function's own member directory —actions.py#L97). So each function gets an isolated<member>/target/, and cargo cannot reuse any compiled dependency across functions. The dependency graph is rebuilt from scratch for every function.Expected behavior
For a workspace, compile once and package many. A single
cargo lambda build --release [--arm64]at the workspace root builds every member binary in one pass, compiling shared deps only once.Local measurement on the same 16-function workspace:
Possible fix
The builder already supports selecting a single binary —
build_commandappends--bin <handler>(actions.py#L90). A workspace-aware path could:cargo lambda buildthere (sharedtarget/, deps compiled once).target/lambda/<name>/output by package/bin name, and copy it into that function'sARTIFACTS_DIR— instead of shelling out perCodeUri.This keeps
BuildMethod: rust-cargolambdatransparent to users: no per-functionMakefiles and no manual binary distribution. (cargo-lambda-cdkalready handles the workspace case, as noted in #634.)Current workaround
Switch each function to
BuildMethod: makefileand drive a single workspacecargo lambda buildyourself, distributing eachbootstrapinto its function dir beforesam buildpackages it. Works, but pushes SAM's build responsibility into user-maintained Makefiles.