Explain oversized functions with too many responsibilities, large dependency graphs, and tangled business logic. Show why this recreates monolith pain inside serverless.
The function-as-a-monolith anti-pattern happens when one serverless handler accumulates too many responsibilities, too many triggers, and too many dependencies. It may start as a shortcut: one function for orders, one function for account management, one function for “all billing work.” Over time, that handler grows into a mini-application hidden inside a single deployment unit.
This recreates monolith pain inside a serverless shape. The code becomes hard to reason about, cold starts get worse, permissions grow broad, and every small change carries risk because unrelated paths are bundled together. The result is not really serverless simplicity. It is a monolith wearing a function name.
flowchart LR
A["API request"] --> B["Large all-purpose function"]
C["Queue event"] --> B
D["Storage event"] --> B
B --> E["Database"]
B --> F["Billing API"]
B --> G["Email service"]
B --> H["Object storage"]
What to notice:
This anti-pattern usually appears because:
That logic is understandable in the short term. The problem is that the cost compounds invisibly until the function becomes the hardest thing in the system to change safely.
The warning signs are usually obvious in hindsight:
1export async function handler(event: any) {
2 if (event.httpPath?.startsWith("/orders")) {
3 return handleOrders(event);
4 }
5
6 if (event.queueName === "billing-jobs") {
7 return processBilling(event);
8 }
9
10 if (event.objectKey?.startsWith("uploads/")) {
11 return processUpload(event);
12 }
13
14 if (event.type === "send-email") {
15 return sendNotification(event);
16 }
17
18 throw new Error("Unsupported event");
19}
What this demonstrates:
A better design does not split functions mechanically into tiny pieces. It separates them by real responsibility and permission shape. That often means:
The goal is not maximum fragmentation. It is bounded ownership.
A team has one function that handles order creation, payment callbacks, export jobs, and customer notifications because “it all touches orders anyway.” Deployments now feel risky and cold starts are getting worse. What should the design review challenge first?
The stronger answer is the function boundary. The issue is not only code size. It is that unrelated triggers, permissions, and dependencies are being deployed and authorized together. The review should identify distinct responsibilities and separate them into bounded handlers with narrower identity and dependency scope.