Lambda functions with almost no invocations
What does ZopNight detect here?
A Lambda function invoked fewer than once a day over 30 days is effectively unused. Lambda bills per invocation, so the function itself costs nothing. Provisioned concurrency does, and that is usually where the recoverable cost sits on an idle function.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-010 |
| Category | idle |
| Severity | medium |
| Metric | none — pure configuration read |
| Source | idle_lambda.go |
Where it applies
Lambda is free when idle, with one exception
Lambda charges per request and per GB-second of execution. A function nobody calls generates neither, so an idle function is genuinely free to keep.
The exception is provisioned concurrency. That reserves warm execution environments and bills hourly whether or not anything invokes the function, the same shape of cost as an idle NAT Gateway. An idle function with provisioned concurrency configured is paying for readiness nobody uses, and that is the real finding here.
The threshold
Below one invocation per day, averaged over 30 days of the Invocations count Lambda reports to CloudWatch. That is deliberately not zero: a function invoked by a weekly job or a rarely-hit error path is used, just infrequently, and a hard zero-test would leave it out while catching nothing extra.
What else it usually points at
An unused function often comes with things that are not free:
- Provisioned concurrency, as above
- An EventBridge rule or SQS trigger still active and pointed at it
- A CloudWatch log group with no retention policy, keeping every log line since creation
- An IAM execution role with whatever permissions the function once needed
The log group is the one that quietly accumulates. Functions get deleted; their log groups usually do not.
Summing Invocations for the function
aws cloudwatch get-metric-statistics \ --namespace AWS/Lambda --metric-name Invocations \ --dimensions Name=FunctionName,Value=my-function \ --start-time "$(date -u -v-30d +%Y-%m-%dT%H:%M:%SZ)" \ --end-time "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ --period 86400 --statistics SumBefore deleting
Archive the code to S3 first. aws lambda get-function returns a download URL for the
deployment package. Then remove provisioned concurrency, detach the triggers, and delete the
function, its log group and its role.