When Middy Isn't Enough - Building Custom Lambda Middleware Frameworks
Discover the production challenges that pushed us beyond Middy's limits and how we built a custom middleware framework optimized for performance and scale
When Middy Isn't Enough - Building Custom Lambda Middleware Frameworks
Middy covers the typical middleware needs of a small Lambda fleet, but the tradeoffs of its generic middleware-chain model become measurable once a service hits about 50 functions sharing a common middleware stack: per-invocation overhead, cold-start cost of the middleware chain, and the coupling that a shared wrapper creates between otherwise unrelated functions. At that scale the question becomes whether to continue layering on top of Middy's abstractions, replace them with AWS Lambda PowerTools, or build a project-specific middleware framework that only pays for the hooks the fleet actually uses.
This is the second part of the Middy series. It covers the scaling limits of Middy's default model, the cold-start and cost accounting, a project-specific middleware framework design with only the hooks a typical serverless backend needs, and the migration path from a Middy-wrapped Lambda to a custom-middleware-wrapped one without breaking the contract.
Production Challenges
The Multi-Tenant Validation Challenge
Our fintech platform served multiple clients, each with completely different validation rules. Customer A required UK postal codes, Customer B needed German VAT validation, and Customer C had entirely custom business rules.
Middy's static middleware approach hit a wall:
We needed dynamic schema generation at runtime, but Middy configures middleware at initialization time. The workaround? Nasty conditional logic scattered throughout our handlers, defeating the entire purpose of clean middleware separation.
Technical Impact: Additional development time and a custom validation layer that increased maintenance overhead.
The Bundle Size Challenge
As our middleware stack grew to 8 different Middy packages, performance monitoring revealed concerning metrics:
Performance Metrics:
- Bundle size: 2MB (up from 400KB)
- Cold start time: 1.2 seconds (target: <500ms)
- Memory usage: 128MB baseline
- First response time: 1.8 seconds
For financial APIs handling frequent transactions, this performance degradation creates user experience issues. The elegant middleware abstraction came at a significant cost to responsiveness.
The Team Consistency Challenge
Across multiple developers working on different services, middleware usage patterns became inconsistent:
Result: Production incidents, debugging complexity, and error handling that worked differently across services. We needed enforcement, not just conventions.
Designing a Custom Middleware Framework
These challenges led us to rethink middleware architecture entirely. Our custom framework addressed three core principles:
1. Performance-First Architecture
We built a lightweight context system and pre-compiled middleware chains for maximum speed:
Key optimization: We pre-compile the middleware chain instead of building it on every request. This single change cut our middleware overhead by 40%.
2. Dynamic Configuration Support
For our multi-tenant validation problem, we built dynamic middleware that resolves configuration at runtime:
This solved our multi-tenant validation while maintaining performance through intelligent caching.
3. Team Convention Enforcement
Instead of hoping developers follow conventions, we built enforcement into the framework:
Now teams couldn't accidentally skip critical middleware or change the ordering. The framework enforced standards.
Performance Benchmarking - The Numbers
We ran comprehensive benchmarks comparing Middy with our custom framework using identical functionality:
Test Scenario:
- Simple HTTP API with auth, validation, error handling
- 1000 cold starts, 10,000 warm requests
- Node.js 18 runtime, 1024MB memory
- Tests run on identical AWS Lambda configurations
- Average values across multiple test runs with consistent conditions
Results:
The benchmark results showed meaningful performance improvements across all measured metrics with our custom framework.
Code Comparison
Middy Approach:
Custom Framework:
Similar API, drastically different performance characteristics.
Real-World Custom Middleware Examples
Here are some production middleware patterns that leverage dynamic behavior unavailable in Middy:
1. Circuit Breaker with Exponential Backoff
This middleware automatically protects downstream services from cascading failures - something that requires significant workarounds in Middy's static configuration model.
2. Smart Caching with Invalidation
This middleware can short-circuit the entire request pipeline when cache hits - a significant performance advantage over Middy's linear middleware execution model.
Migration Strategy - From Middy to Custom
Moving from Middy to our custom framework in production required a careful, phased approach:
Phase 1: Hybrid Approach
Phase 2: Feature Parity
Phase 3: Performance Optimization
Once all middleware were ported, we optimized for our specific use cases, achieving the 67% performance improvement shown earlier.
Phase 4: Team Training & Standards
The final phase involved training the team and establishing new development standards around our custom framework.
When to Choose Custom vs Middy
Based on our experience, here's the decision matrix:
Choose Middy When:
- Team is new to middleware patterns
- Standard use cases (HTTP APIs, basic validation)
- Fast development is the priority
- Bundle size < 1MB is acceptable
- Cold start < 1s is acceptable
- Limited development resources for custom solutions
Choose Custom Framework When:
- Performance is critical (< 500ms cold start required)
- Complex business rules requiring dynamic behavior
- Team has middleware expertise
- Specific compliance/security requirements
- Large-scale applications (50+ functions)
- Need for team standardization and enforcement
Hybrid Approach When:
- Migration phase between solutions
- Different performance requirements per function
- Learning custom patterns while maintaining productivity
Production Lessons Learned
1. Performance vs Developer Experience
Custom frameworks can deliver significant performance improvements but require additional development time. Evaluate this trade-off based on your requirements and team capabilities.
2. Team Adoption is Critical
The best framework is worthless if your team can't adopt it. Change management and training are as important as the technical solution.
3. Maintenance Overhead is Real
Custom solutions mean custom maintenance. Middy's community support has real value - factor this into your decision.
4. Gradual Migration is Safer
Incremental migrations reduce risk. The gradual, phased approach proved much safer and allowed us to validate our approach step by step.
Testing Custom Middleware
Testing our custom framework required a different approach:
Production Checklist
Before taking a custom middleware framework to production:
- Performance benchmarks documented and validated
- Error handling comprehensive across all scenarios
- Monitoring and alerting integrated
- Team training completed with hands-on exercises
- Documentation up-to-date and accessible
- Rollback plan tested and ready
- A/B testing capability implemented
- Security review passed with penetration testing
- Load testing completed under realistic conditions
The Bottom Line
Middy is an excellent starting point for most Lambda applications. But when you're operating at scale, dealing with complex business requirements, or facing strict performance constraints, a custom middleware framework can be transformative.
Key Takeaways:
- Start with Middy - It's proven, production-ready, and great for learning middleware patterns
- Measure before optimizing - Let performance data drive your decisions, not assumptions
- Team consistency matters more than framework choice - Standards and enforcement are critical
- Custom isn't always better - Factor in maintenance costs and team expertise
- Migration requires careful planning - Gradual approaches reduce risk and allow validation
The journey from Middy to a custom framework demonstrates that sometimes the best solution is the one you build yourself - but only when you have compelling technical reasons and the team expertise to execute it well.
The middleware patterns we learned from Middy became the foundation for something even better suited to our specific needs. Whether you stick with Middy or build your own, the principles of clean middleware design will serve you well in your serverless journey.
References
- docs.aws.amazon.com - AWS Lambda best practices.
- web.dev - web.dev performance guidance (Core Web Vitals).
- docs.aws.amazon.com - AWS Lambda Developer Guide.
- serverless.com - Serverless learning resources (patterns and operations).
- nodejs.org - Node.js official documentation.
- typescriptlang.org - TypeScript Handbook and language reference.
- github.com - TypeScript project wiki (FAQ and design notes).
- developer.mozilla.org - MDN Web Docs (web platform reference).
- semver.org - Semantic Versioning specification.
AWS Lambda Middleware Mastery
From Middy basics to building custom middleware frameworks for production-scale Lambda applications