<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Akshay Sarak</title>
    <description>The latest articles on DEV Community by Akshay Sarak (@akshay_sarak).</description>
    <link>https://dev.to/akshay_sarak</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3984009%2Fc5271c18-3bd9-4bf9-9d8e-813e5a7972f4.jpeg</url>
      <title>DEV Community: Akshay Sarak</title>
      <link>https://dev.to/akshay_sarak</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/akshay_sarak"/>
    <language>en</language>
    <item>
      <title>📦 Container Queries Changed Everything for Me</title>
      <dc:creator>Akshay Sarak</dc:creator>
      <pubDate>Sun, 14 Jun 2026 17:08:58 +0000</pubDate>
      <link>https://dev.to/akshay_sarak/container-queries-changed-everything-for-me-5bef</link>
      <guid>https://dev.to/akshay_sarak/container-queries-changed-everything-for-me-5bef</guid>
      <description>&lt;p&gt;For a long time, I believed responsive design meant writing media queries for different screen sizes. It felt like the only correct way to make interfaces adapt. So, like most developers early on, I built layouts around viewport breakpoints: mobile, tablet, desktop — each carefully tuned to match screen width.&lt;/p&gt;

&lt;p&gt;It felt organised at first. However, over time, that sense of control gradually started breaking down.&lt;/p&gt;

&lt;p&gt;💥 The Problem Begins Quietly&lt;/p&gt;

&lt;p&gt;Initially, everything seemed smooth. Layouts responded correctly, components adjusted based on screen size, and most UI elements behaved as expected. There was a strong sense of predictability when designing for fixed breakpoints.&lt;/p&gt;

&lt;p&gt;But problems didn’t appear immediately. They started quietly. A component that looked perfect on a page would break when reused inside a sidebar. The same card that worked in a grid layout would collapse inside a modal. Small layout inconsistencies started appearing in different parts of the application.&lt;/p&gt;

&lt;p&gt;What once felt like a reliable responsive system slowly transformed into a collection of components that behaved differently depending on where they were placed.&lt;/p&gt;

&lt;p&gt;🧠 The Real Issue Was Never Responsiveness&lt;/p&gt;

&lt;p&gt;Initially, I thought responsive design meant adapting everything to screen sizes. That made sense when pages were the primary unit of design.&lt;/p&gt;

&lt;p&gt;However, the real problem was that I wasn’t designing for components; I was designing for screens.&lt;/p&gt;

&lt;p&gt;In real applications, components are reused across different contexts. A component doesn’t care about the full viewport — it only cares about the space available to it inside its parent container.&lt;/p&gt;

&lt;p&gt;When this distinction is ignored, responsiveness becomes inconsistent and fragile.&lt;/p&gt;

&lt;p&gt;⚙️ The Shift: Container-Based Thinking&lt;/p&gt;

&lt;p&gt;Switching from media queries to container queries didn’t feel like a small CSS upgrade at first. It felt like a shift in how I think about UI structure.&lt;/p&gt;

&lt;p&gt;Rather than designing components based on global breakpoints, each component started responding to its own container. A layout no longer depended on screen size assumptions. Instead, it adapted based on actual available space.&lt;/p&gt;

&lt;p&gt;This structure changes your perspective on design. Instead of managing global responsiveness rules, you start building components that are self-aware of their environment.&lt;/p&gt;

&lt;p&gt;⚡ Container Queries’ Arrival&lt;/p&gt;

&lt;p&gt;Media queries alone are not sufficient for modern component-based systems. As applications grow, relying only on viewport-based logic introduces too many constraints.&lt;/p&gt;

&lt;p&gt;Container queries changed this.&lt;/p&gt;

&lt;p&gt;The first major improvement is local responsiveness. Components adapt based on their parent container instead of the global viewport.&lt;/p&gt;

&lt;p&gt;The second improvement is true reusability. The same component can behave differently in a grid, sidebar, modal, or full-page layout without requiring separate styles.&lt;/p&gt;

&lt;p&gt;The third improvement is reduced dependency on breakpoints. Layout decisions move closer to the component itself instead of being scattered across global CSS rules.&lt;/p&gt;

&lt;p&gt;This transforms responsive design from being page-driven to being component-driven.&lt;/p&gt;

&lt;p&gt;🧠 The Mental Shift&lt;/p&gt;

&lt;p&gt;The most significant change isn’t technical, but conceptual.&lt;/p&gt;

&lt;p&gt;Initially, the mindset was to design for devices, assuming that screen size is the primary factor in layout decisions.&lt;/p&gt;

&lt;p&gt;However, working with container queries shifts this perspective. Instead of designing for screens, you start designing for space. Instead of asking what device is being used, you start asking how much room the component actually has.&lt;/p&gt;

&lt;p&gt;Container queries don’t replace media queries; they redefine what responsiveness means in a component-driven world.&lt;/p&gt;

&lt;p&gt;🚀 What Actually Improved&lt;/p&gt;

&lt;p&gt;Once container queries are introduced, the improvements become immediately noticeable in real UI systems.&lt;/p&gt;

&lt;p&gt;Components become truly reusable without layout overrides. Styling becomes more predictable because it reacts to actual container dimensions. Design systems become easier to maintain because responsiveness is encapsulated inside components rather than spread across breakpoints.&lt;/p&gt;

&lt;p&gt;Instead of rewriting styles for different layouts, the same component simply adapts itself naturally to its environment.&lt;/p&gt;

&lt;p&gt;⚠️ Container Queries Aren’t a Full Replacement&lt;/p&gt;

&lt;p&gt;While powerful, container queries are not a complete replacement for media queries. Global layout decisions still require viewport awareness, especially for page-level structure and major breakpoints.&lt;/p&gt;

&lt;p&gt;Without proper balance, relying only on container queries can lead to confusion in large layout systems. Both approaches need to coexist depending on the level of design control required.&lt;/p&gt;

&lt;p&gt;🧩 When Container Queries Make Sense&lt;/p&gt;

&lt;p&gt;Container queries are most useful when building reusable components, design systems, and modular UI architectures where components are expected to live in multiple contexts.&lt;/p&gt;

&lt;p&gt;However, if the layout is strictly page-based and components are not reused across different containers, traditional media queries may still be sufficient.&lt;/p&gt;

&lt;p&gt;🔮 Final Thought&lt;/p&gt;

&lt;p&gt;I didn’t adopt container queries because they were new or modern. I started using them because media queries stopped matching how I naturally think about UI systems.&lt;/p&gt;

&lt;p&gt;Once you begin designing for components instead of screens, responsiveness stops feeling like a set of breakpoints and starts feeling like a property of the component itself.&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>frontend</category>
      <category>uiux</category>
    </item>
    <item>
      <title>Building a RAG pipeline in a weekend</title>
      <dc:creator>Akshay Sarak</dc:creator>
      <pubDate>Sun, 14 Jun 2026 16:58:32 +0000</pubDate>
      <link>https://dev.to/akshay_sarak/building-a-rag-pipeline-in-a-weekend-1b71</link>
      <guid>https://dev.to/akshay_sarak/building-a-rag-pipeline-in-a-weekend-1b71</guid>
      <description>&lt;p&gt;For a long time, I assumed building AI applications meant working with complex research papers, large ML pipelines, and systems that were far beyond typical full-stack development. Things like embeddings, vector databases, and retrieval systems felt like separate worlds from normal web apps.&lt;/p&gt;

&lt;p&gt;So whenever I thought about “AI-powered features,” I instinctively focused on the model itself and assumed the rest would be the hard part.&lt;/p&gt;

&lt;p&gt;That assumption turned out to be wrong.&lt;/p&gt;

&lt;p&gt;🔍 The Problem Starts Quietly&lt;/p&gt;

&lt;p&gt;Initially, everything seemed simple on the surface. You take a document, pass a query to an LLM, and expect intelligent responses. The system appears to work, and for small examples, it does.&lt;/p&gt;

&lt;p&gt;However, as soon as real data enters the picture, problems start appearing. The model begins hallucinating facts. It confidently answers questions that are not present in your documents. It struggles with domain-specific knowledge. Even worse, it behaves differently depending on how the question is phrased.&lt;/p&gt;

&lt;p&gt;Nothing seems broken at the system level, but the outputs are no longer reliable.&lt;/p&gt;

&lt;p&gt;The surprising part is that the model itself isn’t failing in the traditional sense. The issue is that it simply doesn’t have access to the right context.&lt;/p&gt;

&lt;p&gt;Something fundamental is missing.&lt;/p&gt;

&lt;p&gt;🧠 The Real Issue Was Never the Model&lt;/p&gt;

&lt;p&gt;My first instinct was to assume the model needed improvement. Maybe better prompting, maybe a stronger model, maybe fine-tuning.&lt;/p&gt;

&lt;p&gt;However, after breaking down the problem, it became clear that the model wasn’t the real issue.&lt;/p&gt;

&lt;p&gt;The real issue was missing context at runtime.&lt;/p&gt;

&lt;p&gt;LLMs are trained on general knowledge, but they are not aware of your private documents, product data, or application-specific information. Every question is answered based on probability, not grounded truth.&lt;/p&gt;

&lt;p&gt;So even when the model sounds confident, it is often guessing.&lt;/p&gt;

&lt;p&gt;The problem wasn’t intelligence.&lt;/p&gt;

&lt;p&gt;The problem was access.&lt;/p&gt;

&lt;p&gt;📊 Understanding the Cost of Missing Context&lt;/p&gt;

&lt;p&gt;Many developers assume that prompting alone is enough to control model behavior.&lt;/p&gt;

&lt;p&gt;In reality, prompt engineering without context has strict limitations.&lt;/p&gt;

&lt;p&gt;An LLM must rely entirely on what it already knows, which means:&lt;/p&gt;

&lt;p&gt;private data is invisible&lt;br&gt;
domain-specific knowledge is incomplete&lt;br&gt;
factual grounding is inconsistent&lt;br&gt;
answers degrade as complexity increases&lt;/p&gt;

&lt;p&gt;Individually, these issues seem minor. Collectively, they make production AI unreliable.&lt;/p&gt;

&lt;p&gt;A model without context may look smart.&lt;/p&gt;

&lt;p&gt;But it is not grounded.&lt;/p&gt;

&lt;p&gt;⚡ Retrieval Changed Everything&lt;/p&gt;

&lt;p&gt;Rather than trying to force the model to “know more,” the approach shifts completely.&lt;/p&gt;

&lt;p&gt;Instead of increasing model intelligence, we introduce retrieval.&lt;/p&gt;

&lt;p&gt;This is where the RAG pipeline begins.&lt;/p&gt;

&lt;p&gt;Before generating an answer, the system first searches relevant documents. Only the most relevant chunks are passed into the model as context.&lt;/p&gt;

&lt;p&gt;Now the model is no longer answering blindly.&lt;/p&gt;

&lt;p&gt;It is answering with reference material.&lt;/p&gt;

&lt;p&gt;🔬 Pattern #1: Chunking Changes Everything&lt;/p&gt;

&lt;p&gt;One of the first critical insights is that documents cannot be treated as whole units.&lt;/p&gt;

&lt;p&gt;Large documents must be split into smaller chunks so they can be meaningfully retrieved.&lt;/p&gt;

&lt;p&gt;At first, this seems like a simple preprocessing step, but it directly affects system accuracy.&lt;/p&gt;

&lt;p&gt;Poor chunking leads to irrelevant retrieval. Good chunking leads to precise answers.&lt;/p&gt;

&lt;p&gt;The quality of the entire system often depends more on chunking strategy than on the model itself.&lt;/p&gt;

&lt;p&gt;🧠 Pattern #2: Embeddings Are Not Just Data&lt;/p&gt;

&lt;p&gt;The next step is converting text into embeddings.&lt;/p&gt;

&lt;p&gt;Initially, embeddings feel like a technical detail. Just a way to store text in vector form.&lt;/p&gt;

&lt;p&gt;But in reality, embeddings define how the system understands meaning.&lt;/p&gt;

&lt;p&gt;Similar ideas are placed closer together in vector space, even if the wording is different. This enables semantic search instead of keyword search.&lt;/p&gt;

&lt;p&gt;At this point, the system stops matching words and starts matching intent.&lt;/p&gt;

&lt;p&gt;🗄️ Pattern #3: Retrieval Becomes the Real Intelligence Layer&lt;/p&gt;

&lt;p&gt;Once embeddings are stored in a vector database like MongoDB Atlas Vector Search, retrieval becomes the most important part of the system.&lt;/p&gt;

&lt;p&gt;When a query is made, it is also converted into an embedding. The system then searches for the closest semantic matches and retrieves relevant chunks.&lt;/p&gt;

&lt;p&gt;This step becomes the real intelligence layer of the architecture.&lt;/p&gt;

&lt;p&gt;The model is no longer responsible for “knowing everything.”&lt;/p&gt;

&lt;p&gt;It is only responsible for reasoning over retrieved context.&lt;/p&gt;

&lt;p&gt;🤖 Pattern #4: Generation Becomes Grounded&lt;/p&gt;

&lt;p&gt;Once relevant context is retrieved, it is passed into the LLM along with the user query.&lt;/p&gt;

&lt;p&gt;Instead of asking:&lt;/p&gt;

&lt;p&gt;“Answer this question”&lt;/p&gt;

&lt;p&gt;The system now asks:&lt;/p&gt;

&lt;p&gt;“Answer this question using the provided context”&lt;/p&gt;

&lt;p&gt;This single shift changes everything.&lt;/p&gt;

&lt;p&gt;Responses become more accurate, more stable, and more aligned with real data.&lt;/p&gt;

&lt;p&gt;The model stops hallucinating because it is no longer operating in isolation.&lt;/p&gt;

&lt;p&gt;⚡ What Actually Improved&lt;/p&gt;

&lt;p&gt;Once the RAG pipeline is in place, the behavior of the system changes noticeably.&lt;/p&gt;

&lt;p&gt;Responses become grounded in actual documents. Hallucinations reduce significantly. Domain-specific accuracy improves. The system becomes capable of answering questions it could never handle before.&lt;/p&gt;

&lt;p&gt;The application does not become more intelligent.&lt;/p&gt;

&lt;p&gt;It becomes more informed.&lt;/p&gt;

&lt;p&gt;🏛️ RAG Is Not an AI Feature&lt;/p&gt;

&lt;p&gt;Before building this, I thought RAG was an advanced AI technique.&lt;/p&gt;

&lt;p&gt;What I learned instead is that RAG is a system design pattern.&lt;/p&gt;

&lt;p&gt;It combines:&lt;/p&gt;

&lt;p&gt;search systems&lt;br&gt;
data pipelines&lt;br&gt;
vector databases&lt;br&gt;
LLM reasoning&lt;/p&gt;

&lt;p&gt;At its core, it is not about artificial intelligence.&lt;/p&gt;

&lt;p&gt;It is about combining retrieval with generation in a controlled way.&lt;/p&gt;

&lt;p&gt;🔮 Final Thought&lt;/p&gt;

&lt;p&gt;RAG systems rarely fail because of the model.&lt;/p&gt;

&lt;p&gt;They fail because of poor retrieval design.&lt;/p&gt;

&lt;p&gt;By the time outputs look wrong, the issue is usually already in chunking, embeddings, or search quality.&lt;/p&gt;

&lt;p&gt;The biggest lesson wasn’t learning how to use an LLM.&lt;/p&gt;

&lt;p&gt;It was understanding that modern AI systems are not just models — they are architectures built around information flow.&lt;/p&gt;

&lt;p&gt;Once you start thinking in that direction, building AI applications stops feeling like research and starts feeling like engineering.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>webdev</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>The Real Cost of Re-renders in React..💸</title>
      <dc:creator>Akshay Sarak</dc:creator>
      <pubDate>Sun, 14 Jun 2026 15:43:16 +0000</pubDate>
      <link>https://dev.to/akshay_sarak/the-real-cost-of-re-renders-in-react-2j77</link>
      <guid>https://dev.to/akshay_sarak/the-real-cost-of-re-renders-in-react-2j77</guid>
      <description>&lt;p&gt;For a long time, I assumed React performance issues were usually caused by slow APIs, inefficient algorithms, or expensive database queries. Re-renders never felt like a serious concern. After all, React is designed to update the UI efficiently.&lt;/p&gt;

&lt;p&gt;So whenever I noticed a sluggish interface, I instinctively looked everywhere except the component tree.&lt;/p&gt;

&lt;p&gt;That assumption turned out to be wrong.&lt;/p&gt;

&lt;p&gt;🔍 The Problem Starts Quietly&lt;/p&gt;

&lt;p&gt;Initially, everything seemed fine. Components rendered correctly, interactions felt responsive, and development was smooth. There were no obvious signs of performance issues.&lt;/p&gt;

&lt;p&gt;However, as the application grew, small delays began to appear. A simple interaction would occasionally feel sluggish. Certain screens became noticeably slower after new features were added. Nothing seemed broken, but the experience no longer felt as responsive as it once had.&lt;/p&gt;

&lt;p&gt;The surprising part was that the backend wasn't the problem. Network requests were fast, database queries were efficient, and API responses arrived quickly. Yet users still experienced delays.&lt;/p&gt;

&lt;p&gt;Something else was happening beneath the surface.&lt;/p&gt;

&lt;p&gt;🧠 The Real Issue Was Never React&lt;/p&gt;

&lt;p&gt;My first instinct was to blame React itself. Surely the framework was doing too much work.&lt;/p&gt;

&lt;p&gt;However, after profiling the application, it became clear that React wasn't the problem.&lt;/p&gt;

&lt;p&gt;The real issue was unnecessary rendering.&lt;/p&gt;

&lt;p&gt;A single state update was triggering large portions of the component tree to render again. Components that had no relationship to the changed data were still executing their render logic. What appeared to be one update was actually dozens of updates happening throughout the application.&lt;/p&gt;

&lt;p&gt;The problem wasn't that React was slow.&lt;/p&gt;

&lt;p&gt;The problem was that I was asking React to do far more work than necessary.&lt;/p&gt;

&lt;p&gt;📊 Understanding the Cost of Re-renders&lt;/p&gt;

&lt;p&gt;Many developers assume that if the UI doesn't visibly change, a re-render doesn't matter.&lt;/p&gt;

&lt;p&gt;In reality, every render still has a cost.&lt;/p&gt;

&lt;p&gt;React must execute component functions, evaluate hooks, recalculate JSX, compare virtual DOM trees, and determine whether updates should be committed to the browser.&lt;/p&gt;

&lt;p&gt;Individually, these operations are inexpensive. Collectively, they become surprisingly costly when repeated across a large application.&lt;/p&gt;

&lt;p&gt;A single unnecessary render may not matter.&lt;/p&gt;

&lt;p&gt;Hundreds of unnecessary renders absolutely do.&lt;/p&gt;

&lt;p&gt;⚡ Profiling Changed Everything&lt;/p&gt;

&lt;p&gt;Rather than immediately reaching for optimisation techniques, I decided to measure the problem first.&lt;/p&gt;

&lt;p&gt;Using the React Profiler revealed something I hadn't expected.&lt;/p&gt;

&lt;p&gt;The application wasn't suffering from a single expensive component. Instead, it was suffering from a large number of inexpensive components rendering repeatedly.&lt;/p&gt;

&lt;p&gt;The issue wasn't concentrated in one place.&lt;/p&gt;

&lt;p&gt;It was distributed throughout the system.&lt;/p&gt;

&lt;p&gt;That changed how I approached optimisation entirely.&lt;/p&gt;

&lt;p&gt;🔬 Pattern #1: Keep State Close to Where It's Used&lt;/p&gt;

&lt;p&gt;One of the biggest issues came from state placement.&lt;/p&gt;

&lt;p&gt;Over time, state had gradually moved higher and higher in the component hierarchy. It seemed convenient at first, but every update forced large sections of the application to render again.&lt;/p&gt;

&lt;p&gt;The solution wasn't adding optimisation hooks.&lt;/p&gt;

&lt;p&gt;It was improving architecture.&lt;/p&gt;

&lt;p&gt;By keeping state closer to the components that actually consumed it, render boundaries became smaller and updates became more isolated.&lt;/p&gt;

&lt;p&gt;The result was fewer unnecessary renders and a much more predictable component tree.&lt;/p&gt;

&lt;p&gt;🔗 Pattern #2: Stabilise References Intentionally&lt;/p&gt;

&lt;p&gt;The second issue involved objects and functions being recreated on every render.&lt;/p&gt;

&lt;p&gt;From React's perspective, a newly created object is different from the previous one, even if it contains the same values. The same applies to functions.&lt;/p&gt;

&lt;p&gt;This meant child components were re-rendering simply because their props appeared to change.&lt;/p&gt;

&lt;p&gt;Using tools like React.memo, useMemo, and useCallback helped stabilise these references and reduce unnecessary updates.&lt;/p&gt;

&lt;p&gt;The important lesson wasn't to memoise everything.&lt;/p&gt;

&lt;p&gt;It was to understand why a component was rendering in the first place.&lt;/p&gt;

&lt;p&gt;🏗️ Pattern #3: Create Better Rendering Boundaries&lt;/p&gt;

&lt;p&gt;Several components had gradually accumulated too many responsibilities.&lt;/p&gt;

&lt;p&gt;They handled state, data fetching, business logic, and UI rendering all at once.&lt;/p&gt;

&lt;p&gt;As these components grew, even small changes caused large portions of the interface to re-render.&lt;/p&gt;

&lt;p&gt;Breaking them into smaller, focused components introduced natural rendering boundaries. Updates became more targeted, and React had significantly less work to perform.&lt;/p&gt;

&lt;p&gt;Sometimes performance improvements don't come from optimisation.&lt;/p&gt;

&lt;p&gt;They come from better component design.&lt;/p&gt;

&lt;p&gt;⚡ What Actually Improved&lt;/p&gt;

&lt;p&gt;Once these changes were applied, the difference was immediately noticeable.&lt;/p&gt;

&lt;p&gt;Render counts dropped significantly. User interactions became more responsive. Profiling traces became cleaner and easier to reason about. Most importantly, the screen that previously took nearly 800ms to update was now completing the same interaction in roughly 60ms.&lt;/p&gt;

&lt;p&gt;The application didn't gain any new features.&lt;/p&gt;

&lt;p&gt;It simply stopped performing unnecessary work.&lt;/p&gt;

&lt;p&gt;🏛️ Performance Is Often an Architecture Problem&lt;/p&gt;

&lt;p&gt;Before this experience, I viewed React performance primarily as an optimisation problem.&lt;/p&gt;

&lt;p&gt;I assumed the solution was more memoisation, more hooks, or more advanced techniques.&lt;/p&gt;

&lt;p&gt;What I learned instead was that performance is often a consequence of architecture.&lt;/p&gt;

&lt;p&gt;Poor state boundaries create unnecessary renders. Large components create unnecessary work. Unstable references create unnecessary updates.&lt;/p&gt;

&lt;p&gt;React wasn't slow.&lt;/p&gt;

&lt;p&gt;My component structure was.&lt;/p&gt;

&lt;p&gt;🔮 Final Thought&lt;/p&gt;

&lt;p&gt;Performance issues rarely appear overnight. They accumulate gradually as applications grow and complexity increases.&lt;/p&gt;

&lt;p&gt;That is what makes them difficult to spot.&lt;/p&gt;

&lt;p&gt;By the time users notice lag, the underlying rendering problem has often existed for months.&lt;/p&gt;

&lt;p&gt;The biggest lesson wasn't learning a new optimisation technique.&lt;/p&gt;

&lt;p&gt;It was understanding that every state update has a cost, and every re-render should have a reason.&lt;/p&gt;

&lt;p&gt;Once you start thinking about React through that lens, performance stops being something you fix at the end and becomes something you design for from the beginning.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>performance</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>Why I stopped fighting monorepos..</title>
      <dc:creator>Akshay Sarak</dc:creator>
      <pubDate>Sun, 14 Jun 2026 14:54:06 +0000</pubDate>
      <link>https://dev.to/akshay_sarak/why-i-stopped-fighting-monorepos-mmp</link>
      <guid>https://dev.to/akshay_sarak/why-i-stopped-fighting-monorepos-mmp</guid>
      <description>&lt;p&gt;For a long time, I believed monorepos were overkill.  They seemed like something only “big companies” used because they had too much code and not enough structure.  So, like most developers early on, I split everything into separate repositories: frontend in one, backend in another, and shared code in a “cleanly isolated” place.&lt;/p&gt;

&lt;p&gt;It felt organised at first. However, over time, that sense of clarity gradually eroded.&lt;/p&gt;

&lt;p&gt;💥 The Problem Begins Quietly&lt;/p&gt;

&lt;p&gt;Initially, everything seemed smooth. Each repository was independent, each service isolated, and there was no visible coupling between systems. This gave a strong sense of clean architecture.&lt;/p&gt;

&lt;p&gt;But problems didn’t appear immediately. They started quietly. A shared function might be updated in one place, but another repository wouldn’t reflect that change. Types slowly diverged, and imports that once worked silently stopped. Eventually, bugs only appeared in production, not during development.&lt;/p&gt;

&lt;p&gt;What once felt like a clean separation slowly transformed into multiple systems that no longer fully agreed with each other.&lt;/p&gt;

&lt;p&gt;🧠 The Real Issue Was Never Separation&lt;/p&gt;

&lt;p&gt;Initially, I thought I was practising proper modular design by splitting everything into different repositories. I believed I was reducing complexity.&lt;/p&gt;

&lt;p&gt;However, the real problem was that I wasn’t separating concerns; I was separating context.&lt;/p&gt;

&lt;p&gt;In real applications, much logic is naturally shared. Validation rules, API contracts, UI components, utility functions, and types aren’t independent pieces. They’re part of the same system.&lt;/p&gt;

&lt;p&gt;When this shared logic is split across multiple repositories, complexity doesn’t disappear; it simply shifts into synchronisation problems between systems.&lt;/p&gt;

&lt;p&gt;⚙️ The Shift: Monorepo Thinking&lt;/p&gt;

&lt;p&gt;Switching to a monorepo didn’t feel like a tooling decision at first. It felt like a shift in how I thought about code structure.&lt;/p&gt;

&lt;p&gt;Rather than maintaining separate repositories for frontend, backend and shared logic, everything consolidated into a single structured system.  Logically, applications and packages remain distinct but reside within a unified codebase.&lt;/p&gt;

&lt;p&gt;This structure shifts your perspective on code relationships.  Instead of managing multiple independent systems, you now oversee a connected one.&lt;/p&gt;

&lt;p&gt;⚡ Turborepo’s Arrival&lt;/p&gt;

&lt;p&gt;Monorepos alone aren’t sufficient for efficient problem-solving. Without appropriate tooling, they can become cumbersome and slow.&lt;/p&gt;

&lt;p&gt;Turborepo revolutionised this.&lt;/p&gt;

&lt;p&gt;The first major improvement is intelligent caching.  Rather than rebuilding everything repeatedly, only the system’s changing components are rebuilt.&lt;/p&gt;

&lt;p&gt;The second improvement is pipeline execution.  Tasks like build, test and lint run in a structured dependency order automatically, eliminating manual management.&lt;/p&gt;

&lt;p&gt;The third improvement is dependency graph awareness.  The system comprehends package connections, eliminating the need for manual coordination.&lt;/p&gt;

&lt;p&gt;This transforms the monorepo from feeling heavy to efficient.&lt;/p&gt;

&lt;p&gt;🧠 The Mental Shift&lt;/p&gt;

&lt;p&gt;The most significant change isn’t technical, but mental.&lt;/p&gt;

&lt;p&gt;Initially, the mindset was to split code to reduce complexity, assuming separation inherently simplifies system management.&lt;/p&gt;

&lt;p&gt;However, working with monorepos shifts this perspective.  Instead of splitting code to reduce complexity, you group it to control it.&lt;/p&gt;

&lt;p&gt;Monorepos don’t eliminate complexity; they make it visible, structured and easier to manage as a single system.&lt;/p&gt;

&lt;p&gt;🚀 What Actually Improved&lt;/p&gt;

&lt;p&gt;Once everything migrated to a monorepo, the improvements became evident in daily development.&lt;/p&gt;

&lt;p&gt;Shared code became genuinely shared rather than duplicated, improving type safety as everything existed in a single synchronised system.  Testing became more consistent due to a single source of truth, leading to a more predictable and less fragmented developer experience.&lt;/p&gt;

&lt;p&gt;Instead of switching between multiple repositories, everything resided in one place, creating a more connected workflow.&lt;/p&gt;

&lt;p&gt;⚠️ Monorepos Aren’t a Magic Solution&lt;/p&gt;

&lt;p&gt;While powerful, monorepos aren’t magic and come with their own challenges. Initial setup becomes more complex, CI/CD pipelines require advanced features and discipline is needed to maintain the structure.  Tooling also plays a crucial role in ensuring efficiency.&lt;/p&gt;

&lt;p&gt;Without proper structure, a monorepo can become just as messy as multiple separate repositories.&lt;/p&gt;

&lt;p&gt;🧩 When Monorepos Make Sense&lt;/p&gt;

&lt;p&gt;Monorepos are suitable when multiple applications share logic, components are reused across projects, strict type consistency is essential and scalability is a priority.&lt;/p&gt;

&lt;p&gt;However, if systems are truly independent and don’t share meaningful logic, a monorepo may introduce unnecessary overhead rather than solving problems.&lt;/p&gt;

&lt;p&gt;🔮 Final Thought&lt;/p&gt;

&lt;p&gt;I didn’t adopt monorepos because they were trendy or popular. I switched because multiple repositories conflicted with my natural system thinking.&lt;/p&gt;

&lt;p&gt;Once you view software as a connected system rather than isolated parts, monorepos cease feeling like an option and become a structure that finally makes sense.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>systemdesign</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
