
From Monolith to Microservices (and Back): Scaling an AI-Powered SaaS on AWS
How Onvocado evolved from a solo-built product into a platform that can handle hundreds of thousands of real-time interactions.
- Published on October 17, 2025
Phase 1: The Monolith Approach (Speed Over Scale)
When Onvocado began, the entire system existed as a single codebase. This architectural choice wasn't arbitrary. For early-stage products, a monolithic structure provides significant advantages.
A monolith meant tight feedback loops. Code changes deployed in (quarters of) hours, not days. Debugging was straightforward because the entire context lived in one place. Dependencies were explicit, and the blast radius of changes was immediately visible. For a solo founder iterating on product-market fit, this mattered enormously.
The business case was equally compelling. Early users needed to validate whether the core value proposition worked. Infrastructure complexity would only distract from that validation. A monolith required minimal operational overhead compared to managing distributed systems, allowing more resources to flow toward product development.
This approach proved effective. We shipped features rapidly, gathered user feedback, and refined the product without the organizational burden of managing multiple services and deployment pipelines.
Phase 2: Recognizing the Bottleneck
As adoption increased, the monolith's limitations surfaced. The codebase grew heavier. Deployment became riskier as changes touched interconnected systems. Performance degradation appeared in specific high-traffic endpoints. Most critically, a single bug could cascade through the entire system, affecting all customers simultaneously.
Our development methodology evolved alongside these constraints. Early Extreme Programming practices gave way to more formal Scrum processes. We transitioned from running an experimental project to operating a production SaaS system with paying customers who expected reliability. The margin for error shrank dramatically.
The operational reality became clear: a monolith that once supported rapid iteration was now constraining both performance and team velocity.
Phase 3: The Triggering Event - IP-Based Widgets
The architectural reckoning arrived through a specific feature request: IP-based widgets. A customer wanted campaign widgets to display or hide based on visitor geolocation. Conceptually straightforward. Architecturally, it was the stress test that exposed our limits.
The core of Onvocado's system relies on a lightweight pixel (a small JavaScript snippet) that customers embed on their websites. When a visitor loads the page, the pixel makes a backend request to check for active campaigns. If a campaign exists, the backend returns campaign data, and a Shadow DOM custom element renders the widget on the page without disrupting the host page's DOM structure.
This architecture had scaled well initially. But with IP-based logic layered on top, we faced a new reality: hundreds of thousands of pixel calls per day, all routing through a single monolithic backend. Latency became critical. Every millisecond of added processing time multiplied across this traffic volume. Widget rendering delays became perceptible to end users. Performance degradation directly impacted the customer experience.
At this inflection point, moving to microservices transitioned from "future consideration" to "immediate necessity."
Phase 4: Microservices - Decoupling for Performance
Third, we discovered an operational efficiency that warranted highlighting. Amazon CloudFront, AWS's content delivery network, can enrich requests with geolocation headers based on visitor location. This meant we didn't need to purchase a separate geolocation API or maintain that infrastructure. CloudFront solved the problem for the cost of a single dollar distribution. Sometimes the most elegant solutions are already embedded in the infrastructure you're paying for.
The result was measurable: latency dropped significantly, and the system could handle traffic increases without proportional performance degradation. The separation of concerns wasn't just architectural elegance. It directly enabled handling higher throughput while maintaining the responsiveness customers expected.
Phase 5: An Unexpected Return - Embracing AI Agents
After investing considerable effort in service decoupling, we recently moved certain services back into a monolithic structure. This might appear contradictory, but it reflects a pragmatic response to a new constraint: leveraging AI-assisted development.
As coding assistants matured, we recognized an opportunity to amplify our development team without proportional headcount growth. However, these AI agents work most effectively with complete context. They perform better when they can understand the full system architecture, trace dependencies, and propose improvements across the entire codebase.
Managing AI agents across fragmented microservices forced them to context-switch repeatedly. They couldn't develop a coherent mental model of the system. Each service operated as an isolated island of information.
By consolidating certain services back into a monolith, we created an environment where AI agents could maintain broader context. The tradeoff was deliberate: we sacrificed some of the isolation benefits of microservices to unlock the potential of AI-assisted development.
The key insight was that this tradeoff didn't require abandoning microservices entirely. We kept the performance-critical services decoupled (especially the pixel traffic infrastructure). We consolidated areas where AI collaboration yielded the highest value.
The Current Architecture: Hybrid and Pragmatic
Today, Onvocado operates as a hybrid system. High-traffic, latency-sensitive services remain decoupled and independently scalable. Core business logic lives in a monolith optimized for AI collaboration. Database services are segregated based on access patterns and scaling requirements. This architecture isn't theoretically pure, but it serves our actual constraints: handling hundreds of thousands of real-time interactions while maintaining developer productivity through AI assistance.
Key Lessons in Architectural Evolution
Several principles emerged from this journey that may apply beyond Onvocado's specific context.
Architecture should respond to real constraints, not trends. Each transition happened because we hit specific, measurable limitations. We didn't split into microservices because they were fashionable. We did it because the monolith was dropping packets under load.
Early-stage simplicity enables faster learning. Starting with a monolith allowed us to validate the business model before investing in distributed systems complexity. The organizational overhead of managing microservices would have slowed that critical early phase.
Each architectural pattern has tradeoffs. Monoliths offer simplicity but limited scalability. Microservices enable scale but increase operational complexity. Hybrid systems offer flexibility but require careful management. No single approach is universally optimal.
Emerging technologies can reveal new constraints. The rise of practical AI agents created a new optimization target: providing comprehensive context to collaborative tools. This was not just about setting up a structured approach for working with AI on development projects (great overview on a structured approach can be found here). It was also about creating an environment where the agent could understand the full context and suggest meaningful improvements.
This shaped our recent architectural decisions as meaningfully as traffic volume shaped earlier transitions.
Conclusion
The path from monolith to microservices to hybrid system wasn't planned at inception. Each transition addressed real, specific problems that emerged as the product matured. This responsive approach to architecture, rather than adhering to a predetermined design, has allowed Onvocado to grow while maintaining both performance and developer productivity.
The broader lesson is that architecture should be viewed as a tool that evolves with your actual constraints, not as a destination to be reached. The right system today may be suboptimal tomorrow. The ability to recognize when architectural patterns have outlived their usefulness and adapt accordingly may be more valuable than any single architectural decision.