<?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: Mittal Technologies</title>
    <description>The latest articles on DEV Community by Mittal Technologies (@mittal_technologies).</description>
    <link>https://dev.to/mittal_technologies</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3888395%2F6dcf366c-b332-40ff-9b07-dddcf1445cdf.png</url>
      <title>DEV Community: Mittal Technologies</title>
      <link>https://dev.to/mittal_technologies</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mittal_technologies"/>
    <language>en</language>
    <item>
      <title>How to Make a Website Faster: 15 Web Performance Optimization Techniques</title>
      <dc:creator>Mittal Technologies</dc:creator>
      <pubDate>Tue, 18 Aug 2026 12:32:14 +0000</pubDate>
      <link>https://dev.to/mittal_technologies/how-to-make-a-website-faster-15-web-performance-optimization-techniques-4jla</link>
      <guid>https://dev.to/mittal_technologies/how-to-make-a-website-faster-15-web-performance-optimization-techniques-4jla</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi0b6ktkeypzrw104rwyb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi0b6ktkeypzrw104rwyb.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
I've shipped enough slow websites to feel a little embarrassed writing this, honestly. Early in my career I once spent three weeks polishing a hero animation on a client site and completely ignored the fact that the hero image itself was a 4MB PNG. Nobody clapped for the animation. They just bounced before it finished loading. If you're looking for practical &lt;a href="https://mittaltechnologies.com/core-web-vitals-optimization-guide:-what-still-matters-and-what%27s-changed" rel="noopener noreferrer"&gt;web performance optimization techniques&lt;/a&gt; that actually move the needle instead of chasing Lighthouse vanity metrics, here's the list I actually use on real projects, not the theoretical one from a conference talk.&lt;/p&gt;

&lt;p&gt;I'm grouping these into images, code, network, and rendering, because that's roughly the order I audit a slow site in — the same checklist I'd hand to a client comparing options at a &lt;a href="https://mittaltechnologies.com/service/development" rel="noopener noreferrer"&gt;best website designing company in Ludhiana&lt;/a&gt; versus doing it in-house.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Images (Usually the Biggest Win, Fastest)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Compress and resize before upload, not after.&lt;/strong&gt; Sounds obvious, but I still find raw 6000px camera exports sitting in production &lt;code&gt;img&lt;/code&gt; folders more often than I'd like to admit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Serve modern formats.&lt;/strong&gt; WebP and AVIF genuinely cut file size significantly compared to JPEG/PNG for equivalent quality. A basic fallback pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;picture&amp;gt;
  &amp;lt;source srcset="hero.avif" type="image/avif"&amp;gt;
  &amp;lt;source srcset="hero.webp" type="image/webp"&amp;gt;
  &amp;lt;img src="hero.jpg" alt="Hero banner" loading="lazy"&amp;gt;
&amp;lt;/picture&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Lazy-load anything below the fold.&lt;/strong&gt; Native &lt;code&gt;loading="lazy"&lt;/code&gt; gets you most of the way there for free — no library required for the common case.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Use responsive &lt;code&gt;srcset&lt;/code&gt; instead of one giant image for every screen size.&lt;/strong&gt; Mobile users don't need your 2400px desktop hero.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Self-host critical images instead of pulling them through a slow third-party CDN&lt;/strong&gt; you don't control the caching headers on.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Code and Bundle Size&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;6. Audit your bundle before you optimize anything else.&lt;/strong&gt; &lt;code&gt;npx webpack-bundle-analyzer&lt;/code&gt; or the equivalent for your build tool will usually surface an embarrassing dependency you forgot you imported for one function.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. Code-split by route.&lt;/strong&gt; Most frameworks make this close to free now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Dashboard = React.lazy(() =&amp;gt; import('./Dashboard'));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;8. Tree-shake dead code.&lt;/strong&gt; I've found entire unused UI libraries sitting in production bundles because someone imported the whole package instead of the one component they needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9. Defer or async non-critical JavaScript.&lt;/strong&gt; Anything that isn't needed for first paint shouldn't be blocking it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script src="analytics.js" defer&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;10. Kill zombie third-party scripts.&lt;/strong&gt; Old chat widgets, abandoned A/B test tools, tracking pixels nobody checks anymore — audit your &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; every few months and you'll usually find at least one script nobody remembers adding.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Network and Delivery&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;11. Use a CDN properly, not just for static assets but for cached HTML where it makes sense.&lt;/strong&gt; Edge caching shaves real time off Time to First Byte.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;12. Enable HTTP/2 or HTTP/3&lt;/strong&gt; if your hosting supports it. Multiplexed requests mean you stop needing to hack around the old six-connections-per-domain limit with domain sharding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;13. Set proper cache headers.&lt;/strong&gt; I still see sites serving &lt;code&gt;Cache-Control: no-cache&lt;/code&gt; on assets that haven't changed in a year. That's just making every returning visitor re-download everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Rendering and Layout&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;14. Reserve space for images and ads to avoid layout shift.&lt;/strong&gt; This one bit me directly — a client's CLS score tanked because ad slots loaded after content, shoving everything down mid-read. Fix is usually just setting explicit dimensions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;img {
  aspect-ratio: 16 / 9;
  width: 100%;
  height: auto;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;15. Minimize main-thread work during load.&lt;/strong&gt; Heavy synchronous JS on page load blocks interactivity even if the page looks done. Chrome DevTools' Performance tab will show you exactly where the main thread is stuck if you profile a real load.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Part Nobody Wants to Hear&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here's my honest take after doing this for a while — most sites don't need a fancy new framework or a full rebuild to get fast. They need someone to actually sit down, run a Lighthouse audit, and fix the boring stuff nobody prioritized. I've turned five-second load times into sub-two-second ones with nothing more exotic than image compression, script auditing, and proper caching headers. No rewrite required.&lt;/p&gt;

&lt;p&gt;If you're managing this for a client site and don't have the bandwidth to do a full technical audit yourself, it's worth outsourcing to a &lt;a href="https://mittaltechnologies.com/service/development" rel="noopener noreferrer"&gt;web development company in Ludhiana&lt;/a&gt; that specializes in performance work specifically — not every agency treats this as a real discipline, and it shows in the final output.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;A Quick Word on Measuring, Because Guessing Is Useless&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Don't optimize blind. Run Lighthouse, WebPageTest, or Chrome's own Core Web Vitals report before and after every change, and isolate variables where you can — it's the same discipline I'd expect from a &lt;a href="https://mittaltechnologies.com/service/development" rel="noopener noreferrer"&gt;best website designing in Ludhiana&lt;/a&gt; provider running a client audit. I've seen developers "fix" something that wasn't actually the bottleneck because they didn't measure first, then wonder why the numbers didn't move.&lt;/p&gt;

&lt;p&gt;If your team doesn't have someone dedicated to this, &lt;a href="https://mittaltechnologies.com/how-much-should-a-website-cost-in-2026" rel="noopener noreferrer"&gt;checking website development cost&lt;/a&gt; for a focused performance sprint is usually far cheaper than it sounds — this is scoped, contained work, not a full rebuild, and pricing should reflect that.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Wrapping Up&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;None of these 15 techniques are individually revolutionary. That's kind of the point — performance work is rarely about one clever trick, it's about methodically clearing out a dozen small inefficiencies that accumulated because nobody was watching. Pick the three or four from this list that apply most to your stack, measure your baseline, fix them, and measure again. That loop, repeated a few times, will get you further than chasing whatever's trending on Twitter this week.&lt;/p&gt;

&lt;p&gt;One thing I'd add for anyone maintaining a legacy codebase: performance debt compounds the same way tech debt does. A site that was fast at launch three years ago has probably accumulated a dozen small regressions since — a new tracking pixel here, an unoptimized image there, a dependency upgrade that quietly doubled bundle size. Treat performance audits as a recurring calendar item, not a one-time fire drill, and you'll spend a lot less time firefighting later.&lt;/p&gt;

&lt;p&gt;If you're stuck and it's genuinely outside your team's expertise, looking into &lt;a href="https://mittaltechnologies.com/service/development" rel="noopener noreferrer"&gt;affordable website development services&lt;/a&gt; for a dedicated audit is a reasonable move — sometimes an outside set of eyes catches the thing you've been staring at for months.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>webdesign</category>
      <category>performance</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Building a Scalable Mobile App in 2026: Architecture, Tech Stack, and the Mistakes I'd Rather You Skip</title>
      <dc:creator>Mittal Technologies</dc:creator>
      <pubDate>Fri, 07 Aug 2026 11:29:19 +0000</pubDate>
      <link>https://dev.to/mittal_technologies/building-a-scalable-mobile-app-in-2026-architecture-tech-stack-and-the-mistakes-id-rather-you-20ek</link>
      <guid>https://dev.to/mittal_technologies/building-a-scalable-mobile-app-in-2026-architecture-tech-stack-and-the-mistakes-id-rather-you-20ek</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0mfrsrv53003z8v8f91o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0mfrsrv53003z8v8f91o.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
I rebuilt an app's backend architecture twice in eighteen months because nobody asked the scalability question early enough. Twice. That's the kind of mistake that eats a quarter of your roadmap and makes your team quietly resent every sprint planning meeting for weeks. So, when people ask me about building a scalable mobile app in 2026, my answer usually starts with "let's talk about what breaks first," because that's more useful than a generic tech stack recommendation copy-pasted from a comparison article.&lt;/p&gt;

&lt;p&gt;This isn't a theory post. It's mostly things I learned by getting them wrong first.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Start With the Data Layer, Not the UI&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Everyone wants to talk about frontend frameworks first because that's the fun, visible part. Wrong order. Your data layer decisions - how you structure your database, how you handle caching, whether you're using REST or GraphQL, determine how painful scaling becomes six months down the line, long after your onboarding screens are already pixel-perfect. A team that's actually done &lt;a href="https://mittaltechnologies.com/service/mobiledevelopment" rel="noopener noreferrer"&gt;mobile app development in Ludhiana&lt;/a&gt; at any real scale will usually tell you the same thing before they'll even discuss your UI mockups.&lt;/p&gt;

&lt;p&gt;If your app has any kind of social or real-time feature, think hard about read-heavy vs write-heavy patterns before picking your database. Postgres with proper indexing handles a lot more than people give it credit for, and reaching for something exotic before you've hit actual bottlenecks is usually premature optimization dressed up as forward planning.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Pick an Architecture That Assumes Growth, Not One That Assumes Comfort&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Monolithic architecture gets a bad reputation it doesn't always deserve. For a lot of apps, a well-structured modular monolith scales fine well past the point most teams need it to. Microservices solve real problems, but they also introduce real complexity, network latency between services, distributed transaction headaches, deployment orchestration that eats engineering time you'd rather spend on features.&lt;/p&gt;

&lt;p&gt;My rule of thumb now: don't reach for microservices until you can articulate the specific scaling bottleneck they'd solve for you. "It's what big companies do" isn't a technical reason, it's a resume-driven decision, and I've watched teams pay for that mistake in velocity for a full year.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;API Versioning: The Boring Thing That Saves You Later&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This one always gets skipped in tutorials because it's not exciting, but it's saved me more headaches than almost anything else on this list. Once you have multiple app versions live simultaneously across app stores with different rollout speeds, breaking changes without versioning becomes a genuine nightmare. Something as simple as this goes a long way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Express route versioning example
const router = express.Router();

router.use('/api/v1/users', require('./routes/v1/users'));
router.use('/api/v2/users', require('./routes/v2/users'));

// Middleware to handle deprecated version warnings
app.use('/api/v1/*', (req, res, next) =&amp;gt; {
  res.set('X-API-Deprecation-Notice', 'v1 will be sunset on 2026-12-01');
  next();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It looks trivial written out like this. It is not trivial when you're retrofitting it onto an API that fifty thousand active installs are already hitting.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Caching: Build It Before You Need It, Not After&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Redis for session and hot-data caching has saved more launches than I can count, quietly, in the background, where nobody notices until it's missing. Here's roughly the pattern I reach for on read-heavy endpoints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function getUserProfile(userId) {
  const cacheKey = `user:profile:${userId}`;
  const cached = await redis.get(cacheKey);

  if (cached) return JSON.parse(cached);

  const profile = await db.users.findById(userId);
  await redis.set(cacheKey, JSON.stringify(profile), 'EX', 3600);

  return profile;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple, sure, but the number of teams I've watched skip even this basic layer until their database started choking under load is honestly higher than it should be.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Choosing Your Tech Stack Without the Hype Cycle Getting Involved&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This is where a lot of teams get talked into decisions that don't fit their actual needs, often by whoever reads the most Twitter threads that week. A few things I actually weigh now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Team familiarity matters more than theoretical performance gains&lt;/strong&gt;, a team fluent in one stack ships faster and with fewer bugs than a team learning a "better" one mid-project&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-platform frameworks have matured enough&lt;/strong&gt; that native-only decisions need real justification now, not default assumption&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend language choice should match your team's hiring pool&lt;/strong&gt;, not just what's trending in benchmarks nobody on your team will actually read closely&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Third-party dependencies need an exit plan&lt;/strong&gt;, what happens if that SDK gets deprecated or the pricing changes overnight&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A solid &lt;a href="https://mittaltechnologies.com/service/mobiledevelopment" rel="noopener noreferrer"&gt;mobile app development company in Ludhiana&lt;/a&gt; that's shipped past the "comfortable MVP" stage will usually push back on trendy choices for exactly these reasons, and that pushback is worth listening to even when it's not what you wanted to hear.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Automate Your Pipeline Early, Even for Small Teams&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;CI/CD feels like overhead when you're a three-person team shipping your first build. It stops feeling like overhead the first time a manual deployment error takes down production at 11pm. A minimal GitHub Actions setup gets you most of the way there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Mobile CI
on: [push]
jobs:
  test-and-build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm install
      - run: npm run test
      - run: npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The five hours you spend setting this up in month one saves you dozens of hours of manual deployment errors by month six.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Platform-Specific Architecture Decisions Aren't Optional&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A lot of scalability problems aren't really technical, they're experience gaps, teams making the same architectural mistakes another team already made and fixed years ago. An &lt;a href="https://mittaltechnologies.com/service/mobiledevelopment" rel="noopener noreferrer"&gt;android app development company in Ludhiana&lt;/a&gt; with real experience handling device fragmentation and background process limits across manufacturers will architect your app differently from day one, in ways that save serious rework later.&lt;/p&gt;

&lt;p&gt;The iOS side has its own scaling landmines. Memory management quirks and Apple's evolving background execution rules cause a category of bugs that only show up once you're actually at scale, not during testing on a handful of devices, which is exactly why an &lt;a href="https://mittaltechnologies.com/service/mobiledevelopment" rel="noopener noreferrer"&gt;iOS app development company in Ludhiana&lt;/a&gt; familiar with those specifics matters more than people expect going in.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Budget for Scale, Not Just for Launch&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This is the part founders underestimate constantly. Any &lt;a href="https://mittaltechnologies.com/service/mobiledevelopment" rel="noopener noreferrer"&gt;mobile app development cost in Ludhiana&lt;/a&gt; or wherever you're building tends to get quoted against launch requirements, not against what happens once you actually gain traction. Ask specifically what architectural decisions in your quote account for scale, and which ones would need revisiting once you hit meaningful user numbers. That gap between "launch-ready" and "scale-ready" is where budgets quietly blow up six months post-launch.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Honest Takeaway&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Scalability isn't a feature you bolt on later; it's a mindset baked into decisions you make in week one, most of which feel unnecessary at the time because your current user base doesn't need them yet. Build for where you're realistically heading in eighteen months, not for an infinite hypothetical scale you might never reach. That balance, practical, not paranoid, is what actually separates apps that hold up under growth from ones that quietly fall apart the first time something goes right.&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>architecture</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Designing APIs That Survive Product Growth: Lessons from Real Business Applications</title>
      <dc:creator>Mittal Technologies</dc:creator>
      <pubDate>Mon, 03 Aug 2026 12:47:52 +0000</pubDate>
      <link>https://dev.to/mittal_technologies/designing-apis-that-survive-product-growth-lessons-from-real-business-applications-3id0</link>
      <guid>https://dev.to/mittal_technologies/designing-apis-that-survive-product-growth-lessons-from-real-business-applications-3id0</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F905rm5ixdxw7y1y564n4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F905rm5ixdxw7y1y564n4.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
I've rewritten the same API three times in my career. Same core domain, different companies, same mistake pattern each time: designing for the feature request in front of me instead of the shape the product was clearly heading toward. So, this isn't a theory. This is stuff I've paid for in weekend debugging sessions, and I'd rather you skip that part.&lt;/p&gt;

&lt;p&gt;Designing APIs that survive product growth isn't really about picking the "right" framework or following a REST-vs-GraphQL debate to its conclusion. It's about a handful of decisions you make early that either bend or break as your product scales. Let's get into the ones that actually matter.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Versioning Is Not Optional, Even for MVPs&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I get it - when you're shipping v1 of a product, versioning your API feels premature. It isn't. The cost of adding &lt;code&gt;/v1/&lt;/code&gt; to your routes on day one is basically zero. The cost of retrofitting versioning after you've got three external integrations depending on your current response shape is measured in weeks, not hours.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Do this from day one, even if v2 never happens
/api/v1/users
/api/v1/orders
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The one time I skipped this "because it's just an internal tool," that internal tool got exposed to a partner integration eight months later, and I spent a very unpleasant sprint building a compatibility shim instead of just having versioned it originally.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Stop Designing Endpoints Around Your Database Schema&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This is the single most common mistake I see in early-stage codebases. Your &lt;code&gt;/users&lt;/code&gt; endpoint returns exactly what's in the &lt;code&gt;users&lt;/code&gt; table, joined with whatever else seemed convenient at the time. It works fine until the product needs change and now your API response is a weird hybrid of three different features bolted together because nobody separated the resource model from the storage model.&lt;/p&gt;

&lt;p&gt;Design your API around what the client actually needs, not around your ORM's default serialization. It's more upfront work. It saves you from breaking five frontend features every time you refactor a table.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Pagination From the Start, Even If You Only Have 10 Records&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I've watched a &lt;code&gt;/products&lt;/code&gt; endpoint go from returning 12 items to returning 40,000 without anyone touching the response format, because "we'll add pagination later." Later arrives as a production incident, usually. Cursor-based pagination is a little more work to implement than offset-based, but it holds up much better once your dataset is large and mutating frequently.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "data": [...],
  "pagination": {
    "next_cursor": "eyJpZCI6MTIzfQ==",
    "has_more": true
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Error Responses Deserve as Much Design Effort as Success Responses&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Nobody designs their error format until something's already on fire. Then you end up with three different error shapes across your API because different developers handled it differently under pressure. Standardize this early:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Email is already in use",
    "field": "email"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Consistent error shapes matter more than people expect once you've got a frontend team, a mobile team, and maybe a partner integration all-consuming the same API and all needing to handle failures gracefully.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Rate Limiting Before You Think You Need It&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I once built a fairly straightforward B2B integration API with no rate limiting, reasoning that our client volume was low and predictable. Then one client's cron job misfired and hit our endpoint 4,000 times in ten minutes, taking down a shared service for everyone else on the platform. Rate limiting isn't just about abuse prevention - it's about isolating the blast radius of someone else's bug from your own uptime.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Idempotency for Anything That Mutates State&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If your API handles payments, order creation, or anything where a duplicate request causes real damage, idempotency keys aren't a nice-to-have. Client retries happen constantly - flaky networks, timeout misconfigurations, mobile clients on bad connections. Without idempotency support, a single dropped response can trigger a client retry that duplicates a transaction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /orders
Idempotency-Key: 8f14e45f-ceea-4bb7-8f37-1caf1f5f...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Document as You Build, Not After&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This one's less technical and more cultural, but it matters just as much. Undocumented internal APIs accumulate tribal knowledge that lives in three people's heads and dies the moment one of them leaves. OpenAPI specs generated from your route definitions cost you almost nothing if you set it up early, and they save the next developer, possibly future you, from reverse-engineering behavior from response payloads.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Where This Shows Up in Client Work&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I spend a chunk of my time consulting for small businesses building their first real product API, and the pattern above repeats constantly. A founder comes in after outgrowing a no-code backend, and the conversation almost always starts with "how much is this actually going to cost us to fix properly." If you're weighing that decision yourself, it's worth getting a straight answer on &lt;a href="https://mittaltechnologies.com/service/development" rel="noopener noreferrer"&gt;website design and development cost in Ludhiana&lt;/a&gt; before committing to a rebuild, because the backend work I'm describing here is usually a fraction of what people assume once it's scoped honestly.&lt;/p&gt;

&lt;p&gt;That said, not every team needs a full backend overhaul immediately. I've seen founders get quoted for a ground-up rebuild when a targeted API refactor, done through a genuinely &lt;a href="https://mittaltechnologies.com/service/development" rel="noopener noreferrer"&gt;affordable website development services in Ludhiana&lt;/a&gt; provider, would've solved 80% of the pain for a fraction of the price and timeline.&lt;/p&gt;

&lt;p&gt;For teams evaluating who actually builds this stuff well, it's worth treating backend architecture the same way you'd vet website development businesses trust for their frontend - ask for real examples of APIs they've built that survived a scaling event, not just a portfolio of pretty dashboards.&lt;/p&gt;

&lt;p&gt;On the design side specifically, the same scrutiny applies. A &lt;a href="https://mittaltechnologies.com/service/development" rel="noopener noreferrer"&gt;best website designing company in Ludhiana&lt;/a&gt; should be able to explain how their design decisions hold up once real usage data starts coming in, not just how the mockups looked in the pitch.&lt;/p&gt;

&lt;p&gt;If you're further along and need a partner who can own both the product architecture and the delivery timeline end to end, look specifically for a &lt;a href="https://mittaltechnologies.com/service/development" rel="noopener noreferrer"&gt;best website development company in Ludhiana&lt;/a&gt; with engineers who can talk you through their actual API design decisions, not just their tech stack buzzwords. The conversation itself tells you a lot about whether they've actually lived through a scaling problem or just read about one.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Bigger Pattern Here&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Every one of these mistakes shares a root cause: optimizing for the immediate feature instead of the trajectory of the product. It's a genuinely hard discipline to maintain under deadline pressure, and I don't think there's a clean fix for that beyond experience and a bit of institutional scar tissue.&lt;/p&gt;

&lt;p&gt;If you're building internal tooling and thinking "this'll never need to scale," I'd gently push back on that assumption. I've seen a surprising number of "temporary internal APIs" become load-bearing infrastructure within a year. Design accordingly, even when it feels like overkill in the moment - the overkill is a lot cheaper than the rebuild.&lt;/p&gt;

</description>
      <category>api</category>
      <category>webdev</category>
      <category>backend</category>
      <category>architecture</category>
    </item>
    <item>
      <title>What Does a Website Developer Actually Do? Services, Explained by Someone Who's Been in the Trenches</title>
      <dc:creator>Mittal Technologies</dc:creator>
      <pubDate>Tue, 28 Jul 2026 11:47:50 +0000</pubDate>
      <link>https://dev.to/mittal_technologies/what-does-a-website-developer-actually-do-services-explained-by-someone-whos-been-in-the-trenches-4m7f</link>
      <guid>https://dev.to/mittal_technologies/what-does-a-website-developer-actually-do-services-explained-by-someone-whos-been-in-the-trenches-4m7f</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft8xmeiiquswaoe2f547q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft8xmeiiquswaoe2f547q.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
I still remember a client asking me, mid-project, "so what exactly are you doing all day, is it just typing?" Fair question, honestly. From the outside, development looks like a black box - stuff goes in, a website comes out. But if you've actually done this work, you know what a website developer actually does covers a lot more ground than writing HTML and hoping for the best. Let me break down the real service categories, with a few war stories and code snippets along the way, because I think the abstract descriptions people usually give don't tell you much.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Front-End Work: More Than Just "Making It Look Nice"&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This is the part clients understand best, at least on the surface - buttons, layouts, colors, fonts. But the actual work is mostly about behavior under different conditions. Does the nav collapse properly on a 375px screen? Does that hero image not shift the layout while it loads (hello, Cumulative Layout Shift)? I've lost entire afternoons chasing a flexbox bug that only appeared on Safari, which, if you've done frontend work, you already knew was coming before I finished the sentence.&lt;br&gt;
Here's a small, real example - a responsive nav toggle I've rebuilt a dozen times with minor variations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.nav-menu {
  display: none;
}

@media (max-width: 768px) {
  .nav-toggle {
    display: block;
  }
  .nav-menu.active {
    display: flex;
    flex-direction: column;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple on paper. In practice, you're debugging why it snaps shut on iOS Safari but not Chrome, or why the animation stutters on a mid-range Android phone. Nobody tells you at the start of your career that half this job is just "why does this device behave differently."&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Back-End Development: Where the Actual Logic Lives&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This is the part that's invisible to most clients, and honestly, that's kind of the point - if it's working right, you never notice it. Server logic, database structure, API integrations, authentication, all the plumbing that makes forms actually submit somewhere and payments actually process.&lt;br&gt;
A basic example, a simple contact form handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.post('/contact', async (req, res) =&amp;gt; {
  const { name, email, message } = req.body;

  if (!name || !email || !message) {
    return res.status(400).json({ error: 'Missing required fields' });
  }

  try {
    await sendEmail({ to: 'admin@example.com', name, email, message });
    res.status(200).json({ success: true });
  } catch (err) {
    res.status(500).json({ error: 'Failed to send message' });
  }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks basic, and it is, but I've seen this exact pattern implemented wrong more times than I can count - no validation, no error handling, forms that just silently fail and the business owner never finds out they've been missing leads for three months. A competent &lt;a href="https://mittaltechnologies.com/" rel="noopener noreferrer"&gt;website development company Ludhiana&lt;/a&gt; clients rely on will always build this defensively, not optimistically.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Technical SEO: The Part Nobody Asks About Until Traffic Drops&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I used to think SEO was someone else's job, a marketing thing that happened after I shipped the site. I was wrong, and I learned that the hard way on a project where rankings tanked post-launch because nobody had set up canonical tags correctly, and every page was quietly telling Google to index the homepage instead.&lt;br&gt;
A basic schema example I add to most business sites now, without being asked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "@context": "https://schema.org",
  "@type": "LocalBusiness",
  "name": "Business Name",
  "address": {
    "@type": "PostalAddress",
    "addressLocality": "Ludhiana",
    "addressRegion": "Punjab"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Small addition, real impact on how search engines understand the page. If you're evaluating &lt;a href="https://mittaltechnologies.com/" rel="noopener noreferrer"&gt;website development services in Ludhiana&lt;/a&gt;, ask specifically whether structured data and canonical tag hygiene are part of the base package or a separate line item. It shouldn't be treated as optional in 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Performance Optimization: The Unsexy Work That Actually Matters&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Nobody gets excited about lazy loading images or minifying CSS, but this is where a huge chunk of real developer time goes, especially post-launch. Core Web Vitals aren't just a Google checkbox; they genuinely affect whether people stick around or bounce after three seconds of a spinning loader.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;img src="hero.jpg" loading="lazy" width="800" height="600" alt="Product showcase"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That one attribute, &lt;code&gt;loading="lazy"&lt;/code&gt;, seems trivial. But multiply it across a site with forty images and you've meaningfully changed load time. I've had clients skeptical that "such a small thing" mattered, right up until their PageSpeed score jumped fifteen points and their mobile bounce rate dropped noticeably the following month.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Maintenance and Ongoing Support&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This is the part almost nobody budgets for properly, and it's the part that quietly determines whether a site is still functioning well two years from now. Security patches, plugin updates, broken link checks, backup systems, unglamorous, recurring work that prevents the 2 AM "the site is down" phone call.&lt;br&gt;
I always tell clients this directly: a &lt;a href="https://mittaltechnologies.com/" rel="noopener noreferrer"&gt;web developer Ludhiana&lt;/a&gt; businesses can actually rely on long-term isn't just the person who builds the site, it's the person still answering the phone eight months later when something breaks. That distinction matters more than most people realize before they've been burned once.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Consulting and Strategy, Which Is Honestly Half the Job&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A lot of the actual value I provide happens before I write a single line of code, figuring out what the client actually needs versus what they think they're asking for. Someone says, "I want an e-commerce site," and the real conversation is about their inventory size, their shipping logistics, their payment preferences, whether they even need full e-commerce or just a "contact to order" page with a product catalog.&lt;br&gt;
This is where experience in &lt;a href="https://mittaltechnologies.com/" rel="noopener noreferrer"&gt;web development in Ludhiana&lt;/a&gt; specifically starts to matter, because local business patterns, export documentation needs, GST invoicing quirks, regional payment gateway preferences, aren't things you learn from a generic tutorial. You learn them from doing the work here, repeatedly, and getting it wrong at least once.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;So, What Does a Developer Actually Do?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Design, build, secure, optimize, maintain, and occasionally talk a client out of a bad idea before it costs them money. It's less "typing" and more "solving problems that only reveal themselves once real users start clicking around." If you're hiring one, look for a &lt;a href="https://mittaltechnologies.com/" rel="noopener noreferrer"&gt;website developer in Ludhiana&lt;/a&gt; who talks about all six of these areas, not just the pretty frontend part. The invisible work is usually where the real value sits.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>frontend</category>
      <category>developers</category>
    </item>
    <item>
      <title>Next.js + Contentful vs Next.js + Sanity: A Real Performance Comparison</title>
      <dc:creator>Mittal Technologies</dc:creator>
      <pubDate>Mon, 20 Jul 2026 09:29:01 +0000</pubDate>
      <link>https://dev.to/mittal_technologies/nextjs-contentful-vs-nextjs-sanity-a-real-performance-comparison-2ebc</link>
      <guid>https://dev.to/mittal_technologies/nextjs-contentful-vs-nextjs-sanity-a-real-performance-comparison-2ebc</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiqgf3mcvd9snwg48949a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiqgf3mcvd9snwg48949a.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
Everyone recommends "just pick a headless CMS and pair it with Next.js" like it's a five-minute decision. It isn't. When our team was scoping a rebuild for a client who wanted faster page loads without losing editorial flexibility, we actually benchmarked Contentful and Sanity side by side instead of going with whatever had the shinier marketing site. As a &lt;a href="https://mittaltechnologies.com/service/development" rel="noopener noreferrer"&gt;website development company in Ludhiana&lt;/a&gt; that ships client projects on both stacks, here's what the numbers and the day-to-day developer experience actually looked like.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Setup&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;We built the same landing page and blog template twice — once pulling content from Contentful's REST/GraphQL API, once from Sanity's GROQ-powered API — both deployed on Next.js 14 with ISR enabled. Same hosting, same image optimization pipeline, same Lighthouse testing conditions. We wanted a genuinely fair comparison, which meant resisting the urge to over-optimize one stack more than the other just because it happened to be more familiar.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Contentful fetch example
const entries = await client.getEntries({
  content_type: 'blogPost',
  order: '-fields.publishDate',
  limit: 10
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Sanity fetch example using GROQ
const posts = await sanityClient.fetch(
  `*[_type == "post"] | order(publishDate desc)[0...10]`
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;What We Found on Speed&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Sanity's GROQ queries came back noticeably faster for nested, relational content — think blog posts with linked authors, categories, and related posts. Contentful handled flat content types just as well, but once we needed two or three levels of reference resolution, response times crept up unless we restructured the content model. Neither was "slow," to be clear — we're talking differences in the 100-300ms range, which matters for Core Web Vitals but won't make or break a small brochure site.&lt;/p&gt;

&lt;p&gt;Cache behavior differed too. Contentful's CDN-backed delivery API is reliably fast for read-heavy traffic once cached, but the first uncached request after a content update showed a small but measurable lag. Sanity's CDN caching behaved similarly, though its real-time preview mode occasionally introduced its own overhead during active editing sessions, which is worth knowing if your editorial team previews frequently before publishing.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Developer Experience Differences&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Sanity's Studio is code-based and highly customizable, which developers on our team preferred&lt;/li&gt;
&lt;li&gt;Contentful's editor UI is more polished out of the box for non-technical content teams&lt;/li&gt;
&lt;li&gt;GROQ has a steeper learning curve than Contentful's query language&lt;/li&gt;
&lt;li&gt;Contentful's free tier is more generous for small projects; Sanity's pricing scales differently at volume&lt;/li&gt;
&lt;li&gt;Webhooks and real-time preview worked more smoothly with Sanity in our testing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One thing that surprised us: image handling. Sanity's built-in image pipeline with hotspot cropping saved real development time compared to manually configuring Contentful's image API parameters. Small thing, but it adds up across a project with hundreds of images, especially when a client's content team is uploading new photography every week without a developer double-checking crop point.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Content Modeling Differences That Actually Matter&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Beyond raw speed, the two platforms encourage slightly different habits. Contentful's content type builder nudges you toward more rigid, form-like structures, which content editors generally find intuitive. Sanity's schema-as-code approach gives developers more control over validation and conditional fields, but it does mean content modeling becomes a developer task rather than something a content strategist can adjust independently. If your team wants editors to be able to add new fields without filing a dev ticket, that's a real consideration, not a minor one.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Cost at Scale&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Pricing structures diverge more than people expect once a project grows past a handful of content types. Contentful bills primarily around API calls and environments, which can get expensive quickly for high-traffic sites unless caching is well configured. Sanity's pricing leans more on dataset size and bandwidth, which tends to favor content-heavy sites with moderate traffic over traffic-heavy sites with lean content. Neither pricing model is a trap exactly, but both can surprise a client who scaled past their original estimate without revisiting the numbers, so we now build a rough cost projection into every proposal rather than leaving it as a line item nobody checks until the first real invoice arrives.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;When to Pick Which&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Contentful tends to make sense for larger marketing teams who want a familiar, low-friction editor and don't mind paying for that convenience. Sanity fits teams with developers comfortable customizing the editing environment and who need flexible, relational content modeling. We've built client projects on both, and honestly, neither is objectively "better" — it depends on team structure more than raw performance. If your content team is non-technical and change-averse, Contentful reduces friction. If your developers want control, Sanity gives them more of it.&lt;/p&gt;

&lt;p&gt;We put a version of this comparison into practice while rebuilding infrastructure for a client project, where content flexibility mattered more than editorial simplicity, so Sanity ended up being the right call for that particular build — the kind of judgment call a &lt;a href="https://mittaltechnologies.com/service/development" rel="noopener noreferrer"&gt;software company in Ludhiana&lt;/a&gt; makes on a project-by-project basis rather than defaulting to one platform every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What We'd Tell a Team Starting From Scratch&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Don't pick a CMS based on a blog post, including this one. Build a small prototype of your actual content model — not a generic blog template — in both platforms before committing budget to either. The differences that matter most tend to show up in your specific content relationships, not in generic benchmarks. If your team doesn't have the bandwidth to run that kind of trial, our &lt;a href="https://mittaltechnologies.com/service/development" rel="noopener noreferrer"&gt;website designing company in Ludhiana&lt;/a&gt; has done this exact exercise enough times to shortcut the process for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Wrapping Up&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Benchmark your own content structure before committing to either platform — generic comparisons like this one are a starting point, not a final answer. If you want a second opinion on your specific setup, our &lt;a href="https://mittaltechnologies.com/service/development" rel="noopener noreferrer"&gt;website developer in Ludhiana&lt;/a&gt; team has run this exact comparison for multiple client stacks and can walk through what fits yours. Reaching out to us directly is a faster route than another week of research.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Quick reference: fetching with revalidation in Next.js
export async function getStaticProps() {
  const data = await client.getEntries({ content_type: 'post' });
  return { props: { data }, revalidate: 60 };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>nextjs</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>storyblokchallenge</category>
    </item>
    <item>
      <title>MCP Explained for Web Developers</title>
      <dc:creator>Mittal Technologies</dc:creator>
      <pubDate>Thu, 16 Jul 2026 08:24:52 +0000</pubDate>
      <link>https://dev.to/mittal_technologies/mcp-explained-for-web-developers-47fh</link>
      <guid>https://dev.to/mittal_technologies/mcp-explained-for-web-developers-47fh</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbh08f86dw0kfkmza6bgp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbh08f86dw0kfkmza6bgp.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
I ignored MCP for longer than I should have because the acronym soup around AI tooling right now is genuinely exhausting, and I assumed it was another framework-shaped thing I'd need to relearn in six months. Then I actually built something with it over a weekend, a small internal tool connecting Claude to our project's data, and it clicked faster than I expected. If you're a web developer who's been putting this off the same way I did, here's the version of the explanation I wish someone had given me first.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;What MCP Actually Is&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Model Context Protocol is an open standard for connecting AI models to external tools and data sources in a consistent, predictable way, the kind of infrastructure a &lt;a href="https://mittaltechnologies.com/service/digitalmarketing" rel="noopener noreferrer"&gt;best digital marketing company in Ludhiana&lt;/a&gt; building AI-powered client tooling now has to think about too. Before MCP, every AI integration you built was custom, your own function-calling setup, your own auth handling, your own way of describing what the model could do. MCP standardizes that.&lt;/p&gt;

&lt;p&gt;Think of it roughly like this: if REST gave web developers a consistent way to expose data over HTTP, MCP gives AI applications a consistent way to expose tools and data to a model, regardless of which AI provider is calling it.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;The Core Pieces&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;An MCP setup has a few consistent parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MCP Server —&lt;/strong&gt; exposes tools, resources, and prompts that a model can use&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP Client —&lt;/strong&gt; the AI application (like Claude) that connects to one or more servers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tools —&lt;/strong&gt; functions the model can call, similar conceptually to API endpoints&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resources —&lt;/strong&gt; data the model can read, like files or database records&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transport —&lt;/strong&gt; how the client and server actually communicate, commonly over stdio locally or HTTP/SSE for remote servers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've built a REST API before, tools will feel familiar. If you've worked with GraphQL resolvers, resources will feel familiar too.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;A Minimal Example&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here's roughly what a basic MCP server tool definition looks like in practice:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";

const server = new McpServer({
  name: "project-tools",
  version: "1.0.0"
});

server.tool(
  "get_task_status",
  "Retrieve the current status of a project task by ID",
  { taskId: z.string() },
  async ({ taskId }) =&amp;gt; {
    const task = await db.tasks.findById(taskId);
    return {
      content: [{ type: "text", text: JSON.stringify(task) }]
    };
  }
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the whole shape of it. You define a tool, describe what it does in plain language (the model reads that description to decide when to use it), specify the expected input, and return a result. No custom prompt engineering to teach the model your API shape, no brittle regex parsing of model output to extract function calls.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why This Matters If You're Building AI Features&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Before MCP, adding a new data source to an AI feature usually meant a lot of repeated, provider-specific work, exactly the kind of overhead a &lt;a href="https://mittaltechnologies.com/service/digitalmarketing" rel="noopener noreferrer"&gt;digital marketing agency Ludhiana&lt;/a&gt; building custom automation tooling for clients wants to avoid:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Writing custom function definitions for whichever provider's function-calling format you were using&lt;/li&gt;
&lt;li&gt;Rebuilding that integration if you switched providers or supported multiple ones&lt;/li&gt;
&lt;li&gt;Handling auth and connection logic separately for every single integration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With MCP, you write the server once, and any MCP-compatible client can use it, without you rebuilding provider-specific glue code every time the AI landscape shifts, which right now is often.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;A Realistic Use Case&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Say you're building an internal tool where a team wants to ask Claude questions about your company's live inventory data instead of digging through a dashboard. Without MCP, you'd be writing custom prompt templates, stuffing inventory data into context, or a bespoke function-calling setup tied to one provider's API.&lt;br&gt;
With MCP, you'd expose a &lt;code&gt;search_inventory&lt;/code&gt; tool and an &lt;code&gt;inventory_item&lt;/code&gt; resource once. The model calls the tool when it needs live data, gets structured results back, and you're not rewriting integration logic every time you add a new AI feature to the product.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Where People Get Tripped Up Early On&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A few things caught me off guard the first time through, and they're worth knowing before you build anything a &lt;a href="https://mittaltechnologies.com/service/digitalmarketing" rel="noopener noreferrer"&gt;digital marketing in Ludhiana&lt;/a&gt; team might eventually depend on for reporting automation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tool descriptions matter more than you'd expect, since the model relies entirely on your description to decide when and how to call a tool. Vague descriptions produce vague tool usage.&lt;/li&gt;
&lt;li&gt;Error handling needs to be explicit in your return values, since the model can't infer a failure state from a thrown exception the way your app's error boundary would&lt;/li&gt;
&lt;li&gt;Local (stdio) vs remote (HTTP/SSE) transport changes your deployment story significantly, decide early which one your use case actually needs&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Should You Actually Use This Right Now&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If you're building AI features that need to reach live data or perform actions beyond generating text, probably yes. If you're doing straightforward prompt-and-response work with no external tool calls, MCP is overhead you don't need yet. It's a solution to the integration fragmentation problem specifically, not a replacement for basic API design.&lt;/p&gt;

&lt;p&gt;Teams building this kind of AI feature work into client projects, the sort of thing a &lt;a href="https://mittaltechnologies.com/service/digitalmarketing" rel="noopener noreferrer"&gt;best SEO company in Ludhiana&lt;/a&gt; offering broader digital services increasingly gets asked about, tend to treat MCP as infrastructure worth learning now rather than waiting until it's unavoidable.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;A Quick Look at Resources, Not Just Tools&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Tools get most of the attention in MCP writeups, but resources are worth understanding too, since they cover the "give the model read access to data" side rather than the "let the model do something" side:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server.resource(
  "project-tasks",
  "tasks://active",
  { description: "List of currently active project tasks" },
  async () =&amp;gt; {
    const tasks = await db.tasks.findActive();
    return {
      contents: [{
        uri: "tasks://active",
        mimeType: "application/json",
        text: JSON.stringify(tasks)
      }]
    };
  }
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The distinction matters in practice. Tools are for actions and computed results; resources are for exposing data the model can read directly. Mixing the two up early on is a common source of confusion. I initially tried to model everything as a tool, including things that were really just read access to static data, and ended up with a server that was harder to reason about than it needed to be. Once resources and tools are separated cleanly, the rest of the implementation tends to fall into place faster, and it's the sort of infrastructure work a &lt;a href="https://mittaltechnologies.com/service/digitalmarketing" rel="noopener noreferrer"&gt;SEO services in Ludhiana&lt;/a&gt; provider building internal automation would want to set up correctly from the start rather than refactored later.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>mcp</category>
      <category>javascript</category>
      <category>ai</category>
    </item>
    <item>
      <title>JavaScript SEO: Common Rendering Pitfalls (Learned the Hard Way)</title>
      <dc:creator>Mittal Technologies</dc:creator>
      <pubDate>Tue, 14 Jul 2026 11:31:07 +0000</pubDate>
      <link>https://dev.to/mittal_technologies/javascript-seo-common-rendering-pitfalls-learned-the-hard-way-36kc</link>
      <guid>https://dev.to/mittal_technologies/javascript-seo-common-rendering-pitfalls-learned-the-hard-way-36kc</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiq4bfke6y2bo07j09tq1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiq4bfke6y2bo07j09tq1.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
I once spent three days convinced Google was just "being slow" to index a client's newly rebuilt React site. Turned out Googlebot was rendering the page just fine, it just wasn't seeing the same content a user's browser saw, because a chunk of it loaded via a client-side fetch call that fired after an intersection observer triggered on scroll. A crawler doesn't scroll. That was a dumb, expensive lesson, and I've since learned it's an extremely common one.&lt;/p&gt;

&lt;p&gt;JavaScript SEO isn't really about SEO knowledge at all. It's about understanding what actually happens between your framework rendering content and a crawler trying to index it, and that gap is where most rendering pitfalls live.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;The Core Problem, Explained Simply&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Search engines (and increasingly, AI crawlers) need to see your final rendered HTML, not just your initial server response, a distinction that a &lt;a href="https://mittaltechnologies.com/service/digitalmarketing" rel="noopener noreferrer"&gt;SEO services in Ludhiana&lt;/a&gt; provider running technical audits checks before anything else. If your content depends on client-side JavaScript execution to appear, you're trusting the crawler to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Actually, execute your JS correctly&lt;/li&gt;
&lt;li&gt;Wait long enough for async operations to resolve&lt;/li&gt;
&lt;li&gt;Not hit a rendering budget limit before your content loads&lt;/li&gt;
&lt;li&gt;Handle whatever framework-specific quirks your app introduces&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Googlebot generally handles this reasonably well now. A lot of other crawlers, including several AI bots, are far less reliable at it.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Pitfall 1: Content Behind User Interaction&lt;/strong&gt;
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This pattern is a crawler trap&lt;/span&gt;
&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IntersectionObserver&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fetchContent&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;setContent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;);&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;If your important content only loads after a scroll event, a click, or a hover, most crawlers will never see it. I've caught this exact pattern hiding pricing tables, product descriptions, and entire FAQ sections from indexing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; load critical content on initial render and treat scroll-triggered loading as a progressive enhancement for below-the-fold, non-essential content only.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Pitfall 2: Relying Entirely on Client-Side Rendering&lt;/strong&gt;
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Client-only rendering leaves an empty shell for crawlers&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Content&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt; : &amp;lt;Loading /&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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;A crawler hitting this before the fetch resolves sees a loading spinner and not much else. Depending on rendering budget and timeout behavior, that might be all it ever indexes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Server-side rendering (SSR) or static generation solves this at the source&lt;/li&gt;
&lt;li&gt;If a full SSR migration isn't realistic, at minimum pre-render your highest-value pages&lt;/li&gt;
&lt;li&gt;Frameworks like Next.js, Nuxt, and SvelteKit handle this natively, it's usually a configuration problem, not a rewrite&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Pitfall 3: Broken or Missing Canonical Signals in SPAs&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Single-page apps handling routing client-side sometimes fail to update canonical tags, meta descriptions, and title tags per route. I've seen sites where every single route reported the same title tag because the meta update logic only ran on initial load, not on client-side navigation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Easy to miss: update meta tags on route change, not just mount&lt;/span&gt;
&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pageTitle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;updateMetaTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;description&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pageDescription&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// don't forget the dependency array&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Pitfall 4: Infinite Scroll Without Paginated Fallbacks&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Infinite scroll feels great for users. For crawlers, content past the initial load is often invisible unless you're providing an alternative path to it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add paginated URLs alongside infinite scroll (?page=2, ?page=3) even if most users never see them&lt;/li&gt;
&lt;li&gt;Link those paginated URLs somewhere crawlable, a sitemap entry or a visible "load more" link with a real href&lt;/li&gt;
&lt;li&gt;Test with JS disabled to see what actually persists without client-side execution&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Pitfall 5: Render Blocking on Slow Third-Party Scripts&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If your critical content waits on a third-party script (a personalization engine, an A/B testing tool, a chat widget's data layer) to finish before rendering, you're at the mercy of that script's reliability and speed inside a crawler's rendering budget, which is typically far less generous than a real browser's.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Audit what's actually blocking your main content render, not just what's blocking visual paint&lt;/li&gt;
&lt;li&gt;Move non-essential third-party scripts to load after critical content, not before&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How to Actually Test This&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use Google Search Console's URL Inspection tool and look at the rendered HTML, not just the fetched source&lt;/li&gt;
&lt;li&gt;Fetch your page with JavaScript disabled and manually diff it against what a real browser show&lt;/li&gt;
&lt;li&gt;Check server logs for crawler user-agents and confirm they're actually hitting your key routes, not just the homepage, the kind of check a &lt;a href="https://mittaltechnologies.com/service/digitalmarketing" rel="noopener noreferrer"&gt;digital marketing in Ludhiana&lt;/a&gt; team runs routinely as part of ongoing technical maintenance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This kind of technical audit is exactly the layer a &lt;a href="https://mittaltechnologies.com/service/digitalmarketing" rel="noopener noreferrer"&gt;best digital marketing company in Ludhiana&lt;/a&gt; usually runs before touching content strategy at all, since no amount of content work fixes a page, a crawler can't actually see.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What I'd Prioritize First&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If you're triaging a site with rendering issues and can't fix everything at once, this is the order I'd generally recommend, similar to how a &lt;a href="https://mittaltechnologies.com/service/digitalmarketing" rel="noopener noreferrer"&gt;best SEO company in Ludhiana&lt;/a&gt; would sequence a technical audit for a client under time pressure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fix content that's entirely hidden behind interaction first, since that's a hard zero for crawlability&lt;/li&gt;
&lt;li&gt;Move to SSR or pre-rendering for your highest-traffic-potential pages next&lt;/li&gt;
&lt;li&gt;Fix per-route meta tag updates, since this affects how every page gets represented in search results&lt;/li&gt;
&lt;li&gt;Address infinite scroll and third-party render blocking last, since these tend to be partial rather than total visibility losses&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;A Quick Diagnostic Script&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If you want to check any of this yourself without opening DevTools manually, here's a rough script for diffing rendered vs. raw HTML using Puppeteer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;puppeteer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;compareRendering&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rawHtml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newPage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;waitUntil&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;networkidle0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;renderedHtml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;content&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Raw HTML length:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rawHtml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rendered HTML length:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;renderedHtml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Difference:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;renderedHtml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;rawHtml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Anything wildly larger in rendered vs raw is content&lt;/span&gt;
  &lt;span class="c1"&gt;// that depends entirely on JS execution to appear&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;compareRendering&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://example.com/product-page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A large gap between raw and rendered length is a decent early signal that meaningful content is JS-dependent. It's not a substitute for checking Search Console's actual rendered HTML, but it's a fast local sanity check before you go digging deeper, and it's often the first diagnostic a &lt;a href="https://mittaltechnologies.com/service/digitalmarketing" rel="noopener noreferrer"&gt;digital marketing agency Ludhiana&lt;/a&gt; runs before touching anything else on a client audit.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>seo</category>
      <category>webdev</category>
      <category>performance</category>
    </item>
    <item>
      <title>Lessons We Learned Building a Production Flutter App</title>
      <dc:creator>Mittal Technologies</dc:creator>
      <pubDate>Thu, 09 Jul 2026 11:08:44 +0000</pubDate>
      <link>https://dev.to/mittal_technologies/lessons-we-learned-building-a-production-flutter-app-4mn8</link>
      <guid>https://dev.to/mittal_technologies/lessons-we-learned-building-a-production-flutter-app-4mn8</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwz3xf2z17lx3jchytfhu.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwz3xf2z17lx3jchytfhu.jpeg" alt=" " width="800" height="447"&gt;&lt;/a&gt;&lt;br&gt;
We shipped a Flutter app to production about eight months ago for a client in the logistics space, and I want to write down the stuff that actually bit us, because most "Flutter in production" posts I read beforehand were either marketing fluff or way too basic. This one's going to be messier and more specific, closer to what actually happened.&lt;/p&gt;

&lt;p&gt;Quick context: cross-platform requirement (iOS + Android), tight timeline, a small team of three, and a backend already built in Node.js that we had to integrate with, not design from scratch. That combination shaped a lot of the decisions below. On the client side, this was a &lt;a href="https://mittaltechnologies.com/" rel="noopener noreferrer"&gt;website development company Ludhiana&lt;/a&gt;, led engagement, with our team handling the Flutter build specifically while the client's existing web presence stayed with their original team.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;State Management: We Switched Mid-Project and It Was Worth It&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;We started with &lt;code&gt;Provider&lt;/code&gt; because it's what the docs push you toward early on, and honestly, it's fine for small apps. Once our widget tree got deeper and we had cross-screen state that needed to survive navigation (cart contents, auth state, a multi-step form), Provider started producing a lot of boilerplates and some annoying rebuild issues we couldn't cleanly debug.&lt;/p&gt;

&lt;p&gt;We migrated to Riverpod around week six. Painful in the short term, genuinely worth it by the end. The dependency injection is cleaner, testing providers in isolation is much easier, and we stopped fighting &lt;code&gt;context&lt;/code&gt;-based lookups breaking when widgets moved around in the tree.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;final cartProvider = StateNotifierProvider&amp;lt;CartNotifier, CartState&amp;gt;((ref) {
  return CartNotifier(ref.read(apiClientProvider));
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If I were starting fresh today, I'd just start with Riverpod (or Bloc if your team prefers a stricter pattern) and skip Provider entirely, unless the app is genuinely tiny and staying that way.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Platform Channels Are Where the Pain Lives&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Flutter's "write once" promise holds up well for UI. It holds up much less well the moment you need something platform-specific, in our case, a barcode scanner integration and background location updates for delivery tracking. We ended up writing native platform channel code for both, and this is where the estimate blew past what we'd budgeted.&lt;/p&gt;

&lt;p&gt;The barcode scanner especially, we tried three different Flutter plugins before landing on a combination of a maintained plugin plus custom native fallback code for a specific Android device model our client's driver actually used in the field. Turns out that device had a known camera focus bug that only showed up in production, never in our testing on newer phones. Lesson: test on the actual hardware your users have, not whatever's sitting in your office.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;static const platform = MethodChannel('com.example.app/scanner');

Future&amp;lt;String?&amp;gt; scanBarcode() async {
  try {
    final result = await platform.invokeMethod&amp;lt;String&amp;gt;('startScan');
    return result;
  } on PlatformException catch (e) {
    // handle scanner-specific failures here
    return null;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Build Times Got Bad, Then We Fixed Them&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;By month four, our CI build times had crept up to almost 20 minutes for a full iOS build, which killed our iteration speed. Most of it came from an over-bloated dependency list, we'd added packages for things we ended up building custom solutions for anyway and never removed the old dependencies. A dependency audit cut our pubspec down significantly and shaved several minutes off build time.&lt;/p&gt;

&lt;p&gt;We also moved to splitting our CI pipeline, so Android and iOS builds ran in parallel instead of sequentially, which sounds obvious in hindsight but wasn't how our pipeline was originally set up. Small process fix, meaningful time saved across a team running multiple builds a day. It's a fix I'd now recommend to any &lt;a href="https://mittaltechnologies.com/" rel="noopener noreferrer"&gt;website developer in Ludhiana&lt;/a&gt; working on a mobile-and-web hybrid team, since the CI habits that work fine for a single web repo often don't scale cleanly once mobile builds get added into the same pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;API Integration and Error Handling Needed More Structure Than We Planned For&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This is the unglamorous part nobody talks about enough. Our backend team (working separately, coordinated through a &lt;a href="https://mittaltechnologies.com/" rel="noopener noreferrer"&gt;mobile app development in Ludhiana&lt;/a&gt; partnership on our side) had solid API docs, but real-world network conditions, spotty connectivity for delivery drivers moving between areas, exposed gaps in our error handling that our happy-path testing never caught.&lt;/p&gt;

&lt;p&gt;We ended up building a proper retry-with-backoff layer and a local queue for actions taken while offline, syncing once connectivity returned. Should have built this from day one instead of bolting it on in month five once drivers started reporting "lost" data that was actually just stuck in a failed request nobody retried.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Future&amp;lt;T&amp;gt; withRetry&amp;lt;T&amp;gt;(Future&amp;lt;T&amp;gt; Function() action, {int retries = 3}) async {
  for (int attempt = 0; attempt &amp;lt; retries; attempt++) {
    try {
      return await action();
    } catch (e) {
      if (attempt == retries - 1) rethrow;
      await Future.delayed(Duration(seconds: pow(2, attempt).toInt()));
    }
  }
  throw Exception('Retry logic failed unexpectedly');
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Testing Discipline Slipped Under Deadline Pressure, and We Paid For It&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;We had decent widget test coverage early on. Then the deadline got tighter, and testing was the first thing that got quietly deprioritized, which is a classic mistake, and we knew it was a classic mistake even while doing it. Two production bugs that shipped in month six would have been caught by tests we didn't have time to write. Not catastrophic, but embarrassing, and it cost more time to hotfix than it would have taken to just write the tests properly the first time.&lt;/p&gt;

&lt;p&gt;If you're working with an &lt;a href="https://mittaltechnologies.com/" rel="noopener noreferrer"&gt;app developer Ludhiana&lt;/a&gt; team or any external partner on a Flutter project, it's worth setting a hard rule upfront about minimum test coverage for anything touching payments, auth, or offline sync, the categories where bugs are expensive rather than just annoying.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What I'd Actually Do Differently Next Time&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Start with Riverpod, not Provider. Budget real time for platform channel work if there's any hardware integration at all, don't assume a plugin will "just work" on every device. Set up parallel CI builds from day one. And don't let testing slip just because the deadline is tight; it always costs more time later than it saves now.&lt;/p&gt;

&lt;p&gt;Flutter's genuinely good for cross-platform work when the app is UI-heavy and doesn't need deep hardware integration. The moment hardware or background processes get involved, budget extra time and extra patience, because that's where the framework's abstractions start leaking.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>mobile</category>
      <category>architecture</category>
    </item>
    <item>
      <title>I Logged Every AI Suggestion During a Two-Week Client Project. These Were Actually Useful.</title>
      <dc:creator>Mittal Technologies</dc:creator>
      <pubDate>Wed, 08 Jul 2026 06:36:41 +0000</pubDate>
      <link>https://dev.to/mittal_technologies/i-logged-every-ai-suggestion-during-a-two-week-client-project-these-were-actually-useful-1nnj</link>
      <guid>https://dev.to/mittal_technologies/i-logged-every-ai-suggestion-during-a-two-week-client-project-these-were-actually-useful-1nnj</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg0zs7f4au7r847y1ocv1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg0zs7f4au7r847y1ocv1.png" alt=" " width="800" height="447"&gt;&lt;/a&gt;&lt;br&gt;
I got tired of the extremes in this conversation. Half of Twitter acts like AI coding assistants are replacing developers by Friday. The other half insists it's all hallucinated garbage that wastes more time than it saves. So, on a two-week client project last month, I logged every AI suggestion I actually used, rejected, or modified, and the results were a lot more boring and more useful than either camp would have you believe.&lt;/p&gt;

&lt;p&gt;Context first: this was a mid-sized e-commerce platform rebuild, React frontend, Node backend, fairly standard stack. I kept a running note file next to my editor, tagging every suggestion as accepted-as-is, accepted-with-edits, or rejected, along with a one-line reason why. Not scientific, but honest.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;What Actually Turned Out Useful in Two Weeks of Real Work&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Boilerplate and repetitive patterns were where AI suggestions earned their keep, no contest. Writing the fifth nearly identical form validation schema of the week, the AI correctly guessed the pattern from the first four and saved genuine typing time. Same with test scaffolding, given an existing test file's structure, it reliably generated new test cases following the same conventions, which I then filled in with actual assertions. Not glamorous, but it added up to real hours saved across two weeks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// AI correctly inferred this pattern after seeing 3 similar schemas
const productSchema = z.object({
  name: z.string().min(1).max(200),
  price: z.number().positive(),
  sku: z.string().regex(/^[A-Z0-9-]+$/),
  inventory: z.number().int().nonnegative()
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It was also genuinely good at explaining unfamiliar error messages and stack traces from libraries I didn't know well. One dependency threw a cryptic error about a circular reference during serialization, and instead of digging through GitHub issues for twenty minutes, I pasted the trace and got a plausible explanation in seconds, which turned out to be correct once I verified it against the library's source.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Where It Actively Wasted My Time&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Business logic specific to this client's inventory rules was where things fell apart. The platform had a genuinely unusual rule, certain product bundles needed inventory decremented from a shared pool, but only during specific promotional windows, with a fallback to individual inventory tracking otherwise. Every suggestion confidently implemented the common, generic version of bundle inventory logic, which was wrong for this client's actual business rule. It wasn't a bad suggestion in a vacuum. It was a wrong suggestion delivered with total confidence, which is a worse failure mode than an obviously broken suggestion, because it takes longer to notice the mistake.&lt;/p&gt;

&lt;p&gt;I also burned time on suggestions for the payment integration that looked plausible but referenced API methods that didn't exist in the version of the SDK we were actually using. This is the failure mode I trust least, code that reads perfectly reasonably, compiles-looking syntax, references a method name that sounds exactly like something that should exist, and simply isn't real. Caught it because I actually ran the code rather than trusting it on sight, which is the only defense against this particular problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Middle Ground: Accepted With Real Edits&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This was the largest category by volume, honestly. Suggestions that got the shape of the solution right but needed real correction, wrong edge case handling, missing null checks, or a reasonable approach that just didn't account for something specific to this codebase's existing patterns. A good chunk of the API route handlers fell here: the AI correctly guessed our error-handling middleware pattern from context but consistently missed one specific logging call our team always includes for audit purposes on write operations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// AI got the structure right, missed our team's audit logging convention
async function updateInventory(req, res) {
  try {
    const result = await inventoryService.update(req.body);
    auditLog.record('inventory.update', req.user.id, result); // had to add this manually every time
    res.json(result);
  } catch (err) {
    next(err);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That pattern, right shape, missing the project-specific convention, was the single most common thing I logged across the two weeks. It's not a knock against the tooling. It just means these tools are pattern-matching against general conventions, not your specific team's unwritten rules, and there's no shortcut around teaching it those rules through context or just doing the edit yourself.&lt;br&gt;
The same held true on the frontend side. Teams doing &lt;a href="https://mittaltechnologies.com/" rel="noopener noreferrer"&gt;web design in Ludhiana&lt;/a&gt; work know component structure often follows a designer's specific system, not a generic pattern, and AI suggestions for UI components consistently defaulted to the most common layout convention instead of the client's actual design tokens, which had to be corrected by hand every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What I'd Actually Tell a Client About This&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Clients ask us about this constantly now, usually some version of "should we worry about AI replacing our dev team, or should we be using it more aggressively." Working on client projects through &lt;a href="https://mittaltechnologies.com/" rel="noopener noreferrer"&gt;web development in Ludhiana&lt;/a&gt; engagements, my honest answer is that it's a genuinely useful multiplier on the boring 60% of a project, boilerplate, test scaffolding, explaining unfamiliar errors and actively risky on the specific 40% that makes a client's business unique. The two-week log basically confirmed that split numerically instead of just as a vibe.&lt;/p&gt;

&lt;p&gt;If your team is evaluating whether a &lt;a href="https://mittaltechnologies.com/" rel="noopener noreferrer"&gt;website development company Ludhiana&lt;/a&gt; business relies on using these tools responsibly, the actual question to ask isn't "do you use AI." It's "how do you catch the confidently wrong suggestions before they ship." That's the part that actually matters, and it's the part most teams don't have a real answer for yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Discipline That Actually Made This Useful&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;None of this worked well without actually running the code and reading it critically, every single time, no exceptions even for suggestions that looked obviously fine. The moment I got lazy about that, twice, that I caught, was exactly when a subtly wrong suggestion slipped through toward a commit before I caught it in review. Both times it was the "sounds right, isn't real" failure mode, not a logic error, which is genuinely the harder one to catch by just reading code.&lt;/p&gt;

&lt;p&gt;Any &lt;a href="https://mittaltechnologies.com/" rel="noopener noreferrer"&gt;web developer Ludhiana&lt;/a&gt; working with these tools daily should build this same habit, log it if you can, but at minimum, treat every suggestion as a draft from a very fast, very confident junior developer who's read a lot of code but doesn't know your specific codebase's history.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Final Tally&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Across two weeks: roughly a third accepted as-is, mostly boilerplate and scaffolding. A little under half accepted with real edits, mostly missing project-specific conventions. The rest rejected outright, split fairly evenly between wrong business logic and hallucinated API references. Nothing dramatic. Nothing that confirms extreme take you'll find on social media.&lt;/p&gt;

&lt;p&gt;If you're a &lt;a href="https://mittaltechnologies.com/" rel="noopener noreferrer"&gt;website developer in Ludhiana&lt;/a&gt; or anywhere else deciding how much to lean on these tools, the honest answer from two weeks of actually counting is: a lot, for the boring stuff, and cautiously, with your own eyes on every line, for anything that touches the specific reason a client hired you instead of a template. &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>From Localhost to Production: A Developer's Website Hardening Checklist for 2026</title>
      <dc:creator>Mittal Technologies</dc:creator>
      <pubDate>Tue, 07 Jul 2026 08:54:05 +0000</pubDate>
      <link>https://dev.to/mittal_technologies/from-localhost-to-production-a-developers-website-hardening-checklist-for-2026-a7h</link>
      <guid>https://dev.to/mittal_technologies/from-localhost-to-production-a-developers-website-hardening-checklist-for-2026-a7h</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1dzdot0q4bkpffkrmapj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1dzdot0q4bkpffkrmapj.png" alt=" " width="800" height="447"&gt;&lt;/a&gt;&lt;br&gt;
Every developer has that moment. You've been running the app on localhost for weeks, everything's fine, &lt;code&gt;.env&lt;/code&gt; files are loose, CORS is wide open because who cares, it's just you and your terminal. Then deploy day comes and suddenly all that comfortable looseness becomes a liability. This developer's website hardening checklist for 2026 is basically the list we run through every single time before flipping something from dev mode to production, because muscle memory alone isn't enough anymore.&lt;/p&gt;

&lt;p&gt;I say this as someone who's shipped that exact &lt;code&gt;.env&lt;/code&gt; file to a public repo before. Once. Never again but once was enough to build this checklist out properly instead of trusting memory.&lt;/p&gt;

&lt;p&gt;For context, this list comes out of running deploys for a &lt;a href="https://mittaltechnologies.com/" rel="noopener noreferrer"&gt;website development company Ludhiana&lt;/a&gt; clients hire specifically because we treat this stuff as process, not vibes. Doesn't matter how experienced the individual dev is, checklists catch what tired brains miss at 2 AM before a launch.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Environment Variables: The Boring Check That Saves You&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;First thing, always: grep your entire codebase for anything that looks like a secret before you even think about deploying.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;grep -rn "API_KEY\|SECRET\|PASSWORD\|TOKEN" --include="*.js" --include="*.ts" .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This catches the obvious stuff, but the sneakier problem in 2026 is framework specific. If you're on Next.js, double-check that anything without the &lt;code&gt;NEXT_PUBLIC_&lt;/code&gt; prefix genuinely isn't referenced anywhere in client-side code. It's an easy mistake to make when you're refactoring fast and forget which file runs where.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// This leaks to the browser bundle if used client-side
const dbPassword = process.env.DB_PASSWORD; // fine in API routes, disaster in components

// This is the safe pattern for anything the client legitimately needs
const publicKey = process.env.NEXT_PUBLIC_API_KEY;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;CORS: Localhost Habits Don't Survive Production&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;On localhost, it's tempting to just slap &lt;code&gt;Access-Control-Allow-Origin: *&lt;/code&gt; on everything and move on with building features. That habit needs to die before deploy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Localhost comfort, production liability
app.use(cors({ origin: "*" }));

// What should actually ship
app.use(cors({
  origin: process.env.NODE_ENV === "production"
    ? ["https://yourdomain.com"]
    : ["http://localhost:3000"],
  credentials: true
}));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've seen this exact wildcard survive into production more times than I'd like to admit, usually because it got set during early testing and nobody circled back to tighten it. It's worth adding a pre-deploy grep for this pattern specifically.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Rate Limiting Isn't Optional Anymore&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This one didn't used to make every checklist, but with AI-driven scraping and credential stuffing attempts up significantly this year, it's non-negotiable now. Even a basic implementation goes a long way.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import rateLimit from "express-rate-limit";

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 100,
  message: "Too many requests, slow down."
});

app.use("/api/", limiter);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pair this with stricter limits specifically on auth routes, since login endpoints are the most common target for automated attempts.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Database Query Safety: Still the Classic Mistake&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;SQL injection feels like a solved problem until you find it in a client's supposedly modern codebase. It usually hides in places nobody thought to check, like a search feature bolted on late in development.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Vulnerable, still shows up more than you'd expect
const query = `SELECT * FROM users WHERE email = '${userInput}'`;

// Parameterized, the way it should always be written
const query = "SELECT * FROM users WHERE email = $1";
db.query(query, [userInput]);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're on an ORM like Prisma or Drizzle, this risk drops significantly by default, but raw queries still creep in during performance optimization work, so it's worth a manual scan before shipping. Honestly, this is the kind of thing any decent &lt;a href="https://mittaltechnologies.com/" rel="noopener noreferrer"&gt;web developer Ludhiana&lt;/a&gt; team should be scanning for reflexively, ORM or not.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Authentication Token Storage&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Storing JWTs in localStorage is convenient and also a genuinely bad idea for anything handling sensitive data. It's vulnerable to XSS in ways httpOnly cookies simply aren't.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Convenient but vulnerable to XSS token theft
localStorage.setItem("token", jwt);

// Safer approach
res.cookie("token", jwt, {
  httpOnly: true,
  secure: true,
  sameSite: "strict"
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I get why localStorage is tempting, it's simpler to work with in a lot of frontend setups. It's just not worth the tradeoff once real user data is involved.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Headers You're Probably Missing&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Security headers are cheap to add and genuinely useful. This is one of those checks that takes five minutes and prevents entire categories of attack.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.use((req, res, next) =&amp;gt; {
  res.setHeader("X-Content-Type-Options", "nosniff");
  res.setHeader("X-Frame-Options", "DENY");
  res.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
  next();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're on Next.js, this can go in &lt;code&gt;next.config.js&lt;/code&gt; instead, which is cleaner and easier to maintain across the whole app. A clean, well-structured &lt;a href="https://mittaltechnologies.com/" rel="noopener noreferrer"&gt;web design in Ludhiana&lt;/a&gt; teams often build from scratch tends to make this kind of config easier to audit too, versus a messy patchwork of inherited templates and plugins.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Dependency Audit Before Every Deploy&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Run this before every production push, not just occasionally.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm audit --production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fix what's flagged as high or critical severity at minimum. It's tedious, sure, but outdated dependencies are consistently one of the top causes of breaches we've had to clean up after the fact. This kind of gap is exactly what a proper &lt;a href="https://mittaltechnologies.com/" rel="noopener noreferrer"&gt;cybersecurity audit&lt;/a&gt; should catch if your own process misses it.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Working With Someone Outside Your Own Codebase&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Even with a solid personal checklist, there's real value in bringing in outside review before anything customer-facing goes live. It's not about the code being bad, it's about blind spots that come from staring at the same codebase for weeks straight. A second review from a &lt;a href="https://mittaltechnologies.com/" rel="noopener noreferrer"&gt;cyber security company in Ludhiana&lt;/a&gt; or wherever your team's based tends to catch the stuff you've genuinely stopped seeing.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Final Thought&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;None of this is exciting work. It's grep commands and header configs and double-checking things you're pretty sure you already did right. But localhost forgives sloppiness in ways production never does, and the gap between "works on my machine" and "safe in production" is exactly where these checks live.&lt;br&gt;
Ship carefully. The bots are definitely watching your DNS propagate.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>devops</category>
      <category>programming</category>
    </item>
    <item>
      <title>I Ran a 2026 Security Audit on a Fresh WordPress + WooCommerce Site: Here's Everything That Broke</title>
      <dc:creator>Mittal Technologies</dc:creator>
      <pubDate>Mon, 06 Jul 2026 09:22:26 +0000</pubDate>
      <link>https://dev.to/mittal_technologies/i-ran-a-2026-security-audit-on-a-fresh-wordpress-woocommerce-site-heres-everything-that-broke-b90</link>
      <guid>https://dev.to/mittal_technologies/i-ran-a-2026-security-audit-on-a-fresh-wordpress-woocommerce-site-heres-everything-that-broke-b90</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1vochvrqd6e9dg4ri7cy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1vochvrqd6e9dg4ri7cy.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
I spun up a brand new WordPress install last week, added WooCommerce, a handful of the most commonly recommended plugins, and did basically nothing custom. No weird theme hacks, no sketchy nulled plugins, just a standard setup like thousands of small businesses launch every single day. Then I ran a full 2026 security audit on this fresh WordPress and WooCommerce site, expecting maybe two or three minor flags.&lt;br&gt;
I found eleven issues. On a site that was, by all appearances, doing everything "right."&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Setting Up the Baseline&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Stack was simple: WordPress core (latest version), WooCommerce, a popular free theme, and five plugins covering SEO, caching, contact forms, backups, and a security plugin because irony demanded it. Fresh install, no content beyond placeholder products, default settings left mostly untouched, basically the exact starting point a new client site looks like on day one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wp core version
# 6.8.1

wp plugin list --status=active
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I ran the audit using a mix of manual checks and automated scanning, then verified anything the scanner flagged by hand before trusting it.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Issue 1: Default Login URL, No Rate Limiting&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The obvious one, but still worth stating plainly: &lt;code&gt;/wp-login.php&lt;/code&gt; was wide open with zero rate limiting on failed attempts. I simulated repeated login attempts and got no lockout, no CAPTCHA trigger, nothing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for i in {1..20}; do
  curl -s -X POST https://freshsite.test/wp-login.php \
    -d "log=admin&amp;amp;pwd=wrongpass$i" -o /dev/null -w "%{http_code}\n"
done
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All twenty attempts returned 200. On a live site, that's an open invitation for credential stuffing.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Issue 2: WooCommerce REST API Exposing More Than It Should&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This one surprised me more than it probably should have. The WooCommerce REST API, even without generated keys, leaked product and category data through publicly accessible endpoints that weren't properly scoped.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl https://freshsite.test/wp-json/wc/store/v1/products
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Returned full product listings including internal SKUs, which isn't catastrophic on its own, but it's the kind of data leak that becomes ubiquitous across default WooCommerce installs simply because almost nobody checks REST API scope during setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Issue 3: XML-RPC Still Enabled by Default&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I genuinely thought this had mostly died out as a concern, but XML-RPC was active and responding, which still gets used for brute-force amplification attacks via &lt;code&gt;system.multicall&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X POST https://freshsite.test/xmlrpc.php \
  -d '&amp;lt;?xml version="1.0"?&amp;gt;&amp;lt;methodCall&amp;gt;&amp;lt;methodName&amp;gt;system.listMethods&amp;lt;/methodName&amp;gt;&amp;lt;/methodCall&amp;gt;'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Got a full method list back, no restrictions. Disabling this outright, unless something specifically depends on it, is basically free security.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Issue 4: File Permissions Looser Than They Should Be&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Default install left &lt;code&gt;wp-config.php&lt;/code&gt; at 644 permissions instead of the tighter 600 recommended for anything holding database credentials.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ls -la wp-config.php
# -rw-r--r-- 1 www-data www-data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not a critical flaw by itself, but combined with any other vulnerability giving read access to the filesystem, this turns into a much bigger problem fast. Small fix, meaningful risk reduction.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Issue 5 Through 8: The Plugin Pile-Up&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This is where things got genuinely uncomfortable. Two of the five plugins had unpatched vulnerabilities listed in public CVE databases from earlier in the year, both still showing as "up to date" according to the plugin's own version number, because the vulnerability was in a version range that technically wasn't the newest release yet, just recent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wp plugin list --update=available
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is exactly the kind of gap a scheduled &lt;a href="https://mittaltechnologies.com/" rel="noopener noreferrer"&gt;cybersecurity audit&lt;/a&gt; catches that a one-time setup check never will, since plugin vulnerabilities get disclosed on an ongoing basis, not in a single batch.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Issue 9: Checkout Page Missing Additional Transport Security&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;SSL was active, which is table stakes at this point, but the checkout page wasn't setting HSTS headers, meaning a user's first visit over HTTP before any redirect could theoretically be intercepted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.use((req, res, next) =&amp;gt; {
  res.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
  next();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;WordPress doesn't handle this by default, it needs to be added at the server config level, which is easy to forget on a standard shared hosting setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Issue 10 and 11: Admin Account Sprawl and Weak Password Policy&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The install had two admin accounts left over from the setup process, one of which was a leftover default account nobody had bothered removing. Password policy was also essentially nonexistent, accepting anything over six characters with no complexity requirement.&lt;/p&gt;

&lt;p&gt;This is honestly the most common finding across every WordPress site I've personally audited, fresh or otherwise. Access control keeps losing to convenience, every single time, on every kind of project.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What This Means If You're Launching WooCommerce in 2026&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;None of these eleven issues were exotic. Nothing here required advanced exploitation skills, just patience and a checklist. That's honestly the scary part. A fresh, "default" WordPress and WooCommerce site, set up by someone following standard documentation, ships with real exposure baked in from day one.&lt;/p&gt;

&lt;p&gt;If you're running an online store, this is exactly the kind of gap that gets caught by pairing development with a proper &lt;a href="https://mittaltechnologies.com/" rel="noopener noreferrer"&gt;cyber security company in Ludhiana&lt;/a&gt; or equivalent, someone whose entire job is watching for exactly this stuff rather than treating it as a one-time launch checkbox. A &lt;a href="https://mittaltechnologies.com/" rel="noopener noreferrer"&gt;website development company Ludhiana&lt;/a&gt; businesses actually trust for ongoing WooCommerce projects should be running audits like this as standard practice, not as an upsell.&lt;/p&gt;

&lt;p&gt;I'll be re-running this same audit on the same install again in three months just to see how much drifts back open on its own. My guess is at least half of it.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>woocommerce</category>
      <category>webdev</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>How I Reduced API Response Times by 70% Without Changing My Database</title>
      <dc:creator>Mittal Technologies</dc:creator>
      <pubDate>Thu, 02 Jul 2026 08:13:10 +0000</pubDate>
      <link>https://dev.to/mittal_technologies/how-i-reduced-api-response-times-by-70-without-changing-my-database-56cl</link>
      <guid>https://dev.to/mittal_technologies/how-i-reduced-api-response-times-by-70-without-changing-my-database-56cl</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzvc52bosjkv4wdhqueal.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzvc52bosjkv4wdhqueal.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
So, a few months back I got handed a legacy Node.js API that was averaging around 1.4 seconds per request on some of our heavier endpoints. Users were complaining, the frontend team was slapping loading spinners on everything to hide the pain, and the initial instinct from pretty much everyone, including me if I'm honest, was "we need to migrate the database." We didn't. Got the average down to around 420ms without touching the schema or swapping the database engine at all. Writing this up because I think a lot of teams jump to the expensive fix before ruling out the cheap ones.&lt;/p&gt;

&lt;p&gt;Quick context: this was an order management API for a mid-sized e-commerce client, built maybe four years ago, handed off between a couple of different dev teams over that time, the usual story. Nobody fully owned it anymore. That's often exactly the kind of codebase where these problems hide in plain sight.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Step one, actually profile instead of guessing&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Everyone has a theory about what's slow before they've looked at any numbers. I did too, honestly, my first guess was the database. So, I stopped guessing and started measuring. Threw some &lt;code&gt;console.time&lt;/code&gt; blocks through the request lifecycle initially just to get a rough shape of where time was going, then moved to proper APM tracing once I had a hypothesis worth confirming.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.time('db-query');
const result = await db.query(sql, params);
console.timeEnd('db-query');

console.time('serialization');
const payload = serializeResponse(result);
console.timeEnd('serialization');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Turns out the database query itself was taking maybe 80-120ms. Not amazing, but nowhere near the villain everyone assumed it was. The real time sink was everywhere else, N+1 queries hiding inside a "single" endpoint call, redundant serialization work, and basically zero caching on data that barely changes minute to minute.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Fix 1: killed the N+1 queries with proper eager loading&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This was the biggest single win by a wide margin. The endpoint was fetching a list of orders, then looping through and firing off a separate query for each order's line items. Classic N+1, and with pagination set to 50 items per page, that's 51 sequential round trips to the database for what should've been one API call.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// before - N+1 disaster
const orders = await Order.findAll();
for (const order of orders) {
  order.items = await OrderItem.findAll({ where: { orderId: order.id } });
}

// after - single query with join
const orders = await Order.findAll({
  include: [{ model: OrderItem, as: 'items' }]
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This one change alone cut response time nearly in half on the heaviest endpoint. I know N+1 queries are a well-worn topic in performance write-ups, almost a cliché at this point, but I keep finding them in production codebases anyway, so clearly the lesson hasn't fully landed industry-wide.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Fix 2: added a caching layer for data that doesn't need to be real-time&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A decent chunk of the response payload was product metadata, stuff that updates maybe once a day if that. There was no good reason to hit the database for it on every single request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const CACHE_TTL = 300; // 5 minutes

async function getProductMetadata(productId) {
  const cached = await redis.get(`product:${productId}`);
  if (cached) return JSON.parse(cached);

  const data = await Product.findByPk(productId);
  await redis.set(`product:${productId}`, JSON.stringify(data), 'EX', CACHE_TTL);
  return data;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple, almost boringly so, but it removed a huge amount of repeated, unnecessary work from the hot path.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Fix 3: trimmed the response payload to what the frontend actually uses&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Turned out the API was returning full ORM objects with dozens of fields the frontend never touched, half of them internal flags nobody remembered adding. Serializing all of that, especially nested relations, was adding measurable overhead on every single request. Switched to explicit response DTOs instead of just dumping the model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function toOrderResponse(order) {
  return {
    id: order.id,
    status: order.status,
    total: order.total,
    items: order.items.map(i =&amp;gt; ({ name: i.name, qty: i.qty, price: i.price }))
  };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Smaller payloads, faster serialization, faster network transfer on top of that. All three add up more than people expect, especially on mobile connections.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Fix 4: connection pooling had been misconfigured the whole time&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Found the pool size still sitting at the driver's default, way too low for our actual concurrent load. Requests were literally queuing for a free connection during traffic spikes, which doesn't show up clearly when you're profiling a single isolated request, only under real concurrent load.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const pool = new Pool({
  max: 25, // was defaulting to 10
  idleTimeoutMillis: 30000,
  connectionTimeoutMillis: 2000
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the kind of thing that's easy to overlook because it hides behind the symptoms rather than causing an obvious error.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What I'd tell anyone facing a similar problem&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Profile before you assume anything. Everyone's first instinct is to blame the database, and sometimes it genuinely is the culprit, but more often it's the code sitting around the query that's the real problem, redundant calls, missing caching, bloated payloads, connection handling nobody's revisited in years. A full database migration is expensive, risky, and honestly avoidable more often than teams think, especially when nobody's bothered to profile first.&lt;/p&gt;

&lt;p&gt;If you're maintaining an older system and running into similar complaints, it's worth getting a second, less attached set of eyes on it before committing to a rewrite. This kind of performance audit is something we do fairly often at &lt;a href="https://mittaltechnologies.com/" rel="noopener noreferrer"&gt;Mittal Technologies&lt;/a&gt;, working alongside teams that just need someone to actually trace the problem rather than guess at it. If there's a genuine architectural issue underneath, that's usually where a proper &lt;a href="https://mittaltechnologies.com/" rel="noopener noreferrer"&gt;software development company in Ludhiana&lt;/a&gt; earns its keep, digging into the parts nobody's had time to revisit.&lt;/p&gt;

&lt;p&gt;A lot of legacy codebases end up desultory in their architecture, not through any single bad decision, but through years of different hands touching the same system with no shared plan. That's usually where these performance issues quietly accumulate.&lt;/p&gt;

&lt;p&gt;If you're working on something similar and want a structured audit rather than a guess-and-check approach, teams doing &lt;a href="https://mittaltechnologies.com/" rel="noopener noreferrer"&gt;custom software development in Ludhiana&lt;/a&gt; tend to have this exact profiling-first workflow baked into how they approach legacy handoffs, which honestly saves a lot of wasted migration effort down the line.&lt;/p&gt;

&lt;p&gt;Curious if others have run into similar N+1 traps hiding inside seemingly simple endpoints, or connection pool defaults that nobody thought to touch. Feel free to drop your own war stories in the comments, I always enjoy hearing where these things hide in other people's codebases.&lt;/p&gt;

</description>
      <category>node</category>
      <category>performance</category>
      <category>webdev</category>
      <category>backend</category>
    </item>
  </channel>
</rss>
