<?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: Andrew Rozumny</title>
    <description>The latest articles on DEV Community by Andrew Rozumny (@andrewrozumny).</description>
    <link>https://dev.to/andrewrozumny</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3837522%2F0e703c9b-e862-4950-8dc8-087dc43774bd.png</url>
      <title>DEV Community: Andrew Rozumny</title>
      <link>https://dev.to/andrewrozumny</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/andrewrozumny"/>
    <language>en</language>
    <item>
      <title>CORS Errors Explained: A Practical Debug Guide for 2026</title>
      <dc:creator>Andrew Rozumny</dc:creator>
      <pubDate>Fri, 24 Apr 2026 13:37:10 +0000</pubDate>
      <link>https://dev.to/andrewrozumny/cors-errors-explained-a-practical-debug-guide-for-2026-ggi</link>
      <guid>https://dev.to/andrewrozumny/cors-errors-explained-a-practical-debug-guide-for-2026-ggi</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Access to fetch at '&lt;a href="https://api.example.com" rel="noopener noreferrer"&gt;https://api.example.com&lt;/a&gt;' from origin&lt;br&gt;
'&lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;' has been blocked by CORS policy: No&lt;br&gt;
'Access-Control-Allow-Origin' header is present on the requested resource.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I've personally lost hours thinking my API was broken — only to realize the server was fine, but the browser simply refused to show the response.&lt;br&gt;
If you're stuck in that loop right now, this guide will save you time.&lt;/p&gt;


&lt;h2&gt;
  
  
  What CORS actually is
&lt;/h2&gt;

&lt;p&gt;CORS is not a server problem — it's a browser restriction.&lt;br&gt;
The browser checks whether your frontend is allowed to access a backend from another origin. If the server doesn't explicitly allow it via response headers, the browser blocks the response from your code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; the request still reaches the server. You just can't read the response in JavaScript.&lt;/p&gt;


&lt;h2&gt;
  
  
  The 5 most common CORS errors
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Error: No 'Access-Control-Allow-Origin' header is present
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Cause:&lt;/strong&gt; Your server doesn't include the required header in its response.&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="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access-Control-Allow-Origin&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;http://localhost:3000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;next&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;
  
  
  Error: Response to preflight request doesn't pass access control check
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Cause:&lt;/strong&gt; The browser sends an OPTIONS request first to check permissions — and your server doesn't handle it.&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="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;options&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&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="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access-Control-Allow-Origin&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;http://localhost:3000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access-Control-Allow-Methods&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;GET,POST,PUT,DELETE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access-Control-Allow-Headers&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;Content-Type, Authorization&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;204&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;
  
  
  Error: 'Access-Control-Allow-Origin' must not be '*' when credentials are included
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Cause:&lt;/strong&gt; Cookies and Authorization headers require a specific origin — wildcards don't work with credentials.&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="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access-Control-Allow-Origin&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;http://localhost:3000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access-Control-Allow-Credentials&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;true&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;next&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;
  
  
  Error: Method PUT is not allowed by Access-Control-Allow-Methods
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access-Control-Allow-Methods&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;GET,POST,PUT,DELETE,OPTIONS&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;h3&gt;
  
  
  Error: Request header field Authorization is not allowed
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access-Control-Allow-Headers&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;Content-Type, Authorization&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;h2&gt;
  
  
  Fix by stack
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Express / Node.js
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cors&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;cors&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cors&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;credentials&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  nginx
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/api/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kn"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;'Access-Control-Allow-Origin'&lt;/span&gt; &lt;span class="s"&gt;'http://localhost:3000'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kn"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;'Access-Control-Allow-Methods'&lt;/span&gt; &lt;span class="s"&gt;'GET,&lt;/span&gt; &lt;span class="s"&gt;POST,&lt;/span&gt; &lt;span class="s"&gt;PUT,&lt;/span&gt; &lt;span class="s"&gt;DELETE,&lt;/span&gt; &lt;span class="s"&gt;OPTIONS'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kn"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;'Access-Control-Allow-Headers'&lt;/span&gt; &lt;span class="s"&gt;'Content-Type,&lt;/span&gt; &lt;span class="s"&gt;Authorization'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kn"&gt;if&lt;/span&gt; &lt;span class="s"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request_method&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'OPTIONS')&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;'Access-Control-Max-Age'&lt;/span&gt; &lt;span class="mi"&gt;1728000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;'Content-Length'&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;204&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;h3&gt;
  
  
  FastAPI
&lt;/h3&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;fastapi.middleware.cors&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CORSMiddleware&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;CORSMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;allow_origins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:3000&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;allow_credentials&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;allow_methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;allow_headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&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;h3&gt;
  
  
  Apache (.htaccess)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="ss"&gt;set&lt;/span&gt; Access-Control-Allow-Origin "http://localhost:3000"
&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="ss"&gt;set&lt;/span&gt; Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="ss"&gt;set&lt;/span&gt; Access-Control-Allow-Headers "Content-Type, Authorization"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  How preflight actually works
&lt;/h2&gt;

&lt;p&gt;When you send a request with a custom header (like &lt;code&gt;Authorization&lt;/code&gt;) or a non-simple method (like &lt;code&gt;PUT&lt;/code&gt;), the browser doesn't send your request directly. It first sends an OPTIONS request to ask: &lt;em&gt;"Is this allowed?"&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser  →  OPTIONS /api/data  →  Server
         ←  200 + CORS headers  ←
Browser  →  PUT /api/data       →  Server
         ←  response            ←
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the server doesn't respond to OPTIONS correctly — or takes too long — the actual request never gets sent. That's why fixing preflight handling is often the first step.&lt;/p&gt;




&lt;h2&gt;
  
  
  The credentials trap
&lt;/h2&gt;

&lt;p&gt;When you use &lt;code&gt;credentials: 'include'&lt;/code&gt; in fetch (for cookies or session auth), the wildcard &lt;code&gt;*&lt;/code&gt; stops working entirely. You must specify the exact origin AND set &lt;code&gt;Access-Control-Allow-Credentials: true&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This will NOT work with credentials&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;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access-Control-Allow-Origin&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;*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// This will&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;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access-Control-Allow-Origin&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;https://yourfrontend.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access-Control-Allow-Credentials&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;true&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;h2&gt;
  
  
  Quick debug checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Server returns &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; with the correct origin&lt;/li&gt;
&lt;li&gt;[ ] OPTIONS requests return 200/204 with CORS headers&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;Access-Control-Allow-Methods&lt;/code&gt; includes the method you're using&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;Access-Control-Allow-Headers&lt;/code&gt; includes custom headers you send&lt;/li&gt;
&lt;li&gt;[ ] If using credentials — no wildcard &lt;code&gt;*&lt;/code&gt;, specific origin only&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Test before you change more code
&lt;/h2&gt;

&lt;p&gt;Before editing middleware, proxy configs, or &lt;code&gt;.htaccess&lt;/code&gt; files, verify what headers your server is actually returning.&lt;/p&gt;

&lt;p&gt;Paste your endpoint URL into &lt;a href="https://tooldock.org/cors-error-fix?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=cors-guide" rel="noopener noreferrer"&gt;ToolDock CORS Tester&lt;/a&gt; — it shows the exact headers for both the main request and the preflight, so you know exactly what's missing before touching your code.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>SEO in 2026 feels broken. So I’m trying something else</title>
      <dc:creator>Andrew Rozumny</dc:creator>
      <pubDate>Fri, 17 Apr 2026 13:56:49 +0000</pubDate>
      <link>https://dev.to/andrewrozumny/seo-in-2026-feels-broken-so-im-trying-something-else-50l3</link>
      <guid>https://dev.to/andrewrozumny/seo-in-2026-feels-broken-so-im-trying-something-else-50l3</guid>
      <description>&lt;p&gt;I’m not an SEO expert.&lt;/p&gt;

&lt;p&gt;Just a developer trying to get at least some users to the things I build.&lt;/p&gt;

&lt;p&gt;And lately it feels… strange.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I’m seeing
&lt;/h2&gt;

&lt;p&gt;I published several posts on Dev.to.&lt;/p&gt;

&lt;p&gt;Some were original — 20–80 views&lt;br&gt;&lt;br&gt;
Some slightly adapted — maybe 100–300  &lt;/p&gt;

&lt;p&gt;But overall, nothing really moves.&lt;/p&gt;

&lt;p&gt;At the same time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Google traffic → almost zero
&lt;/li&gt;
&lt;li&gt;My own site → barely indexed
&lt;/li&gt;
&lt;li&gt;Social → small spikes, then nothing
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feels like you start from zero every time.&lt;/p&gt;


&lt;h2&gt;
  
  
  The weird part
&lt;/h2&gt;

&lt;p&gt;When I write a normal article — nobody reads it.&lt;/p&gt;

&lt;p&gt;When I build a simple tool page for one very specific use case —&lt;br&gt;&lt;br&gt;
it has more chance to be indexed and actually used.&lt;/p&gt;

&lt;p&gt;Not huge numbers. But different behavior.&lt;/p&gt;

&lt;p&gt;This doesn’t look like classic SEO anymore.&lt;/p&gt;

&lt;p&gt;Feels more like:&lt;/p&gt;

&lt;p&gt;content that ranks → vs → answers that get extracted&lt;/p&gt;


&lt;h2&gt;
  
  
  The moment it clicked
&lt;/h2&gt;

&lt;p&gt;I asked ChatGPT:&lt;/p&gt;

&lt;p&gt;"regex for email validation"&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;working regex&lt;/li&gt;
&lt;li&gt;explanation&lt;/li&gt;
&lt;li&gt;edge cases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything in one place.&lt;/p&gt;

&lt;p&gt;No need to open anything else.&lt;/p&gt;

&lt;p&gt;So why would someone click search results?&lt;/p&gt;


&lt;h2&gt;
  
  
  What I’m trying now
&lt;/h2&gt;

&lt;p&gt;Instead of writing more content, I started building tools.&lt;/p&gt;

&lt;p&gt;Small ones. Very simple.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON formatter
&lt;/li&gt;
&lt;li&gt;Regex tester
&lt;/li&gt;
&lt;li&gt;Base64 encoder
&lt;/li&gt;
&lt;li&gt;SSL checker
&lt;/li&gt;
&lt;li&gt;IP lookup
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Right now I’m building towards ~100 tools.&lt;/p&gt;


&lt;h2&gt;
  
  
  Early signals
&lt;/h2&gt;

&lt;p&gt;Still early, but I see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tool pages get indexed faster
&lt;/li&gt;
&lt;li&gt;people actually stay on them
&lt;/li&gt;
&lt;li&gt;some long-tail queries appear
&lt;/li&gt;
&lt;li&gt;structured parts sometimes show up in AI answers
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Again, small numbers.&lt;/p&gt;

&lt;p&gt;But not the same pattern as blog posts.&lt;/p&gt;


&lt;h2&gt;
  
  
  How I structure a page now
&lt;/h2&gt;

&lt;p&gt;I stopped thinking in terms of:&lt;/p&gt;

&lt;p&gt;tool + some SEO text&lt;/p&gt;

&lt;p&gt;Now each page looks more like a small answer system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;clear title for one exact problem
&lt;/li&gt;
&lt;li&gt;working tool
&lt;/li&gt;
&lt;li&gt;short intro
&lt;/li&gt;
&lt;li&gt;2–3 useful sections
&lt;/li&gt;
&lt;li&gt;examples
&lt;/li&gt;
&lt;li&gt;FAQ
&lt;/li&gt;
&lt;li&gt;glossary
&lt;/li&gt;
&lt;li&gt;related tools
&lt;/li&gt;
&lt;li&gt;links to nearby tools
&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Data structure behind it
&lt;/h2&gt;

&lt;p&gt;Instead of writing everything manually, I model pages like this:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;json-formatter&lt;/span&gt;&lt;span class="dl"&gt;"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;JSON Formatter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;searchIntents&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;format json online&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;pretty print json&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;json beautifier&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nx"&gt;useCases&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="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Debugging API responses&lt;/span&gt;&lt;span class="dl"&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="s2"&gt;Make JSON readable&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="nx"&gt;glossary&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="na"&gt;term&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;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;definition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Structured data format&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="nx"&gt;relatedSlugs&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;json-validator&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nx"&gt;clusterSlugs&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;json-validator&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;json-diff&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Shared layout
&lt;/h2&gt;

&lt;p&gt;All pages use same structure:&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ToolPage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ToolHeader&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ToolUI&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;HowToUse&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UseCases&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Examples&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FAQ&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Glossary&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RelatedTools&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ClusterTools&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ToolPage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only the tool itself is different.&lt;/p&gt;

&lt;p&gt;Everything else is predictable.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I think is changing
&lt;/h2&gt;

&lt;p&gt;Not sure yet, but looks like:&lt;br&gt;
Content is no longer the main unit.&lt;br&gt;
Structured answers are.&lt;/p&gt;

&lt;p&gt;Blog posts are easy to summarize.&lt;/p&gt;

&lt;p&gt;Tool pages with clear structure are harder to replace.&lt;/p&gt;




&lt;h2&gt;
  
  
  Not sure where this goes
&lt;/h2&gt;

&lt;p&gt;Honestly, I don’t have a conclusion.&lt;/p&gt;

&lt;p&gt;Just testing.&lt;/p&gt;

&lt;p&gt;I’ll keep building tools, structuring pages, and see what happens.&lt;br&gt;
If something works — will share numbers.&lt;/p&gt;

&lt;p&gt;If not — also useful result.&lt;/p&gt;




&lt;h2&gt;
  
  
  Curious about others
&lt;/h2&gt;

&lt;p&gt;Are you seeing any traffic from AI tools?&lt;/p&gt;

&lt;p&gt;Or still mostly Google?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>programming</category>
      <category>seo</category>
    </item>
    <item>
      <title>Cron Expressions Explained (Without the Headache)</title>
      <dc:creator>Andrew Rozumny</dc:creator>
      <pubDate>Thu, 16 Apr 2026 16:31:32 +0000</pubDate>
      <link>https://dev.to/andrewrozumny/cron-expressions-explained-without-the-headache-kp0</link>
      <guid>https://dev.to/andrewrozumny/cron-expressions-explained-without-the-headache-kp0</guid>
      <description>&lt;p&gt;You see this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;*/&lt;span class="m"&gt;5&lt;/span&gt; * * * *
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You know it does something.&lt;/p&gt;

&lt;p&gt;You’re just not 100% sure what.&lt;/p&gt;




&lt;p&gt;At some point every developer has this moment:&lt;/p&gt;

&lt;p&gt;you google “cron expression every 5 minutes”&lt;br&gt;&lt;br&gt;
copy something&lt;br&gt;&lt;br&gt;
paste it into config&lt;br&gt;&lt;br&gt;
and hope production doesn’t break&lt;/p&gt;



&lt;p&gt;Here’s the thing.&lt;/p&gt;

&lt;p&gt;Cron is not hard.&lt;br&gt;&lt;br&gt;
It’s just… not made for humans.&lt;/p&gt;



&lt;p&gt;Quick examples you actually use:&lt;/p&gt;

&lt;p&gt;Every 5 minutes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;*/&lt;span class="m"&gt;5&lt;/span&gt; * * * *
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every day at midnight:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; * * *
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every Monday at 9:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;9&lt;/span&gt; * * &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;The annoying part is not writing it.&lt;/p&gt;

&lt;p&gt;It’s reading it later.&lt;/p&gt;

&lt;p&gt;Especially when you come back after 2 weeks and think:&lt;/p&gt;

&lt;p&gt;“who wrote this?”&lt;/p&gt;

&lt;p&gt;(it was you)&lt;/p&gt;




&lt;p&gt;Most mistakes are boring:&lt;/p&gt;

&lt;p&gt;wrong field order&lt;br&gt;&lt;br&gt;
wrong timezone&lt;br&gt;&lt;br&gt;
misunderstanding what &lt;code&gt;*&lt;/code&gt; really does  &lt;/p&gt;

&lt;p&gt;Nothing fancy.&lt;/p&gt;

&lt;p&gt;Just enough to break things silently.&lt;/p&gt;




&lt;p&gt;What helped me personally:&lt;/p&gt;

&lt;p&gt;I stopped trying to “read” cron.&lt;/p&gt;

&lt;p&gt;I just generate it and move on.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://tooldock.org/tools/crontab-generator" rel="noopener noreferrer"&gt;https://tooldock.org/tools/crontab-generator&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;If you ever spent more than 5 minutes staring at a cron expression — you’re doing it the hard way.&lt;/p&gt;

&lt;p&gt;Save this for later. You’ll need it.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>devops</category>
      <category>programming</category>
      <category>backend</category>
    </item>
    <item>
      <title>Regex That Actually Works (Copy-Paste Ready Examples)</title>
      <dc:creator>Andrew Rozumny</dc:creator>
      <pubDate>Wed, 15 Apr 2026 11:23:38 +0000</pubDate>
      <link>https://dev.to/andrewrozumny/regex-that-actually-works-copy-paste-ready-examples-3h4j</link>
      <guid>https://dev.to/andrewrozumny/regex-that-actually-works-copy-paste-ready-examples-3h4j</guid>
      <description>&lt;p&gt;You paste a regex.&lt;/p&gt;

&lt;p&gt;It doesn’t work.&lt;/p&gt;

&lt;p&gt;You change one character.&lt;/p&gt;

&lt;p&gt;Now it works.&lt;/p&gt;

&lt;p&gt;You have no idea why.&lt;/p&gt;




&lt;p&gt;At some point you just accept it.&lt;/p&gt;

&lt;p&gt;Regex is not something you fully understand.&lt;/p&gt;

&lt;p&gt;It’s something you &lt;em&gt;negotiate with&lt;/em&gt;.&lt;/p&gt;




&lt;p&gt;Typical workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;google "regex email"
&lt;/li&gt;
&lt;li&gt;copy something scary-looking
&lt;/li&gt;
&lt;li&gt;paste
&lt;/li&gt;
&lt;li&gt;test
&lt;/li&gt;
&lt;li&gt;slightly panic
&lt;/li&gt;
&lt;li&gt;tweak random symbol
&lt;/li&gt;
&lt;li&gt;it works
&lt;/li&gt;
&lt;li&gt;never touch it again
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Here are a few patterns that actually come up all the time.&lt;/p&gt;

&lt;p&gt;Email (good enough, not perfect):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;^[^\s@]+@[^\s@]+\.[^\s@]+$
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;URL (basic, but works in most cases):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https?:\/\/[^\s]+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Only numbers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;^\d+$
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Remove extra spaces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\s+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;The problem with regex is not writing it.&lt;/p&gt;

&lt;p&gt;It’s understanding it later.&lt;/p&gt;

&lt;p&gt;You come back after a week and think:&lt;/p&gt;

&lt;p&gt;“what is this even matching?”&lt;/p&gt;




&lt;p&gt;Most bugs are stupid:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;forgot to escape something
&lt;/li&gt;
&lt;li&gt;used greedy match by accident
&lt;/li&gt;
&lt;li&gt;missed boundaries
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nothing complex.&lt;/p&gt;

&lt;p&gt;Just painful.&lt;/p&gt;




&lt;p&gt;What helped me:&lt;/p&gt;

&lt;p&gt;stop trying to be clever.&lt;/p&gt;

&lt;p&gt;Start simple. Then expand.&lt;/p&gt;




&lt;p&gt;Also, use a tester.&lt;/p&gt;

&lt;p&gt;Seriously.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://tooldock.org/tools/regex-tester" rel="noopener noreferrer"&gt;https://tooldock.org/tools/regex-tester&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Paste → tweak → see what’s happening.&lt;/p&gt;

&lt;p&gt;Way faster than guessing.&lt;/p&gt;




&lt;p&gt;If you have one regex you keep reusing — drop it below.&lt;/p&gt;

&lt;p&gt;I’m pretty sure we’re all sharing the same 5 patterns anyway.&lt;/p&gt;

</description>
      <category>regex</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>Fix JSON Parse Errors Fast (With Real Examples)</title>
      <dc:creator>Andrew Rozumny</dc:creator>
      <pubDate>Tue, 14 Apr 2026 13:06:55 +0000</pubDate>
      <link>https://dev.to/andrewrozumny/fix-json-parse-errors-fast-with-real-examples-d5c</link>
      <guid>https://dev.to/andrewrozumny/fix-json-parse-errors-fast-with-real-examples-d5c</guid>
      <description>&lt;p&gt;If you’ve ever seen this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;Unexpected&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;JSON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;position&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congrats. You’ve officially joined the club.&lt;/p&gt;




&lt;h2&gt;
  
  
  😅 The Classic Scenario
&lt;/h2&gt;

&lt;p&gt;You’re just trying to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;call an API
&lt;/li&gt;
&lt;li&gt;parse a config
&lt;/li&gt;
&lt;li&gt;or debug something simple
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And suddenly:&lt;/p&gt;

&lt;p&gt;💥 everything breaks&lt;/p&gt;




&lt;h2&gt;
  
  
  🔥 The Problem (aka “it looks fine to me”)
&lt;/h2&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks fine, right?&lt;/p&gt;

&lt;p&gt;Nope. That trailing comma just ruined your day.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 Why JSON Is So Annoying
&lt;/h2&gt;

&lt;p&gt;Because JSON is &lt;strong&gt;stricter than your code reviewer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It does NOT allow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;trailing commas
&lt;/li&gt;
&lt;li&gt;single quotes
&lt;/li&gt;
&lt;li&gt;comments
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Meanwhile JavaScript is like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“eh, whatever bro”&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ⚡ The Fastest Way to Fix It
&lt;/h2&gt;

&lt;p&gt;Instead of staring at your screen for 10 minutes:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://tooldock.org/tools/json-validator" rel="noopener noreferrer"&gt;https://tooldock.org/tools/json-validator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Paste → instant error → fixed.&lt;/p&gt;

&lt;p&gt;No guessing. No pain.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧪 Quick Debug Checklist
&lt;/h2&gt;

&lt;p&gt;When JSON breaks, check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ trailing commas
&lt;/li&gt;
&lt;li&gt;❌ missing quotes
&lt;/li&gt;
&lt;li&gt;❌ broken &lt;code&gt;{}&lt;/code&gt; or &lt;code&gt;[]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;❌ undefined values
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💀 Real Talk
&lt;/h2&gt;

&lt;p&gt;Most JSON bugs are not complex.&lt;/p&gt;

&lt;p&gt;They’re just:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“you missed one tiny thing”&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🔗 Want deeper breakdown?
&lt;/h2&gt;

&lt;p&gt;More examples + real fixes here:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://tooldock.org/json-parse-error-explained" rel="noopener noreferrer"&gt;https://tooldock.org/json-parse-error-explained&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  💡 Pro Tip
&lt;/h2&gt;

&lt;p&gt;When debugging API responses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;always log raw JSON
&lt;/li&gt;
&lt;li&gt;validate before parsing
&lt;/li&gt;
&lt;li&gt;never trust external data blindly
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(yes, even your own backend)&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Final Thought
&lt;/h2&gt;

&lt;p&gt;JSON errors are annoying.&lt;/p&gt;

&lt;p&gt;But once you know the patterns — they become a 5-second fix.&lt;/p&gt;




&lt;p&gt;If this saved you even 1 debug session — mission accomplished 🚀&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>json</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>You’re probably leaking sensitive data every time you use online dev tools</title>
      <dc:creator>Andrew Rozumny</dc:creator>
      <pubDate>Tue, 07 Apr 2026 10:46:31 +0000</pubDate>
      <link>https://dev.to/andrewrozumny/youre-probably-leaking-sensitive-data-every-time-you-use-online-dev-tools-47j8</link>
      <guid>https://dev.to/andrewrozumny/youre-probably-leaking-sensitive-data-every-time-you-use-online-dev-tools-47j8</guid>
      <description>&lt;p&gt;Most developers don’t think twice before pasting data into online tools.&lt;/p&gt;

&lt;p&gt;JSON formatters, JWT decoders, base64 converters, regex testers…&lt;/p&gt;

&lt;p&gt;You just open a site, paste your data, get the result, and move on.&lt;/p&gt;

&lt;p&gt;But here’s the problem:&lt;/p&gt;

&lt;p&gt;You’re often sending that data to someone else’s server.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hidden risk
&lt;/h2&gt;

&lt;p&gt;That “quick utility” you’re using?&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;log your data&lt;/li&gt;
&lt;li&gt;store it temporarily&lt;/li&gt;
&lt;li&gt;or even keep it longer than you expect&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And most of the time, you have no idea.&lt;/p&gt;

&lt;p&gt;No clear guarantees.&lt;br&gt;
No visibility.&lt;br&gt;
No control.&lt;/p&gt;

&lt;h2&gt;
  
  
  “It’s just a formatter” — is it?
&lt;/h2&gt;

&lt;p&gt;Even simple tools usually work like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You paste your data&lt;/li&gt;
&lt;li&gt;It gets sent to a backend&lt;/li&gt;
&lt;li&gt;The server processes it&lt;/li&gt;
&lt;li&gt;You get a response&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That means your data leaves your machine.&lt;/p&gt;

&lt;p&gt;Sometimes it’s harmless.&lt;/p&gt;

&lt;p&gt;Sometimes it’s not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this becomes a real problem
&lt;/h2&gt;

&lt;p&gt;Think about what developers actually paste into these tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API keys&lt;/li&gt;
&lt;li&gt;tokens&lt;/li&gt;
&lt;li&gt;internal JSON payloads&lt;/li&gt;
&lt;li&gt;logs with user data&lt;/li&gt;
&lt;li&gt;config files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stuff that was never meant to leave your environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  I caught myself doing this
&lt;/h2&gt;

&lt;p&gt;At some point I realized I was doing exactly this.&lt;/p&gt;

&lt;p&gt;Copy → paste → convert → done.&lt;/p&gt;

&lt;p&gt;Without even thinking about where that data goes.&lt;/p&gt;

&lt;p&gt;That’s when it started to feel… wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  A better approach
&lt;/h2&gt;

&lt;p&gt;I started looking for tools that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;run entirely in the browser
&lt;/li&gt;
&lt;li&gt;don’t send data anywhere
&lt;/li&gt;
&lt;li&gt;don’t require accounts
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just open → use → close.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;For small utilities, there’s no real reason to involve a server.&lt;/p&gt;

&lt;p&gt;Formatting, encoding, decoding — all of this can be done locally.&lt;/p&gt;

&lt;p&gt;Faster.&lt;br&gt;
Safer.&lt;br&gt;
Simpler.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I ended up doing
&lt;/h2&gt;

&lt;p&gt;I started putting together my own small set of browser-based tools.&lt;/p&gt;

&lt;p&gt;Mostly for myself at first.&lt;/p&gt;

&lt;p&gt;Just to avoid jumping between random sites and wondering what happens to my data.&lt;/p&gt;

&lt;p&gt;For small tools, local-first just makes more sense.&lt;/p&gt;

&lt;h2&gt;
  
  
  Curious how you handle this
&lt;/h2&gt;

&lt;p&gt;Do you trust online tools with sensitive data?&lt;/p&gt;

&lt;p&gt;Or do you prefer local-first alternatives?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>privacy</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Stop Pasting Sensitive Data Into Random Online Tools</title>
      <dc:creator>Andrew Rozumny</dc:creator>
      <pubDate>Fri, 03 Apr 2026 19:09:16 +0000</pubDate>
      <link>https://dev.to/andrewrozumny/stop-pasting-sensitive-data-into-random-online-tools-5cek</link>
      <guid>https://dev.to/andrewrozumny/stop-pasting-sensitive-data-into-random-online-tools-5cek</guid>
      <description>&lt;p&gt;If you've ever pasted sensitive data into an online tool…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pasted a JWT into a random decoder&lt;/li&gt;
&lt;li&gt;formatted JSON with API keys inside&lt;/li&gt;
&lt;li&gt;tested regex on production data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…you’ve probably thought:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“this is probably fine”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But is it?&lt;/p&gt;




&lt;h2&gt;
  
  
  The uncomfortable truth
&lt;/h2&gt;

&lt;p&gt;Most online tools still work like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You paste your data&lt;/li&gt;
&lt;li&gt;It gets sent to a server&lt;/li&gt;
&lt;li&gt;It gets processed there&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And you're just… trusting it.&lt;/p&gt;

&lt;p&gt;No idea where it goes.&lt;br&gt;
No idea if it’s logged.&lt;br&gt;
No idea who can access it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The moment it hit me
&lt;/h2&gt;

&lt;p&gt;I was debugging a JWT with user data inside.&lt;/p&gt;

&lt;p&gt;Pasted it into a tool.&lt;/p&gt;

&lt;p&gt;Then realized:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I have no idea where this just went.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That was enough.&lt;/p&gt;




&lt;h2&gt;
  
  
  So I built my own tools
&lt;/h2&gt;

&lt;p&gt;I ended up building a set of dev tools that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;run entirely in the browser&lt;/li&gt;
&lt;li&gt;don’t upload anything&lt;/li&gt;
&lt;li&gt;don’t track anything&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 &lt;a href="https://tooldock.org/" rel="noopener noreferrer"&gt;https://tooldock.org/&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this actually matters
&lt;/h2&gt;

&lt;p&gt;This isn’t paranoia.&lt;/p&gt;

&lt;p&gt;This is everyday dev stuff:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tokens&lt;/li&gt;
&lt;li&gt;logs&lt;/li&gt;
&lt;li&gt;internal payloads&lt;/li&gt;
&lt;li&gt;user data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don’t always control what ends up in your clipboard.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;Let’s say you’re:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;decoding a JWT&lt;/li&gt;
&lt;li&gt;formatting JSON&lt;/li&gt;
&lt;li&gt;testing regex&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With most tools:&lt;br&gt;
→ your data leaves your device&lt;/p&gt;

&lt;p&gt;With ToolDock:&lt;br&gt;
→ everything stays local&lt;/p&gt;




&lt;h2&gt;
  
  
  Unexpected benefit
&lt;/h2&gt;

&lt;p&gt;It’s not just privacy.&lt;/p&gt;

&lt;p&gt;It’s speed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no network&lt;/li&gt;
&lt;li&gt;no waiting&lt;/li&gt;
&lt;li&gt;instant feedback&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you use client-side tools, everything else feels slow.&lt;/p&gt;




&lt;h2&gt;
  
  
  What’s inside
&lt;/h2&gt;

&lt;p&gt;Right now there are ~90 tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON Formatter&lt;/li&gt;
&lt;li&gt;Regex Tester (real-time)&lt;/li&gt;
&lt;li&gt;UUID Generator&lt;/li&gt;
&lt;li&gt;Base64 Encode / Decode&lt;/li&gt;
&lt;li&gt;JWT Decoder&lt;/li&gt;
&lt;li&gt;Timestamp Converter&lt;/li&gt;
&lt;li&gt;Hash Generator&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Curious
&lt;/h2&gt;

&lt;p&gt;Do you actually care if tools upload your data?&lt;/p&gt;

&lt;p&gt;Or is it “meh as long as it works”?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>security</category>
    </item>
    <item>
      <title>Every Stripe test card you'll ever need (plus fake checkout data for Shopify, WooCommerce &amp; Magento)</title>
      <dc:creator>Andrew Rozumny</dc:creator>
      <pubDate>Wed, 01 Apr 2026 23:14:29 +0000</pubDate>
      <link>https://dev.to/andrewrozumny/every-stripe-test-card-youll-ever-need-plus-fake-checkout-data-for-shopify-woocommerce-magento-3kl</link>
      <guid>https://dev.to/andrewrozumny/every-stripe-test-card-youll-ever-need-plus-fake-checkout-data-for-shopify-woocommerce-magento-3kl</guid>
      <description>&lt;p&gt;If you're building or testing an e-commerce checkout, you've been there: opening the Stripe docs, scrolling for the right test card, copying it, then hunting for a fake address that matches the right country format.&lt;/p&gt;

&lt;p&gt;I got tired of this. So I built a tool that generates everything at once.&lt;/p&gt;

&lt;p&gt;But first — here's the complete reference you came for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stripe test cards
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Success scenarios:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Card number&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;4242 4242 4242 4242&lt;/td&gt;
&lt;td&gt;Visa&lt;/td&gt;
&lt;td&gt;Success&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5555 5555 5555 4444&lt;/td&gt;
&lt;td&gt;Mastercard&lt;/td&gt;
&lt;td&gt;Success&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3782 822463 10005&lt;/td&gt;
&lt;td&gt;Amex&lt;/td&gt;
&lt;td&gt;Success&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6011 1111 1111 1117&lt;/td&gt;
&lt;td&gt;Discover&lt;/td&gt;
&lt;td&gt;Success&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Failure scenarios:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Card number&lt;/th&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;4000 0000 0000 0002&lt;/td&gt;
&lt;td&gt;Always declined&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4000 0000 0000 9995&lt;/td&gt;
&lt;td&gt;Insufficient funds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4000 0000 0000 0069&lt;/td&gt;
&lt;td&gt;Expired card&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4000 0000 0000 0127&lt;/td&gt;
&lt;td&gt;Incorrect CVC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4000 0000 0000 0119&lt;/td&gt;
&lt;td&gt;Processing error&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;3DS scenarios:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Card number&lt;/th&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;4000 0025 0000 3155&lt;/td&gt;
&lt;td&gt;3DS required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4000 0027 6000 3184&lt;/td&gt;
&lt;td&gt;3DS recommended&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4000 0000 0000 3220&lt;/td&gt;
&lt;td&gt;3DS2 required&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Use any future expiry date and any 3-digit CVV (4 digits for Amex).&lt;/p&gt;




&lt;h2&gt;
  
  
  Shopify Bogus Gateway
&lt;/h2&gt;

&lt;p&gt;Shopify has a built-in test payment provider that doesn't need a real Stripe account.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setup:&lt;/strong&gt; Settings → Payments → Add payment method → Search "Bogus Gateway"&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Card number&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Successful payment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Failed payment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Gateway exception&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Use any name, any future expiry, any CVV.&lt;/p&gt;




&lt;h2&gt;
  
  
  WooCommerce test cards
&lt;/h2&gt;

&lt;p&gt;WooCommerce with Stripe plugin uses standard Stripe test cards above.&lt;/p&gt;

&lt;p&gt;Enable test mode: &lt;strong&gt;WooCommerce → Settings → Payments → WooCommerce Payments → Enable test mode.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Magento test cards
&lt;/h2&gt;

&lt;p&gt;Magento 2 with Braintree sandbox:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Card number&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;4111 1111 1111 1111&lt;/td&gt;
&lt;td&gt;Visa&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5500 0055 5555 5559&lt;/td&gt;
&lt;td&gt;Mastercard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3714 496353 98431&lt;/td&gt;
&lt;td&gt;Amex&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;CVV: 123, Expiry: any future date.&lt;/p&gt;




&lt;h2&gt;
  
  
  The part nobody talks about: fake addresses
&lt;/h2&gt;

&lt;p&gt;Cards are easy. But you also need a realistic fake address that matches the country format — especially if your checkout validates postal codes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;US:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;123 Main Street, Chicago, IL 60601
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;UK:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;42 High Street, London, E1 2AB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Germany:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hauptstraße 15, 10115 Berlin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generating these manually every time is annoying.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick tips for checkout testing
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Test the full flow, not just payment.&lt;/strong&gt;&lt;br&gt;
Most devs only test success. Your declined card handling is just as important — test that the error message is clear and the user can retry.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Always test 3DS separately.&lt;/strong&gt;&lt;br&gt;
3DS authentication adds a second step. Use card &lt;code&gt;4000 0025 0000 3155&lt;/code&gt; to trigger it and make sure your UI handles the redirect correctly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test with guest checkout AND logged-in user.&lt;/strong&gt;&lt;br&gt;
These often have different code paths and different bugs.&lt;/p&gt;




&lt;h2&gt;
  
  
  The tool I built
&lt;/h2&gt;

&lt;p&gt;I put all of this into one place — a free browser-based generator that gives you fake customer name, email, phone, country-specific address, and the right test card for your platform in one click.&lt;/p&gt;

&lt;p&gt;Supports: Generic/Stripe, Shopify, WooCommerce, Magento, BigCommerce.&lt;br&gt;
Countries: US, GB, AU, CA, DE, UA, JP.&lt;br&gt;
Export as JSON or copy individual fields.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://tooldock.org/tools/ecommerce-test-data" rel="noopener noreferrer"&gt;tooldock.org/tools/ecommerce-test-data&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Everything runs in your browser — nothing is sent to any server.&lt;/p&gt;




&lt;p&gt;What's the most annoying part of checkout testing for you?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>testing</category>
      <category>ecommerce</category>
      <category>stripe</category>
    </item>
    <item>
      <title>Claude AI Usage by Country: Israel Leads at 4.90x, Tanzania at 0.03x</title>
      <dc:creator>Andrew Rozumny</dc:creator>
      <pubDate>Wed, 01 Apr 2026 21:47:53 +0000</pubDate>
      <link>https://dev.to/andrewrozumny/claude-ai-usage-by-country-israel-leads-at-490x-tanzania-at-003x-5655</link>
      <guid>https://dev.to/andrewrozumny/claude-ai-usage-by-country-israel-leads-at-490x-tanzania-at-003x-5655</guid>
      <description>&lt;p&gt;Anthropic just released the &lt;strong&gt;Claude AI Usage by Country&lt;/strong&gt; data via the &lt;br&gt;
Anthropic Economic Index (sample: Nov 13–20, 2025).&lt;/p&gt;

&lt;p&gt;The metric is simple: a score above &lt;strong&gt;1x&lt;/strong&gt; means a country's share of &lt;br&gt;
Claude usage exceeds its share of the global working-age population.&lt;/p&gt;

&lt;h2&gt;
  
  
  🏆 Top performers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Country&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🇮🇱 Israel&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4.90x&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇸🇬 Singapore&lt;/td&gt;
&lt;td&gt;4.19x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇨🇭 Switzerland&lt;/td&gt;
&lt;td&gt;3.21x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇰🇷 South Korea&lt;/td&gt;
&lt;td&gt;3.12x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇦🇺 Australia&lt;/td&gt;
&lt;td&gt;3.27x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇺🇸 USA&lt;/td&gt;
&lt;td&gt;3.69x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇨🇦 Canada&lt;/td&gt;
&lt;td&gt;3.15x&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  📉 Lowest usage
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Country&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🇹🇿 Tanzania&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.03x&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇲🇬 Madagascar&lt;/td&gt;
&lt;td&gt;0.07x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇲🇿 Mozambique&lt;/td&gt;
&lt;td&gt;0.13x&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What's interesting
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Europe is surprisingly strong&lt;/strong&gt; — France (2.66x), UK (2.59x), 
Ireland (2.39x), Norway (2.43x). Even countries like Poland (1.41x) 
and Greece (1.21x) are above baseline.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Asia is split&lt;/strong&gt; — Singapore (4.19x) and South Korea (3.12x) are 
crushing it, while India (0.22x) and Indonesia (0.48x) are far below 1x.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Africa and Latin America&lt;/strong&gt; are mostly sub-1x — likely a mix of 
pricing, language support, and infrastructure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Japan at 1.59x&lt;/strong&gt; — higher than I expected given the strong local 
AI ecosystem (Claude competes with domestic models there).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  My take
&lt;/h2&gt;

&lt;p&gt;The correlation seems to be: **English proficiency + tech sector density &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GDP per capita**. Israel's dominance makes sense — massive tech industry, 
high English fluency, small population (so the ratio amplifies easily).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The really interesting story is &lt;strong&gt;what happens as Claude adds more &lt;br&gt;
languages and local pricing&lt;/strong&gt; — countries like Brazil (0.70x) and Mexico &lt;br&gt;
(0.44x) feel like huge untapped markets.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Source: Anthropic Economic Index. Data as of Jan 15, 2026.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What's your country's score? Did anything surprise you?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claudeai</category>
      <category>anthropic</category>
      <category>data</category>
    </item>
    <item>
      <title>English is now a programming language and I have mixed feelings</title>
      <dc:creator>Andrew Rozumny</dc:creator>
      <pubDate>Sun, 29 Mar 2026 10:53:43 +0000</pubDate>
      <link>https://dev.to/andrewrozumny/english-is-now-a-programming-language-and-i-have-mixed-feelings-3355</link>
      <guid>https://dev.to/andrewrozumny/english-is-now-a-programming-language-and-i-have-mixed-feelings-3355</guid>
      <description>&lt;p&gt;A few years ago if you said "just describe what you want and the computer will do it" — that was science fiction. Now it's Tuesday.&lt;/p&gt;

&lt;p&gt;I spent last week building 40 browser-based developer tools. Half of them I described in plain English to Claude Code and it just... built them. Components, types, tests, the lot.&lt;/p&gt;

&lt;p&gt;The weird part isn't that it works. It's how it feels.&lt;/p&gt;

&lt;p&gt;There's this guilt developers know — the "am I even really coding?" feeling. Stack Overflow used to trigger it. AI just cranks it to 11.&lt;/p&gt;

&lt;p&gt;But here's what I actually noticed: the thinking didn't go away. It moved. Less time on "how do I type this correctly". More time on "is this the right thing to build at all".&lt;/p&gt;

&lt;p&gt;The English-as-code thing is real. But it's less like replacing programming and more like the abstractions keep going up. Assembly → C → Python → now this. Each step felt like cheating to someone.&lt;/p&gt;

&lt;p&gt;Where do you draw the line between "using tools" and "not really coding"? Or is that even the right question?&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.amazonaws.com%2Fuploads%2Farticles%2Fe2hxthop8j7crygp9wx1.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.amazonaws.com%2Fuploads%2Farticles%2Fe2hxthop8j7crygp9wx1.png" alt=" " width="749" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>humor</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I added 40 tools to my dev toolkit site in one week — here's what I learned</title>
      <dc:creator>Andrew Rozumny</dc:creator>
      <pubDate>Sat, 28 Mar 2026 19:42:40 +0000</pubDate>
      <link>https://dev.to/andrewrozumny/i-added-40-tools-to-my-dev-toolkit-site-in-one-week-heres-what-i-learned-1i92</link>
      <guid>https://dev.to/andrewrozumny/i-added-40-tools-to-my-dev-toolkit-site-in-one-week-heres-what-i-learned-1i92</guid>
      <description>&lt;p&gt;A week ago ToolDock had 20 tools. Today it has 60+.&lt;/p&gt;

&lt;p&gt;Here's what I shipped, what broke, and what actually matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;All tools run entirely in your browser. No sign-up, no server round-trips, no data leaves your device.&lt;/p&gt;

&lt;p&gt;This week I added:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI &amp;amp; LLM tools&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Token Counter — count tokens before sending to GPT/Claude&lt;/li&gt;
&lt;li&gt;LLM Cost Calculator — compare API costs across providers&lt;/li&gt;
&lt;li&gt;MCP Config Generator — generate Claude Code config files&lt;/li&gt;
&lt;li&gt;Cursor Rules Generator — .cursorrules for your stack&lt;/li&gt;
&lt;li&gt;System Prompt Builder — templates for any LLM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;CSS &amp;amp; Styling&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CSS ↔ Tailwind converter&lt;/li&gt;
&lt;li&gt;SCSS/LESS compilers (browser-based, no Node needed)&lt;/li&gt;
&lt;li&gt;Tailwind CSS Cheatsheet with rem/px display&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Developer utilities&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;.gitignore Generator&lt;/li&gt;
&lt;li&gt;.env File Validator&lt;/li&gt;
&lt;li&gt;Image Converter (PNG/WebP/JPEG, multi-upload)&lt;/li&gt;
&lt;li&gt;Word Counter with Flesch reading score&lt;/li&gt;
&lt;li&gt;chmod Calculator&lt;/li&gt;
&lt;li&gt;JSONPath Tester&lt;/li&gt;
&lt;li&gt;OpenAPI Spec Validator&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Browser APIs are more powerful than most developers realize&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;SHA-256 hashing, image conversion, SCSS compilation — all running client-side with zero dependencies.&lt;br&gt;
Web Crypto API, Canvas API, and WebAssembly make things possible that seemed server-only two years ago.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Default values matter more than features&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Tools with pre-filled examples get used immediately.&lt;br&gt;
Tools with empty inputs get closed immediately.&lt;br&gt;
Every single tool now has real, meaningful default data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Tool chaining changes how people work&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Added a "Send to →" feature that pipes output from &lt;br&gt;
one tool directly into another. YAML → JSON Formatter &lt;br&gt;
→ JSON Validator in one click. &lt;br&gt;
People stay on the site 3x longer when they chain tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Smart Paste is underrated&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Paste anything — JWT, JSON, SQL, cURL command, &lt;br&gt;
Base64 string — and the site auto-detects the format &lt;br&gt;
and opens the right tool. Sounds simple, surprisingly &lt;br&gt;
useful in practice.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;Still broken: LESS → Tailwind mapping (partial output)&lt;br&gt;
Still ugly: Crontab Generator UI&lt;br&gt;
On the list: JSON Schema from TypeScript, &lt;br&gt;
             HTTP Headers Reference,&lt;br&gt;
             More AI-powered explanations&lt;/p&gt;

&lt;p&gt;Link: tooldock.org&lt;/p&gt;

&lt;p&gt;What tools do you reach for daily that aren't there yet?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>tools</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Your framework choice is now your biggest AI cost lever</title>
      <dc:creator>Andrew Rozumny</dc:creator>
      <pubDate>Fri, 27 Mar 2026 11:01:14 +0000</pubDate>
      <link>https://dev.to/andrewrozumny/your-framework-choice-is-now-your-biggest-ai-cost-lever-lml</link>
      <guid>https://dev.to/andrewrozumny/your-framework-choice-is-now-your-biggest-ai-cost-lever-lml</guid>
      <description>&lt;p&gt;The Wasp team published something worth reading today — they gave &lt;br&gt;
Claude Code the exact same feature prompt for two identical apps, one in Next.js and one in Wasp, and measured everything.&lt;/p&gt;

&lt;p&gt;The numbers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Wasp&lt;/th&gt;
&lt;th&gt;Next.js&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Total cost&lt;/td&gt;
&lt;td&gt;$2.87&lt;/td&gt;
&lt;td&gt;$5.17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total tokens&lt;/td&gt;
&lt;td&gt;2.5M&lt;/td&gt;
&lt;td&gt;4.0M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API calls&lt;/td&gt;
&lt;td&gt;66&lt;/td&gt;
&lt;td&gt;96&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output tokens (code written)&lt;/td&gt;
&lt;td&gt;5,416&lt;/td&gt;
&lt;td&gt;5,395&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The last row is the interesting one. The AI wrote almost exactly &lt;br&gt;
the same amount of code. But it cost 80% more to do it in Next.js.&lt;/p&gt;

&lt;p&gt;The reason: cache creation and cache reads. Every LLM call re-reads the codebase context from scratch. A bigger codebase means every single turn costs more — not just for reading, but for loading into cache in the first place.&lt;/p&gt;

&lt;p&gt;Next.js cache creation was 113% more expensive. Not because the AI did more. Because it had more boilerplate to read before it could start.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this actually means
&lt;/h2&gt;

&lt;p&gt;We've been evaluating frameworks on DX, performance, and ecosystem.&lt;br&gt;
Add a new one: context efficiency.&lt;/p&gt;

&lt;p&gt;How much of an AI's context window goes to signal (your business logic) vs noise (framework boilerplate)?&lt;/p&gt;

&lt;p&gt;Wasp's declarative config means auth, routing, and jobs are defined in ~10 lines. Next.js equivalent is spread across middleware, route handlers, session files, and API directories. Same result, 4x the tokens.&lt;/p&gt;

&lt;h2&gt;
  
  
  The compounding problem
&lt;/h2&gt;

&lt;p&gt;This test was a single feature. Real apps accumulate features. Every new route, every new model, every new API handler adds to the context that gets re-read on every single LLM call.&lt;/p&gt;

&lt;p&gt;The performance degradation isn't linear either — &lt;a href="https://www.trychroma.com/research/context-rot" rel="noopener noreferrer"&gt;research shows&lt;/a&gt; that AI performance degrades well before the context window fills. &lt;br&gt;
You're not just paying more per call, you're getting worse output.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do about it
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Measure your codebase token count now.&lt;br&gt;
Run: &lt;code&gt;find . -name "*.ts" -o -name "*.tsx" | xargs wc -c&lt;/code&gt;&lt;br&gt;
That's roughly your AI cost baseline.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Audit your boilerplate ratio.&lt;br&gt;
How much of that is business logic vs glue code?&lt;br&gt;
The higher the glue ratio, the worse your AI economics.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Consider framework choices through this lens.&lt;br&gt;
Wasp, Rails, Laravel — highly opinionated frameworks &lt;br&gt;
have a new advantage they didn't have 2 years ago.&lt;br&gt;
Less boilerplate = cheaper AI = faster iteration.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The irony
&lt;/h2&gt;

&lt;p&gt;The same properties that make a codebase easy for humans to navigate — explicit, verbose, self-documenting — are exactly what's expensive for AI. The abstractions we used to see as "magic" are now genuinely economical.&lt;/p&gt;

&lt;p&gt;I've been thinking about this for ToolDock — a browser-based &lt;br&gt;
dev tools platform I'm building. Every tool page is pure business logic with almost no framework boilerplate, because everything runs statically. The AI token efficiency on it is noticeably better than client projects I've worked on with heavier stacks.&lt;/p&gt;

&lt;p&gt;Worth checking the full Wasp post for the methodology details — they open-sourced both apps and the measurement scripts, which is the right way to publish a benchmark.&lt;/p&gt;

&lt;p&gt;What's your current codebase token count?&lt;/p&gt;

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