Why Single Function Lambdas is a terrible choice for Serverless development.

Ankit AabadAnkit Aabad
6 min read

LambdaLiths are Better

Single function lambdas for every endpoint is really bad on every possible front, be it developer experience, debugging experience, deployment efficiency, cost or performance.

One common best practice that’s often pushed by serverless advocates is to create a separate Lambda function for every single endpoint. I think that’s a terrible idea. In this post we will examine the arguments from the other side and see why the arguments lack merit, consistency, or real-world practicality.

This push for extreme separation reminds me of Golang. I never really liked the language itself, but I’ve always appreciated one of its core design philosophies: Less is exponentially more. Interestingly, while I don’t think that idea works well in the context of programming language design, it makes a lot of sense when applied to Serverless infrastructure. When building serverless systems, a few cohesive, well-structured Lambdas often result in simpler, more maintainable architectures than a maze of single-function lambdas.

Less is Exponentially More

Architect Around Work, Not Routes

HTTP paths are not architectural boundaries— workloads are. Lambdas should be shaped by what they actually do and the dependencies they need to run efficiently.

For example, you might have a Lambda that powers your entire web server. Another for data crunching using an npm package that ships with a rust binary (node polars) leveraging multiple vCpus. A third might handle image processing with sharp, triggered by S3 uploads. And maybe another is dedicated to web scraping where you bundle a headless browser like Puppeteer as Layer to Lambda.

Each of these functions serves a real, functional purpose. They have unique performance characteristics, dependency trees, and compute or configuration needs. This is what meaningful separation looks like — it’s intentional , based on real boundaries, and grounded in how the system actually works.

But carving out a separate Lambda just because one endpoint is /user/login and the other is /user/logout? That’s not applying the Single Responsibility Principle — that’s butchering it in broad daylight.

And if you’re worried about routing flexibility, API Gateway invokes the most specific match. That means you can serve all your generic routes through a single Lambda while still routing specific paths to their own dedicated function. You get targeted isolation where it actually matters — without blowing up your architecture into a hundred micro-lambdas.

The Myth of Fine-Grained Access Control and Blast Radius

One of the most frequently cited justifications for having a separate Lambda for every endpoint is “fine-grained access control” or reducing the “blast radius.” It sounds reasonable at first — give each function the minimum permissions it needs, so if it’s compromised or misbehaves, the damage is limited. But if you take this logic to its natural conclusion, it quickly becomes absurd.

If this principle were applied consistently, you’d also be creating a separate Docker container for every HTTP endpoint in a traditional service. But nobody does that — because it’s obviously overkill and stupid.

The same goes for databases. Serverless advocates often promote single-table design ( with DynamoDB). But hang on — doesn’t that violate “fine-grained access control”? If a createUser Lambda has PutItem access on the whole table, what’s stopping it from writing into an unrelated orders record? Should we now split the table into one-per-entity to reduce the blast radius even further? because Logic is the same. Where do we stop?

This isn’t architectural discipline — it’s paranoia masquerading as best practice. Security and isolation are important — but so is pragmatism. The goal is to build systems that are secure, maintainable, and efficient  — not to pass a theoretical purity test.

Don’t believe me. Arc codes is a serverless framework that creates a single IAM role and shares it across all functions. check here and in the playground. Serverless framework is another one that uses single IAM role. check here.

Bundle Size & Cold Starts

One common argument against combining endpoints into a single Lambda (a lambdalith) is that it results in a larger bundle size, which supposedly increases cold start latency. But this concern is often overstated and disconnected from real-world usage patterns.

The truth is: most of your endpoints share the same core dependencies. Your db libraries like node-postgres, drizzle or dynamodb toolbox, zod or arktype for validation all remain the same. Moreover the relation between bundle size and cold start is not linear. The typescript ecosystem is amazing and you have great tree shakeable and optimized libraries. You have honojs for web server, you have zero abstraction ORMs like zapatos.

With a Lambdalith , you unlock powerful reuse: secrets from Parameter Store, database connections, and shared libraries are all initialized once and reused across requests. Since one Lambda handles multiple routes, it receives steady traffic and stays warm, reducing cold starts and latency. But there’s more — even if a Lambda stays warm for 5–6 minutes, DynamoDB’s keep-alive is only ~90 seconds. (personal experience not official number) So if a function isn’t hit frequently, you’ll pay a hidden penalty: a warm Lambda but a cold DB connection. That’s a cold start inside a warm start. Split your app into dozens of tiny Lambdas and you multiply this pain.

The Developer Experience, Debugging Experiece and Deployment Efficiency: Lambdaliths Keep You in Flow

When you’re following the “one Lambda per endpoint” pattern, every new endpoint means deploying a new function  — along with its own permissions, logging config, and event source mappings. It’s ceremony without substance. With Lambdalith you can just sam sync instead of sam deploy which is way faster.

And then there’s IAM: ever added PutItem permissions for DynamoDB and realized you now need BatchWriteItem for DynamoDB? Guess what — time to redeploy.

With single function lambdas you get burried under a maze of log groups. With multiple developers and all running their personal stacks this gets amplified. keep searching your logs in the awful AWS UI.

You can btw have a single log group for all your lambdas but no one practices that and it comes with some dope benefits but that is for some other day.

Developer Experience makes you agile not scrum ceremonies or over engineering.

Event Warming and Provisioned Concurrency

When it comes to event warming or provisioned concurrency , Lambdaliths shine. Why? Because you’re keeping one Lambda warm that serves many routes — that’s maximum ROI on your warm instance. A provisioned concurrency of 50 costs $108 per month. If you want to have that for 20 different micro lambdas that is $2160 And many of those might barely get any traffic.

Over-Engineering Is Good Business (For Them)

Not every “best practice” is about what’s best for your app — sometimes, it’s about what’s best for someone’s business model.

Some third-party vendors charge per Lambda function or CloudFormation stack , so the more you split things up, the more they profit. Even AWS with AWS Inspector charge $0.30 per function per month , and with dozens of Lambdas, that adds up fast. More functions also mean more surface area for observability, monitoring, and security tools — all of which feed into paid services.

Even worse, some vendors charge per user , and managing a highly fragmented setup often demands bigger teams. That’s great for them — more seats, more subscriptions — but not for you.

And let’s not forget the gatekeepers who define “proper serverless” in ways that conveniently align with their consulting gigs.

What looks like architectural purity is often just someone else’s revenue stream in disguise.

The “one Lambda per endpoint” mantra may sound clean in theory, but in practice, it creates unnecessary complexity, inflates costs, bloats your infrastructure, and hurts developer experience. Lambdas should be shaped by functional boundaries, not URL patterns. Lambdaliths give you better cold start performance, resource reuse, simpler deployments, saves you on developer cost all without sacrificing maintainability.

10
Subscribe to my newsletter

Read articles from Ankit Aabad directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ankit Aabad
Ankit Aabad