<?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: Muhammad Iqbal</title>
    <description>The latest articles on DEV Community by Muhammad Iqbal (@iqbalaabi).</description>
    <link>https://dev.to/iqbalaabi</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%2F4180072%2F394f808f-66eb-41c1-b04e-38262945ddb7.png</url>
      <title>DEV Community: Muhammad Iqbal</title>
      <link>https://dev.to/iqbalaabi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/iqbalaabi"/>
    <language>en</language>
    <item>
      <title>PromQL Made Easier: Build, Understand, and Debug Prometheus Queries with AabiTech</title>
      <dc:creator>Muhammad Iqbal</dc:creator>
      <pubDate>Mon, 02 Nov 2026 15:40:34 +0000</pubDate>
      <link>https://dev.to/iqbalaabi/promql-made-easier-build-understand-and-debug-prometheus-queries-with-aabitech-2kdc</link>
      <guid>https://dev.to/iqbalaabi/promql-made-easier-build-understand-and-debug-prometheus-queries-with-aabitech-2kdc</guid>
      <description>&lt;p&gt;If you work with Prometheus, you probably know that writing PromQL (Prometheus Query Language) can become challenging, especially when dealing with complex aggregations, rate calculations, histogram metrics, label matching, and alerting expressions.&lt;/p&gt;

&lt;p&gt;Even experienced developers sometimes need to look up syntax, revisit function documentation, or break down complicated expressions to understand what a query actually does.&lt;/p&gt;

&lt;p&gt;To make this workflow easier, I've built a free online &lt;strong&gt;PromQL Query Builder &amp;amp; Explainer&lt;/strong&gt; as part of AabiTech.&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;Try it here:&lt;/strong&gt; &lt;a href="https://aabitech.com/tools/promql-query-builder" rel="noopener noreferrer"&gt;https://aabitech.com/tools/promql-query-builder&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is the PromQL Query Builder?
&lt;/h2&gt;

&lt;p&gt;The PromQL Query Builder &amp;amp; Explainer is a browser-based workspace that helps developers create, understand, and troubleshoot Prometheus queries.&lt;/p&gt;

&lt;p&gt;Instead of switching between documentation, editors, and different reference websites, you can perform several common PromQL tasks in one place.&lt;/p&gt;

&lt;p&gt;The tool is designed for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DevOps engineers&lt;/li&gt;
&lt;li&gt;Site Reliability Engineers (SREs)&lt;/li&gt;
&lt;li&gt;Backend developers&lt;/li&gt;
&lt;li&gt;Observability engineers&lt;/li&gt;
&lt;li&gt;Kubernetes practitioners&lt;/li&gt;
&lt;li&gt;Students learning Prometheus and monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Visual PromQL Query Builder
&lt;/h3&gt;

&lt;p&gt;Building PromQL expressions manually can be tedious, particularly when combining multiple functions and label matchers.&lt;/p&gt;

&lt;p&gt;The visual builder helps you compose queries using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Metric selectors&lt;/li&gt;
&lt;li&gt;Label matchers&lt;/li&gt;
&lt;li&gt;Range vectors&lt;/li&gt;
&lt;li&gt;Functions&lt;/li&gt;
&lt;li&gt;Aggregations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It provides a more approachable way to construct PromQL expressions without having to remember every syntax detail.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. PromQL Editor with Syntax Support
&lt;/h3&gt;

&lt;p&gt;The integrated editor provides a dedicated environment for writing and editing PromQL expressions.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Syntax highlighting&lt;/li&gt;
&lt;li&gt;Autocomplete support&lt;/li&gt;
&lt;li&gt;Parser diagnostics&lt;/li&gt;
&lt;li&gt;Additional rule-based warnings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes it easier to identify potential issues while working on queries.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. PromQL Query Explainer
&lt;/h3&gt;

&lt;p&gt;Ever found a PromQL query in a dashboard or monitoring configuration that you couldn't immediately understand?&lt;/p&gt;

&lt;p&gt;Paste the expression into the explainer to get a plain-English breakdown of its components.&lt;/p&gt;

&lt;p&gt;It's particularly useful when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learning PromQL.&lt;/li&gt;
&lt;li&gt;Reviewing queries written by other developers.&lt;/li&gt;
&lt;li&gt;Understanding nested functions and aggregations.&lt;/li&gt;
&lt;li&gt;Exploring unfamiliar monitoring expressions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Ready-to-Use PromQL Templates
&lt;/h3&gt;

&lt;p&gt;You don't always need to start from scratch.&lt;/p&gt;

&lt;p&gt;The tool includes practical query templates covering common monitoring scenarios, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP request traffic&lt;/li&gt;
&lt;li&gt;HTTP error rates&lt;/li&gt;
&lt;li&gt;CPU utilization&lt;/li&gt;
&lt;li&gt;Memory usage&lt;/li&gt;
&lt;li&gt;Kubernetes monitoring&lt;/li&gt;
&lt;li&gt;Latency percentiles&lt;/li&gt;
&lt;li&gt;SLO-related metrics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These examples can serve as starting points for building your own queries.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Prometheus Alert Rule YAML Generator
&lt;/h3&gt;

&lt;p&gt;Writing alert rules involves more than creating a PromQL expression.&lt;/p&gt;

&lt;p&gt;The tool also provides functionality to generate draft Prometheus alert rule YAML for HTTP 5xx error ratios, with configurable settings.&lt;/p&gt;

&lt;p&gt;You can use the generated configuration as a starting point for your monitoring setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Privacy-Friendly and Browser-Based
&lt;/h2&gt;

&lt;p&gt;One of the design principles behind AabiTech tools is to keep processing in the browser wherever practical.&lt;/p&gt;

&lt;p&gt;The PromQL Query Builder is designed to work without requiring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User registration&lt;/li&gt;
&lt;li&gt;A connected Prometheus server&lt;/li&gt;
&lt;li&gt;An external AI API&lt;/li&gt;
&lt;li&gt;Uploading your queries to a backend for building and explanation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; The tool provides local syntax diagnostics and static checks. It does not execute queries against a live Prometheus instance or verify metric availability in your monitoring environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Can Benefit From It?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;For beginners:&lt;/strong&gt; Learn PromQL concepts and understand how different functions and operators work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For DevOps engineers:&lt;/strong&gt; Quickly construct common monitoring expressions and prepare alert-rule configurations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For SREs:&lt;/strong&gt; Explore error-rate, latency, and SLO-related queries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For experienced developers:&lt;/strong&gt; Save time when writing, reviewing, and troubleshooting PromQL expressions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;The tool is completely free to use.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://aabitech.com/tools/promql-query-builder" rel="noopener noreferrer"&gt;PromQL Query Builder &amp;amp; Explainer&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'd genuinely appreciate feedback from developers who work with Prometheus in real-world environments.&lt;/p&gt;

&lt;p&gt;A few questions for the community:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Which PromQL functions or expressions do you find most difficult to work with?&lt;/li&gt;
&lt;li&gt;What features would make a PromQL builder more useful in your daily workflow?&lt;/li&gt;
&lt;li&gt;Would you find additional Kubernetes and Grafana-focused query templates useful?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I'm building AabiTech to create practical, accessible tools that solve real problems for developers.&lt;/p&gt;

&lt;p&gt;If you try it, let me know what you think!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>prometheus</category>
      <category>devops</category>
    </item>
    <item>
      <title>A PromQL Query Builder That Doesn't Need Your Prometheus Server</title>
      <dc:creator>Muhammad Iqbal</dc:creator>
      <pubDate>Wed, 28 Oct 2026 14:42:24 +0000</pubDate>
      <link>https://dev.to/iqbalaabi/a-promql-query-builder-that-doesnt-need-your-prometheus-server-35a1</link>
      <guid>https://dev.to/iqbalaabi/a-promql-query-builder-that-doesnt-need-your-prometheus-server-35a1</guid>
      <description>&lt;p&gt;PromQL is one of those languages you only half-remember. You know &lt;code&gt;rate()&lt;/code&gt; goes on counters, you &lt;em&gt;think&lt;/em&gt; it goes before &lt;code&gt;sum()&lt;/code&gt;, and you'll definitely forget the &lt;code&gt;le&lt;/code&gt; label the one time it matters.&lt;/p&gt;

&lt;p&gt;Most tools that help with PromQL assume you already have a running Prometheus or Grafana connected to real data. That's great for day-to-day work, but not when you're:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;learning PromQL for the first time&lt;/li&gt;
&lt;li&gt;reviewing a teammate's query in a PR&lt;/li&gt;
&lt;li&gt;sketching an alert before the exporter is even deployed&lt;/li&gt;
&lt;li&gt;on a locked-down machine with no access to production&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I want to show a different take: the &lt;strong&gt;&lt;a href="https://aabitech.com/tools/promql-query-builder" rel="noopener noreferrer"&gt;PromQL Query Builder &amp;amp; Explainer&lt;/a&gt;&lt;/strong&gt; from AabiTech.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes it different
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. No Prometheus connection required
&lt;/h3&gt;

&lt;p&gt;Everything runs in your browser. The builder, explanations and diagnostics work without a data source, so there's nothing to configure, no credentials to hand over and no signup.&lt;/p&gt;

&lt;p&gt;Most query builders pull metric names and labels from a live server. That makes autocomplete accurate, but it also makes them useless without one. This tool takes the opposite trade-off: it's available anywhere, instantly.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. It explains queries, not just builds them
&lt;/h3&gt;

&lt;p&gt;Paste any expression and the &lt;strong&gt;Explain &amp;amp; lint&lt;/strong&gt; tab gives you a component breakdown: selectors, functions, aggregations and range windows, described in plain English.&lt;/p&gt;

&lt;p&gt;This is great for onboarding and code review. Instead of asking "what does this &lt;code&gt;sum by (le, job)&lt;/code&gt; do?", you can read it.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Built-in pitfall detection
&lt;/h3&gt;

&lt;p&gt;Beyond parser diagnostics, the tool flags common mistakes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;sum()&lt;/code&gt; applied before &lt;code&gt;rate()&lt;/code&gt; on counters (resets get hidden)&lt;/li&gt;
&lt;li&gt;classic histogram queries that may drop the &lt;code&gt;le&lt;/code&gt; label&lt;/li&gt;
&lt;li&gt;overly broad regex matchers&lt;/li&gt;
&lt;li&gt;placeholder or example metric names left in&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Take this classic bug:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sum(http_requests_total) / rate(...)   # aggregating before rate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Aggregating counters first hides resets per series. The tool nudges you toward:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sum by (job) (rate(http_requests_total{status=~"5.."}[5m]))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;These are advisory heuristics, not guarantees, but they catch the mistakes that waste an afternoon.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Four workflows in one workspace
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Query builder:&lt;/strong&gt; structured inputs for metric, label matchers, range function, window and aggregation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explain &amp;amp; lint:&lt;/strong&gt; plain-English breakdown plus static diagnostics&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Templates:&lt;/strong&gt; curated patterns for HTTP rates, 5xx ratios, p95 latency, CPU/memory, disk, down targets, Kubernetes restarts and more&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alert rule helper:&lt;/strong&gt; generates a draft YAML rule for an HTTP 5xx error-ratio alert&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Honest about its limits
&lt;/h3&gt;

&lt;p&gt;I appreciate that the tool says plainly what it &lt;em&gt;can't&lt;/em&gt; do. Parser diagnostics validate syntax only. They can't confirm a metric exists, that the query returns data, or that it's efficient. Templates are starting points, and generated alert YAML is a draft to review.&lt;/p&gt;

&lt;p&gt;That honesty matters in monitoring, where a query that "looks right" can silently return nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick example: p95 latency
&lt;/h2&gt;

&lt;p&gt;Using the templates, a classic-histogram p95 looks like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;histogram_quantile(0.95, sum by (le, job) (rate(http_request_duration_seconds_bucket[5m])))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Drop it into the editor and the explainer walks through each layer. It also reminds you that native histograms work differently.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to use what
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Best fit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Exploring real metrics and labels&lt;/td&gt;
&lt;td&gt;A tool connected to your live data source&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learning, reviewing or drafting queries offline&lt;/td&gt;
&lt;td&gt;This builder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Final validation before production&lt;/td&gt;
&lt;td&gt;Your own Prometheus, always&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;They're complementary. Draft and sanity-check here, then validate against real data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;👉 &lt;a href="https://aabitech.com/tools/promql-query-builder" rel="noopener noreferrer"&gt;aabitech.com/tools/promql-query-builder&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Free, browser-based, no signup. I'd love to hear which PromQL pitfalls bite you most. Drop them in the comments and I'll check whether the linter catches them.&lt;/p&gt;

</description>
      <category>prometheus</category>
      <category>devops</category>
      <category>observability</category>
      <category>monitoring</category>
    </item>
    <item>
      <title>I Migrated a Bootstrap Page to Tailwind Without Losing My Mind (Here's How)</title>
      <dc:creator>Muhammad Iqbal</dc:creator>
      <pubDate>Tue, 27 Oct 2026 16:38:30 +0000</pubDate>
      <link>https://dev.to/iqbalaabi/i-migrated-a-bootstrap-page-to-tailwind-without-losing-my-mind-heres-how-3a73</link>
      <guid>https://dev.to/iqbalaabi/i-migrated-a-bootstrap-page-to-tailwind-without-losing-my-mind-heres-how-3a73</guid>
      <description>&lt;p&gt;Let me guess how you got here.&lt;/p&gt;

&lt;p&gt;You've got a project full of Bootstrap. Somewhere between &lt;code&gt;mb-3&lt;/code&gt; and &lt;code&gt;col-md-6&lt;/code&gt;, you decided Tailwind is the future, or your team did, or you just got tired of fighting &lt;code&gt;!important&lt;/code&gt;. Now you're staring at 40 HTML files and wondering how long a rewrite will take.&lt;/p&gt;

&lt;p&gt;I've been there. The good news is that a lot of the work is mechanical, and mechanical work is exactly what tools are for. In this tutorial I'll walk through the free &lt;a href="https://aabitech.com/tools/bootstrap-to-tailwind-converter" rel="noopener noreferrer"&gt;Bootstrap to Tailwind Converter&lt;/a&gt; from AabiTech, show how it works, and be honest about where it stops and &lt;em&gt;you&lt;/em&gt; have to take over.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the tool does
&lt;/h2&gt;

&lt;p&gt;You paste Bootstrap HTML on one side, and it gives you Tailwind HTML on the other. Conversion updates live as you type. A few things I like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bootstrap 4 and 5&lt;/strong&gt; are both selectable as the source.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailwind CSS 3 and 4&lt;/strong&gt; are selectable as the target.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It runs in your browser.&lt;/strong&gt; The page says your HTML is processed locally and isn't uploaded to a conversion endpoint, which is nice if the markup belongs to a client.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It doesn't hide what it can't convert.&lt;/strong&gt; Classes with no verified mapping stay in the output and get flagged, instead of silently disappearing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last point is the most important one. A converter that quietly drops classes will cause bugs you find three weeks later. One that says "I'm not sure about this one" is a colleague I'd trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Paste a real snippet
&lt;/h2&gt;

&lt;p&gt;Don't start with your whole layout. Pick one small, self-contained chunk, like a card or a hero section. Here's a typical Bootstrap 5 one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col-md-6 mb-3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-center fw-bold mb-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Hello, world&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-muted"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;A small card-ish thing.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-primary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Get started&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pick &lt;strong&gt;Bootstrap 5&lt;/strong&gt; as the source and your Tailwind version as the target. Match the source to what you're actually running. The tool says plainly that the version selector doesn't resolve every version-specific difference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Read the output
&lt;/h2&gt;

&lt;p&gt;The tool's output should look something like this (yours may differ in the details):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container mx-auto px-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-wrap"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"md:w-1/2 mb-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-center font-bold mb-6"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Hello, world&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-gray-500"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;A small card-ish thing.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-primary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Get started&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice what happened:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;fw-bold&lt;/code&gt; became &lt;code&gt;font-bold&lt;/code&gt;, an easy one-to-one swap.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mb-3&lt;/code&gt; became &lt;code&gt;mb-4&lt;/code&gt;, and &lt;code&gt;mb-4&lt;/code&gt; became &lt;code&gt;mb-6&lt;/code&gt;. That's not a bug. Bootstrap and Tailwind use different spacing scales.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;btn btn-primary&lt;/code&gt; stayed put. That's the "needs review" bucket.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 3: Understand the spacing scale
&lt;/h2&gt;

&lt;p&gt;This is where most people get bitten, so here's the cheat sheet. Bootstrap's spacing steps are based on a &lt;code&gt;1rem&lt;/code&gt; spacer, and Tailwind's are based on &lt;code&gt;0.25rem&lt;/code&gt; units:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bootstrap&lt;/th&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;th&gt;Tailwind (default theme)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mb-1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0.25rem&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mb-1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mb-2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0.5rem&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mb-2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mb-3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1rem&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mb-4&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mb-4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1.5rem&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mb-6&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mb-5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3rem&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mb-12&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So the same-looking class means different things. If you ever "fix" a converted file by hand, remember this table.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Check the diagnostics panel
&lt;/h2&gt;

&lt;p&gt;Under the editors, the tool breaks recognized classes into three groups:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Exact mappings:&lt;/strong&gt; safe, boring, great.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Approximations:&lt;/strong&gt; close, but verify them visually.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Need review:&lt;/strong&gt; not converted, left for you.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It also shows an "exact mapping coverage" figure. The page itself warns this is a rule-coverage indicator, not a guarantee that the page will render identically. I'd read it the same way: a rough sense of how much hand-work is left, not a quality score.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Use the live preview, but don't trust it blindly
&lt;/h2&gt;

&lt;p&gt;There's a preview with Mobile, Tablet and Desktop toggles. It's handy for a quick sanity check, and it runs in a sandboxed frame. Two caveats:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It loads Tailwind from a CDN, so you need an internet connection.&lt;/li&gt;
&lt;li&gt;It uses Tailwind's default theme. If your project has custom colors or breakpoints, the real result can differ.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Treat it as a smoke test, not a sign-off.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part no converter can do for you
&lt;/h2&gt;

&lt;p&gt;Here's the honest bit. I'd rather you hear it from me than discover it at 11pm before a deploy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Grid layouts are approximate.&lt;/strong&gt; Bootstrap's &lt;code&gt;row&lt;/code&gt; and &lt;code&gt;col-*&lt;/code&gt; classes come with gutters, negative margins and nesting behavior that can't be fully inferred from class names alone. The converter gives you a starting point. Compare the layout side by side.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Components are a different story.&lt;/strong&gt; &lt;code&gt;btn&lt;/code&gt;, &lt;code&gt;card&lt;/code&gt;, &lt;code&gt;modal&lt;/code&gt;, &lt;code&gt;navbar&lt;/code&gt;, dropdowns and accordions rely on Bootstrap's CSS, structure and sometimes JavaScript. There's no single Tailwind utility that replaces them. You'll want to either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;build your own reusable component (a &lt;code&gt;&amp;lt;Button /&amp;gt;&lt;/code&gt;, or &lt;code&gt;@apply&lt;/code&gt; in a stylesheet), or&lt;/li&gt;
&lt;li&gt;reach for a Tailwind component library.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Your config matters.&lt;/strong&gt; The tool doesn't read your &lt;code&gt;tailwind.config.js&lt;/code&gt; or your Bootstrap Sass variables. If you customized either, expect to adjust.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's not a full-document converter.&lt;/strong&gt; According to the page, scripts, iframes, objects and embeds are removed from the output. Use it for fragments, and move scripts over yourself. It also isn't an HTML sanitizer, so review the markup before putting it into your app.&lt;/p&gt;

&lt;h2&gt;
  
  
  My suggested workflow
&lt;/h2&gt;

&lt;p&gt;If I were migrating a real project tomorrow, I'd do this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Convert &lt;strong&gt;one component at a time&lt;/strong&gt;, not whole pages.&lt;/li&gt;
&lt;li&gt;Paste, convert, and read the &lt;strong&gt;diagnostics first&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Fix the "need review" items by hand, starting with buttons and cards.&lt;/li&gt;
&lt;li&gt;Drop the result into the project and &lt;strong&gt;look at it in the browser&lt;/strong&gt; at a few widths.&lt;/li&gt;
&lt;li&gt;Commit small. Future-you will thank you when something looks off.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A converter won't finish the migration for you. What it does is remove the tedious 70%, the &lt;code&gt;mb-3&lt;/code&gt; to &lt;code&gt;mb-4&lt;/code&gt; busywork, so you can spend your attention on the parts that need judgment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://aabitech.com/tools/bootstrap-to-tailwind-converter" rel="noopener noreferrer"&gt;Bootstrap to Tailwind Converter&lt;/a&gt; is free, needs no signup, and is upfront about its limits. That honesty is why I'd use it. Try it on one ugly legacy snippet, check the diagnostics, and see how much time it saves.&lt;/p&gt;

&lt;p&gt;Have you migrated from Bootstrap to Tailwind? What was the one thing that tripped you up? I'd love to hear it in the comments.&lt;/p&gt;

&lt;p&gt;Happy migrating! 🚀&lt;/p&gt;

</description>
      <category>tailwindcss</category>
      <category>bootstrap</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Generate Pydantic v1/v2 Models from JSON in Seconds (and What to Fix Afterward)</title>
      <dc:creator>Muhammad Iqbal</dc:creator>
      <pubDate>Mon, 26 Oct 2026 13:40:34 +0000</pubDate>
      <link>https://dev.to/iqbalaabi/generate-pydantic-v1v2-models-from-json-in-seconds-and-what-to-fix-afterward-4m0a</link>
      <guid>https://dev.to/iqbalaabi/generate-pydantic-v1v2-models-from-json-in-seconds-and-what-to-fix-afterward-4m0a</guid>
      <description>&lt;p&gt;Hand-writing Pydantic models from a large JSON payload is mechanical work: map types, nest classes, repeat. I've been using a free &lt;a href="https://aabitech.com/tools/json-to-pydantic-converter" rel="noopener noreferrer"&gt;JSON to Pydantic Converter&lt;/a&gt; from AabiTech to skip that step. Here's what it does and where you still need to think.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;Paste JSON (or upload a file, up to 5 MB) and get Python model code back.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nested objects become separate models, and arrays of objects become &lt;code&gt;list[Model]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pydantic v2 or v1 compatibility mode&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Configurable &lt;strong&gt;root model name&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2, 4, or 8 space&lt;/strong&gt; indentation&lt;/li&gt;
&lt;li&gt;Copy to clipboard or download as &lt;code&gt;.py&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Runs client-side; the page states your JSON is processed in the browser and generated code is never executed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No signup required.&lt;/p&gt;

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

&lt;p&gt;Input:&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;"Ayesha"&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;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"active"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&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;Output:&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;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With nested payloads, you get one class per object, referenced from the parent. That's where it saves the most time.&lt;/p&gt;

&lt;h2&gt;
  
  
  v1 vs v2: pick the right mode
&lt;/h2&gt;

&lt;p&gt;The two versions differ enough that wrong-version output will bite you:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Pydantic v1&lt;/th&gt;
&lt;th&gt;Pydantic v2&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Parse a dict&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Model.parse_obj(d)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Model.model_validate(d)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Serialize&lt;/td&gt;
&lt;td&gt;&lt;code&gt;m.dict()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;m.model_dump()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Config&lt;/td&gt;
&lt;td&gt;&lt;code&gt;class Config:&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;model_config = ConfigDict(...)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Select the mode matching your installed version, then verify imports and config anyway.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a single sample can't tell you
&lt;/h2&gt;

&lt;p&gt;Generated models are inferred from one example, so review these before shipping:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Optional vs nullable.&lt;/strong&gt; These are different things.&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="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;            &lt;span class="c1"&gt;# required, but may be None
&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;     &lt;span class="c1"&gt;# may be omitted, may be None
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A sample with &lt;code&gt;"b": null&lt;/code&gt; doesn't tell you whether &lt;code&gt;b&lt;/code&gt; can be absent. Check more records.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Mixed types.&lt;/strong&gt; If a field is &lt;code&gt;int&lt;/code&gt; in some records and &lt;code&gt;str&lt;/code&gt; in others, you need a union or a validator:&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="nb"&gt;id&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="nb"&gt;str&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Key naming.&lt;/strong&gt; &lt;code&gt;firstName&lt;/code&gt;, &lt;code&gt;user-id&lt;/code&gt;, or keys with spaces need Python-safe attribute names plus aliases:&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;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alias&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;firstName&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;Check alias and serialization settings (&lt;code&gt;by_alias=True&lt;/code&gt; on dump) before wiring this to an external API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Empty arrays.&lt;/strong&gt; &lt;code&gt;[]&lt;/code&gt; gives no item type to infer from. Fill it in manually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Constraints.&lt;/strong&gt; No sample will tell you about &lt;code&gt;min_length&lt;/code&gt;, regex patterns, enums, or ranges. Add them yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Suggested workflow
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Validate your JSON first (the site also has a &lt;a href="https://aabitech.com/tools/json-formatter" rel="noopener noreferrer"&gt;JSON Formatter&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Use a representative sample, ideally the most complete record you have&lt;/li&gt;
&lt;li&gt;Generate with the right Pydantic version&lt;/li&gt;
&lt;li&gt;Fix optionals, unions, and aliases&lt;/li&gt;
&lt;li&gt;Add validators and constraints&lt;/li&gt;
&lt;li&gt;Test against both valid and invalid payloads&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Plugged into FastAPI, the result gives you request validation and OpenAPI docs almost immediately:&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="nd"&gt;@app.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/users&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Privacy note
&lt;/h2&gt;

&lt;p&gt;Even though processing happens in the browser, keep tokens, passwords, and real customer data out of sample payloads. Good habit for any online tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://aabitech.com/tools/json-to-pydantic-converter" rel="noopener noreferrer"&gt;aabitech.com/tools/json-to-pydantic-converter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Treat the output as a solid first draft, not a finished schema. How do you handle messy third-party API responses? Share your approach in the comments.&lt;/p&gt;

</description>
      <category>python</category>
      <category>pydantic</category>
      <category>fastapi</category>
      <category>api</category>
    </item>
    <item>
      <title>Tutorial: Tune Your RAG Chunking Visually (Free Browser Tool, No Setup)</title>
      <dc:creator>Muhammad Iqbal</dc:creator>
      <pubDate>Mon, 19 Oct 2026 15:56:34 +0000</pubDate>
      <link>https://dev.to/iqbalaabi/tutorial-tune-your-rag-chunking-visually-free-browser-tool-no-setup-818</link>
      <guid>https://dev.to/iqbalaabi/tutorial-tune-your-rag-chunking-visually-free-browser-tool-no-setup-818</guid>
      <description>&lt;p&gt;Chunking is the RAG step everyone copies from a tutorial ("size 1000, overlap 200") and never looks at again. In this walkthrough, you'll use a free browser tool to actually &lt;em&gt;see&lt;/em&gt; your chunks, compare strategies, estimate costs, and export working splitter code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What you'll need:&lt;/strong&gt; a browser and a sample document (Markdown or plain text works best). No install, no signup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tool:&lt;/strong&gt; &lt;a href="https://aabitech.com/tools/rag-chunking-simulator" rel="noopener noreferrer"&gt;RAG Chunking Simulator &amp;amp; Visualizer&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Per the site, text is processed locally in your browser instead of being sent to a chunking API. For confidential docs, still follow your organization's policies.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What you'll do
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Load a document&lt;/li&gt;
&lt;li&gt;Compare chunking strategies&lt;/li&gt;
&lt;li&gt;Tune size and overlap&lt;/li&gt;
&lt;li&gt;Inspect boundaries&lt;/li&gt;
&lt;li&gt;Check diagnostics&lt;/li&gt;
&lt;li&gt;Try parent-child chunking&lt;/li&gt;
&lt;li&gt;Test retrieval with a keyword query&lt;/li&gt;
&lt;li&gt;Estimate cost, storage, and context budget&lt;/li&gt;
&lt;li&gt;Export code and chunks&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 1: Load a document
&lt;/h2&gt;

&lt;p&gt;Open the tool. Under &lt;strong&gt;Source document&lt;/strong&gt;, you have three options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use a built-in preset: &lt;strong&gt;RAG sample&lt;/strong&gt;, &lt;strong&gt;Markdown sample&lt;/strong&gt;, or &lt;strong&gt;Code sample&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Paste your own text&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Import .txt / .md&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For this tutorial, start with the &lt;strong&gt;Markdown sample&lt;/strong&gt; so heading-aware strategies have something to work with. A live counter shows characters, words, and estimated tokens as you type.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Pick and compare strategies
&lt;/h2&gt;

&lt;p&gt;In &lt;strong&gt;Compare chunking strategies&lt;/strong&gt;, select several at once. The tool supports eight:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Strategy&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Fixed-size&lt;/td&gt;
&lt;td&gt;A simple baseline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recursive character&lt;/td&gt;
&lt;td&gt;General text (paragraph → newline → space fallback)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sentence-aware&lt;/td&gt;
&lt;td&gt;Avoiding mid-sentence cuts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Paragraph-aware&lt;/td&gt;
&lt;td&gt;Keeping related sentences together&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Markdown-aware&lt;/td&gt;
&lt;td&gt;Docs with headings and structure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Heading-based&lt;/td&gt;
&lt;td&gt;Splitting by section&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Regex-based&lt;/td&gt;
&lt;td&gt;Custom formats (you supply the pattern)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Word-based&lt;/td&gt;
&lt;td&gt;Word-count limits instead of characters&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Select &lt;strong&gt;Fixed-size&lt;/strong&gt;, &lt;strong&gt;Recursive&lt;/strong&gt;, and &lt;strong&gt;Markdown-aware&lt;/strong&gt; for now.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;benchmark table&lt;/strong&gt; then shows, per strategy: chunk count, average size, size variance, overlap characters, and estimated cost. Click any row to make it the active strategy in the visualizer below.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What to look for:&lt;/strong&gt; two strategies can produce the same chunk count with very different size variance. High variance usually means some chunks are tiny and others are huge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Tune size and overlap
&lt;/h2&gt;

&lt;p&gt;Under &lt;strong&gt;Chunk parameters&lt;/strong&gt;, adjust:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Chunk size&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Boundary overlap&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Measurement mode&lt;/strong&gt;: Characters, Words, or Estimated tokens&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pick the unit deliberately. A character limit doesn't guarantee a chunk fits your model's token limit. If you choose estimated tokens, set &lt;strong&gt;Chars / token&lt;/strong&gt; (the token counting mode also offers whitespace and word+punctuation counts).&lt;/p&gt;

&lt;p&gt;Try this experiment:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set overlap to &lt;code&gt;0&lt;/code&gt; and note the chunk count and overlap chars.&lt;/li&gt;
&lt;li&gt;Raise overlap gradually.&lt;/li&gt;
&lt;li&gt;Watch the benchmark table: more overlap means more duplicated text, which means more tokens to embed and store.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The goal is the smallest overlap that still keeps context intact across boundaries. There's no universal number, so test on your own documents.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Inspect boundaries visually
&lt;/h2&gt;

&lt;p&gt;Scroll to the &lt;strong&gt;source boundary map&lt;/strong&gt;. Alternating colors mark odd and even chunks, and shared overlap regions are highlighted separately.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;Prev / Next&lt;/strong&gt; or the slider to scrub through chunks one at a time&lt;/li&gt;
&lt;li&gt;Click a block on the &lt;strong&gt;minimap ribbon&lt;/strong&gt; to jump to that span&lt;/li&gt;
&lt;li&gt;Open the &lt;strong&gt;chunk preview inspector&lt;/strong&gt; to read the actual content and its source offsets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ask yourself at each boundary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Did a sentence get cut in half?&lt;/li&gt;
&lt;li&gt;Is a heading separated from its content?&lt;/li&gt;
&lt;li&gt;Is a code block or list broken apart?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If yes, switch strategy or adjust size and re-check.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Read the diagnostics
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Chunk-size distribution &amp;amp; diagnostics&lt;/strong&gt; panel gives you a 6-bucket histogram plus counts for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tiny chunks (configurable &lt;strong&gt;Tiny threshold&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Oversized chunks&lt;/li&gt;
&lt;li&gt;Boundary alerts&lt;/li&gt;
&lt;li&gt;Near duplicates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are review prompts, not a verified quality score. The page itself labels the context-preservation heuristic as "not a validated retrieval-quality score." Use them to know where to look, then judge by reading the chunks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Try parent-child chunking
&lt;/h2&gt;

&lt;p&gt;If small chunks match well but lack context, try &lt;strong&gt;Parent-child hierarchy chunking&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set a &lt;strong&gt;Child size&lt;/strong&gt; (small, for precise matching)&lt;/li&gt;
&lt;li&gt;Set a &lt;strong&gt;Parent size&lt;/strong&gt; (larger, for context)&lt;/li&gt;
&lt;li&gt;Enter a query to see which child chunks rank and which parent context they map to&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This models small-to-large retrieval: match on the child, return the parent. You can export the structure with &lt;strong&gt;Export parent-child JSON&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: Test with the keyword retrieval simulator
&lt;/h2&gt;

&lt;p&gt;In &lt;strong&gt;Keyword retrieval simulator&lt;/strong&gt;, enter a query you expect real users to ask and set &lt;strong&gt;Top K&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is a lexical baseline, not an embedding search, so it won't predict your vector store's results. It's still handy for a quick sanity check: does the chunk that should answer the question rank near the top, or did a boundary scatter the relevant terms?&lt;/p&gt;

&lt;p&gt;If your relevant text keeps landing in the wrong chunk, revisit Steps 3 and 4.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 8: Estimate cost, storage, and context budget
&lt;/h2&gt;

&lt;p&gt;Three panels help with planning:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Embedding cost.&lt;/strong&gt; Enter your provider's &lt;strong&gt;Price / 1M tok ($)&lt;/strong&gt; and compare strategies in the benchmark table. Treat it as a relative comparison, not an invoice. Token counts are estimated from a chars-per-token ratio.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Index storage.&lt;/strong&gt; Set vector dimensions, bytes per dimension (float32 / float16 / int8), and metadata bytes per chunk. The tool reports raw vector payload, metadata payload, and an estimated total. Real vector databases add their own overhead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context-window budget.&lt;/strong&gt; Set a context budget and a reserve for prompt and answer. The tool greedily packs chunks to show how many fit. You can export the selected context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 9: Export code and chunks
&lt;/h2&gt;

&lt;p&gt;Once you've settled on settings, open the &lt;strong&gt;Framework configuration generator&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Choose &lt;strong&gt;LangChain (Python)&lt;/strong&gt; or &lt;strong&gt;LlamaIndex (Python)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Review the generated code (synced to your current sliders)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Copy code&lt;/strong&gt;, &lt;strong&gt;Download Python example&lt;/strong&gt;, or &lt;strong&gt;Download config&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For a recursive strategy, the LangChain output will look something like this (exact output depends on your settings):&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;langchain_text_splitters&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;RecursiveCharacterTextSplitter&lt;/span&gt;

&lt;span class="n"&gt;splitter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RecursiveCharacterTextSplitter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;chunk_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;chunk_overlap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;separators&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="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&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="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;splitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split_text&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To export the chunks themselves, use &lt;strong&gt;JSON, JSONL, CSV, or TXT&lt;/strong&gt;. Before exporting, fill in &lt;strong&gt;Chunk attribution metadata&lt;/strong&gt; (source ID, page, section, plus an optional JSON object) so every record carries its origin.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Heads-up on offsets:&lt;/strong&gt; they're JavaScript UTF-16 code units, not UTF-8 byte offsets. Convert them if your pipeline expects bytes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 10 (optional): Save and share your experiment
&lt;/h2&gt;

&lt;p&gt;Under &lt;strong&gt;Experiment history &amp;amp; state sharing&lt;/strong&gt;, name and save a snapshot in your browser, or use &lt;strong&gt;Copy share settings&lt;/strong&gt; to generate a URL-hash link. Teammates open it and see your exact configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations to keep in mind
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Token counts and costs are &lt;strong&gt;estimates&lt;/strong&gt;. Validate with your embedding model's real tokenizer before production.&lt;/li&gt;
&lt;li&gt;The keyword simulator is lexical, not semantic.&lt;/li&gt;
&lt;li&gt;Good-looking chunks don't guarantee good answers. Evaluate with real queries and measure retrieval relevance and answer quality in your actual pipeline.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;You've now loaded a document, compared strategies, tuned overlap, inspected boundaries, checked diagnostics, tried parent-child retrieval, estimated costs, and exported working code. Total setup time: zero.&lt;/p&gt;

&lt;p&gt;Try it on your own docs: &lt;strong&gt;&lt;a href="https://aabitech.com/tools/rag-chunking-simulator" rel="noopener noreferrer"&gt;aabitech.com/tools/rag-chunking-simulator&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Which strategy and chunk size worked best for your content? Share your findings in the comments. 👇&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rag</category>
      <category>llm</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>I Built a Free Tool to Convert SQL to Laravel Migrations</title>
      <dc:creator>Muhammad Iqbal</dc:creator>
      <pubDate>Sun, 18 Oct 2026 17:41:08 +0000</pubDate>
      <link>https://dev.to/iqbalaabi/i-built-a-free-tool-to-convert-sql-to-laravel-migrations-5737</link>
      <guid>https://dev.to/iqbalaabi/i-built-a-free-tool-to-convert-sql-to-laravel-migrations-5737</guid>
      <description>&lt;p&gt;If you work with Laravel, you have probably faced this situation at least once.&lt;/p&gt;

&lt;p&gt;You get an old database. Maybe it's a &lt;code&gt;.sql&lt;/code&gt; file from a client, or a MySQL schema from a previous project. Now you have to bring it into a Laravel app, and Laravel wants migrations.&lt;/p&gt;

&lt;p&gt;So you open the SQL file and start writing &lt;code&gt;Schema::create()&lt;/code&gt; by hand. Table by table. Column by column. &lt;code&gt;VARCHAR(255)&lt;/code&gt; becomes &lt;code&gt;string()&lt;/code&gt;, &lt;code&gt;BIGINT UNSIGNED&lt;/code&gt; becomes &lt;code&gt;unsignedBigInteger()&lt;/code&gt;, and then you do the same for indexes and foreign keys.&lt;/p&gt;

&lt;p&gt;It's boring work, and it's easy to make small mistakes. I got tired of it, so I built a tool for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Meet the SQL to Laravel Migration Converter
&lt;/h2&gt;

&lt;p&gt;It's a free online tool on &lt;a href="https://aabitech.com/tools/sql-to-laravel-migration-converter" rel="noopener noreferrer"&gt;AabiTech&lt;/a&gt;. You paste your SQL &lt;code&gt;CREATE TABLE&lt;/code&gt; statements, and it gives you Laravel migration code.&lt;/p&gt;

&lt;p&gt;No signup, no install. You just open it in your browser and use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use it
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Paste your SQL schema, or import a &lt;code&gt;.sql&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;Pick your SQL dialect, or leave it on auto detect.&lt;/li&gt;
&lt;li&gt;Choose your Laravel version.&lt;/li&gt;
&lt;li&gt;Copy the migration, or download it as a ZIP.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it.&lt;/p&gt;

&lt;h2&gt;
  
  
  A quick example
&lt;/h2&gt;

&lt;p&gt;Say you have this SQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;BIGINT&lt;/span&gt; &lt;span class="nb"&gt;UNSIGNED&lt;/span&gt; &lt;span class="n"&gt;AUTO_INCREMENT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;updated_at&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You get a Laravel migration with the &lt;code&gt;Schema::create&lt;/code&gt; structure, the right column methods, and the unique index. The exact output depends on the options you pick (more on that below).&lt;/p&gt;

&lt;h2&gt;
  
  
  What I like about it
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;It works in your browser.&lt;/strong&gt; Your SQL is parsed and converted locally. It is not sent to my server. This matters because database schemas can be sensitive, and I wouldn't want to paste a client's schema into a random website either.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It supports several SQL dialects.&lt;/strong&gt; MySQL / MariaDB, PostgreSQL, SQLite, and SQL Server. Or you can let it auto detect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It supports multiple Laravel versions.&lt;/strong&gt; You can target Laravel 9, 10, 11, 12, or 13.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You control the output.&lt;/strong&gt; There are a few options you can change:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Output style:&lt;/strong&gt; Idiomatic, Explicit, or Compatibility-focused&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Naming:&lt;/strong&gt; keep names as they are, or convert to snake_case or lowercase&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smart Laravel idioms:&lt;/strong&gt; for example, collapsing &lt;code&gt;created_at&lt;/code&gt; and &lt;code&gt;updated_at&lt;/code&gt; into &lt;code&gt;timestamps()&lt;/code&gt;, and soft deletes into &lt;code&gt;softDeletes()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Separate FK phase:&lt;/strong&gt; puts foreign keys in their own step, which helps with migration order&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exclude tables:&lt;/strong&gt; skip tables you don't need&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;It can generate more than migrations.&lt;/strong&gt; If you want, it can also create models, factories, and seeders from your &lt;code&gt;INSERT&lt;/code&gt; statements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It gives you a conversion report.&lt;/strong&gt; You can see how many tables and columns were found, how many were converted, and any warnings. There is also a column mapping table that shows each SQL column next to its Laravel version, so you can check it quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Please review the result
&lt;/h2&gt;

&lt;p&gt;I want to be honest about this: no converter is perfect.&lt;/p&gt;

&lt;p&gt;SQL dialects have many database-specific things, like storage engines, collations, generated columns, and special default expressions. Some of these don't map directly to Laravel's Schema Builder.&lt;/p&gt;

&lt;p&gt;So treat the output as a strong starting point, not the final answer. Before you use it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compare the migration with your original SQL&lt;/li&gt;
&lt;li&gt;Check data types, defaults, and nullable columns&lt;/li&gt;
&lt;li&gt;Check the order of your migrations, because foreign keys need the referenced table to exist first&lt;/li&gt;
&lt;li&gt;Run it on a test database before anything serious&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tool saves you the repetitive typing. You still do the thinking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who is it for?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Developers moving a legacy PHP project to Laravel&lt;/li&gt;
&lt;li&gt;Anyone given a &lt;code&gt;.sql&lt;/code&gt; file and asked to "make it Laravel"&lt;/li&gt;
&lt;li&gt;People who want to quickly turn a schema into migrations, models, and factories&lt;/li&gt;
&lt;li&gt;Students learning how SQL types map to Laravel's Blueprint&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;You can find the tool here:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://aabitech.com/tools/sql-to-laravel-migration-converter" rel="noopener noreferrer"&gt;SQL to Laravel Migration Converter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you try it and something doesn't convert correctly, or you have an idea for a feature, please tell me in the comments. Real SQL schemas are messy, and feedback from real projects helps me improve it.&lt;/p&gt;

&lt;p&gt;I'm also adding more free developer tools to &lt;a href="https://aabitech.com/tools" rel="noopener noreferrer"&gt;AabiTech&lt;/a&gt;, so take a look if you're interested.&lt;/p&gt;

&lt;p&gt;Thanks for reading! 🙌&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>webdev</category>
      <category>tools</category>
    </item>
    <item>
      <title>Stop Guessing Your RAG Chunking Strategy. Inspect It</title>
      <dc:creator>Muhammad Iqbal</dc:creator>
      <pubDate>Thu, 15 Oct 2026 16:26:28 +0000</pubDate>
      <link>https://dev.to/iqbalaabi/stop-guessing-your-rag-chunking-strategy-inspect-it-126c</link>
      <guid>https://dev.to/iqbalaabi/stop-guessing-your-rag-chunking-strategy-inspect-it-126c</guid>
      <description>&lt;p&gt;If you've built a RAG pipeline, you know chunking isn't just splitting text into smaller pieces.&lt;/p&gt;

&lt;p&gt;Chunk size affects context retention. Overlap introduces duplication. Splitting on arbitrary boundaries can separate code, paragraphs, or related ideas. And a configuration that looks reasonable on paper might perform poorly during retrieval.&lt;/p&gt;

&lt;p&gt;Usually, figuring this out means tweaking parameters, rerunning scripts, dumping chunks to the console, and comparing outputs manually.&lt;/p&gt;

&lt;p&gt;I built a tool to make that workflow easier.&lt;/p&gt;

&lt;p&gt;Meet the "AabiTech RAG Chunking Simulator" (&lt;a href="https://aabitech.com/tools/rag-chunking-simulator" rel="noopener noreferrer"&gt;https://aabitech.com/tools/rag-chunking-simulator&lt;/a&gt;) — an interactive workspace for experimenting with chunking strategies before integrating them into your RAG pipeline.&lt;/p&gt;

&lt;p&gt;What you can do&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compare strategies: Experiment with fixed-size, recursive, sentence-aware, paragraph-aware, Markdown-aware, and other splitting approaches.&lt;/li&gt;
&lt;li&gt;Inspect boundaries: Visualize how source text is divided and examine individual chunks and overlapping regions.&lt;/li&gt;
&lt;li&gt;Measure trade-offs: Review chunk counts, size distributions, overlap, and estimated token and embedding costs.&lt;/li&gt;
&lt;li&gt;Explore retrieval: Test lightweight keyword retrieval, parent-child chunking, and context-window budgets.&lt;/li&gt;
&lt;li&gt;Export your results: Download chunks in JSON, JSONL, CSV, or text formats, and generate Python splitter examples for supported frameworks.&lt;/li&gt;
&lt;li&gt;Save experiments: Keep configuration snapshots in your browser or share settings through URL hashes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Built with privacy in mind&lt;/p&gt;

&lt;p&gt;The chunking engine processes your source text locally in the browser instead of sending it to a dedicated chunking API.&lt;/p&gt;

&lt;p&gt;That makes it useful for experimenting with documentation, code snippets, and sample datasets without unnecessarily uploading them elsewhere.&lt;/p&gt;

&lt;p&gt;What it's useful for&lt;/p&gt;

&lt;p&gt;This isn't a replacement for evaluating retrieval quality against your real dataset. It's a way to inspect chunking behavior, understand configuration trade-offs, and narrow down the settings worth testing in your actual pipeline.&lt;/p&gt;

&lt;p&gt;If you're building RAG systems, working with vector databases, or experimenting with document retrieval, this workspace may save you some debugging time.&lt;/p&gt;

&lt;p&gt;🔗 Try it and bookmark it: &lt;a href="https://aabitech.com/tools/rag-chunking-simulator" rel="noopener noreferrer"&gt;https://aabitech.com/tools/rag-chunking-simulator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One question for fellow RAG developers: How do you choose chunk size and overlap — fixed defaults, document-specific rules, or evaluation-driven tuning?&lt;/p&gt;

&lt;p&gt;I'd love to hear what works in your pipelines and what you'd like to see added to the tool.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>python</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Why Your Tailwind Email Breaks in Outlook (and How to Inline It Properly</title>
      <dc:creator>Muhammad Iqbal</dc:creator>
      <pubDate>Mon, 12 Oct 2026 17:37:10 +0000</pubDate>
      <link>https://dev.to/iqbalaabi/why-your-tailwind-email-breaks-in-outlook-and-how-to-inline-it-properly-2a14</link>
      <guid>https://dev.to/iqbalaabi/why-your-tailwind-email-breaks-in-outlook-and-how-to-inline-it-properly-2a14</guid>
      <description>&lt;p&gt;You build an email in Tailwind. It looks perfect in the browser, fine in Gmail, and then desktop Outlook turns it into a mess.&lt;/p&gt;

&lt;p&gt;If you've been there, here's why it happens and a workflow that makes it less painful.&lt;/p&gt;

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

&lt;p&gt;Tailwind classes like &lt;code&gt;px-6&lt;/code&gt; or &lt;code&gt;bg-blue-600&lt;/code&gt; don't carry any styling themselves. They point at rules in a stylesheet. Email clients don't reliably load or honor that stylesheet, and each one renders HTML with its own engine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flexbox and grid are unreliable in key clients&lt;/li&gt;
&lt;li&gt;Transforms, animations and advanced selectors often fail&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rem&lt;/code&gt; units and CSS variables can behave inconsistently&lt;/li&gt;
&lt;li&gt;Media queries work in some clients and are ignored in others&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The one thing nearly everything respects is a &lt;code&gt;style&lt;/code&gt; attribute on the element itself. That's what "inlining" gives you.&lt;/p&gt;

&lt;h2&gt;
  
  
  What inlining does
&lt;/h2&gt;

&lt;p&gt;Illustrative example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Before --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"bg-blue-600 text-white px-6 py-3 font-bold"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Confirm email&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- After --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"background-color:#2563eb;color:#ffffff;padding:12px 24px;font-weight:700;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Confirm email&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Doing this by hand across a whole template is slow, and one missed declaration can break a section in a single client without you noticing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tricky parts
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Responsive variants.&lt;/strong&gt; &lt;code&gt;sm:&lt;/code&gt; and &lt;code&gt;md:&lt;/code&gt; need media queries, and inline styles can't contain those. The workable approach is to inline the static utilities and keep responsive rules in a &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; block. Design so the email still looks fine if those rules are ignored.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Units.&lt;/strong&gt; Convert &lt;code&gt;rem&lt;/code&gt; to &lt;code&gt;px&lt;/code&gt; using a known root font size.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layout.&lt;/strong&gt; If a utility depends on flex or grid, plan on swapping it for a table-based structure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Email size.&lt;/strong&gt; Inlining repeats declarations, so HTML grows. Gmail clips messages over roughly 102 KB, which can hide your footer and unsubscribe link.&lt;/p&gt;

&lt;h2&gt;
  
  
  A workflow that works
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Write the template in Tailwind.&lt;/li&gt;
&lt;li&gt;Convert it to inline styles.&lt;/li&gt;
&lt;li&gt;Read the warnings and fix fragile bits.&lt;/li&gt;
&lt;li&gt;Check the output size.&lt;/li&gt;
&lt;li&gt;Test in real clients, especially Outlook.&lt;/li&gt;
&lt;li&gt;Keep the Tailwind file as your source and re-convert after every change. Don't hand-edit the inlined output.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Trying it with a browser-based converter
&lt;/h2&gt;

&lt;p&gt;For step 2, I built a free converter at AabiTech: the &lt;a href="https://aabitech.com/tools/tailwind-css-to-email-safe-inline-style-converter" rel="noopener noreferrer"&gt;Tailwind CSS to Email-Safe Inline Style Converter&lt;/a&gt;. It runs entirely in the browser, so your template isn't uploaded.&lt;/p&gt;

&lt;p&gt;What it does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supports Tailwind v3 and v4, with an Auto option&lt;/li&gt;
&lt;li&gt;Offers Conservative, Balanced and Modern Email modes&lt;/li&gt;
&lt;li&gt;Inlines static utilities and keeps responsive rules in a style block&lt;/li&gt;
&lt;li&gt;Reports unsupported classes instead of silently guessing&lt;/li&gt;
&lt;li&gt;Warns about fragile features like flexbox, grid, transforms and animation&lt;/li&gt;
&lt;li&gt;Shows size change and a Gmail 102 KB check&lt;/li&gt;
&lt;li&gt;Accepts custom theme JSON and &lt;code&gt;@theme&lt;/code&gt; variables, plus options for root font size, &lt;code&gt;!important&lt;/code&gt; on responsive overrides, and Outlook-safe table hints&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It doesn't promise identical rendering everywhere, and neither does any converter. Treat the warnings as a to-do list, then test in the clients your audience uses.&lt;/p&gt;

&lt;p&gt;If the output is hard to read, run it through an &lt;a href="https://aabitech.com/tools/html-beautifier" rel="noopener noreferrer"&gt;HTML beautifier&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pre-send checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] No flex or grid in the layout&lt;/li&gt;
&lt;li&gt;[ ] Warnings reviewed&lt;/li&gt;
&lt;li&gt;[ ] Size comfortably under Gmail's clip limit&lt;/li&gt;
&lt;li&gt;[ ] Responsive rules are enhancements, not requirements&lt;/li&gt;
&lt;li&gt;[ ] Tested in Gmail, Outlook, Apple Mail and mobile&lt;/li&gt;
&lt;li&gt;[ ] Dark mode checked&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Over to you
&lt;/h2&gt;

&lt;p&gt;What's the worst email client bug you've fought? Do you inline at build time, or use something like MJML or a framework instead? I'd like to hear what's working for your team.&lt;/p&gt;

</description>
      <category>tooling</category>
      <category>tailwindcss</category>
      <category>browser</category>
      <category>css</category>
    </item>
  </channel>
</rss>
