ECR Container Lambdas
Deploy Lambda functions as Docker container images instead of ZIP bundles — useful for binaries, large dependencies, or custom runtimes.
Define a Container Lambda
Use defineLambda with packageType: 'container' in a standalone Lambda:
// src/lambdas/standalone/DownloadMedia/index.ts
import { defineLambda } from "@j0nathan-ll0yd/core";
defineLambda({
packageType: "container",
dockerfile: "Dockerfile.download", // relative to project root
architecture: "x86_64", // or 'arm64' (default)
memorySize: 2048,
timeout: 900,
dockerBuildArgs: {
YTDLP_VERSION: "2026.03.25",
DENO_VERSION: "2.2.0",
},
dockerTarget: "production", // multi-stage target (optional)
});
export const handler = async (event: unknown) => {
// handler logic
return { statusCode: 200 };
};Write a Dockerfile
The build step runs esbuild first, then calls docker build. Your Dockerfile receives the compiled index.mjs in the build output directory:
FROM public.ecr.aws/lambda/nodejs:22
# Install runtime dependencies
RUN dnf install -y yt-dlp
# Copy compiled handler
COPY build/lambdas/DownloadMedia/index.mjs ${LAMBDA_TASK_ROOT}/
CMD ["index.handler"]Build
mantle buildmantle build detects container Lambdas and requires Docker to be running. It:
- Runs esbuild (same as ZIP — produces
index.mjs) - Computes a content hash of the Dockerfile + build output
- Runs
docker build --platform linux/amd64|arm64 -t <name>:<hash> - Writes a
.image-tagfile tobuild/lambdas/<Name>/
Deploy
mantle deploy --stage stagingmantle deploy automatically authenticates with ECR, tags the image, and pushes before running OpenTofu:
aws ecr get-login-password | docker login ...
docker tag downloadmedia:<hash> <account>.dkr.ecr.<region>.amazonaws.com/<prefix>/download-media:<hash>
docker push ...
tofu apply -var image_uri_download_media=<full-uri> ...Generated Infrastructure
mantle generate infra produces a .tf file per container Lambda with:
aws_ecr_repository— IMMUTABLE tags, scan-on-push enabledaws_ecr_lifecycle_policy— retains last N images (default: 5)- Lambda module block with
package_type = "Image"andimage_urifrom a Terraform variable
resource "aws_ecr_repository" "download_media" {
name = "${module.core.name_prefix}/download-media"
image_tag_mutability = "IMMUTABLE"
force_delete = true
image_scanning_configuration {
scan_on_push = true
}
tags = module.core.common_tags
}Optional: Registry Configuration
// mantle.config.ts
export default defineConfig({
name: "my-api",
containerRegistry: {
imageRetentionCount: 10, // default: 5
},
});imageRetentionCount is the only key. Image tags are always the build-context content hash, which is what makes redeploying unchanged bytes a no-op against an IMMUTABLE-tagged repository. tagStrategy, repositoryPrefix, and platforms were declared in MantleConfig and read nowhere in the CLI; they were removed rather than left advertising capabilities that did not exist. To record the commit an artifact came from, use Deployment Provenance, which binds the source revision without giving up content-addressed tags.
Constraints
- Container Lambdas cannot use
layers— layers are ZIP-only (warning emitted at build time) - Container Lambdas cannot use
edge: true— Lambda@Edge does not support container images (build fails) dockerfilepath is relative to the project root, not the Lambda directory