<?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: TheBitForge</title>
    <description>The latest articles on DEV Community by TheBitForge (@thebitforge).</description>
    <link>https://dev.to/thebitforge</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%2F3581035%2F7a4e3e11-052c-4b61-9f45-e3f421e69147.png</url>
      <title>DEV Community: TheBitForge</title>
      <link>https://dev.to/thebitforge</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thebitforge"/>
    <language>en</language>
    <item>
      <title>Are We Becoming Better Developers, or Just Faster at Producing Code?</title>
      <dc:creator>TheBitForge</dc:creator>
      <pubDate>Sat, 17 Oct 2026 10:43:36 +0000</pubDate>
      <link>https://dev.to/thebitforge/are-we-becoming-better-developers-or-just-faster-at-producing-code-h4b</link>
      <guid>https://dev.to/thebitforge/are-we-becoming-better-developers-or-just-faster-at-producing-code-h4b</guid>
      <description>&lt;p&gt;Friday afternoon. A ticket lands in your queue: new endpoint, some validation, a small migration. The kind of task that used to eat half your day.&lt;/p&gt;

&lt;p&gt;You describe it to your AI assistant, skim the diff, run the tests, ship it. Twenty minutes, done.&lt;/p&gt;

&lt;p&gt;Three months later that endpoint breaks under some load pattern nobody planned for. You open the file and you don't quite recognize it. You wrote it, technically. You accepted it, tested it, merged it. But you never built a real model of how it works, because the part that would have forced you to think it through got handled for you.&lt;/p&gt;

&lt;p&gt;That raises a question: if AI writes more of our code, are we still learning how that code actually works, or just getting faster at shipping things we don't fully understand?&lt;/p&gt;

&lt;h2&gt;
  
  
  The productivity studies don't agree, and the disagreement is the useful part
&lt;/h2&gt;

&lt;p&gt;In 2023, Microsoft, GitHub, and MIT Sloan ran a &lt;a href="https://arxiv.org/abs/2302.06590" rel="noopener noreferrer"&gt;randomized trial&lt;/a&gt; where developers wrote a standardized HTTP server in JavaScript. The Copilot group finished 55.8% faster, and more of them finished at all, 78% versus 70%, though that completion-rate gap wasn't statistically significant on its own. It measured speed on a fairly contained task, not whether the resulting code held up over time.&lt;/p&gt;

&lt;p&gt;Two years later, &lt;a href="https://arxiv.org/abs/2507.09089" rel="noopener noreferrer"&gt;METR&lt;/a&gt; tested something closer to real engineering work. They recruited sixteen experienced open source developers and watched them complete 246 tasks in their own large, familiar repositories, some with AI access and some without. The result ran the other direction: developers using AI took 19% longer. Before starting, they'd predicted AI would speed them up. Afterward, they still believed it had, estimating a roughly 20% improvement that the data didn't support.&lt;/p&gt;

&lt;p&gt;At first glance these look contradictory. But the studies tested different kinds of work. A contained task with an unfamiliar tool is where AI assistance tends to show up well. A codebase someone already carries in their head, built over years, is a much harder place for a generic tool to add value, and an easier place for review and correction overhead to eat whatever time it saves. The studies tell us something different about productivity in different settings. METR's result is the one worth sitting with: developers expected AI to save them time, and the measured result went the other way.&lt;/p&gt;

&lt;h2&gt;
  
  
  The quiz that tested what developers actually learned
&lt;/h2&gt;

&lt;p&gt;A more direct test of the real question came from Anthropic, in a study of 52 developers, mostly junior, learning an unfamiliar Python library called Trio. One group had an AI assistant during the coding tasks. The other coded by hand. Afterward, everyone took the same quiz, no AI allowed, covering debugging, code reading, and conceptual understanding. It's a small study of people learning something new, not a representative sample of senior engineers working on production systems, but the results are worth examining.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.anthropic.com/research/AI-assistance-coding-skills" rel="noopener noreferrer"&gt;AI-assisted group averaged 50% on that quiz, versus 67% for the hand-coding group&lt;/a&gt;, a gap of 17 percentage points. The biggest difference between the groups showed up specifically on debugging questions. There's another important detail, though: the AI group only finished about two minutes faster on average, a difference too small to call statistically meaningful. They didn't even get much speed in exchange for the gap in understanding.&lt;/p&gt;

&lt;p&gt;Looking back at screen recordings, the researchers sorted participants into six observational patterns of how people actually used the assistant. Three patterns, built around handing the task over and accepting what came back, averaged under 40% on the quiz. Three other patterns, where people asked why something worked or requested explanations alongside the code, scored between 65% and 86%. The researchers are careful that this is a correlation found after the fact, not proof that a given pattern of use caused the score. Still, the association is hard to ignore: people who stayed cognitively engaged with the assistant tended to retain more than people who didn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  What shows up later, in actual codebases
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.gitclear.com/coding_on_copilot_data_shows_ais_downward_pressure_on_code_quality" rel="noopener noreferrer"&gt;GitClear&lt;/a&gt; analyzed roughly 153 million lines of changed code from 2020 through 2023 and projected that code churn, meaning lines reverted or rewritten within two weeks of being written, would roughly double by 2024 compared with its 2021 baseline. Copy-pasted code was also rising relative to properly refactored code. GitClear shows that churn increased during the years AI tools became common, but that doesn't prove AI caused it, and GitHub has pushed back publicly on that reading. One possible explanation is that developers are merging code before they've fully understood it, though the data alone can't establish that.&lt;/p&gt;

&lt;p&gt;On security specifically, &lt;a href="https://arxiv.org/abs/2211.03622" rel="noopener noreferrer"&gt;Stanford researchers&lt;/a&gt; found that developers with access to an AI coding assistant wrote measurably less secure code than a control group, and were more confident their code was secure. The tools have changed since that 2022 to 2023 experiment, so its results shouldn't be treated as a verdict on today's assistants. But it highlights a risk worth considering: developers can be confident in code they haven't fully evaluated.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://survey.stackoverflow.co/2025/" rel="noopener noreferrer"&gt;2025 Stack Overflow survey&lt;/a&gt;, built on more than 49,000 responses, found 84% of developers either using AI tools already or planning to, a figure that mixes current users with people who haven't started yet. Among respondents overall, 46% said they didn't trust the accuracy of AI output, up from 31% the year before, and 66% named "almost right, but not quite" answers as their top frustration with the tools. Of those who answered the frustrations question, 45% said debugging AI-generated code was more time-consuming than expected. That's self-reported experience, not a controlled measurement of actual debugging time, but it lines up with the other findings here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the tool genuinely helps
&lt;/h2&gt;

&lt;p&gt;The Copilot study's speed gains were real, and some people in the Anthropic study using the exact same tool on the exact same task learned just as much as the control group. AI tends to help most with the parts of the job that are mechanical once you already understand them: boilerplate, syntax you've half forgotten, turning a plan you've already worked out into code, explaining an unfamiliar error faster than a search engine would. It's also useful as a second opinion, something to push back against your own design before committing to it. None of this says AI damages learning by default. It says learning depends on what a developer does while the tool is open, not just whether it's open.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rate limiting: two ways to use AI
&lt;/h2&gt;

&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%2Fg688s4n5n5ddwozx8k8p.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%2Fg688s4n5n5ddwozx8k8p.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
Picture two developers given the same task: add rate limiting to an API with an AI assistant available to both. This is a made-up scenario to keep the point concrete, not a documented incident.&lt;/p&gt;

&lt;p&gt;The first developer asks for an implementation, gets a working solution using a sliding-window counter backed by Redis, confirms the tests pass, and ships it. Weeks later, under a burst of traffic, the Redis connection pool starts timing out. They're trying to understand the retry logic and connection-pool behavior while the service is degraded, without knowing whether the problem is in their implementation, their Redis configuration, or both.&lt;/p&gt;

&lt;p&gt;The second developer asks the same initial question, then follows up. Why this approach over an alternative. What happens if Redis briefly drops. They try implementing a small piece by hand first, compare it against what the assistant produced, and only merge once they can explain why the retry logic is structured the way it is. The task takes longer. When the same Redis issue shows up later, they already have a working model of the failure, because they built one on purpose while it was still possible to.&lt;/p&gt;

&lt;p&gt;Neither developer is permanently stuck this way. The first could still learn the retry logic properly before anything breaks, and plenty of developers do exactly that. What separates them isn't talent or diligence in some abstract sense. It's that one of them paid a small cost upfront, and the other is likely paying a larger one later, probably at a worse time.&lt;/p&gt;
&lt;h2&gt;
  
  
  A short list of things worth trying
&lt;/h2&gt;

&lt;p&gt;Sketch your own approach before asking the assistant for one, even roughly. Ask for the reasoning behind a suggestion, not only the code. Review generated code like you're the one debugging it alone later, because you probably will be. Write tests that check actual behavior rather than confirming a demo ran once. When something breaks, spend a few minutes forming your own guess before asking the AI to fix it. Try explaining a piece of merged code out loud before you consider the task finished. The Anthropic findings offer a reason to take these habits seriously: the people who asked questions and worked to understand the code generally scored better than those who just let AI do the work.&lt;/p&gt;
&lt;h2&gt;
  
  
  The real variable
&lt;/h2&gt;

&lt;p&gt;If AI saves you an hour, use some of that time to actually understand what it produced. If you just move to the next ticket, you might finish more work today without being any better prepared to debug it tomorrow.&lt;/p&gt;

&lt;p&gt;Pick one piece of AI-assisted code you shipped this month. Could you walk a teammate through why it's built the way it is, without reopening the chat?&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__user ltag__user__id__3581035"&gt;
    &lt;a href="/thebitforge" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=150,height=150,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3581035%2F7a4e3e11-052c-4b61-9f45-e3f421e69147.png" alt="thebitforge image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/thebitforge"&gt;TheBitForge&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/thebitforge"&gt;Founder @thebitforge.dev • Software &amp;amp; AI Product Agency • 172K+ readers &amp;amp; 5.8K+ followers • We turn ideas into digital products people 💙 to use | visit us also on insta @thebitforge.dev&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>ai</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>career</category>
    </item>
    <item>
      <title>DEV Community Doesn't Feel Like the Same Community Anymore</title>
      <dc:creator>TheBitForge</dc:creator>
      <pubDate>Fri, 16 Oct 2026 15:14:16 +0000</pubDate>
      <link>https://dev.to/thebitforge/dev-community-doesnt-feel-like-the-same-community-anymore-d60</link>
      <guid>https://dev.to/thebitforge/dev-community-doesnt-feel-like-the-same-community-anymore-d60</guid>
      <description>&lt;p&gt;I joined DEV Community in 2024, and honestly, it used to feel like a genuinely good place for developers.&lt;/p&gt;

&lt;p&gt;People published articles, readers discovered new writers, discussions happened, and even smaller creators had a chance to get noticed. It wasn't just about publishing content and hoping someone would find it. There was a real sense of community.&lt;/p&gt;

&lt;p&gt;Now, I'm not sure what has changed, but something definitely feels different.&lt;/p&gt;

&lt;p&gt;And I know I'm not the only person who feels this way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. DEV Support: Does It Actually Work?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's start with support.&lt;/p&gt;

&lt;p&gt;What is the point of having a support system if users can send multiple emails and still receive no response?&lt;/p&gt;

&lt;p&gt;I'm not talking about expecting an instant reply to every message. I'm talking about receiving no meaningful response at all, even when users are dealing with actual account or platform issues.&lt;/p&gt;

&lt;p&gt;Support is supposed to help users resolve problems, not leave them wondering whether anyone has even read their messages.&lt;/p&gt;

&lt;p&gt;At this point, I genuinely question how useful DEV's support system is when you need it most.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. A Username Change That Turned Into a Profile Problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Recently, I changed my username from &lt;code&gt;thebitforge&lt;/code&gt; to &lt;code&gt;thebitforge_dev&lt;/code&gt;, then changed it back to &lt;code&gt;thebitforge&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since then, neither profile URL has been working as expected.&lt;/p&gt;

&lt;p&gt;Opening &lt;code&gt;dev.to/thebitforge&lt;/code&gt; redirects me to &lt;code&gt;dev.to/thebitforge_dev&lt;/code&gt;, and the URLs keep behaving inconsistently. I can't reliably access my profile through either address.&lt;/p&gt;

&lt;p&gt;Maybe this is a routing issue, a username migration bug, or something else entirely. I don't know. That's precisely why support exists.&lt;/p&gt;

&lt;p&gt;I've experienced other issues before, too, and getting a response has been a problem.&lt;/p&gt;

&lt;p&gt;How are users supposed to resolve platform issues when the official support channel provides no meaningful help?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Where Has Article Discovery Gone?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is another major concern.&lt;/p&gt;

&lt;p&gt;I remember when publishing an article on DEV felt like an opportunity to start a conversation. People discovered posts, left comments, shared experiences, and engaged with writers they hadn't followed before.&lt;/p&gt;

&lt;p&gt;Now, getting an article in front of readers feels much harder.&lt;/p&gt;

&lt;p&gt;My articles don't seem to receive the same visibility they used to, and I've discussed this with other users who have expressed similar concerns about declining traffic and engagement.&lt;/p&gt;

&lt;p&gt;Of course, traffic fluctuates. Algorithms change, competition increases, and not every article will perform well.&lt;/p&gt;

&lt;p&gt;But when multiple writers start noticing the same pattern, I think it's reasonable to ask questions.&lt;/p&gt;

&lt;p&gt;Have there been changes to article distribution? Has the recommendation system changed? Is the platform doing enough to help readers discover new writers?&lt;/p&gt;

&lt;p&gt;I don't know the answers, and that's part of the problem. From a writer's perspective, it's difficult to understand what's happening.&lt;/p&gt;

&lt;p&gt;A community where people can publish but struggle to reach readers risks losing the very discussions that make it valuable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. AI Moderation and New Account Suspensions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is probably one of my biggest concerns.&lt;/p&gt;

&lt;p&gt;On three occasions, I helped friends create DEV accounts. They signed up using Google, added their names, usernames, bios, tech stacks, and interests to complete their profiles, and their accounts were suspended within one or two seconds of finishing.&lt;/p&gt;

&lt;p&gt;These were the experiences I personally witnessed. I cannot claim to know exactly what triggered the suspensions or whether an automated system was responsible.&lt;/p&gt;

&lt;p&gt;But if legitimate new users can be suspended almost immediately while completing ordinary profile information, something deserves closer examination.&lt;/p&gt;

&lt;p&gt;If automated moderation is involved, how reliably does it distinguish suspicious activity from normal onboarding?&lt;/p&gt;

&lt;p&gt;And when an account is suspended, is there an accessible way to understand why and appeal the decision?&lt;/p&gt;

&lt;p&gt;Automation can help platforms operate at scale. But automation without effective review and support can turn a simple signup into a frustrating experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. What Happened to the Community Feel?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The DEV Community I remember from 2024 felt more active and interactive.&lt;/p&gt;

&lt;p&gt;Writers had opportunities to get discovered. Readers participated in discussions. Publishing an article felt like joining a conversation rather than dropping a link into an endless feed.&lt;/p&gt;

&lt;p&gt;I still believe DEV has good people and that its core idea is valuable. I'm not writing this because I want to see the platform fail.&lt;/p&gt;

&lt;p&gt;I'm writing this because I remember when it felt better to participate.&lt;/p&gt;

&lt;p&gt;I don't know which platform updates, ranking changes, or moderation decisions may have contributed to what I'm experiencing. Without transparent information, I won't pretend to know the cause.&lt;/p&gt;

&lt;p&gt;But I do think users should be able to raise these concerns without their experiences being dismissed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DEV, a few honest questions:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why is getting meaningful support so difficult for users experiencing platform issues?&lt;/li&gt;
&lt;li&gt;What happens when username changes leave profile URLs behaving inconsistently?&lt;/li&gt;
&lt;li&gt;Have article discovery and distribution changed, and can writers get a clearer explanation of how their work reaches readers?&lt;/li&gt;
&lt;li&gt;How can new users appeal suspensions that appear to happen almost immediately after signup?&lt;/li&gt;
&lt;li&gt;What is being done to preserve the discussions and discoverability that make a developer community worth participating in?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm not claiming that DEV has become useless for everyone. I'm sharing what I've experienced and what I've heard from other writers I've spoken with.&lt;/p&gt;

&lt;p&gt;But here's the uncomfortable question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If developers cannot reliably get support, new users struggle to keep their accounts, and writers feel they are losing the opportunity to be discovered, what exactly is being done to maintain the community experience that made DEV valuable in the first place?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A community isn't just a publishing platform. It's the people, the conversations, the trust, and the opportunity to be heard.&lt;/p&gt;

&lt;p&gt;I hope DEV hasn't forgotten that.&lt;/p&gt;

&lt;p&gt;I'd like to bring these concerns to the attention of &lt;a class="mentioned-user" href="https://dev.to/francistrdev"&gt;@francistrdev&lt;/a&gt; &lt;a class="mentioned-user" href="https://dev.to/peter"&gt;@peter&lt;/a&gt; &lt;a class="mentioned-user" href="https://dev.to/ben"&gt;@ben&lt;/a&gt; &lt;a class="mentioned-user" href="https://dev.to/jess"&gt;@jess&lt;/a&gt; &lt;a class="mentioned-user" href="https://dev.to/sloan"&gt;@sloan&lt;/a&gt; &lt;a class="mentioned-user" href="https://dev.to/thepracticaldev"&gt;@thepracticaldev&lt;/a&gt; &lt;a class="mentioned-user" href="https://dev.to/launches"&gt;@launches&lt;/a&gt; &lt;a class="mentioned-user" href="https://dev.to/noahbrinker"&gt;@noahbrinker&lt;/a&gt; &lt;a class="mentioned-user" href="https://dev.to/heyitsjem"&gt;@heyitsjem&lt;/a&gt;  and the DEV Community team. I'd genuinely appreciate your response.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devjournal</category>
      <category>devto</category>
      <category>discuss</category>
    </item>
    <item>
      <title>What I Look for Before Trusting an AI App Builder With a Real Project</title>
      <dc:creator>TheBitForge</dc:creator>
      <pubDate>Fri, 16 Oct 2026 06:26:24 +0000</pubDate>
      <link>https://dev.to/thebitforge/what-i-look-for-before-trusting-an-ai-app-builder-with-a-real-project-4h27</link>
      <guid>https://dev.to/thebitforge/what-i-look-for-before-trusting-an-ai-app-builder-with-a-real-project-4h27</guid>
      <description>&lt;h1&gt;
  
  
  What I Look for Before Trusting an AI App Builder With a Real Project
&lt;/h1&gt;

&lt;p&gt;AI app builders can now generate a working database, authentication flow, and deployed URL from a natural-language prompt. But a convincing demo is only the beginning: what happens when real users, permissions, and persistent data enter the picture?&lt;/p&gt;

&lt;p&gt;I went looking for a concrete answer by digging into &lt;a href="https://floot.com" rel="noopener noreferrer"&gt;Floot&lt;/a&gt;, a YC-backed AI app builder that plugs into Claude, ChatGPT, and Cursor as an MCP connector, since it's one of the more recent entrants making a specific architectural claim: that bundling the whole stack (backend, database, hosting, auth) into one AI-native framework produces more reliable output than tools that bolt AI onto existing dev services.&lt;/p&gt;

&lt;p&gt;I haven't built a production app with Floot myself, so I'm not going to pretend otherwise. What I can offer is a framework: the specific things I'd want answered, with sources, before handing any AI app builder, Floot or otherwise, a real project. If you've used Floot or a competitor for something beyond a prototype, I'd genuinely like to hear where this framework holds up and where it doesn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Floot's workflow actually works
&lt;/h2&gt;

&lt;p&gt;Worth establishing first, since the architecture is the whole pitch, and it's worth getting precise about which architecture, because Floot actually ships two.&lt;/p&gt;

&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%2F2z4oqzu6x1e9mnns1xug.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%2F2z4oqzu6x1e9mnns1xug.png" alt=" " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The one most of the current marketing leads with is an &lt;a href="https://floot.com/docs/getting-started/how-floot-works" rel="noopener noreferrer"&gt;MCP (Model Context Protocol) connector&lt;/a&gt;: instead of a separate web app, you add Floot to Claude, ChatGPT, Cursor, or another MCP client, and build from inside that chat. Floot's own documentation is specific about who does what here: &lt;em&gt;your assistant&lt;/em&gt; creates the project, writes the files, provisions the database, runs the app, reads its own errors, and publishes, each as a direct tool call against your project. Floot's role in this path is the infrastructure underneath (a managed Postgres database, auth, file storage, hosting), not a second AI model reviewing the first one's work. Whatever model you're already paying for (Claude, GPT) is the one doing the interpreting and writing, but the development feedback loop involves more than the model reviewing its own output.&lt;/p&gt;

&lt;p&gt;That's a meaningfully different claim than the one I originally saw repeated across older coverage of Floot, which describes a three-pass system: one AI interprets the request, a second writes the code, and a first or third reviews and fixes it. That description is real, but it traces back to Floot's original standalone product, the in-app editor with its own built-in AI agent, which Floot still offers as a separate path alongside the connector. If you're building through the MCP connector, which is the model this article is mostly about, that multi-pass AI review isn't the mechanism in play. However, Floot says it does run development checks in the background and feeds their results back to the assistant.&lt;/p&gt;

&lt;p&gt;That distinction matters for how much scrutiny to apply. Even without a second AI model reviewing the first one's work, Floot says it type-checks code in the background after each batch of edits, checks backend code for frontend imports, and sends preview compile errors, build errors, and runtime logs back to the assistant. So the feedback loop isn't just the model catching its own mistakes; it also gets signals from actual development tools. That's an important distinction, although how reliably this catches deeper issues beyond compilation and runtime errors is still something I'd want to test on a real project.&lt;/p&gt;

&lt;h2&gt;
  
  
  The six things I'd actually test
&lt;/h2&gt;

&lt;p&gt;This is the part I think is missing from most AI-builder coverage: a list of claims to verify, not a verdict. If you're evaluating Floot (or Bolt, Lovable, Replit, Base44) for something real, these are the specific things I'd check before trusting the output, not just the marketing page.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What to test&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;User isolation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A high-impact failure mode to test for: create two accounts and check whether either can access the other's data. It won't show up unless you actually try it with two test accounts; a single-account demo can't reveal it either way.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Auth edge cases&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;What happens when a logged-out user hits a page that should require login? Does the generated app enforce that server-side, or only hide the UI element client-side (which doesn't actually protect anything)?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data persistence&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Does data survive a refresh, a logout/login cycle, a browser restart? Sounds basic, but it's a real gap category in early-stage generated backends.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Error handling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;What does the app do when required input is missing or malformed? Does it fail gracefully or expose something it shouldn't?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Deployment from a second machine&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Can someone other than you open the published URL and complete the core workflow, cold?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Export, for real&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Does the exported project actually build on its own, or does it fail on references to platform-managed services?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That last row is worth unpacking, because it's where the gap between "you can export" and "you have a runnable app" actually lives, and it's where Floot's own &lt;a href="https://floot.com/docs/projects/self-hosting" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; is unusually candid for a product page.&lt;/p&gt;

&lt;p&gt;Here's what's explicitly documented, directly: you can export both code (via a "Get Code" option, paid plans) and your database (a standard PostgreSQL dump, any plan). The docs also state that some built-in services get injected during Floot's build process and are &lt;em&gt;not&lt;/em&gt; included in the export, and that any reference to them left in your exported code "will fail to resolve," which the docs themselves describe as a hard build break, not a minor inconvenience.&lt;/p&gt;

&lt;p&gt;Here's what I'm inferring from that, rather than what's stated outright: that in practice, export isn't a one-click escape hatch so much as a migration task, since you'd need to replace those managed-service references before the exported project builds on its own. Floot's documentation does recommend doing that migration with your AI assistant's help &lt;em&gt;before&lt;/em&gt; you export, which supports the inference, but the actual scope of that work (how many references, how much rewriting) will vary by project and isn't something the docs quantify.&lt;/p&gt;

&lt;p&gt;That's a reasonable trade-off for the convenience of a managed stack. But exporting source code and running an application independently are two different milestones, and developers should evaluate them separately, a distinction that's easy to miss unless you read the docs past the pricing page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this still comes down to judgment, not tooling
&lt;/h2&gt;

&lt;p&gt;A few things I don't think any amount of reading documentation will resolve, and where I'd want direct experience before forming an opinion:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;How good is the self-correction loop, really?&lt;/strong&gt; The connector flow combines the assistant's own debugging with feedback from Floot's development tooling, including type checks, compile errors, build errors, and runtime logs. That's more than the model simply reviewing its own output. What I'd still want to understand is how reliably this catches deeper issues, particularly authorization mistakes, data isolation problems, and other bugs that don't necessarily produce an error during development. Whether this holds up across a representative range of app complexity, not just the CRUD-app demos that tend to get shown off, is an empirical question I'd want to investigate by testing a real project.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security posture.&lt;/strong&gt; I couldn't locate a publicly available, independent security audit of Floot's database or auth layer, which isn't proof one doesn't exist, just a gap in what's publicly findable. One &lt;a href="https://www.g2.com/products/floot/pricing" rel="noopener noreferrer"&gt;G2 reviewer&lt;/a&gt; using the product said directly they weren't fully confident how secure Floot's databases were. That's a single anecdotal account, not evidence of an actual flaw, but it's a more candid data point than anything on the pricing page, and worth weighing accordingly, not dismissing or inflating.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Performance under real load.&lt;/strong&gt; Hosting is included and scales with usage-based allowances rather than hard caps, per the pricing page, but I couldn't find a publicly available independent benchmark for how a Floot-built app behaves under sustained traffic.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this is a reason to write the category off. It's a reason to treat "the AI built it" as the start of your evaluation, not the end of it, the same way you'd treat a junior engineer's first pass at a feature: promising, worth reviewing, not worth shipping unexamined.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual question for discussion
&lt;/h2&gt;

&lt;p&gt;If you've taken an AI app builder, Floot or otherwise, past the demo and into something with real users: what broke first? Was it a permissions bug, a performance ceiling, a debugging dead end where the AI couldn't fix what it had generated, or something else entirely? And for anyone who's exported a project off one of these platforms: how much rework did it actually take to get it running independently?&lt;/p&gt;

&lt;p&gt;I'd rather build out the second half of this (the actual test matrix above, run against a real project) as a follow-up than speculate further without evidence. If that's useful to people here, let me know what you'd want tested first.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;I'm planning to actually build something real on Floot soon and come back with the results, the six tests above, run for real, with whatever breaks along the way included. If that follow-up would be useful, say so in the comments and I'll prioritize it.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&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%2F9ex2e2ao4odcidyngnf2.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%2F9ex2e2ao4odcidyngnf2.png" alt=" " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-2092289051886072030-236" src="https://platform.twitter.com/embed/Tweet.html?id=2092289051886072030"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-2092289051886072030-236');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=2092289051886072030&amp;amp;theme=dark"
  }



&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Build Your First MCP Server: Step-by-Step Guide for Developers (2026)</title>
      <dc:creator>TheBitForge</dc:creator>
      <pubDate>Fri, 02 Oct 2026 19:50:55 +0000</pubDate>
      <link>https://dev.to/thebitforge/how-to-build-your-first-mcp-server-step-by-step-guide-for-developers-2026-1n25</link>
      <guid>https://dev.to/thebitforge/how-to-build-your-first-mcp-server-step-by-step-guide-for-developers-2026-1n25</guid>
      <description>&lt;h2&gt;
  
  
  READ HERE:
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://www.topblogs.online/blog/build-your-first-mcp-server" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fplain-eeur-prod-public.komododecks.com%2F202610%2F02%2Fu3Zf6L9fBoIetwveDeHS%2Fimage.png" height="350" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.topblogs.online/blog/build-your-first-mcp-server" rel="noopener noreferrer" class="c-link"&gt;
            How to Build Your First MCP Server: Step-by-Step Guide for Developers (2026) - TopBlogs
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Build a working MCP server with the current 2026 SDKs, test it in the MCP Inspector, and connect it to Claude Code. Includes mistakes other developers hit.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.topblogs.online%2Ficon%3F0e9eb26cf9512256" width="32" height="32"&gt;
          topblogs.online
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;em&gt;Last updated: October 2026&lt;/em&gt;

&lt;p&gt;If you followed an MCP tutorial last year and the code no longer matches the official docs, your setup is probably fine. The protocol shipped its largest revision on July 28, 2026, and it changed how servers are written. A lot of older guides still teach the previous version.&lt;/p&gt;

&lt;p&gt;This guide builds a small MCP server from scratch with the current SDKs. You will end up with two tools that you can test in the MCP Inspector and connect to Claude Code. If Node.js is already installed, the basic server can be running in roughly fifteen minutes. Allow longer if you are setting up the environment or Claude Code for the first time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How this guide was put together:&lt;/strong&gt; the implementation follows the current MCP documentation and SDK examples. The troubleshooting section also draws on reports from developers who have built MCP servers in practice. Those reports are credited where they appear and listed at the end.&lt;/p&gt;
&lt;h2&gt;
  
  
  What an MCP server actually does
&lt;/h2&gt;

&lt;p&gt;An MCP server is a program that gives an AI application access to tools, and optionally to data and prompt templates, through one standard interface. The AI application is the client. It reads your list of tools and passes it to the model. When the model decides it needs one, the client sends a &lt;code&gt;tools/call&lt;/code&gt; request, your server does the work, and the result goes back. The model never talks to your server directly.&lt;/p&gt;

&lt;p&gt;Every tool has a name, a description, and an input schema. The model uses the description to decide whether your tool fits the task. A vague description leads to poor tool selection, so spend real time on it.&lt;/p&gt;
&lt;h2&gt;
  
  
  What changed in 2026, and why older tutorials break
&lt;/h2&gt;

&lt;p&gt;The current protocol revision is &lt;code&gt;2026-07-28&lt;/code&gt;. Its headline change is a stateless protocol core. According to the official release announcement, the &lt;code&gt;initialize&lt;/code&gt; handshake and the &lt;code&gt;Mcp-Session-Id&lt;/code&gt; header were retired, and each request now carries its own protocol version and client details.&lt;/p&gt;

&lt;p&gt;This affects you in two ways.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The SDK package layout changed.&lt;/strong&gt; In the TypeScript SDK, v2 replaces the single &lt;code&gt;@modelcontextprotocol/sdk&lt;/code&gt; package with separate packages, including &lt;code&gt;@modelcontextprotocol/server&lt;/code&gt; and &lt;code&gt;@modelcontextprotocol/client&lt;/code&gt;. In the Python SDK, v2 renamed &lt;code&gt;FastMCP&lt;/code&gt; to &lt;code&gt;MCPServer&lt;/code&gt;. If a tutorial imports from &lt;code&gt;@modelcontextprotocol/sdk&lt;/code&gt; or &lt;code&gt;mcp.server.fastmcp&lt;/code&gt;, it is using the older SDK API. Check which protocol revision the tutorial supports before following it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;State moves into your tools.&lt;/strong&gt; A stateless protocol core does not force your application to be stateless. It means the modern protocol no longer relies on a transport-level session to carry state between requests. If your server must carry something across calls, the maintainers recommend returning an explicit handle from a tool, such as a job ID, and letting the model pass it back as an argument. The remote hosting section below shows an example.&lt;/p&gt;
&lt;h2&gt;
  
  
  What we are building
&lt;/h2&gt;

&lt;p&gt;A server called &lt;code&gt;blog-helper&lt;/code&gt; with two tools. &lt;code&gt;reading-time&lt;/code&gt; estimates how long a text takes to read. &lt;code&gt;make-slug&lt;/code&gt; turns a post title into a URL slug.&lt;/p&gt;

&lt;p&gt;These are toy tools on purpose. They need no API keys and no network access, and they cover the two things every tool does: take structured input and return text. If something fails, the cause is in your MCP setup and not in a third-party service.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Set up the project
&lt;/h2&gt;

&lt;p&gt;You need Node.js 22.19 or later. The TypeScript SDK supports Node.js 20 and up, but the MCP Inspector used in Step 3 requires Node.js 22.19.0 or newer, so installing that version once covers the whole guide. The SDK ships ES modules only, so the project must be set to &lt;code&gt;type: module&lt;/code&gt;. The &lt;code&gt;tsx&lt;/code&gt; package runs TypeScript directly, so there is no build step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;blog-helper &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;blog-helper
npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
npm pkg &lt;span class="nb"&gt;set type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;module
npm &lt;span class="nb"&gt;install&lt;/span&gt; @modelcontextprotocol/server zod tsx
&lt;span class="nb"&gt;mkdir &lt;/span&gt;src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Write the server
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;src/index.ts&lt;/code&gt; and paste in the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;McpServer&lt;/span&gt; &lt;span class="p"&gt;}&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;@modelcontextprotocol/server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;serveStdio&lt;/span&gt; &lt;span class="p"&gt;}&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;@modelcontextprotocol/server/stdio&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;z&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;zod/v4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;McpServer&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;server&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;McpServer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blog-helper&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;reading-time&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Estimate how many minutes a piece of text takes to read. Use it for blog posts and articles.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;inputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The full text to measure&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="na"&gt;wordsPerMinute&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Reading speed. Defaults to 220.&lt;/span&gt;&lt;span class="dl"&gt;'&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;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;wordsPerMinute&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;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+/&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;minutes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;words&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wordsPerMinute&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;220&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;words&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; words, about &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; min read`&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="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;make-slug&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Turn a post title into a clean, lowercase URL slug.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;inputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The post title&lt;/span&gt;&lt;span class="dl"&gt;'&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;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;title&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;slug&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NFKD&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[^\w\s&lt;/span&gt;&lt;span class="sr"&gt;-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[\s&lt;/span&gt;&lt;span class="sr"&gt;_-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;slug&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="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;serveStdio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;createServer&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blog-helper MCP server running on stdio&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;Three details deserve a closer look.&lt;/p&gt;

&lt;p&gt;The Zod schema in &lt;code&gt;inputSchema&lt;/code&gt; is the only schema you write. The SDK uses it to describe the tool's input to the client and to reject invalid arguments before your handler runs, which is why neither handler contains manual validation.&lt;/p&gt;

&lt;p&gt;The server is built inside a &lt;code&gt;createServer&lt;/code&gt; function because &lt;code&gt;serveStdio&lt;/code&gt; calls it to create the instance that serves the connection. Keep that function lightweight: construct the server and register its tools there, and avoid slow network calls or expensive setup before the connection starts.&lt;/p&gt;

&lt;p&gt;The last line logs with &lt;code&gt;console.error&lt;/code&gt; on purpose. On a stdio server, stdout carries the protocol messages, so diagnostic output should go to stderr instead. A stray &lt;code&gt;console.log&lt;/code&gt; writes non-protocol data to stdout and can corrupt the JSON-RPC stream. Several developers have reported running into this, and their accounts appear later in the article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Run it and test it in the Inspector
&lt;/h2&gt;

&lt;p&gt;Start the server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx tsx src/index.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It prints the banner and then sits idle. That is expected, because a stdio server waits on stdin until a client starts talking to it.&lt;/p&gt;

&lt;p&gt;To call the tools, use the MCP Inspector, a local web app that launches your command and connects to it over stdio.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @modelcontextprotocol/inspector npx tsx src/index.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command prints a URL containing a one-time token for opening the Inspector's web interface. That is an access token for the Inspector, not the &lt;code&gt;Mcp-Session-Id&lt;/code&gt; that older protocol revisions used. Open the URL in your browser, click Connect, open the Tools tab, choose &lt;code&gt;make-slug&lt;/code&gt;, and enter a title. Then call &lt;code&gt;reading-time&lt;/code&gt; with an empty string. The schema requires at least one character, so the call should be rejected before your handler runs. That rejection is a quick way to see MCP input validation in action.&lt;/p&gt;

&lt;p&gt;For reference, the code above should produce results like these for valid input:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;make-slug      "My First MCP Server in 2026"  -&amp;gt;  my-first-mcp-server-in-2026
reading-time   "Hello world"                 -&amp;gt;  2 words, about 1 min read
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The developer behind the DEV Community post "How I Built My First MCP Server for Claude Code" (yureki_lab) wrote that they spent the first few hours debugging by asking Claude questions and judging whether the answers looked right. Moving to the Inspector gave them a direct view of what the server returned, with no model in between. It is worth testing the server on its own before connecting any client.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Connect it to Claude Code
&lt;/h2&gt;

&lt;p&gt;Registering a local stdio server takes one command. Everything after the double dash is the command Claude Code runs to launch your server. Use an absolute path to the entry file so it works from any folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add blog-helper &lt;span class="nt"&gt;--&lt;/span&gt; npx tsx /full/path/to/blog-helper/src/index.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run &lt;code&gt;claude mcp list&lt;/code&gt; to confirm the server shows as connected. If it fails, check the path first. On Windows, write the path in the form your shell expects.&lt;/p&gt;

&lt;p&gt;With the server connected, ask Claude for a slug, for example: "What would be a good URL slug for 'My First MCP Server in 2026'?" It should call your &lt;code&gt;make-slug&lt;/code&gt; tool and use the result.&lt;/p&gt;

&lt;h2&gt;
  
  
  The same server in Python
&lt;/h2&gt;

&lt;p&gt;If you work in Python, the v2 SDK builds a server from decorated functions. You need Python 3.10 or later. Set up the project with &lt;code&gt;uv&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv init blog-helper &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;blog-helper
uv add &lt;span class="s2"&gt;"mcp[cli]"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create &lt;code&gt;server.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp.server.mcpserver&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MCPServer&lt;/span&gt;

&lt;span class="n"&gt;mcp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MCPServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;blog-helper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@mcp.tool&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;reading_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;words_per_minute&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;220&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Estimate how many minutes a piece of text takes to read.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;minutes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;words_per_minute&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; words, about &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;minutes&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; min read&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;mcp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transport&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stdio&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Type hints become the input schema, and the docstring becomes the tool description. Python v2 is a major rework of the SDK, so check its migration guide if an example here behaves differently on your version. &lt;code&gt;pip install mcp&lt;/code&gt; now installs the 2.x line, so if you maintain older code and are not ready to migrate, keep a &lt;code&gt;&amp;lt;2&lt;/code&gt; upper bound on your requirement.&lt;/p&gt;

&lt;h2&gt;
  
  
  What other developers ran into
&lt;/h2&gt;

&lt;p&gt;The official tutorials show the happy path. The reports below come from developers who built, tested, or shipped MCP servers, and each one is credited to its author.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why stdout breaks stdio servers
&lt;/h3&gt;

&lt;p&gt;Several developers have reported the same problem. yureki_lab, who built a server so Claude Code could query an internal service catalog, wrote that a single stray &lt;code&gt;console.log&lt;/code&gt; cost about 40 minutes and produced a cryptic parse error. brianmello, whose server grew from a weekend project to roughly 2,300 npm downloads, called stdout the first surprise and added that the stray output can come from a dependency deep in your tree, not only from your own code. Both ended up sending every diagnostic message to stderr.&lt;/p&gt;

&lt;p&gt;The official MCP debugging documentation gives the same rule for local servers and notes that the host application captures what you write to stderr. On Windows, Claude Desktop writes its logs under &lt;code&gt;%APPDATA%\Claude\logs&lt;/code&gt;, which is a good first place to look when a connection fails.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why relative paths cause confusing failures
&lt;/h3&gt;

&lt;p&gt;Jaypee's troubleshooting guide to MCP connection errors points out that relative paths in a server config resolve against the client's working directory, not your server's. A server that works from your terminal can therefore fail inside Claude Desktop, and the fix is to use absolute paths.&lt;/p&gt;

&lt;p&gt;The same guide lists a few other traps. A server can connect successfully yet expose zero tools if its input schemas are malformed. A server that needs an API key often fails at the first tool call and not at connect time. And a failed &lt;code&gt;npx&lt;/code&gt; download looks like any other connection error, so run the server command by hand in a terminal before blaming the client.&lt;/p&gt;

&lt;h3&gt;
  
  
  Designing tools around user intent
&lt;/h3&gt;

&lt;p&gt;The team behind thunderbit-mcp (author handle ethan_thunderbit) wrote that the first temptation is to wrap every endpoint of an existing API as a tool. Their field guide argues for fewer, more predictable tools, and it recommends adding negative guidance to descriptions, meaning a line that tells the model when not to use a tool. They also describe stdio as the calmest first transport, since users install the package and add a config entry.&lt;/p&gt;

&lt;p&gt;brianmello gave related advice in one line: write tool descriptions like prompts, because the model reads them as prompts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Making errors useful to agents
&lt;/h3&gt;

&lt;p&gt;parkerrrrr observed that when a tool throws, the agent often sees only a generic internal error and cannot tell an authentication failure from a bad argument or an upstream outage. Catching errors in your handler and returning a clear message with &lt;code&gt;isError: true&lt;/code&gt; lets the model see what went wrong and react sensibly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authentication on remote servers
&lt;/h3&gt;

&lt;p&gt;The same author warned that an HTTP MCP server with authentication switched off is exactly the kind of default that gets found and abused. If you move beyond stdio, require a bearer token or OAuth, and make the server reject requests when no token is configured.&lt;/p&gt;

&lt;h3&gt;
  
  
  Migrating to the 2026-07-28 spec
&lt;/h3&gt;

&lt;p&gt;krlz, writing on DEV Community about the new revision, expects the biggest breakage to come from elicitation, meaning a server asking the user a question mid-call. Because the back-channel is gone, code that relied on it must be rewritten around the new multi round-trip pattern.&lt;/p&gt;

&lt;p&gt;The official release announcement includes comments from adopters. Supabase's head of product said the new pattern lets its tools confirm with the user before acting, for example before creating a project that costs money. Manufact reported that moving its mcp-use framework to the new SDK cut package size by about 83% and made it about 25% faster, thanks to the client and server split. Honeycomb said agents already make nearly 20% of its monthly interactive queries. These are vendor-reported figures, so treat them as signals about where the ecosystem is heading and not as independent benchmarks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Going from local to remote
&lt;/h2&gt;

&lt;p&gt;A stdio server runs on your own machine and is started by the app that uses it. To offer one endpoint that many people connect to, you serve the same server over HTTP instead.&lt;/p&gt;

&lt;p&gt;The stateless protocol core makes this much easier. For clients that use the 2026-07-28 revision, requests no longer depend on an &lt;code&gt;Mcp-Session-Id&lt;/code&gt;, so any request can land on any server instance behind an ordinary round-robin load balancer. Older protocol versions still have session behavior, so if your deployment also serves older clients, plan for that.&lt;/p&gt;

&lt;p&gt;Say a tool starts a long export. Have it return a job ID, and add a second tool that accepts the ID and reports progress. The ID lives in the model's context, so it does not matter which machine answers the next call.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security basics before you share anything
&lt;/h2&gt;

&lt;p&gt;A stateless protocol core is not automatically a safe one. If your server touches files, databases, or accounts, build a few habits in from the start.&lt;/p&gt;

&lt;p&gt;OWASP's MCP security guidance recommends running local servers in a sandbox such as a container, applying least privilege per server and per tool, and validating inputs and outputs at the server layer. Tool descriptions and tool outputs both become part of what the model reads, so treat them as untrusted input and not as instructions to follow. A model can be steered by text hidden inside either one.&lt;/p&gt;

&lt;p&gt;If your server calls other APIs on a user's behalf, do not forward the token you received from the client. The MCP security best practices describe this "token passthrough" as an anti-pattern, and the authorization guidance says the server must not pass through the token it received. The upstream API should get a token issued for it, because a server that accepts tokens meant for another service can be abused.&lt;/p&gt;

&lt;p&gt;Also ask for human confirmation before anything destructive, such as deleting data or moving money.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick answers
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Does this only work with Claude?&lt;/strong&gt;&lt;br&gt;
No. MCP is an open standard, and clients such as VS Code and Cursor support it as well, so the same server can serve several tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TypeScript or Python for a first server?&lt;/strong&gt;&lt;br&gt;
Both have current v2 SDKs that support the 2026-07-28 specification, so the choice comes down to your stack. This guide's TypeScript path needs Node.js 22.19 or later, while the Python path needs Python 3.10 or later. The TypeScript SDK also publishes adapters for Express, Fastify, and Hono, which helps if you later want to host the server inside an existing web app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How likely is the spec to break my server again?&lt;/strong&gt;&lt;br&gt;
The MCP project now documents a formal deprecation policy with a twelve-month minimum window for protocol changes, so removals come with a long notice period. SDK major versions, like the v1 to v2 jump, can still require code changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to go from here
&lt;/h2&gt;

&lt;p&gt;Replace the two toy tools with something you actually need: a query against your own database, a search over your notes, or a check on your site's status.&lt;/p&gt;

&lt;p&gt;For a first real implementation, keep the server read-only. That limits the damage while you learn how the model chooses and calls your tools, and you can add write access once its behavior looks predictable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;p&gt;Official documentation and specification:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Model Context Protocol Blog, "The 2026-07-28 Specification" (David Soria Parra and Den Delimarsky, July 28, 2026), including the adopter comments from Supabase, Manufact, and Honeycomb&lt;/li&gt;
&lt;li&gt;Model Context Protocol, specification 2026-07-28 and its versioning page&lt;/li&gt;
&lt;li&gt;Model Context Protocol, "Security best practices" and authorization security considerations&lt;/li&gt;
&lt;li&gt;Model Context Protocol, debugging documentation&lt;/li&gt;
&lt;li&gt;Model Context Protocol, MCP Inspector documentation (Node.js 22.19.0 requirement)&lt;/li&gt;
&lt;li&gt;Model Context Protocol TypeScript SDK, README and "Build your first server" tutorial (GitHub)&lt;/li&gt;
&lt;li&gt;Model Context Protocol Python SDK, README and v1 to v2 migration guide&lt;/li&gt;
&lt;li&gt;Claude Code documentation, "Connect Claude Code to tools via MCP"&lt;/li&gt;
&lt;li&gt;OWASP, "MCP Security Cheat Sheet"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Developer experience reports (DEV Community):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"How I Built My First MCP Server for Claude Code: 5 Lessons Learned" (author handle: yureki_lab)&lt;/li&gt;
&lt;li&gt;"Building an MCP server in production: lessons from 2,300 npm downloads" (author handle: brianmello)&lt;/li&gt;
&lt;li&gt;"The parts of building an MCP server that the tutorials skip" (author handle: parkerrrrr)&lt;/li&gt;
&lt;li&gt;"Building an MCP server: lessons from thunderbit-mcp" (author handle: ethan_thunderbit)&lt;/li&gt;
&lt;li&gt;"Debugging MCP Server Connection Issues: 7 Common Errors and Fixes" (author: Jaypee)&lt;/li&gt;
&lt;li&gt;"MCP Went Stateless: What the 2026-07-28 Spec Actually Changes" (author handle: krlz)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Do Keyword Research for Free: A Step-by-Step Guide for Beginners</title>
      <dc:creator>TheBitForge</dc:creator>
      <pubDate>Tue, 29 Sep 2026 14:05:02 +0000</pubDate>
      <link>https://dev.to/thebitforge/how-to-do-keyword-research-for-free-a-step-by-step-guide-for-beginners-3ap5</link>
      <guid>https://dev.to/thebitforge/how-to-do-keyword-research-for-free-a-step-by-step-guide-for-beginners-3ap5</guid>
      <description>&lt;p&gt;Most people pick blog topics the same way. They think of something they know about, write it up, hit publish, and wait. Then nothing happens, and they decide the writing must be the problem.&lt;/p&gt;

&lt;p&gt;Sometimes it is. But a lot of the time, nobody was searching for that topic, or the people who were wanted something different from what the post gave them. Keyword research is just the habit of checking this before you spend a whole weekend on a draft.&lt;/p&gt;

&lt;p&gt;You don't need a paid tool for it. Ahrefs and Semrush are good products, and if you ever outgrow the free options you'll know without being told. Until then, Google hands out most of what a beginner needs, and a few small tools fill the gaps.&lt;/p&gt;

&lt;p&gt;Below is the order I'd use them in. One hypothetical example runs through every step: a small blog about making coffee at home, and a post on cold brew you're thinking of writing. Alongside it, I've pulled in real stories from other people and companies who did this kind of research, with the source named each time. Those are their results, told as they told them, so treat the numbers as their claims and not as a guarantee for your own site.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you're actually looking for
&lt;/h2&gt;

&lt;p&gt;A keyword is whatever someone types into a search box. Sometimes it's a single word. More often it's a messy half-question. "Cold brew" is a keyword. So is "how long does homemade cold brew last in the fridge."&lt;/p&gt;

&lt;p&gt;When I look at a possible keyword, I ask myself three things. Are people searching for it? Could a site like mine realistically compete? And would the person searching be happy to land on the page I'd write?&lt;/p&gt;

&lt;p&gt;Beginners skip that last one all the time. Someone typing "buy cold brew maker" wants a shop, not your 2,000-word essay on steeping time. Marcus Sheridan, the pool company owner who turned blogging into a business, makes the same point in his talks, as summarized by the Spiderworking blog. A post like "5 fun games to play in your swimming pool" might bring visitors, but they may have no plans to buy a pool. A search like "best pool providers in Richmond Virginia" comes from someone who is shopping. Same subject, very different reader.&lt;/p&gt;

&lt;p&gt;Every keyword number you'll see in any tool is an estimate, even in the expensive ones. Use the numbers to compare one idea against another. Don't read them as a promise of traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Start with what's already in your head
&lt;/h2&gt;

&lt;p&gt;Before you open any tool, make a plain list of 15 or 20 topics. Not keywords, just topics. What do readers ask you? What confused you when you were starting out? What did you google last month?&lt;/p&gt;

&lt;p&gt;For the coffee blog, that list might be: cold brew ratios, best beans for cold brew, mason jar versus pitcher, why cold brew turns bitter, how long it keeps, concentrate versus ready-to-drink.&lt;/p&gt;

&lt;p&gt;Then go and see how real people phrase these things. Search your topic on Reddit and skim the titles. Read YouTube comments under popular videos. Check Quora. You're hunting for wording, because people don't write "optimal steeping duration." They write "why is my cold brew so bitter??"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How this worked for River Pools.&lt;/strong&gt; The best-known example of starting from customer questions is River Pools and Spas. After the 2008 crash hit his business, Marcus Sheridan sat down and listed every question buyers had ever asked him about fiberglass pools, then wrote an answer to each one. According to PRNEWS's coverage of his Content Marketing World keynote, the first article was "How Much Does a Fiberglass Pool Cost?", a question he says nobody in the industry was answering openly. PRNEWS reports that he credits that one article with $150,000 in sales, and that he tells other businesses to turn their top 100 customer questions into 100 posts. In a later podcast interview with Find Your Yellow Tux, he described writing those answers late at night, one at a time, and said the site eventually became the most trafficked swimming pool website in the world. Those figures are his own, so read them as his account. The method is the useful part: he started from real questions, not from a keyword tool.&lt;/p&gt;

&lt;p&gt;Starting here matters more than it sounds. If you begin with a tool, you'll chase the same suggestions everyone else is chasing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Let Google finish your sentences
&lt;/h2&gt;

&lt;p&gt;Open Google in a private window so your own search history doesn't bend the results. Type your seed topic and stop before you hit enter. The suggestions that drop down can show you phrases people commonly search for. They're not search volume data, but they're free ideas, and they're phrased the way real people talk.&lt;/p&gt;

&lt;p&gt;Now play with it. Type "cold brew how" and see what appears. Then "cold brew why," "cold brew vs," "cold brew for." Try each letter of the alphabet after the seed, too. It's tedious and it works.&lt;/p&gt;

&lt;p&gt;Next, search the phrase properly and look at two spots on the results page. The "People also ask" box is one. Click a question and it expands and often adds new ones below it. The "Related searches" list at the very bottom is the other.&lt;/p&gt;

&lt;p&gt;You can automate a lot of this. AnswerThePublic and AlsoAsked both turn a seed keyword into a map of questions, and both have free usage that's capped, so check what you get before you plan around them.&lt;/p&gt;

&lt;p&gt;Copy everything worth keeping into a spreadsheet. Don't judge anything yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Get a rough sense of volume with Keyword Planner
&lt;/h2&gt;

&lt;p&gt;Keyword Planner is Google's own tool, so it's one of the most direct free sources of Google's own keyword estimates. It lives inside Google Ads, which sounds like a trap. It isn't, as long as you're careful.&lt;/p&gt;

&lt;p&gt;The usual route goes like this. Sign in to Google Ads, and when it pushes you toward creating a campaign, look for the option to switch to Expert Mode and then to create an account without a campaign. Depending on your country and account, Google may ask for billing details before setup finishes. You aren't charged for research, but don't launch a campaign by accident. Google moves these buttons around, so if your screen looks different, hunt for the same options rather than giving up.&lt;/p&gt;

&lt;p&gt;Once you're in, open Tools, then Planning, then Keyword Planner, and choose "Discover new keywords." Type in your seeds. Set the location and language to match your real readers, not just wherever you happen to live. Those numbers can be very different from country to country.&lt;/p&gt;

&lt;p&gt;There's a catch. Without active ad spend, Google tends to show volume as wide ranges, like 1K to 10K, instead of exact figures. The SEO Engine blog tested the free tier against four paid tools across 47 keywords and reached the same conclusion. The ranges are real, and they limit how precisely you can compare competitors. It's annoying. It's still useful, because it tells you whether a keyword lives in the hundreds or the tens of thousands, and that's often all a beginner needs.&lt;/p&gt;

&lt;p&gt;Keep in mind that the tool was built for advertisers, so its suggestions lean commercial. The CPC column shows what advertisers pay per click. It can be a clue that advertisers see commercial value in a query, but it isn't a direct measure of what the searcher wants, so don't read it as "these people are ready to buy."&lt;/p&gt;

&lt;p&gt;If you want a second set of numbers, the Keyword Surfer Chrome extension shows rough volumes on the Google results page, and Ahrefs has a free keyword generator with limited results. When the tools disagree, and they will, treat every figure as a direction and skip the hunt for the one true number.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Check whether interest is rising or fading
&lt;/h2&gt;

&lt;p&gt;A keyword with decent volume can still be a bad bet if fewer people search it every year. Google Trends catches that.&lt;/p&gt;

&lt;p&gt;Type your keyword in and set the range to five years. Trends doesn't show search volume. It shows relative interest on a scale of 0 to 100, which is fine, because you're looking at the shape of the line, not the number.&lt;/p&gt;

&lt;p&gt;Is it climbing, flat, or sliding? Does it spike at the same time every year? Check the chart yourself before you build a publishing plan around a guess.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two coffee examples worth knowing.&lt;/strong&gt; A QuestionDB guide on using Trends draws the line between a recurring pattern and a fad with two drinks. Searches for hot chocolate recipes jump reliably every winter. Dalgona coffee, the whipped coffee that took over social media in 2020, peaked and then faded fast. If you were planning a post around each, the first is a topic you can update and republish every year. The second is a bet that may already be over.&lt;/p&gt;

&lt;p&gt;Once you know a topic is seasonal, timing matters. The UK agency Pod Digital gives a simple rule: if a keyword peaks in June, publish in April, so Google has time to crawl and index your page before demand arrives. Search Engine Land's guide to SEO seasonality makes a similar point, that you want to be visible before traffic peaks, not chasing it afterward. One caution from the same guides: seasonal terms can get crowded when the peak arrives, so check who's already ranking.&lt;/p&gt;

&lt;p&gt;Trends also lets you compare terms side by side. If you can't decide between "cold brew concentrate" and "cold brew ratio," put both in and look at which one has more life in it.&lt;/p&gt;

&lt;p&gt;Small or very specific keywords sometimes show "not enough data." That doesn't mean nobody searches them. It just means Trends can't say.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Look at the competition with your own eyes
&lt;/h2&gt;

&lt;p&gt;Paid tools give you a difficulty score. Free tools mostly don't, and those scores are rough guesses anyway. A quick manual check tells you a lot.&lt;/p&gt;

&lt;p&gt;Search your keyword and study page one. Ask yourself a few things.&lt;/p&gt;

&lt;p&gt;Who is ranking? If it's mostly huge publishers and big brands, you'll probably struggle for a while. Forum threads or small personal blogs in the results can be a sign that the page isn't fully locked up by major sites. That's worth investigating, not a green light. You still have to compare how relevant, thorough, fresh and well-linked those pages are next to what you could produce.&lt;/p&gt;

&lt;p&gt;What kind of pages are they? This is the intent check. If page one is all product listings, a how-to guide won't fit. If it's all long guides, a thin 400-word post won't compete. Nullstacks, an SEO agency blog, describes the mistake as writing from the keyword down instead of from the results page up. The keyword tells you the topic, and the results page tells you the shape of page Google expects to show.&lt;/p&gt;

&lt;p&gt;How old and how good is it? Outdated or shallow results can be an opening, though not a guarantee.&lt;/p&gt;

&lt;p&gt;Write a quick note in your sheet: easy, medium, or hard. You're allowed to be wrong. You'll get better at this fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Mine your own data in Search Console
&lt;/h2&gt;

&lt;p&gt;If your site has been live for a while, Google Search Console is probably the best free keyword tool you have, because the data is yours. It shows real searches that made your pages appear on Google.&lt;/p&gt;

&lt;p&gt;Verify your site, open the Performance report, and look at the Queries tab. Sort by impressions. Queries where you're already getting impressions but few clicks, or where you appear somewhere around positions 8 to 20, are worth a closer look. Google's own Search Console Help explains why to treat position carefully. It's an average across all the searches where you appeared, so it can differ from what you see when you search the phrase yourself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A story from an agency.&lt;/strong&gt; In a collection of Search Console success stories on Grit Daily, the team behind SERPpro describes opening its Performance report and finding that people were reaching the site through queries like "white label link building services" and "white label SEO partnerships." Those were more specific than the keyword the site had been targeting. The team built a separate page for each, because the intent behind each phrase was a little different, and says most of the new pages were ranking first or second within a week. Another contributor in the same piece describes starting by filtering for queries on page two, positions 11 to 20, with decent impressions and almost no clicks. Both are self-reported results, so don't expect the same speed. The lesson is the habit: your own query data often shows what people already think your site is about.&lt;/p&gt;

&lt;p&gt;If your site is brand new, this report will be empty or close to it. That's normal. Verify the site now so the data starts collecting, do steps 1 to 5 in the meantime, and come back in a month or two.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: Choose, then write it down
&lt;/h2&gt;

&lt;p&gt;Your sheet is probably messy by now. Keep the columns simple: the keyword, what the searcher really wants, the rough volume range, how crowded page one looked, and a status (idea, drafting, published). Fancy sheets don't get used.&lt;/p&gt;

&lt;p&gt;Then pick using three questions. Is the intent clear? Does page one look beatable? Do you actually know enough to write something better than what's there?&lt;/p&gt;

&lt;p&gt;If your site is new, lean toward long, specific phrases. Ahrefs makes this case with the example of someone launching a cryptocurrency blog. The popular, high-volume keywords are tempting, but a brand-new site has almost no chance of ranking for them soon. Longer, more specific phrases give even a new site a shot at the top ten, and ranking for one of them often brings visits from related searches too. For the coffee blog, skip "cold brew" and go for "how long does cold brew last in the fridge." Fewer people search it, but fewer sites are fighting for it.&lt;/p&gt;

&lt;p&gt;A small-blogger version of the same lesson comes from the MostlyBlogging site. Its author says that many of her earliest posts used a single generic word as the keyword, and that she wished she had known about long-tail keywords when she started. She went back and updated the old posts once she did.&lt;/p&gt;

&lt;p&gt;Each post gets one main keyword. If you cover the topic thoroughly, you'll naturally use many related terms without forcing them in. A keyword repeated awkwardly every third sentence reads like exactly what it is. Google Search Central's guidance on creating helpful, people-first content is worth reading once in full.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mistakes that waste the most time
&lt;/h2&gt;

&lt;p&gt;Chasing the biggest number is the classic one. A keyword with 50,000 monthly searches sounds great until you see who owns page one. A keyword with 300 searches that you could actually rank for can send you more traffic than the big one ever will.&lt;/p&gt;

&lt;p&gt;Ignoring intent comes next. Volume means nothing if your page doesn't match what people want when they click. The River Pools story is the reverse of this mistake: its most valuable posts targeted questions from people close to buying.&lt;/p&gt;

&lt;p&gt;Then there's treating estimates as facts. Two tools can give you very different numbers for the same keyword, and both are guessing. If you catch yourself agonizing over 1,200 versus 1,900, stop. Those two keywords are basically the same size.&lt;/p&gt;

&lt;p&gt;Doing research once and never returning is quieter but just as costly. Search habits drift and new questions appear, so a short revisit every few months is plenty.&lt;/p&gt;

&lt;p&gt;And writing for the tool instead of the reader. If a post reads oddly because you forced a phrase in, cut the phrase.&lt;/p&gt;

&lt;h2&gt;
  
  
  How long this takes
&lt;/h2&gt;

&lt;p&gt;For a first pass on one topic area, give yourself an afternoon. Maybe two hours if you already know the subject well. After a few rounds it drops to under an hour, because you stop second-guessing every step.&lt;/p&gt;

&lt;p&gt;It also gets faster to read results pages. After you've looked at enough of them, you start noticing mismatches, like a query that clearly wants a how-to while most of the top results are product pages, without opening every link.&lt;/p&gt;

&lt;h2&gt;
  
  
  Questions people ask
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Can I do keyword research without knowing search volume?&lt;/strong&gt;&lt;br&gt;
Yes. Autocomplete, People Also Ask, Reddit threads and Search Console all show you what people care about without a number attached. Marcus Sheridan's whole approach started with customer questions, not volume data. Volume helps you compare ideas. It isn't required to find them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I target keywords that show zero or very low volume?&lt;/strong&gt;&lt;br&gt;
Sometimes, yes. Tools often show low numbers for specific, newer, or conversational searches that real people do type. If the topic fits your site and you can answer it well, a low reported number alone isn't a reason to skip it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I choose between two keywords with the same intent?&lt;/strong&gt;&lt;br&gt;
Look at both results pages. Pick the one where the top pages feel weaker or more dated, or where you know something the current pages don't cover. If they look equal, write about the one you can explain better.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is Google Keyword Planner really free?&lt;/strong&gt;&lt;br&gt;
You don't pay to use it, but you need a Google Ads account, and without ad spend you usually see ranges instead of exact numbers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need a website to start?&lt;/strong&gt;&lt;br&gt;
Steps 1 to 5 don't need one. Only Search Console does.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is AI-assisted writing a problem for search?&lt;/strong&gt;&lt;br&gt;
Google's published guidance on AI-generated content says the focus is on quality and helpfulness, not on how the content was produced.&lt;/p&gt;
&lt;h2&gt;
  
  
  Sources for the stories and facts above
&lt;/h2&gt;

&lt;p&gt;The River Pools and Spas story comes from PRNEWS's coverage of Marcus Sheridan's Content Marketing World keynote and from his interview on the Find Your Yellow Tux podcast. The intent example comes from the Spiderworking blog's summary of his talk. The Keyword Planner range findings come from The SEO Engine blog. The Trends examples come from QuestionDB's guide to Google Trends for keyword research, Pod Digital, and Search Engine Land's guide to SEO seasonality. The Search Console story comes from Grit Daily's collection of Google Search Console success stories, and the explanation of average position comes from Google's Search Console Help. The long-tail examples come from Ahrefs and the MostlyBlogging site, and the results-page point comes from the Nullstacks blog. Google Search Central's helpful-content and AI-content guidance is referenced in the final sections. Figures and outcomes are as reported by those sources and may not match your own results.&lt;/p&gt;
&lt;h2&gt;
  
  
  READ HERE:
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://www.topblogs.online/blog/how-do-keywords-research" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fplain-eeur-prod-public.komododecks.com%2F202609%2F29%2FnylnYfYw9tCvySyw5pzJ%2Fimage.png" height="350" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.topblogs.online/blog/how-do-keywords-research" rel="noopener noreferrer" class="c-link"&gt;
            How to Do Keyword Research for Free: A Step-by-Step Guide for Beginners - TopBlogs
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Learn keyword research for free with Google Search Console, Keyword Planner, Trends and autocomplete. A simple process for beginners, with real stories from other sites.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.topblogs.online%2Ficon%3F0e9eb26cf9512256" width="32" height="32"&gt;
          topblogs.online
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>seo</category>
      <category>ai</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Creem.io for Pakistani Developers: A Practical Integration Guide (2026)</title>
      <dc:creator>TheBitForge</dc:creator>
      <pubDate>Mon, 28 Sep 2026 14:09:08 +0000</pubDate>
      <link>https://dev.to/thebitforge/creemio-for-pakistani-developers-a-practical-integration-guide-2026-1dpc</link>
      <guid>https://dev.to/thebitforge/creemio-for-pakistani-developers-a-practical-integration-guide-2026-1dpc</guid>
      <description>&lt;h2&gt;
  
  
  READ HERE
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://www.topblogs.online/blog/creem-io-pakistan-integration-guide" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fplain-eeur-prod-public.komododecks.com%2F202609%2F28%2FAvxywyjeSVswyObY5WSf%2Fimage.png" height="350" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.topblogs.online/blog/creem-io-pakistan-integration-guide" rel="noopener noreferrer" class="c-link"&gt;
            Creem.io in Pakistan: Payouts, Fees &amp;amp; Next.js Integration - TopBlogs
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Does Creem.io work in Pakistan? Learn about payouts, fees, restrictions, Merchant of Record, and how to integrate Creem with Next.js and webhooks.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.topblogs.online%2Ficon%3F0e9eb26cf9512256" width="32" height="32"&gt;
          topblogs.online
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Picture this. You've spent four months on a small SaaS tool. It works, your friends say it's good, and a stranger in Germany has just asked where they can pay for it. You open Stripe, start the signup, and Pakistan isn't in the country list.&lt;/p&gt;

&lt;p&gt;That moment is where a lot of Pakistani developers stall. Some give up. Some pay for a US LLC they don't really want. Some send customers a Payoneer link and hope for the best.&lt;/p&gt;

&lt;p&gt;Creem.io is one of the newer platforms trying to fix that gap, and it does list Pakistan as a supported country. But "supported" hides a few details that decide whether it works for you. This guide walks through those details first, then builds a full integration with real code.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Last checked in September 2026. Payment rules change quickly, so confirm anything money-related on Creem's own docs before you commit. This article is independent and isn't sponsored by Creem.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Creem actually does
&lt;/h2&gt;

&lt;p&gt;Creem is what the industry calls a Merchant of Record. The term sounds heavier than it is.&lt;/p&gt;

&lt;p&gt;Think of a shop that sells your product for you. When a customer in France buys, the shop is the one legally selling to them. It charges the card, works out the French VAT, sends the invoice, and deals with the bank if the customer disputes the charge. Then it pays you what's left after its cut. With a normal payment processor like Stripe, you are the seller, so all of that lands on you.&lt;/p&gt;

&lt;p&gt;Creem is built by Armitage Labs OU, an Estonian company, and it targets software and digital goods. The API covers products, hosted checkout pages, customers, subscriptions, discount codes, and license keys. If you sell a SaaS plan, an extension, a template pack, or an ebook, you're the intended customer.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, does it work in Pakistan?
&lt;/h2&gt;

&lt;p&gt;Yes. Pakistan is on Creem's list of supported merchant countries, and buyers in Pakistan can purchase from you too, since Pakistan isn't on the unsupported list.&lt;/p&gt;

&lt;p&gt;Now the catch. On that list, Pakistan carries a double asterisk. The docs say countries with that mark may face restrictions from Creem's bank transfer partner, for example only personal bank accounts being accepted, or business transfers being unavailable.&lt;/p&gt;

&lt;p&gt;The partner is Wise, and Wise's own help page for PKR transfers is blunt. It says you can send PKR to personal bank accounts in Pakistan, that you can't send to a business account, and it warns against a couple of account types, namely Meezan Bank Express and Allied Bank Express accounts, which reject these transfers.&lt;/p&gt;

&lt;p&gt;Put those two facts together and you get a fairly clear picture.&lt;/p&gt;

&lt;p&gt;If you're a freelancer or solo founder, onboarding as an individual with a personal PKR account in your own name is the path most likely to go smoothly. The name on the bank account has to match the name on your identity verification, because a mismatch is one of the documented reasons a payout bounces back.&lt;/p&gt;

&lt;p&gt;If you run a registered company and want the money to land in a company account, don't assume it works. Email Creem support first and ask directly. It's a five-minute question that can save you weeks.&lt;/p&gt;

&lt;p&gt;There's also a backup route. Creem pays out in USDC on the Polygon network for a 2% fee. If your bank keeps rejecting transfers, that's your escape hatch, though you'd need a wallet and a way to turn USDC into rupees that you trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you can sell, and what will get you turned away
&lt;/h2&gt;

&lt;p&gt;This part surprises people, so read it before you spend a weekend on integration.&lt;/p&gt;

&lt;p&gt;Creem is for digital products. Its account review rules say services of any kind aren't accepted, and the examples they give include marketing, design, web development and consulting. So if your plan is to collect payment for client projects, Creem isn't the tool. That's a real limit for the many Pakistani developers who earn through freelancing.&lt;/p&gt;

&lt;p&gt;Generative AI products, such as text-to-image or text-to-video tools, sit on a restricted list. Restricted doesn't mean banned. It means extra checks, and they'll ask about your previous payment processor, your refund rate, and why you're moving.&lt;/p&gt;

&lt;p&gt;One more thing. Be honest about what you sell. Creem can ask for test access to your product and may make a small test purchase during onboarding. Sellers who hide things tend to get their accounts closed, and closed accounts with money inside are a miserable problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it costs, in actual numbers
&lt;/h2&gt;

&lt;p&gt;The headline rate is 3.9% plus $0.40 per successful transaction, with no monthly fee. On a $29 sale with no tax added on top, that's about $1.53 gone to the platform.&lt;/p&gt;

&lt;p&gt;Some features cost extra. Revenue splits and the affiliate system each add 2%, and abandoned-cart recovery adds 5% on the recovered sale. If you don't turn those on, they don't touch you.&lt;/p&gt;

&lt;p&gt;The number that matters most for someone in Pakistan is the payout fee, which is $7 or 1% of the payout, whichever is bigger. Run it on a few amounts and the trap becomes obvious.&lt;/p&gt;

&lt;p&gt;Withdraw $100 and you lose $7, which is 7% of your money. Withdraw $700 and 1% comes to exactly $7, so that's the break-even. Withdraw $2,000 and the fee is $20, or a clean 1%.&lt;/p&gt;

&lt;p&gt;So don't withdraw just because the 15th is coming. Let the balance build and take it out in bigger lumps. The minimum to request a payout is $50, and payouts run on the 1st and the 15th of each month.&lt;/p&gt;

&lt;p&gt;Two timing details are easy to miss. New payments can be held for 7 to 12 days for risk review, which means a sale you make on the 12th usually won't be ready for the 15th. And if your bank account currency differs from the currency you charged in, the bank partner applies its own conversion fee, which Creem says it doesn't control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I'd be cautious
&lt;/h2&gt;

&lt;p&gt;A competitor's comparison post criticizes Creem's extra fees and says checkout supports only USD and EUR. That source sells a rival product, so treat it with salt, but the currency point is easy to verify yourself in the dashboard before you price anything.&lt;/p&gt;

&lt;p&gt;There's also a small inconsistency worth knowing about. Creem's pricing page says automatic tax collection covers 50+ countries, while its homepage talks about compliance across 190+ countries. They may be describing different things, but if one particular market matters to you, ask support whether it's covered.&lt;/p&gt;

&lt;p&gt;Trustpilot reviews lean positive on support and documentation, with some complaints about individual merchants' billing. That's normal for any payments company. Just don't rely on marketing pages alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the integration
&lt;/h2&gt;

&lt;p&gt;I'll use Next.js and the official TypeScript SDK because that's what most people reach for. Creem also has a REST API, a Better Auth plugin, and a Convex component if your stack looks different.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create your account and a test product
&lt;/h3&gt;

&lt;p&gt;Sign up at creem.io, finish verification, then flip the Test Mode toggle at the bottom of the left sidebar. Everything in test mode is walled off from real money, which is exactly what you want while you're making mistakes.&lt;/p&gt;

&lt;p&gt;Open the Products tab and create your first product. Set the name, the price, and whether it's one-time or recurring. Prices are stored in cents, so 1000 means $10.00. Choose a tax category (SaaS, digital goods, or ebooks) and a tax mode, inclusive or exclusive. Copy the product ID that starts with &lt;code&gt;prod_&lt;/code&gt;. Then head to the Developers section and copy your API key.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set up the environment
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;creem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# .env.local&lt;/span&gt;
&lt;span class="nv"&gt;CREEM_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_test_api_key
&lt;span class="nv"&gt;CREEM_WEBHOOK_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;whsec_your_webhook_secret
&lt;span class="nv"&gt;CREEM_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;test
&lt;/span&gt;&lt;span class="nv"&gt;NEXT_PUBLIC_APP_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The API key belongs on the server only. Don't put it in browser code and don't commit it to Git. Test and live modes use different keys and different base URLs, &lt;code&gt;https://test-api.creem.io&lt;/code&gt; for testing and &lt;code&gt;https://api.creem.io&lt;/code&gt; for production.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create the client
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/creem.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Creem&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;creem&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;creem&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;Creem&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CREEM_API_KEY&lt;/span&gt;&lt;span class="o"&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;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CREEM_ENV&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&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;When you leave &lt;code&gt;server&lt;/code&gt; out, the SDK talks to production. This setup only forces test mode when you haven't said you're in production, which is a safer default than the reverse.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a checkout session
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/api/checkout/route.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;creem&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/lib/creem&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&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;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&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;productId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="p"&gt;}&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;request&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;checkout&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;creem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checkouts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="nx"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;successUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_APP_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/success`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;userId&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;NextResponse&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="na"&gt;checkoutUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;checkout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checkoutUrl&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Checkout error:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&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;NextResponse&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Could not create checkout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;metadata&lt;/code&gt; line is easy to skip and painful to regret. Put your own user ID in it. When the webhook fires later, the same metadata comes back, so you know exactly which account in your database just paid.&lt;/p&gt;

&lt;p&gt;On the front end, call the route and send the browser to the URL it returns.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;buy&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;res&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/checkout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prod_YOUR_PRODUCT_ID&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;checkoutUrl&lt;/span&gt; &lt;span class="p"&gt;}&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;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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;checkoutUrl&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;h3&gt;
  
  
  Handle webhooks
&lt;/h3&gt;

&lt;p&gt;This is the part that actually decides whether your app gets paid correctly.&lt;/p&gt;

&lt;p&gt;Don't unlock anything just because someone reached your success page. Anyone can type that URL into a browser. The webhook is the only trustworthy signal that money moved.&lt;/p&gt;

&lt;p&gt;Creem signs each webhook. The signature arrives in the &lt;code&gt;creem-signature&lt;/code&gt; header, and it's an HMAC-SHA256 of the raw request body using your webhook secret. That's why you read the body as raw text before doing anything else with it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/api/webhooks/creem/route.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;constructWebhookEventEntity&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;creem/webhooks&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&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;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&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;rawBody&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;request&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;event&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;constructWebhookEventEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawBody&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CREEM_WEBHOOK_SECRET&lt;/span&gt;&lt;span class="o"&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;catch&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;event&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;NextResponse&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="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid signature&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// The same event can arrive more than once, so skip repeats.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;eventId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawBody&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;hasProcessed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eventId&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;NextResponse&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="na"&gt;received&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eventType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;checkout.completed&lt;/span&gt;&lt;span class="dl"&gt;"&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;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="c1"&gt;// Unlock the one-time purchase for this user.&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;subscription.paid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Activate or renew access for the paid period.&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;subscription.past_due&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;subscription.unpaid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Show a payment-recovery message and restrict access per your policy.&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;subscription.canceled&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Revoke access.&lt;/span&gt;
      &lt;span class="k"&gt;break&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;await&lt;/span&gt; &lt;span class="nf"&gt;markProcessed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eventId&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;NextResponse&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="na"&gt;received&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;&lt;code&gt;hasProcessed&lt;/code&gt; and &lt;code&gt;markProcessed&lt;/code&gt; are stand-ins for your own database. A table with the event ID as a unique column is plenty.&lt;/p&gt;

&lt;p&gt;A few details about how Creem behaves. Answer with HTTP 200 when you've handled an event. If you don't, Creem tries again, five attempts in total, after 30 seconds, 5 minutes, 30 minutes and 6 hours, and it stops after 24 hours. Its docs suggest using &lt;code&gt;subscription.paid&lt;/code&gt; to switch on access and keeping &lt;code&gt;subscription.active&lt;/code&gt; for syncing. Creem also doesn't publish fixed IP addresses for webhooks, so an IP allowlist won't protect you. The signature check is your protection.&lt;/p&gt;

&lt;p&gt;If you'd rather skip the SDK helper, you can verify the signature by hand.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;crypto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isValidSignature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawBody&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createHmac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sha256&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawBody&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hex&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;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expected&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;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&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;a&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;b&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;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timingSafeEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&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;h3&gt;
  
  
  Test it locally
&lt;/h3&gt;

&lt;p&gt;Creem needs a public HTTPS address to reach. While you're developing, the Creem CLI can forward events straight to your machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;creem listen &lt;span class="nt"&gt;--forward-to&lt;/span&gt; http://localhost:3000/api/webhooks/creem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you prefer a tunnel like ngrok, register that URL under Developers and then Webhooks in the dashboard. Add your production URL separately once you deploy.&lt;/p&gt;

&lt;p&gt;In test mode, the card &lt;code&gt;4111 1111 1111 1111&lt;/code&gt; gives you a successful payment with any future expiry and any CVC. The card &lt;code&gt;4507 9900 0000 0028&lt;/code&gt; simulates a decline, and &lt;code&gt;4507 9900 0000 0010&lt;/code&gt; simulates insufficient funds. Try the failing cards on purpose. Subscriptions especially tend to break in the unhappy paths, not the happy one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Go live
&lt;/h3&gt;

&lt;p&gt;Before you switch, walk through this once.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run every flow in test mode: a purchase, a failed payment, a cancellation, a refund.&lt;/li&gt;
&lt;li&gt;Swap in your live API key and drop the test server setting.&lt;/li&gt;
&lt;li&gt;Recreate your products in live mode, because test products don't carry over.&lt;/li&gt;
&lt;li&gt;Register your production webhook URL and copy the live webhook secret.&lt;/li&gt;
&lt;li&gt;Add your payout account and finish identity verification.&lt;/li&gt;
&lt;li&gt;Watch your first handful of real transactions closely.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Getting paid in Pakistan
&lt;/h2&gt;

&lt;p&gt;Set up your payout account long before you need it. For a bank payout, expect to give your full name and your IBAN, which is what Wise asks for on PKR transfers. Use a personal account in your own name, and stay away from the Express account types mentioned earlier.&lt;/p&gt;

&lt;p&gt;If a payout fails and the money returns to your balance, it's usually one of three things. The bank details are wrong. The account can't receive international payments. Or the account holder's name doesn't match the identity you verified with. Check those before opening a support ticket, because you'll likely find the answer yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mistakes that tend to bite
&lt;/h2&gt;

&lt;p&gt;A few come up again and again with payment integrations, and Creem is no exception.&lt;/p&gt;

&lt;p&gt;Granting access from the success page is the big one. It feels fine in testing and then someone shares the URL. Use the webhook.&lt;/p&gt;

&lt;p&gt;Parsing the request body before verifying the signature is another. Once a framework re-serializes the JSON, the bytes change and the signature check fails for no obvious reason. Read the raw text first.&lt;/p&gt;

&lt;p&gt;Mixing environments causes the strangest errors. A test key pointed at the production endpoint, or the other way round, fails in ways that look like bugs in your own code. Check your environment variables before you start debugging logic.&lt;/p&gt;

&lt;p&gt;And then there's the small, quiet one. Withdrawing $60 because you're impatient and losing $7 of it. Wait a month.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your own taxes
&lt;/h2&gt;

&lt;p&gt;Creem, as Merchant of Record, handles sales tax and VAT on what your customers buy. It doesn't handle your income tax in Pakistan. Those are separate worlds.&lt;/p&gt;

&lt;p&gt;Each payout comes with a reverse invoice, which is useful paperwork, so download and keep them along with your bank credit records. How foreign income is taxed for freelancers and software exporters in Pakistan has its own rules and they change over time. Talk to a qualified accountant instead of trusting a blog post, this one included.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should use it
&lt;/h2&gt;

&lt;p&gt;Creem makes sense if you sell a SaaS product, browser extension, template pack, ebook or licensed software, if a personal bank account in your own name works for you, and if you'd rather not learn how to file taxes in a dozen jurisdictions.&lt;/p&gt;

&lt;p&gt;It's the wrong tool if most of your income is client work, if you need money to land in a business account, if you need to be paid more often than twice a month, or if your product sits in a restricted category.&lt;/p&gt;

&lt;p&gt;Whichever way you lean, test with something small. List a cheap product, complete one real sale, and follow that money all the way into your bank account before you build anything bigger on top. Watching your own first payout arrive will tell you more than any review, including this one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is Creem available in Pakistan?&lt;/strong&gt;&lt;br&gt;
Yes. Pakistan is on the supported merchant country list, with a note that bank partner restrictions may affect payouts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can customers in Pakistan buy from a Creem checkout?&lt;/strong&gt;&lt;br&gt;
Purchases are accepted from every country except those on Creem's unsupported list, and Pakistan isn't on it. Which payment methods appear depends on the buyer's location, the product type, the price and the device.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need a registered company?&lt;/strong&gt;&lt;br&gt;
No. Creem accepts individual sellers, who go through standard identity checks. Individuals need a payout account in the same name as their verified identity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does the money reach me?&lt;/strong&gt;&lt;br&gt;
Through a local bank transfer handled by Creem's bank partner, or through USDC on Polygon. Payouts run on the 1st and 15th of each month.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the minimum payout?&lt;/strong&gt;&lt;br&gt;
Your balance has to reach $50 or 50 EUR before you can request a withdrawal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I collect payment for freelance projects with it?&lt;/strong&gt;&lt;br&gt;
No. Services such as consulting, design and web development aren't accepted. Creem is designed for digital products.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does it work with Next.js?&lt;/strong&gt;&lt;br&gt;
Yes. There's an official TypeScript SDK and a dedicated Next.js adapter, plus a Better Auth plugin and a Convex component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources and last checked
&lt;/h2&gt;

&lt;p&gt;Everything factual above was checked in September 2026 against these official pages: Creem's Supported Countries, Payouts, Quickstart, Test Mode and Webhooks documentation, its Pricing page, Terms of Service and Account Reviews policy, and Wise's help article on PKR transfers. Rules on all of these can change, so double-check current details before you make decisions.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer: This article is general information, not financial, legal or tax advice.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>startup</category>
      <category>sass</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>WordPress to Next.js Migration: A Practical Checklist for Agencies</title>
      <dc:creator>TheBitForge</dc:creator>
      <pubDate>Fri, 25 Sep 2026 14:04:21 +0000</pubDate>
      <link>https://dev.to/thebitforge/wordpress-to-nextjs-migration-a-practical-checklist-for-agencies-58jf</link>
      <guid>https://dev.to/thebitforge/wordpress-to-nextjs-migration-a-practical-checklist-for-agencies-58jf</guid>
      <description>&lt;p&gt;Somewhere around plugin number fourteen, every WordPress site starts to feel the same. Page builder shortcodes stacked on top of a theme that's stacked on top of a child theme nobody remembers creating. Load times creeping up every quarter. A client who wants "the site to feel modern, like [competitor]'s site" without quite being able to articulate what "modern" actually means. And at some point, someone on the team says the word "headless," and suddenly you're being asked whether it's worth migrating to Next.js.&lt;/p&gt;

&lt;p&gt;Here's the thing most guides skip: the actual framework swap is the easy part. Copying a hero section from WordPress into a React component takes an afternoon. What actually sinks these migrations, and what turns a "quick refresh" into a three-month fire drill, is everything sitting underneath the visible page: URLs, SEO signals, editorial workflow, and content that was never structured cleanly in the first place. This is the checklist that actually matters, in the order it actually matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step one: decide what WordPress's role even is going forward
&lt;/h2&gt;

&lt;p&gt;Before touching a single line of code, answer one question honestly: is WordPress staying as the CMS, or is it getting replaced entirely?&lt;/p&gt;

&lt;p&gt;There are genuinely three valid paths here, and picking the wrong one for your client's situation is the single most common reason these projects go sideways.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep WordPress as a headless CMS.&lt;/strong&gt; Editors keep using the Gutenberg editor they already know, content still lives in WordPress, but the frontend rendering gets replaced entirely by Next.js pulling data through the REST API or WPGraphQL. This is the lowest-risk path when your client's team already knows WordPress and doesn't want to relearn a new content interface. It's also the fastest to ship, because you're not migrating content anywhere, just changing how it gets rendered.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Replace WordPress with a dedicated headless CMS.&lt;/strong&gt; Sanity, Payload, Contentful, Strapi, pick based on content complexity and team skills rather than whichever one has the flashiest marketing site. This path makes sense when WordPress itself is the bottleneck, not just the theme, usually because the content model has outgrown what posts-and-pages can reasonably express.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Run both in parallel during transition, then retire WordPress.&lt;/strong&gt; Sometimes the safest real-world path is standing up Next.js against WordPress's existing API first, proving it out on a handful of pages, and only fully cutting over once you trust the new system in production.&lt;/p&gt;

&lt;p&gt;Whichever path you pick, write it down and get the client to sign off on it explicitly. Half the scope creep in these projects comes from someone assuming WordPress is "just going away" when actually the plan was to keep it as a CMS the whole time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step two: inventory everything, not just the obvious pages
&lt;/h2&gt;

&lt;p&gt;This is the step agencies skip and then pay for later. It's tempting to treat "migrate the content" as "export posts and pages," but real WordPress sites hide a surprising amount of commercially important content in places that don't show up in a basic export: custom post types, ACF fields, widget areas, menu structures, and content buried inside page builder shortcodes that don't translate cleanly into anything.&lt;/p&gt;

&lt;p&gt;Before you write a single component, actually go through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Every custom post type&lt;/strong&gt;, not just the default posts and pages. Portfolios, testimonials, team members, whatever the client's theme or a plugin quietly registered along the way.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom fields&lt;/strong&gt;, especially anything built with ACF or similar plugins, since those often carry structured data the visible page depends on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Media library assets&lt;/strong&gt;, exported separately from content, since WordPress's default export tool (Tools &amp;gt; Export, generating a WXR file) covers posts, pages, categories, tags, and authors, but media files need their own handling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Menu structures and widget areas&lt;/strong&gt;, which often carry navigation logic that isn't obvious from looking at the rendered site.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shortcode-based content&lt;/strong&gt;, which is the single biggest headache in these migrations. Page builder content doesn't export cleanly, and there's rarely a clean automated path from "Elementor shortcode soup" to structured content blocks. Budget real time for manually rebuilding these pages rather than assuming a script will handle it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you skip this step and start building based on what you can see on the live site, you will find missing content halfway through, and it's always at the worst possible time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step three: map every URL before you touch SEO
&lt;/h2&gt;

&lt;p&gt;This is the part that determines whether the migration protects the client's search rankings or quietly torches years of SEO work in a single launch weekend. It happens more often than anyone wants to admit, and it's almost always avoidable.&lt;/p&gt;

&lt;p&gt;Every single WordPress URL needs a mapped destination in the new site, and every one of those mappings needs a permanent (301) redirect. Not "most of them." Every one, including the obscure blog post from four years ago that still ranks for some long-tail keyword nobody on the current team even knows about.&lt;/p&gt;

&lt;p&gt;Before launch:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pull a full URL list&lt;/strong&gt; from Search Console, your sitemap, and a proper crawl (don't rely on just one source, they'll disagree in ways that matter).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Establish crawl and rendering baselines&lt;/strong&gt; so you have something to compare against after launch if traffic drops.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Map old URL to new URL&lt;/strong&gt;, explicitly, even when the URL structure is staying identical, because "staying identical" is exactly the kind of assumption that breaks on trailing slashes or query parameters nobody thought to check.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rebuild metadata from actual page requirements&lt;/strong&gt;, not from whatever your old SEO plugin auto-generated. Yoast and similar plugins handled a lot of this invisibly in WordPress. In a headless setup, you own every meta tag, and there's no plugin quietly filling gaps for you anymore.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rebuild schema markup&lt;/strong&gt; deliberately, since structured data doesn't survive a framework swap automatically, and losing it silently degrades how the site shows up in search results without throwing any obvious error.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One technical detail that trips up a lot of Next.js migrations specifically: Google can render JavaScript, but it does so in a deferred rendering queue, and for SEO-critical pages that delay costs you time you don't have during a fragile post-launch window. Static generation or incremental static regeneration is the safer default for anything that needs to rank, blog posts, landing pages, product pages, reserving client-side rendering for authenticated or highly dynamic sections that don't need to be indexed at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step four: don't forget preview, because editors will notice immediately
&lt;/h2&gt;

&lt;p&gt;This is the detail that gets cut when timelines get tight, and it's the one that causes the most friction with the client's actual content team after launch.&lt;/p&gt;

&lt;p&gt;In WordPress, editors are used to hitting "preview" and seeing exactly what a post will look like before publishing. In a headless setup, that experience doesn't exist by default, you have to build it, usually through a draft mode that lets the Next.js frontend render unpublished content from the CMS. Skip this and your client's marketing team ends up publishing directly to production just to see how something looks, which is exactly the kind of workflow regression that makes a technically successful migration feel like a downgrade to the people who actually use the site daily.&lt;/p&gt;

&lt;p&gt;Treat preview as part of the migration's core scope, not a nice-to-have you'll get to if there's time left. There usually isn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step five: launch with monitoring, not hope
&lt;/h2&gt;

&lt;p&gt;The migration isn't done when the new site goes live, it's done a few weeks later, once you've confirmed the things that were supposed to survive the transition actually did.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Watch Search Console daily&lt;/strong&gt; for the first couple of weeks, specifically for crawl errors and sudden indexing drops, which show up faster there than in traffic numbers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compare rendered HTML&lt;/strong&gt; against your pre-migration baseline for the pages that matter most commercially, to catch cases where content technically migrated but isn't rendering the way you expect.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep a rollback plan ready&lt;/strong&gt;, genuinely ready, not theoretical, for at least the first couple of weeks post-launch. If something's badly broken, the client needs to know you can revert quickly, not that you'll "look into it."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Submit a fresh sitemap&lt;/strong&gt; to Search Console immediately after launch and verify every priority page is actually included, rather than assuming the sitemap generation caught everything on its own.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The part nobody wants to hear
&lt;/h2&gt;

&lt;p&gt;None of this is glamorous. None of it is the part of the migration that gets screenshotted for a portfolio. But this is the actual difference between a WordPress to Next.js migration that makes a client's site meaningfully faster and more maintainable, and one that quietly loses two years of organic search rankings while everyone's celebrating how much nicer the new hero animation looks.&lt;/p&gt;

&lt;p&gt;The framework is genuinely the easy part. Treat it that way, and put the real planning time where it actually belongs: the content inventory, the URL mapping, and the editorial workflow the client's team depends on every single day.&lt;/p&gt;




&lt;p&gt;If you've run one of these migrations, what actually broke that you didn't expect going in? The redirect mapping and the shortcode content always seem to be where the real time goes, curious if others are seeing the same pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read More
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://www.topblogs.online/blog/what-is-digital-marketing" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fplain-eeur-prod-public.komododecks.com%2F202609%2F17%2FGmYYmSuwjbX7TNz0ZksF%2Fimage.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.topblogs.online/blog/what-is-digital-marketing" rel="noopener noreferrer" class="c-link"&gt;
            What Is Digital Marketing? A Complete Beginner's Guide - TopBlogs
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            A plain-English breakdown of what digital marketing actually is, the channels that make it up, and where to start if you're completely new to the field.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.topblogs.online%2Ficon%3F0e9eb26cf9512256" width="32" height="32"&gt;
          topblogs.online
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>3 AI Coding Agents Compared: Which One Handles a Real Landing Page Best</title>
      <dc:creator>TheBitForge</dc:creator>
      <pubDate>Fri, 25 Sep 2026 13:59:45 +0000</pubDate>
      <link>https://dev.to/thebitforge/3-ai-coding-agents-compared-which-one-handles-a-real-landing-page-best-29pp</link>
      <guid>https://dev.to/thebitforge/3-ai-coding-agents-compared-which-one-handles-a-real-landing-page-best-29pp</guid>
      <description>&lt;p&gt;Everyone's got an opinion on which AI coding agent is "the best" right now, and almost none of those opinions are useful, because "best" depends entirely on what you're actually building. A tool that's fantastic at a 750,000-line refactor is overkill for a client landing page. A tool that's great for quick in-editor edits will fall apart the moment you need it to reason across a whole design system. So instead of asking "which one is best," the more honest question is: for a real, client-facing landing page build (hero section, animated scroll, responsive layout, form, the usual agency bread and butter), which agent actually gets you the furthest without babysitting it the whole way?&lt;/p&gt;

&lt;p&gt;I run a small agency, and landing pages are basically our bread and butter, so this isn't an abstract question for me. Here's how the three most commonly recommended agents actually stack up for that specific kind of work, based on what's publicly known about how each one is built and where each one is documented to shine or struggle.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three worth talking about
&lt;/h2&gt;

&lt;p&gt;There are more than three agents on the market now, opencode, Cline, Aider, Windsurf, Devin, and a handful of others each carve out their own niche. But for a landing page build specifically, three keep coming up in every serious comparison: &lt;strong&gt;Claude Code&lt;/strong&gt;, &lt;strong&gt;Cursor&lt;/strong&gt;, and &lt;strong&gt;GitHub Copilot&lt;/strong&gt;. Each one approaches the same problem from a genuinely different angle, and that angle matters more than any benchmark score.&lt;/p&gt;

&lt;h3&gt;
  
  
  Claude Code: deep reasoning, terminal-first, built for context
&lt;/h3&gt;

&lt;p&gt;Claude Code started life as a command-line agent and has since expanded into VS Code, JetBrains, the web, GitHub Actions, Slack, and mobile, but its core identity is still terminal-first. What makes it stand out for landing page work isn't speed, it's how much of the project it can actually hold in its head at once. A 1M-token context window means it can read through a whole repo without needing a prebuilt index, which matters more than people expect once your landing page has a component library, a design system, animation utilities, and a handful of client-specific overrides all interacting with each other.&lt;/p&gt;

&lt;p&gt;Where this shows up in practice: if you're asking an agent to wire a GSAP ScrollTrigger animation into an existing Lenis smooth-scroll setup without breaking three other animations already living in the same file, that's a reasoning problem, not a typing-speed problem. Claude Code is built for exactly that kind of cross-file, "understand the whole thing before touching anything" task. It can also split work across subagents when a change spans multiple concerns at once, so it's genuinely capable of handling the hero animation and the form validation logic as separate threads instead of doing everything sequentially.&lt;/p&gt;

&lt;p&gt;The tradeoff is token usage. Deep reasoning isn't free, and Claude Code tends to run more expensive than lighter in-editor tools if you're not being deliberate about how you scope tasks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cursor: the fastest feedback loop, best for iterating live
&lt;/h3&gt;

&lt;p&gt;Cursor's whole pitch is that it lives inside your editor and lets you describe changes in natural language across multiple files, and for a landing page, that iteration speed is genuinely valuable. Landing pages are visual by nature. You're not just writing logic, you're constantly eyeballing spacing, checking breakpoints, nudging animation timing until it feels right. That's a workflow where a fast, in-editor loop beats a slower, more deliberate reasoning process almost every time.&lt;/p&gt;

&lt;p&gt;Cursor's agent mode handles multi-file edits well, and its integration with both Anthropic and OpenAI models means you can switch models depending on the task without switching tools. For the kind of rapid back-and-forth that landing page polish actually requires ("make this section breathe more," "the hero text is too close to the nav on mobile," "that transition feels sluggish, tighten it up") Cursor's speed advantage is real and it's the part most developers notice first.&lt;/p&gt;

&lt;p&gt;Where it's weaker is on the kind of deep, whole-project reasoning Claude Code handles well. If the landing page is simple and self-contained, that weakness rarely surfaces. If it's tangled into a larger app with shared components and global state, Cursor can start making changes that are locally correct and globally wrong.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub Copilot: the safest choice for GitHub-heavy teams
&lt;/h3&gt;

&lt;p&gt;Copilot's biggest strength has never been raw agentic power, it's how deeply it's wired into GitHub itself. If your workflow already runs through GitHub issues, pull requests, and CI, Copilot's agent mode turning an issue directly into a PR is a genuinely useful loop that neither Claude Code nor Cursor replicates as natively. For an agency juggling multiple client repos under one GitHub org, that consistency has real value, even if the actual code generation isn't the sharpest of the three.&lt;/p&gt;

&lt;p&gt;For landing page work specifically, Copilot tends to be the safer, more conservative option. It's less likely to make a sweeping, confident-but-wrong architectural decision, but it's also less likely to independently solve a genuinely tricky animation-sequencing bug the way Claude Code sometimes can. It's the agent you reach for when you want steady, predictable, well-scoped changes inside an established workflow, not the one you reach for when you're trying to get an agent to reason its way through something novel.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually matters for a landing page build
&lt;/h2&gt;

&lt;p&gt;Strip away the marketing and the benchmark charts, and three things determine how well any of these agents perform on a real landing page:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How well it understands the whole file tree before making a change.&lt;/strong&gt; Landing pages look simple from the outside but they're often held together by shared design tokens, a couple of layout components, and animation utilities that touch more files than you'd guess. An agent that edits file-by-file without real repo context will happily break something two components away from wherever it's currently looking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it handles anything visual.&lt;/strong&gt; None of these agents can actually see your rendered page (unless you're pairing them with a screenshot or a visual testing setup), so anything involving spacing, timing, or "does this feel right" still needs a human eye on the result. The agent that gets you closest on the first pass, without needing five rounds of "no, still not quite right," saves the most real time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost versus how much babysitting it needs.&lt;/strong&gt; A cheaper agent that requires constant correction isn't actually cheaper once you count your own time reviewing and fixing its output. This is the part that gets ignored in most comparisons, because token pricing is easy to put in a table and "how many times did I have to intervene" is not.&lt;/p&gt;

&lt;h2&gt;
  
  
  So which one, for a landing page
&lt;/h2&gt;

&lt;p&gt;If the page is genuinely self-contained, a single hero section, a form, some scroll effects, not deeply wired into a larger app, Cursor's speed usually wins. You'll iterate faster and the lack of deep repo reasoning barely matters because there isn't much repo to reason about.&lt;/p&gt;

&lt;p&gt;If the landing page lives inside a bigger Next.js app with a shared component library and design system, Claude Code earns its higher cost by actually understanding how the page fits into everything around it, which matters a lot once you're touching shared animation utilities or global styles.&lt;/p&gt;

&lt;p&gt;If the team already lives and breathes GitHub workflows and values consistency and predictability over raw capability, Copilot is the one that fits without friction, even if it's not going to independently solve your trickiest animation bug.&lt;/p&gt;

&lt;p&gt;None of these are "the best AI coding agent" in some universal sense, and anyone telling you there's one clear winner across every kind of project is skipping the part where context actually matters. For a landing page specifically, pick based on how self-contained the page is and how much your team already depends on GitHub, not based on whichever benchmark chart happened to go viral this week.&lt;/p&gt;




&lt;p&gt;Which one are you actually using day to day for frontend work, and has it held up once the project got more tangled than a single page? Curious whether other agency folks are landing on the same picks or something completely different.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read More
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://www.topblogs.online/blog/beginner-seo-checklist" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fplain-eeur-prod-public.komododecks.com%2F202609%2F19%2FHiAdUhv1bUWZT4XNZGjI%2Fimage.jpg" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.topblogs.online/blog/beginner-seo-checklist" rel="noopener noreferrer" class="c-link"&gt;
            Beginner's SEO Checklist: 15 Things That Matter, 5 to Skip - TopBlogs
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            A practical beginner SEO checklist: 15 things worth doing on a new site, and 5 popular pieces of advice you can safely skip. Free tools only.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.topblogs.online%2Ficon%3F0e9eb26cf9512256" width="32" height="32"&gt;
          topblogs.online
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Clean Code vs Clear Code: What Actually Makes Code Easy to Read</title>
      <dc:creator>TheBitForge</dc:creator>
      <pubDate>Fri, 25 Sep 2026 13:55:39 +0000</pubDate>
      <link>https://dev.to/thebitforge/clean-code-vs-clear-code-what-actually-makes-code-easy-to-read-2h00</link>
      <guid>https://dev.to/thebitforge/clean-code-vs-clear-code-what-actually-makes-code-easy-to-read-2h00</guid>
      <description>&lt;p&gt;Okay so here's a sentence that's going to sound like nitpicking until I explain it: clean code and clear code are not the same thing. I know, I know, they sound identical. Half of you just read that and went "yeah... obviously?" Stick with me for a second, because this distinction has cost me actual billable hours more than once, and I'd bet money it's cost you some too, even if you never had a name for it.&lt;/p&gt;

&lt;p&gt;I run a small dev agency. We do a mix of WordPress/Woo builds, Next.js apps, and a lot of GSAP/Lenis-heavy frontend work for clients who want their site to &lt;em&gt;feel&lt;/em&gt; expensive. Which means I inherit codebases. A lot of them. Other agencies' work, freelancers who ghosted mid-project, in-house devs who left before I showed up. And there's a very specific kind of pain that only happens when the code you're staring at is, by every textbook metric, &lt;em&gt;good&lt;/em&gt;, and you're still lost.&lt;/p&gt;

&lt;p&gt;Short functions ✅. Sensible names ✅. No copy-pasted blocks ✅. Looks like it walked straight out of a Clean Code slide deck. And yet I'm five minutes into a bug fix going "why does this exist" out loud to an empty room.&lt;/p&gt;

&lt;p&gt;That's the gap. That's the whole article, basically. Let's actually dig into it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What people mean when they say "clean code"
&lt;/h2&gt;

&lt;p&gt;Nine times out of ten, when a dev says "clean code" in a standup or a PR comment, they're quoting, knowingly or not, Robert C. Martin's &lt;em&gt;Clean Code&lt;/em&gt;. That book is basically load-bearing infrastructure for how a whole generation of us think about code quality. And honestly? A lot of it holds up fine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Functions that do one thing, not four things wearing a trench coat&lt;/li&gt;
&lt;li&gt;Names that tell you what a variable &lt;em&gt;is&lt;/em&gt; without needing a tooltip&lt;/li&gt;
&lt;li&gt;No copy-pasted logic scattered across six files&lt;/li&gt;
&lt;li&gt;Formatting that doesn't make your eyes bleed&lt;/li&gt;
&lt;li&gt;Nesting shallow enough that you don't need a bookmark to find your place&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of that is controversial. If you've got a function called &lt;code&gt;handleStuff()&lt;/code&gt; that's 240 lines long with if-statements nested five deep, sure, go fix that, nobody's arguing otherwise.&lt;/p&gt;

&lt;p&gt;But, and this is the part that gets glossed over constantly, clean code is fundamentally a &lt;strong&gt;style question&lt;/strong&gt;. It's about the shape of the thing. Does it look organized? Is it consistent? Would it survive a code review without someone leaving eleven comments? Clean code answers one, and only one, question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What does this code do?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's it. That's the ceiling. It doesn't tell you why the code does it &lt;em&gt;that&lt;/em&gt; way instead of some other way, and it was never trying to.&lt;/p&gt;

&lt;h2&gt;
  
  
  What clear code is actually asking
&lt;/h2&gt;

&lt;p&gt;Clear code is a different animal, and it's answering a question that's genuinely harder to satisfy:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why does this exist, and why does it look like &lt;em&gt;this specifically&lt;/em&gt;?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That question lives somewhere nastier than syntax. It lives in whatever the original developer was thinking at 4:47pm on a Thursday when they wrote that weird conditional, and that context doesn't survive very long. It doesn't survive a job change. It barely survives a two-week vacation. Half the time it doesn't survive the &lt;em&gt;weekend&lt;/em&gt;, honestly, because we've all had the experience of looking at our own code from a month ago and going "past me, what were you even doing here."&lt;/p&gt;

&lt;p&gt;Here's a small example, and I promise it's not a strawman, I've written this exact line more than once:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MAX_RETRIES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Perfectly clean. Good constant name, no magic number sitting naked in the middle of a function, passes any linter you throw at it. But why 3? Is that because a third-party API you're hitting starts throwing 429s after three tries? Is it a number someone picked because it "felt right" during a sprint two years ago and nobody's touched it since? Is it load-bearing, or is it decorative?&lt;/p&gt;

&lt;p&gt;Clean code cannot answer that. It was never built to. Clear code answers it in one line above the constant, and that one line is the difference between a five-second read and a twenty-minute git-blame spiral that ends with you messaging someone who left the company in March.&lt;/p&gt;
&lt;h2&gt;
  
  
  The comments argument, and why the "no comments" crowd is wrong about half the time
&lt;/h2&gt;

&lt;p&gt;There's a school of thought, loud, confident, shows up in nearly every "clean code" discussion thread, that says comments are basically an admission of failure. If your code needs a comment to be understood, the argument goes, you haven't refactored hard enough. Extract the method, rename the variable, and the code will explain itself. No comments needed, ever.&lt;/p&gt;

&lt;p&gt;I get the appeal. I even agree with maybe 60% of it. A comment that says &lt;code&gt;// loop through the array&lt;/code&gt; above a for-loop is genuinely worthless and yes, delete it, it's not helping anyone.&lt;/p&gt;

&lt;p&gt;But the "code should never need comments" position falls apart the second you hit anything with real density. Try explaining a gnarly regex through naming alone. Try explaining a bitwise trick used for performance reasons through variable names alone. Try explaining why a form validation deliberately skips one specific field because a client's legal team asked for it after an incident eighteen months ago that nobody currently on the team was around for. No amount of renaming fixes that. The reasoning simply does not live in the syntax, full stop.&lt;/p&gt;

&lt;p&gt;And the usual counter-argument ("put that reasoning in the commit message, that's what git blame is for") sounds reasonable until you actually think about when people use git blame. Nobody runs git blame on code that looks fine. You only go digging once something's already broken, once you're already under pressure, and by that point the person who actually knew the reasoning has usually moved teams, left the company, or just forgotten. Commit history isn't documentation. It's a graveyard you visit after something's already gone wrong.&lt;/p&gt;

&lt;p&gt;So here's the rule I actually use, and it's short enough to fit on a sticky note:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you had to stop and think before writing a line, write down what you were thinking. If the line was obvious, leave it alone.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's the whole heuristic. Not "comment everything." Not "comment nothing." Comment the moments where your brain paused. A comment earns its spot in the code when it's doing one of these jobs, and basically nothing else:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Translating something genuinely dense (regex, bit tricks, math that isn't self-evident)&lt;/li&gt;
&lt;li&gt;Explaining a decision that looks wrong or arbitrary at first glance but isn't&lt;/li&gt;
&lt;li&gt;Warning the next person what breaks if they "clean up" something that looks messy on purpose&lt;/li&gt;
&lt;li&gt;Recording a decision that has an actual expiry date, not a TODO that's been sitting there since 2023&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Everything outside those four jobs is noise. And ironically, a file stuffed with noisy, decorative comments isn't clear either, it's just cluttered in a different direction than messy code is. Over-commenting and under-commenting are the same failure wearing different outfits.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why this distinction actually costs money, not just annoyance
&lt;/h2&gt;

&lt;p&gt;I want to get specific here instead of staying theoretical, because this is where the agency angle actually matters.&lt;/p&gt;

&lt;p&gt;I've taken over projects that scored well on every clean-code checklist you could throw at them. Small components. No duplicated logic. Naming that a linter would happily approve. And I still burned hours because nobody could tell me why a &lt;code&gt;z-index&lt;/code&gt; was hardcoded to &lt;code&gt;9999&lt;/code&gt; on one specific div, or why a scroll animation had a hardcoded 300ms delay that broke the second I tried to make it responsive, or why one form field silently skipped validation while every other field on the same form didn't.&lt;/p&gt;

&lt;p&gt;None of that shows up in a "is this code clean" review. It only shows up once you're the person who has to modify it under a deadline, with a client watching a staging link, and no way to ask the original developer anything because that developer is three jobs away by now.&lt;/p&gt;

&lt;p&gt;That's the actual cost. Clean code gets you through a code review. It makes a good first impression and it genuinely does reduce a certain kind of friction, nobody's arguing you should go back to writing 300-line functions with variables named &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;temp2&lt;/code&gt;. But clear code is what determines whether the codebase is still survivable six months from now, when the person who wrote it is gone and somebody else has inherited both the logic and the reasoning behind it, minus the reasoning part.&lt;/p&gt;
&lt;h2&gt;
  
  
  So which one do you actually chase
&lt;/h2&gt;

&lt;p&gt;Both. But treat them as solving two separate problems, because they are, and fixing one does not automatically fix the other.&lt;/p&gt;

&lt;p&gt;Clean code principles get your codebase readable at a glance: good names, small functions, no duplication, consistent formatting. That's the baseline. Skip it and nothing else in this article matters, because nobody can get far enough into unreadable code to even need the "why."&lt;/p&gt;

&lt;p&gt;Clear code practices (targeted comments, honest documentation, defaults that make sense without archaeology) preserve the reasoning that the syntax was never going to carry on its own, no matter how well-named your variables are.&lt;/p&gt;

&lt;p&gt;Optimize only for clean and you get a codebase that looks great in a portfolio screenshot and still requires a Slack message to the original author every single time something non-obvious needs to change. Optimize only for clear without the clean foundation underneath it, and you end up with comments trying to compensate for logic that's genuinely tangled, which is its own flavor of mess, just dressed up with more prose.&lt;/p&gt;

&lt;p&gt;The actual goal was never "clean." It was never really about how the code looks in a screenshot. The goal is understandable, by someone who wasn't in the room when the decision got made, wasn't there for the client call that caused the weird edge case, and doesn't have access to whatever was in your head the day you wrote it.&lt;/p&gt;



&lt;p&gt;Genuinely curious how other teams handle this in practice, is there an actual house rule for when a comment is required where you work, or is it just vibes and whatever the reviewer happens to nitpick that day? Drop it in the comments, I want to steal good ideas.&lt;/p&gt;
&lt;h2&gt;
  
  
  Read More
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://www.topblogs.online/blog/beginner-seo-checklist-2" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fplain-eeur-prod-public.komododecks.com%2F202609%2F22%2FOXMjHk1iVjOoDzWn8NeZ%2Fimage.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.topblogs.online/blog/beginner-seo-checklist-2" rel="noopener noreferrer" class="c-link"&gt;
            The Practical GEO Checklist We Use in 2026 - TopBlogs
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Ranking on Google isn't enough anymore. Here's the exact GEO checklist we run on every post to get cited by ChatGPT, Gemini, and Perplexity, and what we skip.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.topblogs.online%2Ficon%3F0e9eb26cf9512256" width="32" height="32"&gt;
          topblogs.online
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How AI Agents Went From Buzzword to Everywhere So Quickly</title>
      <dc:creator>TheBitForge</dc:creator>
      <pubDate>Wed, 23 Sep 2026 13:37:59 +0000</pubDate>
      <link>https://dev.to/thebitforge/how-ai-agents-went-from-buzzword-to-everywhere-so-quickly-1jpf</link>
      <guid>https://dev.to/thebitforge/how-ai-agents-went-from-buzzword-to-everywhere-so-quickly-1jpf</guid>
      <description>&lt;h2&gt;
  
  
  Read Here
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://www.topblogs.online/blog/ai-agents-buzzword-to-everywhere" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fplain-eeur-prod-public.komododecks.com%2F202609%2F23%2FxUGkg4Pb2iT0dti5kBFj%2Fimage.png" height="423" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.topblogs.online/blog/ai-agents-buzzword-to-everywhere" rel="noopener noreferrer" class="c-link"&gt;
            How AI Agents Went From Buzzword to Everywhere So Quickly - TopBlogs
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            AI agents went from an AI buzzword to a major software trend remarkably fast. Here's what changed, why businesses are adopting them, and what comes next.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.topblogs.online%2Ficon%3F0e9eb26cf9512256" width="32" height="32"&gt;
          topblogs.online
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;I noticed it first in a Slack channel, of all places. A coworker dropped a link to some new "agent framework" like it was old news, and I sat there wondering when this had become something everyone just knew about. A couple of months ago the term mostly showed up in AI conference talks. Now it's in changelogs, job postings, investor updates.&lt;/p&gt;

&lt;p&gt;So I went and looked at what actually happened, instead of just going off the vibe that something had changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happened on September 23
&lt;/h2&gt;

&lt;p&gt;On September 23, a Google open source project called ax picked up more than 2,300 GitHub stars in one day. I went and looked at the repo myself before writing this, half expecting to find something underwhelming behind the number. I didn't. It's built to run agent workloads the way Kubernetes runs containers, with commands like ax apply, ax describe, ax suspend, and it comes with a warning baked right into the docs: agents can burn money in a loop if nobody's watching them.&lt;/p&gt;

&lt;p&gt;That line stuck with me more than the star count did.&lt;/p&gt;

&lt;p&gt;The same day, a couple of other agent infrastructure projects launched close together too. Maybe that's coincidence. It might just mean a few teams hit the same wall at the same time and shipped their fix in the same week. I don't have a way to prove which one it is, so I'll leave it there.&lt;/p&gt;

&lt;p&gt;The reason agents need their own infrastructure becomes pretty obvious once you look at how they actually run: a normal app either waits for a request or runs a job and finishes. Agents don't work like that. They hold state across steps, they need to be boxed in, and they keep calling out to models and tools in a loop that doesn't stop on its own unless something tells it to. Left alone, that loop can keep spending compute and API credits while technically doing something that looks like work, without anyone noticing it's gone sideways. I've seen a smaller version of this myself, a script that kept retrying an API call all weekend because I forgot a stop condition, and it cost me about forty dollars in credits for nothing. Multiply that by an agent making its own decisions instead of following a fixed script, and you start to see why teams are building real guardrails around this instead of just duct taping a chatbot to a few tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  An agent is not just a fancier chatbot
&lt;/h2&gt;

&lt;p&gt;A chatbot answers what you ask it, and the interaction ends there. An agent gets a goal instead of a question, and it works out its own steps, pulling from more than one source, checking what it finds, acting on it, often without a person approving each move.&lt;/p&gt;

&lt;p&gt;You're not asking a model something anymore. You're handing it a task and walking away from your desk.&lt;/p&gt;

&lt;p&gt;There's data suggesting people are already leaning into this. HigherVisibility reported daily AI search usage in the US climbed from about 14 percent to 29 percent over six months. Separately, eMarketer cited IAB data putting AI-assisted shopping research at around 38 percent of shoppers, most of whom still double check details before buying. I haven't verified either firm's methodology myself, so treat those two numbers as reported figures, not as something I've independently confirmed. What matches what I'm seeing anecdotally is the shape of it: the agent does more of the digging, the human still makes the final call, for now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why so many products are suddenly adding agent features
&lt;/h2&gt;

&lt;p&gt;Here's what I think is happening: if more research and comparison shopping gets done by software instead of a person clicking through search results, then ranking on Google stops being the whole game. Getting recommended by the agent doing the comparing might start to matter just as much.&lt;/p&gt;

&lt;p&gt;I don't know if that's fully true yet. But it would explain why tools that had nothing to do with AI a year ago are shipping agent features now. Some of this is probably just marketing. But there's also a real possibility that companies are preparing for a world where software itself becomes part of the buying process.&lt;/p&gt;

&lt;h2&gt;
  
  
  It hasn't all gone smoothly
&lt;/h2&gt;

&lt;p&gt;Giving software this much independence has already caused problems. Google disclosed that its Gemini model got unauthorized access to outside systems during an internal test, and that the model apparently thought those systems were part of the sandboxed test environment when they were actually connected to the live internet. Nobody was reported hurt, and Google caught it, but it's the kind of story that makes a cautious engineering lead a lot less eager to say yes to full autonomy.&lt;/p&gt;

&lt;p&gt;Anthropic's CEO Dario Amodei has been publicly asking the industry to slow down and let safety work catch up with how fast capability is moving. According to AI Weekly's coverage, OpenAI's Sam Altman and xAI's Elon Musk have both said they agree with him. Executives at competing labs publicly backing each other's safety concerns like this is notable on its own, whatever you think of the underlying argument.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should you actually care
&lt;/h2&gt;

&lt;p&gt;If you build or run a product, probably a little, yes. Not in a rush-something-out-by-Friday way. I'd ask two things. Is there a task in your product that someone still does manually, step by step, that an agent could handle? And if an AI agent were evaluating your product for someone, would it have enough clear information to recommend you, or would it just get confused and move on?&lt;/p&gt;

&lt;p&gt;If you're just reading this because the term kept showing up everywhere, the simple version is: you're going to keep running into "agent" features in tools you already use, whether you asked for them or not. Knowing a real agent from a chatbot wearing an agent costume is useful. One saves you time. The other's just another button you'll never touch.&lt;/p&gt;

&lt;p&gt;I'm not convinced this slows down in a quarter. Whether it's actually good for the average person yet, I genuinely don't know. But the plumbing being built right now, orchestration, guardrails, whatever comes after this, is going to be the thing everything else sits on top of. Worth watching, even if you're not ready to hand over the keys.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Why You're Not Getting Interviews (And It's Probably Not Your Resume)</title>
      <dc:creator>TheBitForge</dc:creator>
      <pubDate>Mon, 21 Sep 2026 16:51:07 +0000</pubDate>
      <link>https://dev.to/thebitforge/why-youre-not-getting-interviews-and-its-probably-not-your-resume-14pb</link>
      <guid>https://dev.to/thebitforge/why-youre-not-getting-interviews-and-its-probably-not-your-resume-14pb</guid>
      <description>&lt;p&gt;John, a job seeker in Naples, Florida, has a business degree, a master's in data analytics, and roughly 2,000 applications from a year of searching. He told a personal-finance radio show that he had landed a handful of interviews, and as Benzinga reported, every one of them came through an internal referral.&lt;/p&gt;

&lt;p&gt;The usual response to a stalled search is more applications and another pass at the resume. Sometimes that's the fix. Often it isn't, and the rest of this article looks at the other places to check.&lt;/p&gt;

&lt;h2&gt;
  
  
  How long a search takes now
&lt;/h2&gt;

&lt;p&gt;Huntr's Q1 2026 report covers 139,927 applications from 25,635 job seekers. The median time from starting a search to a first offer reached 108 days, up 30% from the previous quarter and the longest Huntr has recorded. That's the median for people who got offers. Six weeks without one is frustrating, but by that dataset it isn't unusual.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 1: Too many of the wrong jobs
&lt;/h2&gt;

&lt;p&gt;A lot of people apply whenever a job title looks vaguely familiar, and end up against hundreds of people for roles they only half fit. One roundup of recruiter comments put entry-level postings at 400 to 600 applicants and some engineering roles past 2,000. Nobody reads that many resumes carefully.&lt;/p&gt;

&lt;p&gt;In Huntr's Q1 2026 data, people who sent 11 to 20 applications got interviews on 9.25% of them. People who sent 100 or more got 2.58%. John's case sits at the far end of that. His radio hosts told him to do more of what had produced his interviews, meaning referrals, and Glassdoor's poll, cited in the same report, found referrals are about 35% more likely to end in an offer.&lt;/p&gt;

&lt;p&gt;A quick check before you apply: can you finish the sentence "They should pick me over the other 400 people because..."? If you can't, skip that job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 2: The resume
&lt;/h2&gt;

&lt;p&gt;Recruiters skim. In Enhancv's January 2026 interviews with 25 recruiters, the advice was to write for the first ten seconds of a human read, leading with skills that fit the role and proof of results, such as metrics. In practice that puts your most relevant experience at the top, not on page two, and replaces duties with results. "Managed onboarding" says nothing. "Cut onboarding from three weeks to ten days" says plenty. If the job post says "customer success" and your resume says "client happiness," the reader has to translate, so use their wording where it's accurate. A cluttered layout loses a tired reader, so keep it plain.&lt;/p&gt;

&lt;p&gt;Huntr lists matching your resume to the job description among the best things you can do. It takes time on every application, which is one more reason not to apply to every vaguely relevant job you see.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does software reject most resumes?
&lt;/h2&gt;

&lt;p&gt;The claim usually comes with a number like 75% attached. One analysis traced that figure to a defunct recruiting-services company that never disclosed how it got it. Recruiters interviewed elsewhere said automatic rejections generally come from knockout questions they set up themselves, such as work authorization, and not from an algorithm grading your wording. So a rejection thirty seconds after you apply is most likely a knockout question ("Do you have 5+ years of X?") or sheer volume. Nobody can read 2,000 resumes.&lt;/p&gt;

&lt;p&gt;Keep the formatting clean for the human who'll read it, and skip the week of keyword gaming.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 3: Where the application goes
&lt;/h2&gt;

&lt;p&gt;Camille Manaois spent months applying online and got mostly silence. So she mailed paper envelopes to six employers, each with a short note, her resume, a cover letter and a recommendation from a coworker. She told CNBC Make It the note felt embarrassing to write, but a letter addressed to a person would at least get opened. Four of the six companies replied, some with rejections. One passed her materials to a communications agency in the same building, and the agency's vice president hired her.&lt;/p&gt;

&lt;p&gt;Huntr also looked at where applications were sent. Through job boards and aggregators, about 1.95% reached an interview. Straight into an applicant tracking system, 3.16%. Through a company's own career page, 6.87%. Part of that gap probably comes from who uses each route. People who go to a company's site tend to be more selective, and Huntr notes that one-click and bulk-apply tools are easy for everyone to use, which drags their numbers down.&lt;/p&gt;

&lt;p&gt;Finding a role on a board and then applying on the company's own site costs nothing extra. Neither does applying early: one 2026 analysis found a posting live for over a month is far more likely to be a ghost job than one from the last few days. And a message to someone on the team, or an introduction from a person who knows your work, is worth the awkwardness. Every interview John got came that way.&lt;/p&gt;

&lt;p&gt;Ghost jobs are listings that aren't tied to an open role at all. Estimates range widely: one guide says roughly 18% to 27% of listings, another study found about 1 in 7 active posts. If a posting is old, vague, shows no pay range and isn't on the company's own careers page, don't spend an hour on it.&lt;/p&gt;

&lt;p&gt;Ontario has gone as far as legislating. Since January 1, 2026, employers there with 25 or more staff have to disclose pay ranges in postings and tell every interviewed candidate the outcome within 45 days.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 4: Interviews without offers
&lt;/h2&gt;

&lt;p&gt;Getting interviews but no offers means the resume is doing its job. The gap is in the conversation. Have one clear story ready about a project you're proud of, be able to say why you want this role in particular, and bring a couple of real questions about the work. Record yourself answering "tell me about yourself" and watch it back. It's uncomfortable, but it shows you things you can't hear while you're talking. After each interview, write down what you'd change while you still remember it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Working out where yours is breaking
&lt;/h2&gt;

&lt;p&gt;If you've sent dozens of tailored applications with no replies, look at the roles you're targeting first, then the top third of your resume. Replies only from mass-apply boards, and never from the roles you wanted, point to the route, so try company sites and a message to someone on the team. Interviews that never reach a second round call for a mock interview with a friend. And a rejection that arrives within seconds is worth checking for a knockout question or another hard requirement you may not meet.&lt;/p&gt;

&lt;p&gt;Keep a simple record of every application: company, role, date, where you applied, what happened. After a few weeks the pattern is usually visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  If the search still stalls
&lt;/h2&gt;

&lt;p&gt;Say you've narrowed the roles, tightened the resume and changed how you apply, and a solid stretch has still passed with nothing. Sending even more applications probably isn't the next step. The roles you want may sit in a squeezed part of the market. One skill or certification might keep showing up in the postings you're missing. A neighboring job title might be an easier way in.&lt;/p&gt;

&lt;p&gt;Sam Rabinowitz, a finance graduate, sent more than 1,000 applications without luck, then spent $136 of the roughly $700 left in his account on a poster and stood outside the New York Stock Exchange asking for work. He told Fortune it was worth it. A partner at an IPO company called him over and he got an interview, though when the story ran in September 2025 he hadn't heard back about a job.&lt;/p&gt;

&lt;p&gt;Whatever you try, change one thing at a time and keep the application record going, so you can tell whether it made a difference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How many applications should I send each week?&lt;/strong&gt;&lt;br&gt;
There isn't a number that works for everyone. Huntr's data points toward fewer, more targeted applications over pure volume, so pick a pace where each one still gets real effort.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need to rewrite my resume for every job?&lt;/strong&gt;&lt;br&gt;
Not from scratch. Keep a strong base version and adjust the top section and key bullets for each role.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is it worth applying to old postings?&lt;/strong&gt;&lt;br&gt;
Sometimes. If it's still on the company's own careers page and lists a specific role and pay range, it's worth a try. If it's been sitting there for weeks with a vague description, skip it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I worry about AI screening?&lt;/strong&gt;&lt;br&gt;
Some employers use software to sort or rank applications. That's no reason to stuff your resume with keywords. Keep it readable and make the relevant evidence easy for a recruiter to find.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;General career information, not personalized advice. Statistics come from the third-party sources listed below and may change.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Research reports and original reporting&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Huntr, Q1 2026 Job Search Trends Report&lt;/li&gt;
&lt;li&gt;Huntr, The Best Job Boards of 2026, Ranked by Interview Rate&lt;/li&gt;
&lt;li&gt;CNBC Make It, Camille Manaois's mailed-resume story&lt;/li&gt;
&lt;li&gt;Moneywise, follow-up on the same story&lt;/li&gt;
&lt;li&gt;Fortune (via Yahoo), Sam Rabinowitz's Wall Street sign&lt;/li&gt;
&lt;li&gt;Benzinga (via AOL), report on a job seeker's 2,000 applications and Glassdoor's referral data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Recruiting and career blogs (context, less rigorous)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Interview Guys, The ATS Resume Rejection Myth&lt;/li&gt;
&lt;li&gt;Enhancv, Does the ATS Reject Your Resume? 25 Recruiters Explain&lt;/li&gt;
&lt;li&gt;HR Gazette, Debunking the ATS Rejection Myth&lt;/li&gt;
&lt;li&gt;DAVRON, ATS Systems Explained&lt;/li&gt;
&lt;li&gt;Metaintro, Ghost Jobs Are Breaking the 2026 Hiring Market&lt;/li&gt;
&lt;li&gt;MintCareer, Ghost Jobs in 2026&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Read Here
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://www.topblogs.online/blog/why-not-getting-interviews" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fplain-eeur-prod-public.komododecks.com%2F202609%2F21%2FYlnYSNRjbYPBngAbdTv6%2Fimage.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.topblogs.online/blog/why-not-getting-interviews" rel="noopener noreferrer" class="c-link"&gt;
            Not Getting Interviews? 4 Places Your Job Search Breaks - TopBlogs
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Applied to dozens of jobs and heard nothing? Use real hiring data and job seekers' stories to find which of four stages is breaking your search.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.topblogs.online%2Ficon%3F0e9eb26cf9512256" width="32" height="32"&gt;
          topblogs.online
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>why everyone on dev.to is arguing about vibe coding this week (and who's actually right)</title>
      <dc:creator>TheBitForge</dc:creator>
      <pubDate>Sat, 19 Sep 2026 09:09:20 +0000</pubDate>
      <link>https://dev.to/thebitforge/why-everyone-on-devto-is-arguing-about-vibe-coding-this-week-and-whos-actually-right-13ne</link>
      <guid>https://dev.to/thebitforge/why-everyone-on-devto-is-arguing-about-vibe-coding-this-week-and-whos-actually-right-13ne</guid>
      <description>&lt;p&gt;Every developer feed I opened this week had some version of the same argument. Someone writes code with AI, ships it without really reading it, and somebody else asks: is that engineering, or is that just typing?&lt;/p&gt;

&lt;p&gt;I read the post that started it, went through a chunk of the comments, and followed a few of the studies people kept linking in there. Here's what's actually in them, and who said what.&lt;/p&gt;

&lt;h2&gt;
  
  
  Giorgi Kobaidze started it
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://dev.to/georgekobaidze/vibe-coding-isnt-the-problem-calling-it-engineering-is-lm1"&gt;Vibe Coding Isn't the Problem. Calling It Engineering Is&lt;/a&gt;&lt;/strong&gt; by &lt;strong&gt;&lt;a href="https://dev.to/georgekobaidze"&gt;Giorgi Kobaidze&lt;/a&gt;&lt;/strong&gt; pulled in over 200 comments, which for dev.to is a lot. Not quick reactions either, people were writing full paragraphs, some coming back a second time to keep arguing.&lt;/p&gt;

&lt;p&gt;Giorgi splits AI-assisted coding into three modes. Vibe coding is prompt, get code, ship it, without reading or really understanding what you shipped. AI-assisting is the AI writes it but a human reviews every line before it goes anywhere. AI-assisted is somewhere in between, human and model actually working together with the human still driving.&lt;/p&gt;

&lt;p&gt;He's fine with the first one for personal stuff, weekend projects, things nobody depends on. Where he draws a hard line is anything touching money or personal data. His exact reasoning: if you build something real, something processing people's data or handling money, and you vibe code it start to finish, that tells him one of three things, you're not willing to spend two to four weeks learning the basics, you don't actually understand what you shipped, or you're doing it anyway just to prove a point. His line on that last one was blunt, doing it to prove a point will cause absolute chaos.&lt;/p&gt;

&lt;p&gt;One commenter, who said they build things this way themselves, actually agreed more than they pushed back. They pointed out the trend toward more abstraction has been going on since assembly language, and maybe the job eventually becomes mostly prompting. But they landed in the same place Giorgi did, that's a question about where the industry is headed, not whether we're ready to run financial systems and health apps on unreviewed code right now. Their answer to that second question was no.&lt;/p&gt;

&lt;p&gt;Someone else in the thread put it in a way I keep coming back to. It's not really about how much code the AI wrote. It's about whether someone can still explain the architecture, name the assumptions, and say where it's going to break. You could have AI write 95 percent of a system and it still counts as engineering, as long as a person can back up every part of it if asked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dhruv Jani brought the data
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://dev.to/dj29/ai-didnt-remove-the-engineering-work-it-just-made-it-easier-to-pretend-you-did-42m9"&gt;AI Didn't Remove the Engineering Work. It Just Made It Easier to Pretend You Did.&lt;/a&gt;&lt;/strong&gt; by &lt;strong&gt;&lt;a href="https://dev.to/dj29"&gt;Dhruv Jani&lt;/a&gt;&lt;/strong&gt; got its own solid comment thread going. Worth noting, Dhruv's an upcoming trainee engineer, still a student. So this isn't a twenty-year veteran being nostalgic, it's someone walking into the field right as this argument is playing out.&lt;/p&gt;

&lt;p&gt;His piece leans on actual research instead of gut feeling. He cites a Carnegie Mellon study that tracked over 800 open-source projects after teams adopted AI coding tools, checked against a control group that didn't. The pattern showed up consistently, an early burst of speed, then code complexity and static-analysis warnings climbing, then eventually future velocity dropping below where it started. Faster at first, slower later. He also references similar METR findings, this time in developers who already knew their codebase well, so even familiarity didn't fully protect against the slowdown.&lt;/p&gt;

&lt;p&gt;He's not arguing AI is bad. His point is closer to, AI speeds up the boring parts, boilerplate, prototypes, repetitive scaffolding, and that's genuinely useful. It just doesn't make the hard engineering decisions go anywhere, understanding failure modes, architecture, how something behaves under real load. Those two things get treated as the same thing in a lot of the AI-replaces-engineers takes, and they're not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Elmar Chavez's post sits with you longer
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://dev.to/codingwithjiro/the-slow-and-quiet-cognitive-atrophy-of-a-modern-software-engineer-3lbh"&gt;The Slow and Quiet Cognitive Atrophy of a Modern Software Engineer&lt;/a&gt;&lt;/strong&gt; by &lt;strong&gt;&lt;a href="https://dev.to/codingwithjiro"&gt;Elmar Chavez&lt;/a&gt;&lt;/strong&gt; goes somewhere different. He's not worried about one project shipping broken. He's worried about what happens to your own instincts after months of accepting suggestions instead of actually working through a problem yourself. You don't notice it in any single sprint. You notice it the day the tool isn't there and you realize you've lost the thread of how you used to think something through.&lt;/p&gt;

&lt;h2&gt;
  
  
  The security research surprised me a bit
&lt;/h2&gt;

&lt;p&gt;I expected the security angle to be the weak part of this argument, the part where people exaggerate. It wasn't. A security firm called Escape.tech scanned about 5,600 apps built on popular AI app-building platforms and found over 2,000 vulnerabilities, 400 exposed secrets, and 175 cases involving leaked personal data, some of it medical records and bank details. Separately, a different team tested five popular AI coding tools by having each build the same three applications, fifteen apps total, and found 69 vulnerabilities across them, six critical.&lt;/p&gt;

&lt;p&gt;There's an academic study too, 200 real feature-request tasks pulled from actual open-source projects, run through several coding agents. Most of the solutions worked functionally. Only around one in ten were actually secure. Even hinting at the vulnerability in the prompt didn't fix that much.&lt;/p&gt;

&lt;p&gt;None of this means the tools are useless, obviously they're not, people are shipping real things with them every day. It just means the gap between something that runs and something that's safe to hand to real users is bigger than most of us assume, and closing that gap is still mostly a person's job, not the model's.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I actually land on this
&lt;/h2&gt;

&lt;p&gt;I run a small agency. Most of what we build is fast-turnaround client work, animation-heavy frontends, the kind of thing where the deadline is real and nobody's paying me to sit and admire my own code for a week before it ships. I use AI every day now, it's changed how fast I get from a blank file to something working.&lt;/p&gt;

&lt;p&gt;But a few months back I had a client site where AI had generated a form submission handler that looked completely fine, worked in testing, and quietly duplicated database entries under load because of a race condition I didn't catch until a client complained about seeing double bookings. Nothing about the code looked wrong on a read-through. That's the part that stuck with me. Giorgi's framing matches that experience closer than I expected, it wasn't that AI wrote bad code, it's that I didn't understand it well enough yet to know what to check for.&lt;/p&gt;

&lt;p&gt;For me the actual test isn't how much code the AI wrote. It's whether I still understand the decisions behind it well enough to fix it fast when it breaks, usually at a bad time, usually with someone messaging me about it.&lt;/p&gt;

&lt;p&gt;You still review. You still ask why something works the way it does. You still need to know the architecture well enough to catch the thing that technically runs but is going to bite you in three months. The security numbers above make that review step feel a lot less skippable than it used to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this leaves things
&lt;/h2&gt;

&lt;p&gt;None of the three writers here are saying AI shouldn't touch serious codebases, Giorgi even said he'd welcome a future that's mostly prompting. The disagreement is about where responsibility sits once something ships, and that's worth arguing about properly instead of picking a side based on a headline.&lt;/p&gt;

&lt;p&gt;I don't think there needs to be one universal rule for how much AI-written code still counts as engineering. But there's a point past which using the tool stops being useful if you can't explain what it actually produced. That's roughly the line I try to hold myself to, some days better than others.&lt;/p&gt;

&lt;p&gt;Credit to &lt;a class="mentioned-user" href="https://dev.to/georgekobaidze"&gt;@georgekobaidze&lt;/a&gt; , &lt;a class="mentioned-user" href="https://dev.to/dj29"&gt;@dj29&lt;/a&gt; , and &lt;a class="mentioned-user" href="https://dev.to/codingwithjiro"&gt;@codingwithjiro&lt;/a&gt;  for kicking off a conversation this week that was actually worth reading in full, not just skimming the title.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Curious if anyone else here has had a similar wake-up moment with AI-written code.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Read More :
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://www.topblogs.online/blog/dario-amodei-pace-the-frontier-ai-safety-explained" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fplain-eeur-prod-public.komododecks.com%2F202609%2F15%2FmU0O2JEFf4WPYfWaZg3G%2Fimage.png" height="450" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.topblogs.online/blog/dario-amodei-pace-the-frontier-ai-safety-explained" rel="noopener noreferrer" class="c-link"&gt;
            Dario Amodei's "Pace the Frontier": What Anthropic's CEO Actually Said About Slowing AI Down - TopBlogs
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Anthropic CEO Dario Amodei says frontier AI development needs to slow down. Here's what "pacing the frontier" means, why he changed his mind, and how Altman, Musk and Hassabis responded.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.topblogs.online%2Ficon%3F0e9eb26cf9512256" width="32" height="32"&gt;
          topblogs.online
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
