serverlessfinopssaascost-optimization

Serverless cost per tenant: attributing a shared function bill

Serverless pricing is per request, which makes per-tenant attribution possible in a way shared servers never allow. Doing it well requires instrumenting the right dimensions. Here is the method.

The C3X Team··7 min read

Quick answer

Serverless bills per invocation and per GB-second, so tenant cost is computable if you record invocations, billed duration, and memory per tenant. A 512 MB function at 200 ms costs $0.0000017 in duration plus $0.0000002 in requests, so $1.90 per million requests. Add the storage and messaging each tenant touches and you get a real unit cost. The practical method is to emit a structured log line per invocation carrying the tenant id and billed duration, aggregate it, and multiply by published rates. Shared infrastructure that does not vary with tenants, such as a NAT gateway at $32.85 a month or an always-on database, is allocated separately as fixed overhead.

Knowing what a customer costs you is the foundation of pricing, margin analysis, and deciding which tenants to invest in. On shared servers this is close to impossible: an instance costs the same whether one tenant or a hundred use it. Serverless changes that. Because almost everything is billed per request or per gigabyte, a well-instrumented serverless application can attribute most of its bill to individual tenants with real precision.

What is attributable and what is not

CostAttributable?Basis
Lambda invocations and durationYesPer-request tenant id
DynamoDB on-demandYesConsumed capacity per request
API Gateway requestsYesPer-request tenant id
S3 storage and requestsYesPer-prefix or per-bucket
Data transfer outMostlyResponse bytes per request
NAT gateway, VPC endpointsNoFixed, allocate as overhead
Provisioned concurrencyNoCapacity, not usage
Always-on database instanceNoFixed, allocate by usage share

The split matters because the fixed portion sets your minimum cost per tenant. If shared infrastructure costs $400 a month and you have 20 tenants, each carries $20 before doing anything. At 200 tenants that same overhead is $2 each, which is why per-tenant economics improve dramatically with tenant count in a well-designed serverless system.

Instrumenting the variable portion

The mechanism is simple: emit one structured log line per invocation containing the tenant id, the function name, the memory size, and the billed duration. Lambda already reports billed duration in the REPORT line, and you can capture it in the runtime or parse it downstream. Aggregate by tenant, then multiply.

Cost per invocation equals memory in GB times billed seconds times $0.0000166667, plus $0.0000002 for the request. For a 512 MB function at 200 ms, that is $0.00000167 plus $0.0000002, so $0.00000187, or $1.87 per million requests. Multiply each tenant's aggregated GB-seconds and invocation count by the published rates and you have their compute cost to several decimal places.

TenantInvocationsGB-secondsCompute cost
Enterprise A4,200,0001,050,000$18.34
Growth B820,000131,000$2.35
Starter C41,0004,900$0.09
Trial D1,200190$0.003

Adding the data layer

DynamoDB returns consumed capacity on every request if you ask for it, which makes per-tenant data cost exact: multiply consumed write units by $1.25 per million and read units by $0.25 per million. S3 is easier still when tenants map to prefixes, since S3 Storage Lens and inventory reports break down storage by prefix. Egress is derived from response content length, which most frameworks already log.

The log lines themselves cost money. At $0.50 per GB ingested, a 400 byte attribution record per invocation on 100 million invocations is 40 GB, which is $20 a month. That is reasonable for the visibility, but push it to a cheap store rather than keeping long CloudWatch retention: the standard pattern is to send attribution records to S3 and query with Athena at $5 per TB scanned, which keeps ongoing cost near zero.

Silo versus pool changes everything

Tenant isolation model determines how much of the bill is fixed. A pooled architecture, where all tenants share functions, tables, and queues, keeps nearly everything variable and attributable. A silo model, where each tenant gets its own stack, converts the same workload into per-tenant fixed cost: a dedicated database at $47 a month, a NAT gateway at $32.85, and a load balancer at $16.43 is $96 per tenant before any usage, which makes small tenants structurally unprofitable. Bridge models are common, pooling compute and messaging while siloing only the data store, and they are worth pricing explicitly because the isolation decision is usually made for compliance reasons without anyone computing what it does to the floor.

What the numbers reveal

Three findings recur once teams have this data. First, cost per tenant is wildly unequal, often following a power law where the top 5 percent of tenants generate half the infrastructure cost. Second, some tenants on flat-rate plans cost more than they pay, typically because of a pattern such as aggressive polling or oversized exports. Third, the fixed overhead per tenant is usually larger than anyone guessed, which changes the economics of free tiers.

Acting on that is the point. Price plans against measured unit cost. Rate-limit the patterns that create outliers. Move expensive tenants to usage-based terms. And when a new feature is designed, estimate its per-tenant cost the way you would estimate any otherunit economics question. Price the underlying resources against the resource catalog so the cost per request is known before the feature ships.

FAQ

Can you calculate serverless cost per tenant accurately?

Yes, for the variable portion. Lambda bills per invocation and per GB-second, DynamoDB returns consumed capacity per request, and API Gateway bills per request, so recording the tenant id alongside billed duration and consumed capacity lets you multiply by published rates. Fixed costs such as NAT gateways and always-on databases are allocated separately as overhead.

What does one serverless request cost?

For a 512 MB function running 200 ms, duration costs 0.5 GB times 0.2 seconds times $0.0000166667, which is $0.00000167, plus $0.0000002 for the request itself. That totals about $1.87 per million requests. Adding an HTTP API at $1.00 per million and a couple of DynamoDB operations typically brings a full request to $3 to $5 per million.

How do I instrument tenant cost attribution?

Emit one structured log line per invocation containing the tenant id, function name, memory size, and billed duration, which Lambda reports in its REPORT line. Add consumed DynamoDB capacity, which the API returns on request, and response byte counts for egress. Aggregate by tenant and multiply by the published rates for each service.

What serverless costs cannot be attributed to a tenant?

Fixed infrastructure that does not vary with usage: NAT gateways at about $32.85 a month each, VPC endpoints, provisioned concurrency, and always-on database instances. These set a minimum cost per tenant, so a $400 monthly overhead is $20 per tenant at 20 tenants but only $2 at 200, which is why per-tenant economics improve with scale.

Does cost attribution logging get expensive?

It can. At $0.50 per GB of CloudWatch Logs ingestion, a 400 byte attribution record per invocation across 100 million invocations is 40 GB, about $20 a month. The common pattern is to route attribution records to S3 instead and query them with Athena at $5 per TB scanned, which keeps ongoing cost near zero.

How does C3X help with per-tenant cost?

C3X prices the resources behind a feature from Terraform, which gives you the per-request cost inputs that attribution multiplies. Knowing what a function, table, and API stage cost per unit before deployment lets you model the per-tenant cost of a new feature at design time rather than reconstructing it from logs afterwards.

What to do next

Know your cost per request before you price per tenant. C3X reads your Terraform and prices your resources against a live catalog. Start with the quickstart.

Try C3X on your own Terraform

Free and open source. No API key required. One command to install, one command to estimate.