<?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: Ujjawal Tyagi</title>
    <description>The latest articles on DEV Community by Ujjawal Tyagi (@ujjawal_tyagi_c5a84255da4).</description>
    <link>https://dev.to/ujjawal_tyagi_c5a84255da4</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%2F3895717%2F736edd7f-31cd-4b8b-9c6d-05f4f0042c58.png</url>
      <title>DEV Community: Ujjawal Tyagi</title>
      <link>https://dev.to/ujjawal_tyagi_c5a84255da4</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ujjawal_tyagi_c5a84255da4"/>
    <language>en</language>
    <item>
      <title>Building LLMs for Bharat: What 6 Months of Rural AI Deployment Taught Us</title>
      <dc:creator>Ujjawal Tyagi</dc:creator>
      <pubDate>Fri, 24 Apr 2026 10:55:37 +0000</pubDate>
      <link>https://dev.to/ujjawal_tyagi_c5a84255da4/building-llms-for-bharat-what-6-months-of-rural-ai-deployment-taught-us-7j9</link>
      <guid>https://dev.to/ujjawal_tyagi_c5a84255da4/building-llms-for-bharat-what-6-months-of-rural-ai-deployment-taught-us-7j9</guid>
      <description>&lt;p&gt;Most coverage of "AI for India" treats the subject the way Silicon Valley treats emerging markets — translate the product, localize the UI, and you're done. Six months of production deployment of 7S Samiti, our AI tutor for rural Indian students, has taught us that this framing is almost completely wrong.&lt;/p&gt;

&lt;p&gt;This is a piece about what we actually learned building an LLM-powered education product for students in low-connectivity, low-literacy-adjacent environments in rural India. It's not a case study about an AI that worked. It's a case study about the specific, surprising ways it broke, and what we did about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem We Were Solving
&lt;/h2&gt;

&lt;p&gt;7S Samiti is a mission-driven edtech platform. The goal: deliver personalized, adaptive learning to rural Indian students at a price point that doesn't exclude them. The stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mobile app (Flutter, offline-first) deployed to entry-level Android phones.&lt;/li&gt;
&lt;li&gt;AI tutor that generates quizzes, assignments, and study notes on demand, in the student's preferred language.&lt;/li&gt;
&lt;li&gt;Local caching + selective sync for areas with 2G-only connectivity.&lt;/li&gt;
&lt;li&gt;Parent/teacher dashboard for progress tracking.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We deployed to pilot schools in three states (Uttar Pradesh, Maharashtra, Rajasthan). 2,400 students in the initial rollout.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure #1: The Tokenization Problem
&lt;/h2&gt;

&lt;p&gt;Every multilingual LLM paper talks about "parameter efficiency across languages." What they don't talk about: &lt;strong&gt;Hindi and Marathi have 2-4x worse tokenization efficiency than English in most off-the-shelf models.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A 200-word Hindi paragraph eats ~600 tokens where the English equivalent eats ~150. Latency is higher. Cost is higher. Quality of generation is often lower because you're burning context budget on writing the same content.&lt;/p&gt;

&lt;p&gt;Three fixes that worked:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Route by language.&lt;/strong&gt; English queries to GPT-4. Hindi/Marathi queries through a dedicated pathway with tokenizer-aware prompts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Translate-generate-translate for complex content.&lt;/strong&gt; For long-form study notes, we generate in English and translate to Hindi/Marathi as a post-process. Three model calls instead of one. Surprisingly produces higher-quality Hindi than direct generation, because the model's reasoning in English is stronger.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Pre-generate common content.&lt;/strong&gt; 80% of what students request is predictable. We batch-generate overnight, cache it, and serve from cache for 90% of requests.&lt;/p&gt;

&lt;p&gt;Result: latency dropped from ~4s to ~800ms for cached content. API cost dropped by 70%.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure #2: Voice vs. Text
&lt;/h2&gt;

&lt;p&gt;Our initial app was text-first. Deployment showed us: &lt;strong&gt;rural Indian students use voice input 8x more often than text.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Many students are the first generation in their family learning to read and write fluently in their regional language. Typing in Devanagari or Marathi script on a tiny phone keyboard is slow and intimidating. Speaking is natural.&lt;/p&gt;

&lt;p&gt;What we did:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Voice input became the default UX.&lt;/strong&gt; App usage doubled within two weeks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audio output for all AI responses.&lt;/strong&gt; Students listen 3x longer than they read.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multimodal interaction for math.&lt;/strong&gt; Students photo a math problem, we OCR + solve + explain by voice. Drove 40% of daily active usage in month one.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Failure #3: Connectivity Reality
&lt;/h2&gt;

&lt;p&gt;We designed for "low bandwidth." Reality: &lt;strong&gt;students use the app during a 15-minute window when they have signal, then go offline for hours.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The naive implementation — real-time cloud LLM calls — doesn't work. Students tap "solve," wait 8 seconds, then lose signal mid-request.&lt;/p&gt;

&lt;p&gt;What we shipped:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Queue-and-sync model.&lt;/strong&gt; Students ask questions offline. App queues, syncs when signal arrives, pushes responses back.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On-device inference for basic queries.&lt;/strong&gt; Distilled quantized model (~4B params) runs locally for ~30% of common requests. Zero connectivity required.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Selective sync with priority.&lt;/strong&gt; Prioritize unanswered questions &amp;gt; content updates &amp;gt; analytics when the 15-minute window arrives.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Impact: session completion rate went from 34% to 88%.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure #4: What the AI Didn't Know About Students
&lt;/h2&gt;

&lt;p&gt;First prompts were generic. Output was technically correct but culturally irrelevant. We'd explain algebra using apples and oranges to a student who'd never seen an orange. Chemistry with lab metaphors to students who'd never seen a Bunsen burner.&lt;/p&gt;

&lt;p&gt;Fixed at the prompt layer:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Regional context injection.&lt;/strong&gt; Every prompt includes the student's state, language, and region-appropriate analogies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Textbook alignment.&lt;/strong&gt; State boards use different textbooks. We pre-ingested Maharashtra Board, CBSE, UP Board syllabi.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Humility prompts.&lt;/strong&gt; "If outside the standard textbook for the grade, say so and offer the closest related question." Reduced confidently-wrong answers by 80%.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Deployment Data
&lt;/h2&gt;

&lt;p&gt;After 6 months in production:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;2,400 students&lt;/strong&gt; across 3 states.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;~38K AI interactions per day&lt;/strong&gt; at peak (mid-exam season).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;~₹0.02 per interaction&lt;/strong&gt; (after optimization).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Session completion rate: 88%&lt;/strong&gt; (up from 34% at launch).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Voice input share: 76%&lt;/strong&gt; of total queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cached content hit rate: 89%&lt;/strong&gt; during exam-prep weeks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Monthly AI-serving cost per student: ~₹285. Target price ₹99/month. We lose money today but the trajectory works once we hit 10K+ students.&lt;/p&gt;

&lt;h2&gt;
  
  
  Five Lessons
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Vernacular LLMs are a tokenization problem before they're a model problem.&lt;/strong&gt; Fix tokens + prompts before picking a model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Voice-first changes everything.&lt;/strong&gt; If building for rural India, voice IS the interface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design for bursty connectivity.&lt;/strong&gt; 15-minute-window sessions are the real use case.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cultural context in prompts is not optional.&lt;/strong&gt; Analogies matter more than raw model quality.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On-device + cloud hybrid is the only viable architecture.&lt;/strong&gt; Neither alone works.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Where This Goes
&lt;/h2&gt;

&lt;p&gt;Building AI for Bharat is not a translation problem. It's a systems problem involving tokenization, connectivity, UX modality, and cultural context — all of which need to be solved in concert.&lt;/p&gt;

&lt;p&gt;At &lt;a href="https://www.xenotixlabs.com" rel="noopener noreferrer"&gt;Xenotix Labs&lt;/a&gt; we've shipped 7S Samiti + Growara (WhatsApp AI automation) + Alcedo (AI-powered education discovery) — three different LLM-powered products for Indian users. Each taught us something that contradicted what the AI literature said would happen. If you're building &lt;a href="https://www.xenotixlabs.com/services/" rel="noopener noreferrer"&gt;AI solutions for startups&lt;/a&gt; in the Indian context, these failure modes are probably in your future. Getting ahead of them saves months.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Ujjawal Tyagi is the founder of Xenotix Labs, a product engineering studio that's shipped 30+ production apps including 7S Samiti (AI tutor for rural India), Growara (AI WhatsApp automation), and Cricket Winner (real-time cricket trading).&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>india</category>
      <category>llm</category>
    </item>
    <item>
      <title>What It Actually Takes to Build AI WhatsApp Automation for Indian SMBs (Lessons From Growara)</title>
      <dc:creator>Ujjawal Tyagi</dc:creator>
      <pubDate>Fri, 24 Apr 2026 10:42:36 +0000</pubDate>
      <link>https://dev.to/ujjawal_tyagi_c5a84255da4/what-it-actually-takes-to-build-ai-whatsapp-automation-for-indian-smbs-lessons-from-growara-15i</link>
      <guid>https://dev.to/ujjawal_tyagi_c5a84255da4/what-it-actually-takes-to-build-ai-whatsapp-automation-for-indian-smbs-lessons-from-growara-15i</guid>
      <description>&lt;p&gt;Every Indian founder I've met in the last two years has the same WhatsApp problem. Customers DM them at all hours. Half the queries are the same five questions. The founder ends up being the company's unpaid, always-on customer support. At 50 customers a day it's manageable. At 500 it breaks the business.&lt;/p&gt;

&lt;p&gt;We built Growara to solve this. It's an AI-powered WhatsApp automation platform — businesses plug it into their WhatsApp Business account and the AI handles FAQs, books appointments, escalates complex queries to humans, and goes quiet when it should. Sounds simple. Wasn't.&lt;/p&gt;

&lt;p&gt;This piece is about what actually broke when we shipped it to Indian SMBs, the decisions that worked, and the ones we'd revisit.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Lazy Assumption Everyone Makes
&lt;/h2&gt;

&lt;p&gt;Before we started, every article I read about "AI WhatsApp bots" treated the problem as solved: "Just plug GPT into the WhatsApp Business API." I believed that for about two weeks.&lt;/p&gt;

&lt;p&gt;Three things break that premise when you ship to real Indian SMBs:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Language.&lt;/strong&gt; Indian customers don't chat in clean English. They chat in Hinglish — "bhai price kitne ka hai?" — or in full Hindi, Marathi, Tamil, or Gujarati, often in Roman script. Off-the-shelf LLMs handle English beautifully and Hinglish surprisingly well, but regional-language-in-Roman-script is a minefield. "Kya" is Hindi for "what," but depending on context the model sometimes reads it as a name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. WhatsApp's 24-hour window.&lt;/strong&gt; WhatsApp Business API has a hard rule: after 24 hours of silence from the customer, you cannot message them first unless you use an approved template. Your bot CANNOT just "follow up tomorrow" without pre-registering a template with Meta and paying per-template fees. This one rule shaped half our architecture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The "human handoff" edge case.&lt;/strong&gt; The hardest question in any AI support system isn't "can the AI answer?" It's "how does the AI know when it can't?" Getting this wrong means either (a) an AI that gives confidently wrong answers, or (b) an AI that escalates everything and adds no value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our Actual Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[WhatsApp user message]
     | (Meta Business API webhook)
[Node.js Gateway]
     |
[Message Classifier — small fine-tuned model]
     | branches to:
  |-- [Template Response] — for repeated FAQs (cached)
  |-- [LLM Response] — for freeform queries
  +-- [Human Handoff Queue] — for complex/ambiguous
     |
[WhatsApp Business API reply]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The classifier matters more than the LLM.&lt;/strong&gt; Most queries — "What are your prices?" "Where are you located?" "When do you open?" — don't need an LLM at all. A small fine-tuned classifier (we use a distilled version of a multilingual BERT) catches them and returns a pre-written, founder-approved answer. Latency: 80ms. Cost: effectively zero. This handles about 65% of real message volume.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The LLM is only called for the hard 35%.&lt;/strong&gt; When the classifier isn't confident, we go to the LLM with a heavily engineered prompt that includes business context, recent conversation history, and explicit escalation criteria.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The human handoff queue is the safety net.&lt;/strong&gt; When the LLM's output is below a confidence threshold OR when certain red-flag keywords fire (price negotiation, complaint, payment issue), the message goes to a dashboard where the business owner replies from their browser. The AI never fakes confidence it doesn't have.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hinglish Problem, Solved
&lt;/h2&gt;

&lt;p&gt;Our most-hated bug in the early weeks was the classifier confidently labeling "mujhe price batao bhai" as an appointment-booking request because the word "batao" appeared in some appointment training data.&lt;/p&gt;

&lt;p&gt;What worked:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Fine-tune on real data, not synthetic.&lt;/strong&gt; We bootstrapped with a few thousand messages from our own WhatsApp Business pilots. The gap between synthetic and real Hinglish was humbling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Add a translation pass for the LLM.&lt;/strong&gt; For the 35% that goes to the LLM, we first translate Hinglish/Marathi/Tamil into English using a small dedicated model, prompt GPT in English, then translate the response back. Three model calls instead of one. Latency bump ~600ms. Accuracy jump ~22 percentage points. Worth it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Per-vendor terminology list.&lt;/strong&gt; Each vendor onboards with a 20-term glossary (product names, service names, industry jargon) that gets prepended to every LLM prompt. Vendor-specific context beats bigger models.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Handoff Threshold That Actually Works
&lt;/h2&gt;

&lt;p&gt;The single highest-impact tuning decision we made: we set the LLM confidence threshold for human handoff aggressively high — meaning the AI hands off more readily than most teams would.&lt;/p&gt;

&lt;p&gt;Counterintuitive? Yes. Customers would rather talk to a human than a wrong AI. Vendor satisfaction jumped when we &lt;em&gt;reduced&lt;/em&gt; the AI's eagerness to answer edge cases. We also added four hard-coded handoff triggers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Any message containing "refund", "complaint", "problem", "issue", or their Hindi equivalents.&lt;/li&gt;
&lt;li&gt;Any numeric question about price &amp;gt;₹500 — our vendors' margins require human negotiation.&lt;/li&gt;
&lt;li&gt;Any message after a previous human handoff in the same conversation.&lt;/li&gt;
&lt;li&gt;Any message from a customer flagged as VIP.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These four rules alone improved our Net Promoter Score for the automation by 18 points.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Math Looks Like
&lt;/h2&gt;

&lt;p&gt;For a typical vendor processing 500 WhatsApp messages per day:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;65%&lt;/strong&gt; handled by classifier alone: ~325 messages, near-zero marginal cost&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;25%&lt;/strong&gt; handled by LLM after classifier miss: ~125 messages, ~₹3.50 per message&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;10%&lt;/strong&gt; escalated to human: ~50 messages, vendor's own time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Monthly infrastructure cost per vendor: ₹3,000–5,000. Monthly LLM API cost: ₹13,000–15,000. We charge ₹25,000/month. The economics work because the classifier absorbs most volume.&lt;/p&gt;

&lt;p&gt;Without the classifier — if we sent every message to GPT — cost per vendor would be ~₹45,000/month and the product wouldn't exist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Five Lessons Compressed
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The AI is never the hard part.&lt;/strong&gt; The WhatsApp Business API, the language edge cases, and the handoff UX consumed 80% of engineering time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Small models beat big models on tight-context tasks.&lt;/strong&gt; A fine-tuned classifier for intent routing is cheaper, faster, and more accurate than calling GPT-4 for every message.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hinglish needs real data.&lt;/strong&gt; Synthetic training sets lie to you. Pay to collect real conversation logs from pilot vendors before shipping.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design for the 24-hour window from day one.&lt;/strong&gt; Templates aren't an afterthought — they're a core data model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hand off more, not less.&lt;/strong&gt; Customers forgive a human-in-the-loop AI. They don't forgive a confidently wrong AI.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Taking the Leap
&lt;/h2&gt;

&lt;p&gt;If you're an Indian SMB tech team thinking about building something similar, the path is real but narrower than the marketing suggests. You need a ruthless focus on the top 20 FAQs your customers actually send, real conversation data before you train anything, an explicit human-handoff UX that your vendors actually want to use, a template library per vendor registered with Meta, and a classifier-first architecture where LLMs are the expensive exception, not the default.&lt;/p&gt;

&lt;p&gt;At &lt;a href="https://www.xenotixlabs.com" rel="noopener noreferrer"&gt;Xenotix Labs&lt;/a&gt; we've built this stack — Growara is one of several &lt;a href="https://www.xenotixlabs.com/services/" rel="noopener noreferrer"&gt;AI solutions for startups&lt;/a&gt; we've shipped. If you're exploring WhatsApp automation as part of your product roadmap or looking at &lt;a href="https://www.xenotixlabs.com/solutions/mvp-development-services-for-startups/" rel="noopener noreferrer"&gt;MVP development services for startups&lt;/a&gt;, the patterns above apply whether you build with us or roll it yourself.&lt;/p&gt;

&lt;p&gt;AI WhatsApp bots are a real product category in India. The teams that win are the ones honest about where the AI stops working.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Ujjawal Tyagi is the founder of &lt;a href="https://www.xenotixlabs.com" rel="noopener noreferrer"&gt;Xenotix Labs&lt;/a&gt;, a product engineering studio that's shipped 30+ production apps including Growara (AI WhatsApp), Cricket Winner (real-time cricket trading), and 7S Samiti (AI tutor for rural India).&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>whatsapp</category>
      <category>node</category>
      <category>india</category>
    </item>
    <item>
      <title>From Figma to Production in Six Weeks: The Design-to-Code Pipeline We Use to Ship Flutter Apps</title>
      <dc:creator>Ujjawal Tyagi</dc:creator>
      <pubDate>Fri, 24 Apr 2026 10:07:15 +0000</pubDate>
      <link>https://dev.to/ujjawal_tyagi_c5a84255da4/from-figma-to-production-in-six-weeks-the-design-to-code-pipeline-we-use-to-ship-flutter-apps-18p7</link>
      <guid>https://dev.to/ujjawal_tyagi_c5a84255da4/from-figma-to-production-in-six-weeks-the-design-to-code-pipeline-we-use-to-ship-flutter-apps-18p7</guid>
      <description>&lt;p&gt;Every Flutter team has the same broken ritual. The designer finishes a beautiful Figma file. The developer opens it, stares at a spacing value of "14.3px", sighs, and rebuilds the UI from scratch. Three weeks later, the product ships with colors and paddings that don't match the design. The designer files a bug. The developer pushes back. Trust breaks down. The next project is worse.&lt;/p&gt;

&lt;p&gt;This is solvable. Over the last two years, we've shipped more than twenty production Flutter apps at &lt;a href="https://www.xenotixlabs.com" rel="noopener noreferrer"&gt;Xenotix Labs&lt;/a&gt;, and we've built a design-to-code pipeline that gets us from final Figma to staging build in six working weeks on most projects. Not because our designers and developers are faster than yours — they aren't — but because the handoff is engineered, not improvised.&lt;/p&gt;

&lt;p&gt;This is the pipeline. If you're a founder tired of design drift, or a developer tired of rebuilding the same components from scratch, or a designer tired of being told "it'll be fine in development", this is for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Core Principle: Design Tokens Are a Contract
&lt;/h2&gt;

&lt;p&gt;Most teams treat Figma files as a picture of the app. That's the wrong mental model. A Figma file is a contract between design and engineering. Contracts are machine-readable. Pictures aren't.&lt;/p&gt;

&lt;p&gt;Before we start any new project at Xenotix Labs, we spend three days — not more, not less — on what we call the &lt;em&gt;token foundation&lt;/em&gt;. This is a Figma library that defines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Color tokens&lt;/strong&gt;: never named &lt;code&gt;Red_500&lt;/code&gt;. Always named by role: &lt;code&gt;color/surface/primary&lt;/code&gt;, &lt;code&gt;color/border/danger&lt;/code&gt;, &lt;code&gt;color/text/on-inverse&lt;/code&gt;. The designer picks the hex; the role is what the developer consumes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spacing scale&lt;/strong&gt;: a rigid 4-point or 8-point grid. No "14px" spacing allowed, ever. If designers need 14, they pick 12 or 16.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Typography ramp&lt;/strong&gt;: 6–8 text styles, each with font family, weight, size, line-height, and letter-spacing. Named by role (&lt;code&gt;text/heading/large&lt;/code&gt;, &lt;code&gt;text/body/default&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Radius and elevation scales&lt;/strong&gt;: same rigor. Discrete steps, named by role.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This foundation takes three days because most design teams have never built one, and most dev teams have never asked for one. Once it exists, the handoff becomes deterministic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Figma to Tokens Studio to JSON
&lt;/h2&gt;

&lt;p&gt;We use the Tokens Studio plugin for Figma to export our tokens as JSON. The output looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"color"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"surface"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"primary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#0F172A"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"on-inverse"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#F8FAFC"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"spacing"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"4"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"16"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"6"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"24"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"radius"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"md"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"12"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This JSON gets checked into the app's repo, in a folder called &lt;code&gt;design-tokens/&lt;/code&gt;. It's version-controlled. It has its own PR review process. Designers can push updates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: JSON to Flutter Theme Extensions
&lt;/h2&gt;

&lt;p&gt;We've written a small Dart generator (it's about 200 lines, nothing clever) that takes the tokens JSON and emits strongly-typed Dart code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppColors&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;AppColors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;surfacePrimary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0xFF0F172A&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;textOnInverse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0xFFF8FAFC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppSpacing&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;AppSpacing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;s4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;16.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;s6&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;24.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we register these as a &lt;code&gt;ThemeExtension&lt;/code&gt; on the Flutter &lt;code&gt;ThemeData&lt;/code&gt;, which means developers can pull tokens out of context like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;colors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Theme&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;extension&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AppColorsExt&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;surfacePrimary&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the critical moment. From here on, developers &lt;em&gt;cannot type hex codes into the app code&lt;/em&gt;. Our linter catches it. Pull requests get blocked. The only way to add a new color is to add it to the Figma token library, regenerate, and ship.&lt;/p&gt;

&lt;p&gt;The outcome: design drift becomes mechanically impossible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Component Library - Built Once, Used Everywhere
&lt;/h2&gt;

&lt;p&gt;After tokens, we build a shared component library in Flutter — around 40 to 60 components, depending on the project. Buttons, input fields, cards, chips, modals, bottom sheets, app bars, typography components. Each one consumes tokens, not raw values.&lt;/p&gt;

&lt;p&gt;We version the component library as its own internal package. For a project like Veda Milk (the D2C dairy subscription platform we built), the end-user app and the delivery-boy app both depend on version 1.8.3 of the shared component library. When we update the button component, both apps pick it up on next build. One source of truth.&lt;/p&gt;

&lt;p&gt;Developers don't build screens from Figma. They build screens by composing components from the library. If a component they need doesn't exist, they don't invent one — they propose it. It gets added to the library, reviewed by a designer, and then used.&lt;/p&gt;

&lt;p&gt;This is the shift that gets us from "twelve weeks" to "six weeks" on most projects. Most Flutter development time gets burned rebuilding buttons, input fields, and cards for the fifth time. Once the component library is solid, developers assemble screens in hours, not days.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: The Handoff Ritual
&lt;/h2&gt;

&lt;p&gt;Every screen goes through a 15-minute handoff call between the designer and the assigned developer. Not a long meeting. A short, structured one. The developer opens the Figma file. The designer walks them through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Which components are reused&lt;/strong&gt;, which are new.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Any states&lt;/strong&gt; not immediately visible (empty state, error state, loading state, skeleton).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Any animations&lt;/strong&gt; (we document these in a separate Framer or Principle file, not left to imagination).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The "one weird thing"&lt;/strong&gt;: every screen has one non-obvious interaction. Surfacing it upfront costs 30 seconds and saves two days.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We log this call in a one-page doc in Notion. Developer signs off ("I understand everything here"). Designer signs off ("I've covered everything"). If a bug surfaces later that one of them missed, it becomes a learning moment for the ritual, not a blame moment for the person.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: The Three-Pass Review
&lt;/h2&gt;

&lt;p&gt;Every screen goes through three reviews before it ships to staging:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pass 1: Pixel review.&lt;/strong&gt; Developer takes screenshots of the built screen and overlays them on the Figma frame in Figma Jam or Eagle. Diffs over 2 pixels get fixed. This takes 5 minutes per screen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pass 2: Interaction review.&lt;/strong&gt; Designer plays with the built screen on a real device. Not the simulator. A mid-range Android and an iPhone. This is where you catch "the button hit area is too small" or "the loading shimmer flickers when the screen loads fast."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pass 3: Production-state review.&lt;/strong&gt; QA runs the screen through real data — empty lists, 200-character names, missing images, bad network. This is where most Flutter apps visibly fail in App Store reviews. Catching it internally saves a review rejection cycle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: The Continuous Design QA Loop
&lt;/h2&gt;

&lt;p&gt;Once the app is in staging, we run a weekly Design QA pass. The designer opens the app for an hour, notes everything that feels off, and files tickets. These tickets are labeled &lt;code&gt;design-qa&lt;/code&gt;, tagged to the designer and a developer, and don't count against the feature backlog — they're treated as debt, paid down every sprint.&lt;/p&gt;

&lt;p&gt;This is how we avoid the classic pattern where the app ships and then feels 80% right for the rest of its life. Design QA is a practice, not an event.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tech Stack That Makes This Possible
&lt;/h2&gt;

&lt;p&gt;For anyone trying to build this pipeline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Design tooling&lt;/strong&gt;: Figma + Tokens Studio plugin + Storybook-equivalent (we use Widgetbook for Flutter).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code tooling&lt;/strong&gt;: Dart token generator, Flutter ThemeExtension, strict linter rules (&lt;code&gt;avoid_hardcoded_colors&lt;/code&gt;), Melos for monorepo packages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review tooling&lt;/strong&gt;: Figma Jam for pixel diff overlays, Eagle for screenshot comparisons, Notion for handoff docs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD&lt;/strong&gt;: Every PR runs a visual diff test (we use golden tests) that flags any screen where pixels have shifted without an accompanying design update.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these tools are exotic. The discipline is what's rare.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Six Weeks Looks Like in Practice
&lt;/h2&gt;

&lt;p&gt;To make this concrete, here's the timeline for a typical Xenotix Labs project — say, a two-sided marketplace mobile app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Week 1&lt;/strong&gt;: Token foundation + component library skeleton + Figma sign-off on flows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Week 2&lt;/strong&gt;: 70% of components built and in Widgetbook. Screens start getting composed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Week 3&lt;/strong&gt;: First 12 screens complete, first pixel review pass, first interaction review.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Week 4&lt;/strong&gt;: Remaining screens, state handling, empty/error/loading states.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Week 5&lt;/strong&gt;: Integration with backend APIs, real data testing, production-state review.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Week 6&lt;/strong&gt;: Design QA pass, App Store / Play Store submissions, staging-to-production migration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Six weeks. Two designers, two developers, one QA. A shippable production app that matches the Figma file within 2 pixels on every screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Unlock Isn't Speed - It's Trust
&lt;/h2&gt;

&lt;p&gt;The pipeline above sounds like it's about speed. It isn't. It's about trust.&lt;/p&gt;

&lt;p&gt;When designers and developers trust each other, they ship better work. When they don't, they ship compromised work and gradually dislike each other. The pipeline isn't there to make development faster. It's there to remove the friction points that cause teams to distrust each other.&lt;/p&gt;

&lt;p&gt;Six weeks is a byproduct. The product is mutual respect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to Go From Here
&lt;/h2&gt;

&lt;p&gt;If you're a founder looking at a Flutter build and wondering how to avoid the design-drift disaster, there are three things you can do tomorrow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Make the design tokens a contract.&lt;/strong&gt; Don't start coding until the token library is locked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build the component library before the first screen.&lt;/strong&gt; It feels slow on week one. It pays back threefold by week three.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Institute the three-pass review.&lt;/strong&gt; Pixel, interaction, production-state. Every screen. No exceptions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you want the pipeline built for you — or you're looking at a product roadmap and want a team that already operates this way — you can browse our &lt;a href="https://www.xenotixlabs.com/services/" rel="noopener noreferrer"&gt;full-stack development services&lt;/a&gt; or read how we've applied this to 30+ production apps including Veda Milk, Cricket Winner, and Nursery Wallah. If you're hiring in India and want to skip the ramp-up, we also offer an option to &lt;a href="https://www.xenotixlabs.com/solutions/hire-react-native-developers-india/" rel="noopener noreferrer"&gt;hire React Native developers in India&lt;/a&gt; who already know this workflow.&lt;/p&gt;

&lt;p&gt;Good design-to-code is engineered. The teams that get it right aren't smarter than the ones that don't. They're just a little more disciplined about the contract.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Ujjawal Tyagi is the founder of &lt;a href="https://www.xenotixlabs.com" rel="noopener noreferrer"&gt;Xenotix Labs&lt;/a&gt;, a product engineering studio building mobile apps, web platforms, and AI solutions for startups. His team has shipped 30+ production apps using the Figma-to-Flutter pipeline described above.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>design</category>
      <category>figma</category>
      <category>mobile</category>
    </item>
    <item>
      <title>The Real Engineering Cost of Scaling an Indian Cricket App From 1K to 1M Users on Kafka</title>
      <dc:creator>Ujjawal Tyagi</dc:creator>
      <pubDate>Fri, 24 Apr 2026 10:03:36 +0000</pubDate>
      <link>https://dev.to/ujjawal_tyagi_c5a84255da4/the-real-engineering-cost-of-scaling-an-indian-cricket-app-from-1k-to-1m-users-on-kafka-5h06</link>
      <guid>https://dev.to/ujjawal_tyagi_c5a84255da4/the-real-engineering-cost-of-scaling-an-indian-cricket-app-from-1k-to-1m-users-on-kafka-5h06</guid>
      <description>&lt;p&gt;Most engineering blogs that talk about Kafka either quote the Netflix case study or walk you through the "hello world" producer-consumer example. Both are useless if you're actually trying to decide whether to adopt Kafka for a product that might hit a million users — or stay at ten thousand forever.&lt;/p&gt;

&lt;p&gt;This is a story from the trenches of building Cricket Winner, a real-time cricket scores, news, and opinion-trading platform for the Indian market. I'll walk through the decisions we made, the decisions we got wrong, and the numbers we wish someone had shared with us when we started.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Product, in One Paragraph
&lt;/h2&gt;

&lt;p&gt;Cricket Winner does three things in real time: it streams live ball-by-ball updates during matches, pushes breaking cricket news as it happens, and runs an opinion-trading engine where users take positions on outcomes ("Will Kohli score a fifty this innings?"). During an India vs. Pakistan match, a single over can produce a burst of 40,000+ user actions — upvotes, trades, opinion updates, comment floods. The rest of the time, the system sits idle.&lt;/p&gt;

&lt;p&gt;That bursty profile is why we chose Kafka. It's also why we almost abandoned Kafka three months in.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Decision That Nearly Killed Us
&lt;/h2&gt;

&lt;p&gt;When we started, our backend was a monolithic Node.js service with a PostgreSQL database and WebSockets for live updates. It worked fine for 5,000 concurrent users during beta testing with a state-league match. Then the first IPL match hit production, we crossed 60,000 concurrent users in the first 20 minutes, and WebSocket connection storms took the entire app down for 90 minutes.&lt;/p&gt;

&lt;p&gt;The post-mortem was simple: our "real-time" architecture was secretly synchronous. Every ball update had to fan out through the same Node process that was also handling auth, trading settlements, and news dispatch. One slow database query anywhere in the chain backed up every single live connection.&lt;/p&gt;

&lt;p&gt;We had two options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Add more Node instances behind a load balancer&lt;/strong&gt; (classic horizontal scale) — but our database was a single Postgres instance, so we'd just be moving the bottleneck.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decouple the real-time pipeline from the transactional pipeline&lt;/strong&gt; using an event-driven architecture.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We picked option 2. That meant Kafka.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Kafka and Not RabbitMQ
&lt;/h2&gt;

&lt;p&gt;This is the question we get most often from other Indian dev teams. We already used RabbitMQ on another project (Veda Milk, a D2C dairy subscription platform) and we'd been happy with it. So why not reuse it?&lt;/p&gt;

&lt;p&gt;Three reasons:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Throughput ceiling.&lt;/strong&gt; RabbitMQ peaks at ~50K messages/sec per node in practical Indian cloud setups. Kafka comfortably does 500K+ on the same hardware. During a cricket match final, we've hit 180K messages/sec sustained. RabbitMQ would have fallen over.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Replay.&lt;/strong&gt; During an outage (and there will be outages), Kafka lets you replay the event log. That matters a lot when your opinion-trading engine crashed mid-match and you need to reconstruct user positions from the last 30 minutes of events. RabbitMQ is a "fire and forget" queue — once a message is acked, it's gone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fan-out topology.&lt;/strong&gt; In our system, a single "ball bowled" event needs to reach four consumers simultaneously: the live score broadcaster, the trading settlement engine, the notification dispatcher, and the analytics pipeline. Kafka's consumer group model handles this natively. With RabbitMQ you end up creating exchange-bindings that get complex fast.&lt;/p&gt;

&lt;p&gt;For Veda Milk we kept RabbitMQ — it's a D2C subscription platform where order volume is high but bursts are small and replay doesn't matter. Right tool for the right job.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture We Actually Ship
&lt;/h2&gt;

&lt;p&gt;Here's our production topology, simplified:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Mobile/Web client]
     | (WebSocket)
[API Gateway — Node.js + Socket.io]
     | (Kafka producer)
[Kafka cluster — 3 brokers, AWS MSK]
     | (Kafka consumers)
  |-- Live score service (publishes to socket rooms)
  |-- Trading engine (writes positions to Postgres)
  |-- Notifications (pushes FCM/APNs)
  |-- Analytics (writes to ClickHouse)
  |-- News dispatcher (fan-out to feed service)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each consumer is its own microservice, deployed independently on ECS. When the trading engine deploys a new version, the live scores keep streaming. When the news dispatcher has a bug, it can be restarted without affecting anything else. Before this decoupling, a single deployment would cause a 15-second read-availability blip for everyone.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cost That Nobody Tells You About
&lt;/h2&gt;

&lt;p&gt;Every Kafka blog post glosses over this: operating Kafka is not free, and it's not easy.&lt;/p&gt;

&lt;p&gt;Our AWS MSK bill for Cricket Winner alone runs ₹85,000–₹1,10,000/month (approximately $1,000–$1,300). That's for a 3-broker cluster (kafka.m5.large), with replication factor 3. On top of that, we run self-managed Zookeeper for historical reasons (newer MSK versions use KRaft, we're migrating).&lt;/p&gt;

&lt;p&gt;The human cost is bigger. You need at least one engineer on the team who understands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consumer-group rebalancing dynamics (what happens when a consumer crashes mid-partition-assignment).&lt;/li&gt;
&lt;li&gt;Partition key selection (we partition by &lt;code&gt;match_id&lt;/code&gt;, not &lt;code&gt;user_id&lt;/code&gt; — took us a month to figure that out).&lt;/li&gt;
&lt;li&gt;Exactly-once vs at-least-once semantics and how to write idempotent consumers.&lt;/li&gt;
&lt;li&gt;How to debug a lagging consumer at 2am when India is beating Australia in the final.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you don't have that engineer, or can't hire one, Kafka will punish you. The "hello world" Kafka is lovely. Production Kafka has sharp edges.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We'd Tell Our Past Selves
&lt;/h2&gt;

&lt;p&gt;Five lessons, compressed:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Don't adopt Kafka until you actually need it.&lt;/strong&gt; Before we had 50K+ concurrent users, RabbitMQ + good database indexes would have been plenty. We jumped to Kafka slightly too early. The complexity tax was real.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Partition keys are everything.&lt;/strong&gt; Your throughput, your ordering guarantees, and your consumer parallelism are all downstream of this one decision. Spend a week thinking about it before you ship.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Write idempotent consumers from day one.&lt;/strong&gt; You will reprocess events. You will redeploy during a match. You will have duplicates. If your consumer isn't idempotent, every one of those events will corrupt state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Monitor consumer lag, not throughput.&lt;/strong&gt; Throughput tells you what happened. Consumer lag tells you what's about to break. We added lag alerts on day 40 of production; we should have added them on day 1.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. The "Kafka vs. RabbitMQ" debate is a false dichotomy in real systems.&lt;/strong&gt; We run both. Kafka for high-throughput event streams that need fan-out and replay. RabbitMQ for work queues and background jobs. Use the right one for the right job.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Actually Possible in the Indian Market
&lt;/h2&gt;

&lt;p&gt;If you're a founder reading this and wondering whether your app needs this kind of architecture — here's the honest answer:&lt;/p&gt;

&lt;p&gt;You need Kafka if: you're building real-time (gaming, trading, cricket, live sports, live commerce), your traffic has 10x+ spikes, and you need to fan out the same event to 3+ downstream systems. Cricket Winner, FYZ (short-video), Bolcall (dating app with live calls) all fit this profile.&lt;/p&gt;

&lt;p&gt;You don't need Kafka if: you're building a marketplace, a standard e-commerce site, a services platform, or an internal B2B tool. RabbitMQ is enough. We built Veda Milk, Nursery Wallah, Cremaster, Housecare, Abomed, My Shaadi Store, and Prepe — all subscription or marketplace products — on RabbitMQ and none of them have needed Kafka.&lt;/p&gt;

&lt;p&gt;The cost of over-engineering is real. The cost of under-engineering only hits you once, but it hits you hard. Get it right the first time by being honest about what you're actually building.&lt;/p&gt;

&lt;h2&gt;
  
  
  Taking the Leap
&lt;/h2&gt;

&lt;p&gt;Building a real-time platform in India is different from building one in the US. Our users have flakier connectivity, lower tolerance for lag, and usage patterns that cluster around a few moments (the ball, the goal, the finale) rather than distributing evenly through the day. That shapes your architecture in ways Western tech blogs don't capture.&lt;/p&gt;

&lt;p&gt;If you're evaluating whether to go monolith vs microservices, or RabbitMQ vs Kafka, for your next product — the answer is almost always "start simpler than you think, and decouple only when the pain is real." That's the path we took at &lt;a href="https://www.xenotixlabs.com" rel="noopener noreferrer"&gt;Xenotix Labs&lt;/a&gt;, and it's the path we'd take again. You can browse more of our engineering case studies in our &lt;a href="https://www.xenotixlabs.com/portfolio/" rel="noopener noreferrer"&gt;software development case studies&lt;/a&gt; — including the full Cricket Winner teardown — or read about the full &lt;a href="https://www.xenotixlabs.com/stack/" rel="noopener noreferrer"&gt;microservices and Kafka stack&lt;/a&gt; we use across our builds.&lt;/p&gt;

&lt;p&gt;The boring truth about production systems is that the best architecture is always the simplest one that works. Kafka is a fantastic tool. It's also a sharp one. Use accordingly.&lt;/p&gt;




&lt;p&gt;*Ujjawal Tyagi is the founder of &lt;a href="https://www.xenotixlabs.com" rel="noopener noreferrer"&gt;Xenotix Labs&lt;/a&gt;, a product engineering studio that's shipped 30+ production apps across Flutter, Next.js, and Node.js for Indian and international startups. Case studies include Cricket Winner (real-time trading on Kafka), Veda Milk (D2C dairy on RabbitMQ), and Growara (AI WhatsApp automation).&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>kafka</category>
      <category>node</category>
      <category>scaling</category>
    </item>
    <item>
      <title>30 Products in 4 Years: Our Flutter + Next.js + Node.js Playbook</title>
      <dc:creator>Ujjawal Tyagi</dc:creator>
      <pubDate>Fri, 24 Apr 2026 09:41:17 +0000</pubDate>
      <link>https://dev.to/ujjawal_tyagi_c5a84255da4/30-products-in-4-years-our-flutter-nextjs-nodejs-playbook-3a94</link>
      <guid>https://dev.to/ujjawal_tyagi_c5a84255da4/30-products-in-4-years-our-flutter-nextjs-nodejs-playbook-3a94</guid>
      <description>&lt;p&gt;At Xenotix Labs (&lt;a href="https://www.xenotixlabs.com" rel="noopener noreferrer"&gt;https://www.xenotixlabs.com&lt;/a&gt;), we've shipped 30+ production apps in 4 years across D2C, edtech, fintech, healthtech, SaaS, and marketplaces. Every single one followed the same playbook.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Flutter for mobile (iOS + Android in one codebase)&lt;/li&gt;
&lt;li&gt;Next.js for web (SSR for SEO)&lt;/li&gt;
&lt;li&gt;Node.js + PostgreSQL/MongoDB for backend&lt;/li&gt;
&lt;li&gt;RabbitMQ for background jobs, Kafka for high-throughput streams&lt;/li&gt;
&lt;li&gt;Microservices on AWS from day one&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Case Studies
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Veda Milk&lt;/strong&gt; — a Country Delight-style D2C dairy subscription platform with three apps: end-user, delivery boy, admin panel. RabbitMQ handles daily subscription cycles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cricket Winner&lt;/strong&gt; — real-time cricket scores plus opinion trading. WebSockets for live sync, Kafka for news ingestion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Legal Owl&lt;/strong&gt; — a LegalTech super-app. Courses, community, journals, and an Advisor Hub where users can call a lawyer from inside the app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Growara&lt;/strong&gt; — AI WhatsApp automation. Meta Business API + LLM. 24/7, no manual effort.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ClaimsMitra&lt;/strong&gt; — insurance survey platform with 114+ REST API endpoints.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7S Samiti&lt;/strong&gt; — AI tutor for rural India. Offline-first Flutter, LLM-powered adaptive learning.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We Don't Do
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Hourly billing — fixed scope, milestone-based&lt;/li&gt;
&lt;li&gt;PM handoffs — founders stay in the WhatsApp group&lt;/li&gt;
&lt;li&gt;Skip testing — unit → integration → production is non-negotiable&lt;/li&gt;
&lt;li&gt;Use templates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're building something, talk to us at &lt;a href="https://www.xenotixlabs.com" rel="noopener noreferrer"&gt;https://www.xenotixlabs.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>nextjs</category>
      <category>startup</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
