<?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: Ravi Kishan</title>
    <description>The latest articles on DEV Community by Ravi Kishan (@ravikishan).</description>
    <link>https://dev.to/ravikishan</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%2F1011719%2F31bfaa0f-44f8-4cc2-84ba-9ebaaed4e4c3.png</url>
      <title>DEV Community: Ravi Kishan</title>
      <link>https://dev.to/ravikishan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ravikishan"/>
    <language>en</language>
    <item>
      <title>RustDNS: Writing a Recursive DNS Resolver in Rust, Byte by Byte</title>
      <dc:creator>Ravi Kishan</dc:creator>
      <pubDate>Tue, 06 Oct 2026 15:31:56 +0000</pubDate>
      <link>https://dev.to/ravikishan/rustdns-writing-a-recursive-dns-resolver-in-rust-byte-by-byte-56p9</link>
      <guid>https://dev.to/ravikishan/rustdns-writing-a-recursive-dns-resolver-in-rust-byte-by-byte-56p9</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: RustDNS is a recursive DNS resolver written in plain Rust with &lt;strong&gt;zero dependencies&lt;/strong&gt;, just &lt;code&gt;std::net::UdpSocket&lt;/code&gt; and a 512-byte array. It parses DNS packets by hand, follows compression pointers, starts every lookup at a root server and walks the tree down to the answer, then serves that answer to &lt;code&gt;dig&lt;/code&gt; on port 2053. This post goes through the code byte by byte, and then through what broke when I ran it against the real internet.&lt;/p&gt;


&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/ravikisha/rustdns &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;rustdns
cargo run &lt;span class="nt"&gt;--release&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;🔗 &lt;a href="https://github.com/ravikisha/rustdns" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · 🐛 &lt;a href="https://github.com/ravikisha/rustdns/issues" rel="noopener noreferrer"&gt;Issues&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Why I built this&lt;/li&gt;
&lt;li&gt;DNS in two minutes&lt;/li&gt;
&lt;li&gt;Hello, resolver&lt;/li&gt;
&lt;li&gt;The map of the code&lt;/li&gt;
&lt;li&gt;A 512-byte cursor&lt;/li&gt;
&lt;li&gt;Twelve bytes of header&lt;/li&gt;
&lt;li&gt;Names, labels and compression pointers&lt;/li&gt;
&lt;li&gt;One enum per record type&lt;/li&gt;
&lt;li&gt;Walking the tree: recursive resolution&lt;/li&gt;
&lt;li&gt;Serving dig on port 2053&lt;/li&gt;
&lt;li&gt;Breaking it on purpose&lt;/li&gt;
&lt;li&gt;How fast is it?&lt;/li&gt;
&lt;li&gt;What I learned&lt;/li&gt;
&lt;li&gt;What's next&lt;/li&gt;
&lt;li&gt;Try it&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Why I built this
&lt;/h2&gt;

&lt;p&gt;Every network request you have ever made started with a question: &lt;em&gt;what is the IP address of this name?&lt;/em&gt; You type &lt;code&gt;github.com&lt;/code&gt;, and before a single byte of HTML moves, something somewhere has to turn those ten characters into &lt;code&gt;20.207.73.82&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For years that "something" was a black box to me. I knew the words (resolver, root server, TTL, A record) the way you know the names of planets. I'd never &lt;em&gt;touched&lt;/em&gt; one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa1l8007tfbb1c49dzr1l.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa1l8007tfbb1c49dzr1l.jpg" alt="Cover of a 1928 Swedish national telephone directory, the Rikstelefonkatalogen" width="800" height="1200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The usual analogy is that DNS is the internet's phone book. It's a good analogy, but it hides the interesting part. A phone book is one big printed list. DNS is a &lt;em&gt;distributed&lt;/em&gt; phone book: no single machine knows every name, so a resolver has to ask a chain of servers, each of which only knows who to ask next.&lt;/p&gt;

&lt;p&gt;I wanted to see that chain with my own eyes, and I wanted to do it in Rust, because DNS is a binary protocol full of bit fields, offsets and length prefixes. That's exactly the kind of code where Rust's &lt;code&gt;Result&lt;/code&gt; and bounds checks earn their keep. Malformed packets are not hypothetical on the open internet.&lt;/p&gt;

&lt;p&gt;I built RustDNS by working through Emil Hernvall's excellent &lt;a href="https://github.com/EmilHernvall/dnsguide" rel="noopener noreferrer"&gt;dnsguide&lt;/a&gt;, and if you want a step-by-step tutorial, that guide is the place to go. This post is the other half: a tour of the finished code, plus what happened when I ran it against the real internet two years later.&lt;/p&gt;

&lt;h2&gt;
  
  
  DNS in two minutes
&lt;/h2&gt;

&lt;p&gt;DNS names are a tree, read right to left. The invisible dot at the end of &lt;code&gt;google.com.&lt;/code&gt; is the &lt;strong&gt;root&lt;/strong&gt;. Below it sit the top-level domains (&lt;code&gt;.com&lt;/code&gt;, &lt;code&gt;.org&lt;/code&gt;, &lt;code&gt;.in&lt;/code&gt;), below those the domains people register, and below those whatever names the owner creates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv3rjytpmxmmsb8twuxjc.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv3rjytpmxmmsb8twuxjc.webp" alt="mermaid diagram" width="640" height="324"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Diagram from &lt;a href="https://www.ravikishan.me/blog/rustdns-recursive-dns-resolver-in-rust" rel="noopener noreferrer"&gt;the original&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Each level is &lt;strong&gt;delegated&lt;/strong&gt;. The root servers don't know Google's IP. They only know which servers are in charge of &lt;code&gt;.com&lt;/code&gt;. The &lt;code&gt;.com&lt;/code&gt; servers don't know it either; they know which servers are in charge of &lt;code&gt;google.com&lt;/code&gt;. Only those last servers, the &lt;strong&gt;authoritative&lt;/strong&gt; ones, have the actual answer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqyu9b7xia9cvq1ur8u42.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqyu9b7xia9cvq1ur8u42.jpg" alt="Black-and-white photo of telephone operators at a long Bell System switchboard, patching calls by hand" width="600" height="491"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;recursive resolver&lt;/strong&gt; is the operator in this picture. You ask it one question, and it makes all the calls on your behalf: root, then TLD, then authoritative, then it hands you the answer. Your laptop normally uses one run by your ISP, Google (&lt;code&gt;8.8.8.8&lt;/code&gt;) or Cloudflare (&lt;code&gt;1.1.1.1&lt;/code&gt;). RustDNS is a tiny one you can run yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hello, resolver
&lt;/h2&gt;

&lt;p&gt;Build and run it. There are no dependencies to download, so it compiles in seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo run &lt;span class="nt"&gt;--release&lt;/span&gt;
&lt;span class="c"&gt;# listening on 0.0.0.0:2053 (UDP)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Port 2053 instead of 53 is deliberate: ports below 1024 need root on Linux, and this way you don't have to &lt;code&gt;sudo&lt;/code&gt; a learning project. In a second terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dig @127.0.0.1 &lt;span class="nt"&gt;-p&lt;/span&gt; 2053 google.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No &lt;code&gt;dig&lt;/code&gt; on Windows? Neither did I while writing this post, so here is a 12-line client in Python that builds a query packet by hand. It's also a nice preview of the wire format we're about to dissect:&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;import&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qtype&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;HHHHHH&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x1234&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x0100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# header: id, flags (RD=1), 1 question
&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="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;q&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nf"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;             &lt;span class="c1"&gt;# [6]google[3]com
&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;HH&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qtype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                 &lt;span class="c1"&gt;# end of name, QTYPE, QCLASS=IN
&lt;/span&gt;
&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SOCK_DGRAM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;settimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&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;127.0.0.1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2053&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recvfrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server prints every step of its search. This is a real run from my machine, unedited:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Received query: DnsQuestion { name: "google.com", qtype: A }
attempting lookup of A google.com with ns 198.41.0.4
attempting lookup of A google.com with ns 192.41.162.30
attempting lookup of A google.com with ns 216.239.34.10
Answer: A { domain: "google.com", addr: 142.250.29.100, ttl: 300 }
Answer: A { domain: "google.com", addr: 142.250.29.101, ttl: 300 }
Answer: A { domain: "google.com", addr: 142.250.29.138, ttl: 300 }
Answer: A { domain: "google.com", addr: 142.250.29.113, ttl: 300 }
Answer: A { domain: "google.com", addr: 142.250.29.139, ttl: 300 }
Answer: A { domain: "google.com", addr: 142.250.29.102, ttl: 300 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three lines, three servers: &lt;code&gt;198.41.0.4&lt;/code&gt; is &lt;strong&gt;a.root-servers.net&lt;/strong&gt;, &lt;code&gt;192.41.162.30&lt;/code&gt; is &lt;strong&gt;l.gtld-servers.net&lt;/strong&gt; (one of the &lt;code&gt;.com&lt;/code&gt; servers), and &lt;code&gt;216.239.34.10&lt;/code&gt; is &lt;strong&gt;ns2.google.com&lt;/strong&gt;. That's the whole tree from the diagram above, walked in about half a second.&lt;/p&gt;

&lt;p&gt;A CNAME chain works too. Asking for &lt;code&gt;www.github.com&lt;/code&gt; comes back with an alias &lt;em&gt;and&lt;/em&gt; the address it points to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Answer: CNAME { domain: "www.github.com", host: "github.com", ttl: 3600 }
Answer: A { domain: "github.com", addr: 20.207.73.82, ttl: 60 }
Authority: NS { domain: "github.com", host: "dns1.p08.nsone.net", ttl: 900 }
Authority: NS { domain: "github.com", host: "ns-421.awsdns-52.com", ttl: 900 }
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So how does it do that?&lt;/p&gt;

&lt;h2&gt;
  
  
  The map of the code
&lt;/h2&gt;

&lt;p&gt;The whole server lives in one file, &lt;a href="https://github.com/ravikisha/rustdns/blob/main/src/main.rs" rel="noopener noreferrer"&gt;&lt;code&gt;src/main.rs&lt;/code&gt;&lt;/a&gt;, and &lt;code&gt;Cargo.toml&lt;/code&gt; has an empty &lt;code&gt;[dependencies]&lt;/code&gt; table. It layers neatly from raw bytes up to a running server:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsie4gkkxa3zo7wr0zw5p.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsie4gkkxa3zo7wr0zw5p.webp" alt="mermaid diagram" width="640" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Diagram from &lt;a href="https://www.ravikishan.me/blog/rustdns-recursive-dns-resolver-in-rust" rel="noopener noreferrer"&gt;the original&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Everything that touches the wire goes through &lt;code&gt;BytePacketBuffer&lt;/code&gt;. Everything above it works with plain Rust structs and enums. Let's go bottom-up.&lt;/p&gt;

&lt;h2&gt;
  
  
  A 512-byte cursor
&lt;/h2&gt;

&lt;p&gt;The original DNS spec (&lt;a href="https://www.rfc-editor.org/rfc/rfc1035" rel="noopener noreferrer"&gt;RFC 1035&lt;/a&gt;) caps a UDP message at &lt;strong&gt;512 bytes&lt;/strong&gt;. So the buffer is just a fixed array and a position:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;BytePacketBuffer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/// Buffer for holding the packet contents&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="cd"&gt;/// Field for keeping track of where we are&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No heap allocation, no &lt;code&gt;Vec&lt;/code&gt;, no growing. Reading is a cursor that walks forward and refuses to fall off the end:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.pos&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;512&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"End of the buffer"&lt;/span&gt;&lt;span class="nf"&gt;.into&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.pos&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.pos&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;DNS is &lt;strong&gt;big-endian&lt;/strong&gt; ("network byte order"), so multi-byte integers are assembled most-significant byte first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;read_u16&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u16&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u16&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;?&lt;/code&gt; after every &lt;code&gt;read()&lt;/code&gt; is the quiet hero here. A truncated or malicious packet can end at any byte, and every single read propagates that as an error instead of reading garbage. Writing mirrors reading: &lt;code&gt;write_u8&lt;/code&gt;, &lt;code&gt;write_u16&lt;/code&gt;, &lt;code&gt;write_u32&lt;/code&gt;, each splitting the integer back into bytes with shifts.&lt;/p&gt;

&lt;p&gt;There are two more primitives that matter later: &lt;code&gt;get(pos)&lt;/code&gt; peeks at a byte &lt;em&gt;without&lt;/em&gt; moving the cursor, and &lt;code&gt;set_u16(pos, val)&lt;/code&gt; overwrites two bytes we already wrote. Hold on to both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Twelve bytes of header
&lt;/h2&gt;

&lt;p&gt;Every DNS message, query or response, starts with the same 12-byte header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                                1  1  1  1  1  1
  0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                      ID                       |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR|   OPCODE  |AA|TC|RD|RA| Z|AD|CD|   RCODE   |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    QDCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    ANCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    NSCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    ARCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Bits&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ID&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;Chosen by the client, copied into the reply so answers can be matched to questions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;QR&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0 = query, 1 = response&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;OPCODE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0 = standard query&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;AA&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Authoritative answer: the server &lt;em&gt;owns&lt;/em&gt; this name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TC&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Truncated: the answer didn't fit, retry over TCP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;RD&lt;/code&gt; / &lt;code&gt;RA&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;1 + 1&lt;/td&gt;
&lt;td&gt;Recursion desired (client asks) / available (server offers)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;AD&lt;/code&gt; / &lt;code&gt;CD&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;1 + 1&lt;/td&gt;
&lt;td&gt;DNSSEC: authenticated data / checking disabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RCODE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0 NOERROR, 2 SERVFAIL, 3 NXDOMAIN, …&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;QDCOUNT&lt;/code&gt; … &lt;code&gt;ARCOUNT&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;16 each&lt;/td&gt;
&lt;td&gt;How many entries follow in each of the four sections&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The flags live in the middle 16 bits. &lt;code&gt;DnsHeader::read&lt;/code&gt; splits them into a high byte &lt;code&gt;a&lt;/code&gt; and low byte &lt;code&gt;b&lt;/code&gt; and picks them apart with masks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="nf"&gt;.read_u16&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mi"&gt;0xFF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.recursion_desired&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.truncated_message&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.authoritative_answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.opcode&lt;/span&gt;               &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mi"&gt;0x0F&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.response&lt;/span&gt;             &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.rescode&lt;/span&gt;              &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;ResultCode&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mi"&gt;0x0F&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.checking_disabled&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.authed_data&lt;/span&gt;          &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.z&lt;/span&gt;                    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.recursion_available&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bit-twiddling is much easier to &lt;em&gt;feel&lt;/em&gt; than to read. Click any bit below to flip it and watch the decoded header change. It starts at &lt;code&gt;0x8180&lt;/code&gt;, the flags of a normal successful response: QR, RD and RA set, RCODE 0. Try setting the low bits to &lt;code&gt;0011&lt;/code&gt; to make an NXDOMAIN.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg7ok03bp17lg6z4ef08p.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg7ok03bp17lg6z4ef08p.webp" alt="p5 visualisation" width="800" height="225"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A frame from the interactive sketch in &lt;a href="https://www.ravikishan.me/blog/rustdns-recursive-dns-resolver-in-rust" rel="noopener noreferrer"&gt;the original&lt;/a&gt; — &lt;a href="https://www.ravikishan.me/api/media/devto/p5-1ach2ez16j1tod-motion.webm" rel="noopener noreferrer"&gt;watch it run&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Writing the header is the same thing in reverse: shift each boolean back into position and OR the pieces together into two bytes.&lt;/p&gt;

&lt;h3&gt;
  
  
  A real packet, byte by byte
&lt;/h3&gt;

&lt;p&gt;The repo keeps two captured packets, &lt;a href="https://github.com/ravikisha/rustdns/blob/main/query_packet.txt" rel="noopener noreferrer"&gt;&lt;code&gt;query_packet.txt&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/ravikisha/rustdns/blob/main/response_packet.txt" rel="noopener noreferrer"&gt;&lt;code&gt;response_packet.txt&lt;/code&gt;&lt;/a&gt;. The query is 28 bytes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;79 88 01 20 00 01 00 00 00 00 00 00   header: id 0x7988, RD=1, 1 question
06 67 6f 6f 67 6c 65 03 63 6f 6d 00   [6]google[3]com[0]
00 01 00 01                           QTYPE A, QCLASS IN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response is 44. The sketch below steps through every field. Watch byte 28: it's where things get clever.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcpgp081y7f3n7cskzeq4.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcpgp081y7f3n7cskzeq4.webp" alt="p5 visualisation" width="799" height="283"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A frame from the interactive sketch in &lt;a href="https://www.ravikishan.me/blog/rustdns-recursive-dns-resolver-in-rust" rel="noopener noreferrer"&gt;the original&lt;/a&gt; — &lt;a href="https://www.ravikishan.me/api/media/devto/p5-17nbmmco52wxr-motion.webm" rel="noopener noreferrer"&gt;watch it run&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Names, labels and compression pointers
&lt;/h2&gt;

&lt;p&gt;Domain names on the wire aren't dotted strings. They're a sequence of &lt;strong&gt;labels&lt;/strong&gt;, each prefixed by its length, ending with a zero-length label:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;www.google.com  →  [3] w w w [6] g o o g l e [3] c o m [0]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A length byte can only use 6 of its 8 bits, which is where the famous label limit comes from: 

&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;2&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;6&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;1&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;63&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 characters.&lt;/p&gt;

&lt;p&gt;The top two bits are reserved for something much better. If both are set (&lt;code&gt;0b11xxxxxx&lt;/code&gt;), the byte isn't a length at all. It's the start of a &lt;strong&gt;compression pointer&lt;/strong&gt;: the remaining 14 bits are an offset elsewhere in the packet where the rest of the name can be found.&lt;/p&gt;

&lt;p&gt;$$&lt;br&gt;
\text{offset} = \big((b_0 \mathbin{&amp;amp;} \texttt{0x3F}) \ll 8\big) \mathbin{|} b_1&lt;br&gt;
$$&lt;/p&gt;

&lt;p&gt;That's exactly what &lt;code&gt;c0 0c&lt;/code&gt; at byte 28 of the response means: offset &lt;code&gt;0x000C&lt;/code&gt;, byte 12, where &lt;code&gt;google.com&lt;/code&gt; was already written in the question. Two bytes instead of twelve. In a response with ten records about the same domain, that saving is the difference between fitting in 512 bytes and not.&lt;/p&gt;

&lt;p&gt;Here's the flow of &lt;code&gt;read_qname&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbnuazqoqrzwomn6apxcz.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbnuazqoqrzwomn6apxcz.webp" alt="mermaid diagram" width="640" height="920"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Diagram from &lt;a href="https://www.ravikishan.me/blog/rustdns-recursive-dns-resolver-in-rust" rel="noopener noreferrer"&gt;the original&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And the heart of the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;read_qname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outstr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.pos&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// local cursor, independent of the buffer's&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;jumped&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;max_jumps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;jumps_performed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;delim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;loop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// A crafted packet can contain a pointer loop. Never trust the wire.&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;jumps_performed&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;max_jumps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Limit of {} jumps exceeded"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_jumps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.into&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mi"&gt;0xC0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0xC0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Move the *shared* cursor past the pointer, but only once&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;jumped&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.seek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;b2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u16&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(((&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="mi"&gt;0xC0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;b2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="n"&gt;jumped&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;jumps_performed&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;outstr&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delim&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;str_buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.get_range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;outstr&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_utf8_lossy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str_buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.to_lowercase&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;delim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;jumped&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.seek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details I really like here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Two cursors.&lt;/strong&gt; The function walks the name with a &lt;em&gt;local&lt;/em&gt; &lt;code&gt;pos&lt;/code&gt;, but the buffer's shared cursor has to end up right after the name &lt;em&gt;as it appears in this record&lt;/em&gt;. After a jump, those are different places. So the shared cursor is moved exactly once, at the first pointer, and never touched again.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The jump limit.&lt;/strong&gt; A malicious server can send a pointer that points to itself. Without &lt;code&gt;max_jumps&lt;/code&gt;, &lt;code&gt;read_qname&lt;/code&gt; would spin forever and one UDP packet would take down the resolver. Five jumps is plenty for any honest packet.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  One enum per record type
&lt;/h2&gt;

&lt;p&gt;Answers, authorities and additionals are all &lt;strong&gt;resource records&lt;/strong&gt; with the same envelope: name, type, class, TTL, data length, then type-specific data. Rust's enums model that perfectly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;DnsRecord&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;UNKNOWN&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qtype&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data_len&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c1"&gt;// anything else&lt;/span&gt;
    &lt;span class="n"&gt;A&lt;/span&gt;       &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Ipv4Addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;              &lt;span class="c1"&gt;// 1&lt;/span&gt;
    &lt;span class="n"&gt;NS&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;                &lt;span class="c1"&gt;// 2&lt;/span&gt;
    &lt;span class="n"&gt;CNAME&lt;/span&gt;   &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;                &lt;span class="c1"&gt;// 5&lt;/span&gt;
    &lt;span class="n"&gt;MX&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c1"&gt;// 15&lt;/span&gt;
    &lt;span class="n"&gt;AAAA&lt;/span&gt;    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Ipv6Addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;              &lt;span class="c1"&gt;// 28&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;QueryType&lt;/code&gt; has an &lt;code&gt;UNKNOWN(u16)&lt;/code&gt; variant too, so a record type the server has never heard of doesn't crash the parser. It reads &lt;code&gt;data_len&lt;/code&gt; and skips over the data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nn"&gt;QueryType&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;UNKNOWN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="nf"&gt;.step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_len&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;DnsRecord&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;UNKNOWN&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qtype&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;qtype_num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ttl&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reading an A record is four bytes turned into an &lt;code&gt;Ipv4Addr&lt;/code&gt;. AAAA is sixteen bytes turned into eight &lt;code&gt;u16&lt;/code&gt; segments. NS, CNAME and MX contain &lt;em&gt;names&lt;/em&gt;, so they reuse &lt;code&gt;read_qname&lt;/code&gt;, compression pointers and all.&lt;/p&gt;

&lt;h3&gt;
  
  
  Writing: backpatching the length
&lt;/h3&gt;

&lt;p&gt;Writing has one fun problem. Every record carries an &lt;code&gt;RDLENGTH&lt;/code&gt; field &lt;em&gt;before&lt;/em&gt; its data, but for a name-valued record you don't know the length until you've written the name. So RustDNS writes a placeholder, writes the data, measures, and goes back to patch it in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nn"&gt;DnsRecord&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;CNAME&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ttl&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="nf"&gt;.write_qname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="nf"&gt;.write_u16&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;QueryType&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;CNAME&lt;/span&gt;&lt;span class="nf"&gt;.to_num&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="nf"&gt;.write_u16&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;       &lt;span class="c1"&gt;// class IN&lt;/span&gt;
    &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="nf"&gt;.write_u32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="nf"&gt;.pos&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="nf"&gt;.write_u16&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;       &lt;span class="c1"&gt;// placeholder RDLENGTH&lt;/span&gt;

    &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="nf"&gt;.write_qname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="nf"&gt;.pos&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="nf"&gt;.set_u16&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// backpatch&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's what &lt;code&gt;set_u16&lt;/code&gt; was for. It's the same trick assemblers use for forward jumps, and it shows up any time a format puts a length before the thing being measured.&lt;/p&gt;

&lt;h2&gt;
  
  
  Walking the tree: recursive resolution
&lt;/h2&gt;

&lt;p&gt;Everything so far is a parser. This is the part that makes it a &lt;em&gt;resolver&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;lookup()&lt;/code&gt; does one round trip: build a packet with one question, send it to one server over UDP, parse whatever comes back:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qtype&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;QueryType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Ipv4Addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;u16&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DnsPacket&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;UdpSocket&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="s"&gt;"0.0.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;43210&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;packet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;DnsPacket&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="py"&gt;.header.id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6666&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="py"&gt;.header.questions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="py"&gt;.header.recursion_desired&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="py"&gt;.questions&lt;/span&gt;&lt;span class="nf"&gt;.push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;DnsQuestion&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qname&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;qtype&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;req_buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;BytePacketBuffer&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="nf"&gt;.write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;req_buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="nf"&gt;.send_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;req_buffer&lt;/span&gt;&lt;span class="py"&gt;.buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;req_buffer&lt;/span&gt;&lt;span class="py"&gt;.pos&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;res_buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;BytePacketBuffer&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="nf"&gt;.recv_from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;res_buffer&lt;/span&gt;&lt;span class="py"&gt;.buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nn"&gt;DnsPacket&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;res_buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Keep an eye on that fixed port &lt;code&gt;43210&lt;/code&gt; and fixed ID &lt;code&gt;6666&lt;/code&gt;. We'll come back to them.)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;recursive_lookup()&lt;/code&gt; calls it in a loop, starting at a root server and following &lt;strong&gt;referrals&lt;/strong&gt; downward:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faoeej6xutvjkay15noq4.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faoeej6xutvjkay15noq4.webp" alt="mermaid diagram" width="640" height="1982"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Diagram from &lt;a href="https://www.ravikishan.me/blog/rustdns-recursive-dns-resolver-in-rust" rel="noopener noreferrer"&gt;the original&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A referral is a response with no answer, but with &lt;strong&gt;NS records&lt;/strong&gt; in the authority section ("ask these servers instead") and, usually, matching &lt;strong&gt;A records in the additional section&lt;/strong&gt;. Those A records are called &lt;strong&gt;glue&lt;/strong&gt;, and they save a round trip: the root doesn't just say "ask &lt;code&gt;l.gtld-servers.net&lt;/code&gt;", it also tells you its IP.&lt;/p&gt;

&lt;p&gt;Finding the next server with glue is a neat little iterator chain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;get_resolved_ns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Ipv4Addr&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.get_ns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                      &lt;span class="c1"&gt;// (domain, host) pairs from NS records&lt;/span&gt;
        &lt;span class="nf"&gt;.flat_map&lt;/span&gt;&lt;span class="p"&gt;(|(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;)|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.resources&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.filter_map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nn"&gt;DnsRecord&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;None&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="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;addr&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="c1"&gt;// first NS that has glue wins&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When there's no glue (the nameserver lives in a different zone, like GitHub's &lt;code&gt;ns-421.awsdns-52.com&lt;/code&gt;), the resolver has to stop, resolve the &lt;em&gt;nameserver's&lt;/em&gt; name from scratch, then continue. That's literally recursion: &lt;code&gt;recursive_lookup&lt;/code&gt; calls itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;new_ns_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="nf"&gt;.get_unresolved_ns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;None&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Down the rabbit hole: a whole new lookup in the middle of this one.&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;recursive_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;recursive_lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;new_ns_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;QueryType&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_ns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;recursive_response&lt;/span&gt;&lt;span class="nf"&gt;.get_random_a&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_ns&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the &lt;code&gt;google.com&lt;/code&gt; run from earlier as a sequence, with the real servers from the log:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8zmi8qqobds5u5eo85hf.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8zmi8qqobds5u5eo85hf.webp" alt="mermaid diagram" width="640" height="254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Diagram from &lt;a href="https://www.ravikishan.me/blog/rustdns-recursive-dns-resolver-in-rust" rel="noopener noreferrer"&gt;the original&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And here it is moving. The upstream legs are slowed down so you can follow them. Click the canvas to switch to what a &lt;strong&gt;cache&lt;/strong&gt; would do (more on that later; RustDNS doesn't have one yet):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A frame from the interactive sketch in &lt;a href="https://www.ravikishan.me/blog/rustdns-recursive-dns-resolver-in-rust" rel="noopener noreferrer"&gt;the original&lt;/a&gt; — it does not render here.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Serving dig on port 2053
&lt;/h2&gt;

&lt;p&gt;The last layer turns the resolver into a server. &lt;code&gt;main()&lt;/code&gt; is a single loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;UdpSocket&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="s"&gt;"0.0.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2053&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;loop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="nf"&gt;handle_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
            &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;eprintln!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"An error occurred: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An error in one query is logged and the loop moves on, so one bad packet never kills the server. &lt;code&gt;handle_query&lt;/code&gt; receives a packet, resolves it, and builds a response:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1ch21tysr1xd01vmbrmh.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1ch21tysr1xd01vmbrmh.webp" alt="mermaid diagram" width="640" height="1092"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Diagram from &lt;a href="https://www.ravikishan.me/blog/rustdns-recursive-dns-resolver-in-rust" rel="noopener noreferrer"&gt;the original&lt;/a&gt;.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;packet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;DnsPacket&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="py"&gt;.header.id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="py"&gt;.header.id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="c1"&gt;// echo the client's ID&lt;/span&gt;
&lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="py"&gt;.header.recursion_desired&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="py"&gt;.header.recursion_available&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="py"&gt;.header.response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="py"&gt;.questions&lt;/span&gt;&lt;span class="nf"&gt;.pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;recursive_lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="py"&gt;.name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="py"&gt;.qtype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="py"&gt;.questions&lt;/span&gt;&lt;span class="nf"&gt;.push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="py"&gt;.header.rescode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="py"&gt;.header.rescode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="py"&gt;.answers&lt;/span&gt;&lt;span class="nf"&gt;.extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="py"&gt;.answers&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;       &lt;span class="c1"&gt;// (the repo uses for-loops with logging)&lt;/span&gt;
        &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="py"&gt;.authorities&lt;/span&gt;&lt;span class="nf"&gt;.extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="py"&gt;.authorities&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="py"&gt;.resources&lt;/span&gt;&lt;span class="nf"&gt;.extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="py"&gt;.resources&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="py"&gt;.header.rescode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;ResultCode&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SERVFAIL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="py"&gt;.header.rescode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;ResultCode&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;FORMERR&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response codes are the polite part of the protocol. A failed upstream lookup becomes &lt;code&gt;SERVFAIL&lt;/code&gt; ("I tried, it broke"), and a packet with no question becomes &lt;code&gt;FORMERR&lt;/code&gt; ("that's not a valid query"). The client always gets &lt;em&gt;something&lt;/em&gt; back.&lt;/p&gt;

&lt;p&gt;At least, that was the theory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Breaking it on purpose
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbpcnjs57fwag8a3bh3o2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbpcnjs57fwag8a3bh3o2.jpg" alt="Close-up of a server rack labelled A, with a column of 1U servers and neatly bundled white network cables" width="800" height="1204"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I wrote RustDNS in September 2024. To write this post, I built it again and threw real queries at it. Most worked. Two did not, and both are great lessons in why protocols look the way they do.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bug 1: the MX query that never came back
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Received query: DnsQuestion { name: "gmail.com", qtype: MX }
attempting lookup of MX gmail.com with ns 198.41.0.4
attempting lookup of MX gmail.com with ns 192.41.162.30
attempting lookup of MX gmail.com with ns 216.239.34.10
Answer: MX { domain: "gmail.com", priority: 5, host: "gmail-smtp-in.l.google.com", ttl: 3600 }
...   (5 MX answers, then 5 A and 5 AAAA additional records)
An error occurred: End of the buffer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The resolution &lt;em&gt;succeeded&lt;/em&gt;. Google's server sent five MX records plus glue for every mail host, and that response fit comfortably in 512 bytes because Google compresses names with pointers.&lt;/p&gt;

&lt;p&gt;RustDNS doesn't compress when it &lt;em&gt;writes&lt;/em&gt;. &lt;code&gt;write_qname&lt;/code&gt; spells every name out in full, so the same response grows:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Part&lt;/th&gt;
&lt;th&gt;Bytes, uncompressed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Header + question&lt;/td&gt;
&lt;td&gt;27&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5 MX answers&lt;/td&gt;
&lt;td&gt;275&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5 A additionals&lt;/td&gt;
&lt;td&gt;230&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5 AAAA additionals&lt;/td&gt;
&lt;td&gt;290&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;822&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The writer runs out of room partway through the A records, &lt;code&gt;write()&lt;/code&gt; returns &lt;code&gt;Err("End of the buffer")&lt;/code&gt;, &lt;code&gt;handle_query&lt;/code&gt; bails out with &lt;code&gt;?&lt;/code&gt;, and the error is logged. &lt;strong&gt;Nothing is sent.&lt;/strong&gt; The client just waits until it times out. My Python client gave up after 20 seconds.&lt;/p&gt;

&lt;p&gt;The fix is a ladder of increasingly blunt tools, and real resolvers use all of them:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Compress names on write.&lt;/strong&gt; Keep a map of &lt;code&gt;name → offset&lt;/code&gt; while writing and emit a pointer the second time a name appears. That alone would shrink this response well under 512 bytes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Drop the additional section.&lt;/strong&gt; Glue records are optional hints. Header, question and answers here are only 302 bytes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set the TC bit.&lt;/strong&gt; If even that doesn't fit, send what you can with &lt;code&gt;truncated_message = true&lt;/code&gt;, which tells the client to retry over TCP. (RustDNS would then also need a TCP listener.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EDNS(0)&lt;/strong&gt;, from &lt;a href="https://www.rfc-editor.org/rfc/rfc6891" rel="noopener noreferrer"&gt;RFC 6891&lt;/a&gt;, lets client and server agree on UDP payloads larger than 512 bytes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A sketch of step 2, which is a few lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Sketch, not in the repo yet&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;res_buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;BytePacketBuffer&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="nf"&gt;.write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;res_buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.is_err&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="py"&gt;.resources&lt;/span&gt;&lt;span class="nf"&gt;.clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;                  &lt;span class="c1"&gt;// additionals are optional&lt;/span&gt;
    &lt;span class="n"&gt;res_buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;BytePacketBuffer&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="nf"&gt;.write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;res_buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.is_err&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="py"&gt;.answers&lt;/span&gt;&lt;span class="nf"&gt;.clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="py"&gt;.authorities&lt;/span&gt;&lt;span class="nf"&gt;.clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="py"&gt;.header.truncated_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// "retry over TCP"&lt;/span&gt;
        &lt;span class="n"&gt;res_buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;BytePacketBuffer&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="nf"&gt;.write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;res_buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Bug 2: an NXDOMAIN that lies about itself
&lt;/h3&gt;

&lt;p&gt;Asking for a name that doesn't exist looked fine in the logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Received query: DnsQuestion { name: "doesnotexist-xyz123.com", qtype: A }
attempting lookup of A doesnotexist-xyz123.com with ns 198.41.0.4
attempting lookup of A doesnotexist-xyz123.com with ns 192.41.162.30
Authority: UNKNOWN { domain: "com", qtype: 6, data_len: 61, ttl: 900 }
Skipping record: UNKNOWN { domain: "com", qtype: 6, data_len: 61, ttl: 900 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Type 6 is &lt;strong&gt;SOA&lt;/strong&gt;, the record a server attaches to an NXDOMAIN so resolvers know how long to cache the "no". RustDNS doesn't model SOA, so it parses it as &lt;code&gt;UNKNOWN&lt;/code&gt;, and when writing, &lt;code&gt;UNKNOWN&lt;/code&gt; writes nothing at all. But &lt;code&gt;DnsPacket::write&lt;/code&gt; sets the header counts from the vectors &lt;em&gt;before&lt;/em&gt; writing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.header.authoritative_entries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.authorities&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u16&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the response says "one authority record follows", and then the packet ends:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;12 34 81 83 00 01 00 00 00 01 00 00  13 64 6f 65 73 ...
         ^ RCODE=3         ^ NSCOUNT = 1, but zero bytes of records follow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A lenient client shrugs and reads the NXDOMAIN rcode. A strict one rejects the whole packet as malformed. The quick fix is one line: &lt;code&gt;packet.authorities.retain(|r| !matches!(r, DnsRecord::UNKNOWN { .. }))&lt;/code&gt; before writing. The proper fix is adding an &lt;code&gt;SOA&lt;/code&gt; variant to &lt;code&gt;DnsRecord&lt;/code&gt;. Either way, &lt;strong&gt;a header count is a promise&lt;/strong&gt;, and a writer must never count something it doesn't write.&lt;/p&gt;

&lt;h3&gt;
  
  
  Smaller things I found reading the code again
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Label length check.&lt;/strong&gt; &lt;code&gt;write_qname&lt;/code&gt; rejects labels longer than &lt;code&gt;0x34&lt;/code&gt;, which is 52, but the error message (and the spec) say 63. It should be &lt;code&gt;0x3F&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Off-by-one in &lt;code&gt;get_range&lt;/code&gt;.&lt;/strong&gt; It errors when &lt;code&gt;start + len &amp;gt;= 512&lt;/code&gt;, so a range ending exactly at byte 512 is rejected. That should be &lt;code&gt;&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;get_random_a&lt;/code&gt; isn't random.&lt;/strong&gt; It returns the first A record. Harmless, but the name over-promises.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zone matching with &lt;code&gt;ends_with&lt;/code&gt;.&lt;/strong&gt; &lt;code&gt;get_ns&lt;/code&gt; keeps NS records where &lt;code&gt;qname.ends_with(domain)&lt;/code&gt;, so &lt;code&gt;notgoogle.com&lt;/code&gt; "ends with" &lt;code&gt;google.com&lt;/code&gt;. Comparing on a label boundary (&lt;code&gt;qname == domain&lt;/code&gt; or &lt;code&gt;qname.ends_with(&amp;amp;format!(".{}", domain))&lt;/code&gt;) is the correct check.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The serious one: spoofing
&lt;/h3&gt;

&lt;p&gt;Remember &lt;code&gt;lookup()&lt;/code&gt;? Every upstream query goes out from &lt;strong&gt;port 43210&lt;/strong&gt; with &lt;strong&gt;ID 6666&lt;/strong&gt;, and the reply's ID is never checked. An attacker who can send UDP packets to the resolver only has to guess... nothing. They can race a forged answer for any name and it will be believed.&lt;/p&gt;

&lt;p&gt;This is the class of attack Dan Kaminsky made famous in 2008, and the industry's response was to make forgeries expensive to guess: a random 16-bit ID &lt;em&gt;and&lt;/em&gt; a random source port, roughly 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;2&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;&lt;span class="mord mtight"&gt;16&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;×&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;2&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;&lt;span class="mord mtight"&gt;16&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;≈&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;4.3&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;×&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;1&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;0&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;9&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 combinations instead of one. It's a small change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Sketch, not in the repo yet&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;hash_map&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;RandomState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;BuildHasher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Hasher&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;time&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;random_u16&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;u16&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;RandomState&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.build_hasher&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.finish&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u16&lt;/span&gt; &lt;span class="c1"&gt;// fine for a toy; use getrandom for real&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;UdpSocket&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="s"&gt;"0.0.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;           &lt;span class="c1"&gt;// OS picks a random ephemeral port&lt;/span&gt;
&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="nf"&gt;.set_read_timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_secs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// a dead server can't hang us forever&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;random_u16&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// ... send, receive ...&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="py"&gt;.header.id&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"response ID mismatch"&lt;/span&gt;&lt;span class="nf"&gt;.into&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The read timeout fixes a quieter problem too: today, if an upstream server never answers, &lt;code&gt;recv_from&lt;/code&gt; blocks forever and the whole server freezes with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How fast is it?
&lt;/h2&gt;

&lt;p&gt;Every query I sent was a &lt;strong&gt;cold&lt;/strong&gt; lookup, because RustDNS doesn't cache anything. Each one walked root → TLD → authoritative, and took between &lt;strong&gt;533 and 568 ms&lt;/strong&gt; end to end on my connection.&lt;/p&gt;

&lt;p&gt;That's almost entirely network time. Cold latency is roughly the sum of the round trips:&lt;/p&gt;

&lt;p&gt;$$&lt;br&gt;
T_{\text{cold}} \approx \sum_{i=1}^{h} \mathrm{RTT}_i \qquad (h = 3 \text{ for google.com})&lt;br&gt;
$$&lt;/p&gt;

&lt;p&gt;Parsing a 44-byte packet takes microseconds; waiting on three servers in a row takes hundreds of milliseconds. Which is why every real resolver caches. With a hit rate 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
:&lt;/p&gt;

&lt;p&gt;$$&lt;br&gt;
\mathbb{E}[T] = p \cdot T_{\text{hit}} + (1 - p) \cdot T_{\text{miss}}&lt;br&gt;
$$&lt;/p&gt;

&lt;p&gt;At a modest 90% hit rate, with a hit costing about 1 ms and a miss 550 ms, the average drops from 550 ms to about 56 ms. The TTL on each record (300 seconds for Google's A records, 3600 for the gmail MX records) is the server telling you exactly how long you're allowed to keep it.&lt;/p&gt;

&lt;p&gt;There's a second, sneakier cost. The server handles &lt;strong&gt;one query at a time&lt;/strong&gt;. While it spends half a second walking the tree for one client, every other client waits in the socket's queue. And because &lt;code&gt;lookup()&lt;/code&gt; binds a fixed port, you couldn't simply spawn a thread per request: the second thread would fail with "address in use". The spoofing fix above (port 0) happens to unblock concurrency too.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Binary protocols are honest.&lt;/strong&gt; There is no "kind of parsed". Either the 12 bytes are a header or they aren't, and Rust's &lt;code&gt;Result&lt;/code&gt; plus &lt;code&gt;?&lt;/code&gt; on every read made each failure path explicit rather than a crash waiting to happen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every limit has a story.&lt;/strong&gt; 512 bytes, 63-character labels, 14-bit pointers, 16-bit IDs. Each one is a design decision from 1987 that the internet has spent decades working around with compression, TCP fallback and EDNS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parsing and writing are not symmetric.&lt;/strong&gt; RustDNS &lt;em&gt;reads&lt;/em&gt; compression pointers perfectly and never &lt;em&gt;writes&lt;/em&gt; one. That asymmetry is invisible on small answers and fatal on large ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Header counts are promises.&lt;/strong&gt; Counting a record you then skip produces a packet that's wrong in a way only a strict parser notices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never trust the wire.&lt;/strong&gt; The jump limit in &lt;code&gt;read_qname&lt;/code&gt; is the line I'm proudest of, and the fixed query ID is the one I'd fix first. Same lesson, both directions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DNS is a cache with a protocol attached.&lt;/strong&gt; Resolution itself is a handful of round trips. Everything that makes it fast in practice is caching and TTLs.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TTL cache.&lt;/strong&gt; A &lt;code&gt;HashMap&amp;lt;(String, QueryType), (Vec&amp;lt;DnsRecord&amp;gt;, Instant)&amp;gt;&lt;/code&gt; behind a &lt;code&gt;Mutex&lt;/code&gt;, respecting each record's TTL, including negative caching from the SOA.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency.&lt;/strong&gt; A thread per request with &lt;code&gt;socket.try_clone()&lt;/code&gt;, or a move to &lt;code&gt;tokio&lt;/code&gt;, once upstream sockets use ephemeral ports.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spoofing defences.&lt;/strong&gt; Random IDs and source ports, ID verification and read timeouts, as sketched above.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name compression on write&lt;/strong&gt;, plus graceful truncation with the TC bit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More record types&lt;/strong&gt;: SOA, TXT, SRV and PTR.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TCP and EDNS(0)&lt;/strong&gt; for responses bigger than 512 bytes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A &lt;code&gt;config.toml&lt;/code&gt;&lt;/strong&gt; for the listen address, root hints and an optional upstream forwarder.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests&lt;/strong&gt; built on the captured packets in the repo, so every fix above comes with a regression test.&lt;/li&gt;
&lt;/ul&gt;

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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/ravikisha/rustdns &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;rustdns
cargo run &lt;span class="nt"&gt;--release&lt;/span&gt;

&lt;span class="c"&gt;# in another terminal&lt;/span&gt;
dig @127.0.0.1 &lt;span class="nt"&gt;-p&lt;/span&gt; 2053 google.com
dig @127.0.0.1 &lt;span class="nt"&gt;-p&lt;/span&gt; 2053 www.github.com
dig @127.0.0.1 &lt;span class="nt"&gt;-p&lt;/span&gt; 2053 gmail.com MX   &lt;span class="c"&gt;# spoiler: see "Breaking it on purpose"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's a single file with no dependencies, so it's a nice codebase to read in one sitting. If you've never looked inside DNS, I'd recommend opening &lt;code&gt;main.rs&lt;/code&gt; next to &lt;a href="https://www.rfc-editor.org/rfc/rfc1035" rel="noopener noreferrer"&gt;RFC 1035&lt;/a&gt; and a packet capture; it all clicks surprisingly fast.&lt;/p&gt;

&lt;p&gt;If you liked this kind of build-it-to-understand-it post, I've done the same for &lt;a href="https://dev.to/blog/exploring-development-paradigms-sequential-asynchronous-and-"&gt;link checkers in Rust&lt;/a&gt; and for &lt;a href="https://dev.to/blog/relaxnative-native-c-cpp-rust-zig-go-for-nodejs"&gt;calling Rust from Node.js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;⭐ Star it on &lt;strong&gt;&lt;a href="https://github.com/ravikisha/rustdns" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/strong&gt;, and if you'd like to pick up anything from the "What's next" list, &lt;a href="https://github.com/ravikisha/rustdns/issues" rel="noopener noreferrer"&gt;open an issue&lt;/a&gt; or a PR. The NXDOMAIN fix is a great first contribution.&lt;/p&gt;

&lt;p&gt;Happy resolving! 🦀&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Photo credits: cover and rack photos by Derrick Coetzee, &lt;a href="https://commons.wikimedia.org/wiki/File:UPS_Power_Management_Module,_racks_with_network_cabling_in_NERSC_data_center.jpg" rel="noopener noreferrer"&gt;CC0&lt;/a&gt;, via Wikimedia Commons. Bell System switchboard, &lt;a href="https://commons.wikimedia.org/wiki/File:Photograph_of_Women_Working_at_a_Bell_System_Telephone_Switchboard_-_NARA_-_1633445.jpg" rel="noopener noreferrer"&gt;public domain&lt;/a&gt;, U.S. National Archives. 1928 Rikstelefonkatalogen, &lt;a href="https://commons.wikimedia.org/wiki/File:Telefonkatalog_1928.jpg" rel="noopener noreferrer"&gt;public domain&lt;/a&gt;, Televerket Sverige.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>networking</category>
      <category>systemdesign</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Relaxnative: Import C, C++, Rust, Zig and Go Straight into Node.js</title>
      <dc:creator>Ravi Kishan</dc:creator>
      <pubDate>Mon, 05 Oct 2026 08:01:26 +0000</pubDate>
      <link>https://dev.to/ravikishan/relaxnative-import-c-c-rust-zig-and-go-straight-into-nodejs-20pn</link>
      <guid>https://dev.to/ravikishan/relaxnative-import-c-c-rust-zig-and-go-straight-into-nodejs-20pn</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: Relaxnative is a Node.js library that lets you write a function in &lt;strong&gt;C, C++, Rust, Zig or Go&lt;/strong&gt;, point &lt;code&gt;loadNative()&lt;/code&gt; at the file, and call it from JavaScript like any other function. No &lt;code&gt;node-gyp&lt;/code&gt;, no &lt;code&gt;binding.gyp&lt;/code&gt;, no hand-written N-API glue. It compiles on first import, caches by content hash, can ship &lt;strong&gt;prebuilt&lt;/strong&gt; so production needs no compiler, and lets you choose how much a native crash is allowed to hurt.&lt;/p&gt;


&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i relaxnative
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;🔗 &lt;a href="https://github.com/Ravikisha/RelaxNative" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · 📦 &lt;a href="https://www.npmjs.com/package/relaxnative" rel="noopener noreferrer"&gt;npm&lt;/a&gt; · 🐛 &lt;a href="https://github.com/Ravikisha/RelaxNative/issues" rel="noopener noreferrer"&gt;Issues&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Why I built this&lt;/li&gt;
&lt;li&gt;Hello, native&lt;/li&gt;
&lt;li&gt;Five languages, one call&lt;/li&gt;
&lt;li&gt;What &lt;code&gt;loadNative()&lt;/code&gt; actually does&lt;/li&gt;
&lt;li&gt;Reading signatures: tree-sitter and friends&lt;/li&gt;
&lt;li&gt;The types contract&lt;/li&gt;
&lt;li&gt;A cache keyed by everything&lt;/li&gt;
&lt;li&gt;Ahead-of-time builds: no compiler in production&lt;/li&gt;
&lt;li&gt;Three isolation modes&lt;/li&gt;
&lt;li&gt;Annotations: &lt;code&gt;@sync&lt;/code&gt;, &lt;code&gt;@async&lt;/code&gt;, &lt;code&gt;@cost&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Benchmarks: where native wins (and where it loses)&lt;/li&gt;
&lt;li&gt;RelaxRegistry and supply-chain trust&lt;/li&gt;
&lt;li&gt;Developer experience&lt;/li&gt;
&lt;li&gt;What I learned&lt;/li&gt;
&lt;li&gt;What's next&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Why I built this
&lt;/h2&gt;

&lt;p&gt;JavaScript is fast, often surprisingly fast. But every Node developer eventually hits a wall where it isn't fast enough:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;64-bit integer math.&lt;/strong&gt; JS numbers are doubles, so real &lt;code&gt;u64&lt;/code&gt; work means &lt;code&gt;BigInt&lt;/code&gt;, and &lt;code&gt;BigInt&lt;/code&gt; is slow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Raw byte crunching&lt;/strong&gt;, like image pixels, checksums and histograms, where you want tight loops over memory with no bounds checks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code that already exists&lt;/strong&gt; in C or Rust that you'd rather reuse than rewrite.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The traditional answer is a native addon: &lt;code&gt;node-gyp&lt;/code&gt;, a &lt;code&gt;binding.gyp&lt;/code&gt;, N-API boilerplate, a C++ wrapper per function, and a build that breaks on every other Windows machine. It works, but it's a lot of ceremony for "I want to call &lt;code&gt;add(a, b)&lt;/code&gt; written in C".&lt;/p&gt;

&lt;p&gt;I wanted something closer to Python's &lt;code&gt;ctypes&lt;/code&gt; or Bun's &lt;code&gt;bun:ffi&lt;/code&gt;, but for &lt;strong&gt;plain Node&lt;/strong&gt;, for &lt;strong&gt;several languages&lt;/strong&gt;, and with &lt;strong&gt;real answers for safety&lt;/strong&gt;. What happens when native code segfaults? What happens when you install someone else's native code? That's Relaxnative.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hello, native
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;native/add.c&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// @sync&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Call it from JavaScript:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;loadNative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;native/add.c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isolation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;worker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the whole integration. The first &lt;code&gt;loadNative()&lt;/code&gt; finds a compiler, builds a shared library, reads the function signatures out of your source and binds them. Every later run hits the cache.&lt;/p&gt;

&lt;p&gt;Not sure which toolchains you have? Ask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx relaxnative doctor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ C compiler detected (clang 22.1.8)
✓ C++ compiler detected (clang 22.1.8)
✓ Rust compiler detected (rustc 1.97.1)
✗ Zig compiler missing (install zig)
✓ Go toolchain detected (go-wsl: go1.22.2 linux/amd64)
✓ Worker threads supported
✓ Cache directory OK
✓ ESM loader supported (Node &amp;gt;= 18)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Five languages, one call
&lt;/h2&gt;

&lt;p&gt;Each language compiles to a C-ABI shared library (&lt;code&gt;.dll&lt;/code&gt; / &lt;code&gt;.so&lt;/code&gt; / &lt;code&gt;.dylib&lt;/code&gt;), so from JavaScript they all look the same:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Language&lt;/th&gt;
&lt;th&gt;Extension&lt;/th&gt;
&lt;th&gt;How you export&lt;/th&gt;
&lt;th&gt;Compiler&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.c&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;plain top-level functions&lt;/td&gt;
&lt;td&gt;clang / gcc / MSVC &lt;code&gt;cl&lt;/code&gt; / &lt;code&gt;zig cc&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C++&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.cpp&lt;/code&gt; &lt;code&gt;.cc&lt;/code&gt; &lt;code&gt;.cxx&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;extern "C"&lt;/code&gt; functions&lt;/td&gt;
&lt;td&gt;clang++ / g++ / &lt;code&gt;cl&lt;/code&gt; / &lt;code&gt;zig c++&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rust&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.rs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;#[no_mangle] pub extern "C" fn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;rustc --crate-type cdylib&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zig&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.zig&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;export fn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;zig build-lib -dynamic&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Go&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.go&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;//export Name&lt;/code&gt; + &lt;code&gt;import "C"&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;go build -buildmode=c-shared&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// add.rs&lt;/span&gt;
&lt;span class="nd"&gt;#[no_mangle]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;,&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;i32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight zig"&gt;&lt;code&gt;&lt;span class="c"&gt;// add.zig&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;i32&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;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// add.go&lt;/span&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt;
&lt;span class="c"&gt;//export add&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;int&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;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;loadNative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;native/add.zig&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isolation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;in-process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 42&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One Zig install is a cheat code here: &lt;code&gt;zig cc&lt;/code&gt; and &lt;code&gt;zig c++&lt;/code&gt; are clang-based, so a single download covers &lt;strong&gt;C, C++ and Zig&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Go on Windows was the fun one. To build a real Windows DLL, Relaxnative cross-compiles inside &lt;strong&gt;WSL&lt;/strong&gt; with &lt;code&gt;GOOS=windows CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc go build -buildmode=c-shared&lt;/code&gt;, so you only need &lt;code&gt;go&lt;/code&gt; and &lt;code&gt;mingw-w64&lt;/code&gt; inside your distro.&lt;/p&gt;

&lt;p&gt;Multi-file builds work too. Extra C/C++ sources get linked into the same library, Rust files are &lt;code&gt;mod&lt;/code&gt;-declared, Zig files are &lt;code&gt;@import&lt;/code&gt;ed, and Go files form one &lt;code&gt;main&lt;/code&gt; package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;loadNative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;native/main.c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;isolation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;in-process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;sources&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="s1"&gt;native/helper.c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;includePaths&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="s1"&gt;native/include&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;libraries&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="s1"&gt;m&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;flags&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="s1"&gt;-O3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What &lt;code&gt;loadNative()&lt;/code&gt; actually does
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp14ycdlwuw9ue5apv7p5.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp14ycdlwuw9ue5apv7p5.webp" alt="What loadNative() does: prebuilt check, toolchain detection, content-hash cache, compile, parse, bind, wrap" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The whole library is built around one pipeline in &lt;a href="https://github.com/Ravikisha/RelaxNative/blob/main/src/loader.ts" rel="noopener noreferrer"&gt;&lt;code&gt;src/loader.ts&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Prebuilt?&lt;/strong&gt; If &lt;code&gt;.relaxnative/prebuilt/&lt;/code&gt; has an artifact for this platform &lt;em&gt;and&lt;/em&gt; this exact source content, use it and skip compiling entirely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Detect the toolchain&lt;/strong&gt; for the file's language (clang, gcc, &lt;code&gt;cl&lt;/code&gt;, zig, rustc, go).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hash the compile inputs.&lt;/strong&gt; On a cache hit, reuse the library.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compile&lt;/strong&gt; to a shared library on a miss. C/C++ get &lt;code&gt;-O2&lt;/code&gt; by default, because building at &lt;code&gt;-O0&lt;/code&gt; makes native code lose badly to V8's JIT and that's an embarrassing benchmark.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parse the signatures&lt;/strong&gt; from your source to learn names, parameter types and return types.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bind&lt;/strong&gt; them with &lt;a href="https://koffi.dev" rel="noopener noreferrer"&gt;koffi&lt;/a&gt;, a fast FFI library for Node.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wrap&lt;/strong&gt; each function according to the isolation mode you picked.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The result is a plain object of JavaScript functions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading signatures: tree-sitter and friends
&lt;/h2&gt;

&lt;p&gt;To bind a function, Relaxnative has to know its signature &lt;em&gt;without you writing it twice&lt;/em&gt;. So it reads your source:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;C, C++ and Rust&lt;/strong&gt; are parsed with &lt;a href="https://tree-sitter.github.io/tree-sitter/" rel="noopener noreferrer"&gt;tree-sitter&lt;/a&gt; grammars, giving a real syntax tree instead of regex guesses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zig and Go&lt;/strong&gt; use small lexical scanners that look for &lt;code&gt;export fn&lt;/code&gt; and &lt;code&gt;//export&lt;/code&gt; and map types like &lt;code&gt;i32&lt;/code&gt;, &lt;code&gt;[*]u8&lt;/code&gt; or &lt;code&gt;C.int&lt;/code&gt; to the shared type model.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Real C is messier than it looks, and the parser has the scars to prove it. My favourite: for a pointer-returning function like &lt;code&gt;char *greet(int)&lt;/code&gt;, tree-sitter nests the function declarator &lt;em&gt;inside&lt;/em&gt; a &lt;code&gt;pointer_declarator&lt;/code&gt; and hangs the &lt;code&gt;*&lt;/code&gt; there, not on the return type. The first version read the name as &lt;code&gt;greet(int)&lt;/code&gt;, found no parameters, decided the return type was &lt;code&gt;unknown&lt;/code&gt;, and &lt;strong&gt;silently dropped the function&lt;/strong&gt;. The fix unwraps every &lt;code&gt;pointer_declarator&lt;/code&gt; layer and folds the stars back into the return type.&lt;/p&gt;

&lt;p&gt;Other details it handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;foo(void)&lt;/code&gt; means "no parameters", so the lone &lt;code&gt;void&lt;/code&gt; is dropped.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Variadic&lt;/strong&gt; functions (&lt;code&gt;printf&lt;/code&gt;-style) are detected and rejected instead of being called with a garbage stack.&lt;/li&gt;
&lt;li&gt;Pointer stars can live in the declarator (&lt;code&gt;uint8_t *buf&lt;/code&gt;), so type and declarator text are combined &lt;em&gt;with a space&lt;/em&gt;. Otherwise &lt;code&gt;unsigned long long x&lt;/code&gt; becomes &lt;code&gt;unsigned long longx&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And there's a rule: &lt;strong&gt;if a type isn't recognized, fail fast.&lt;/strong&gt; A wrong FFI signature doesn't throw a nice error. It corrupts memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  The types contract
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;C / C++&lt;/th&gt;
&lt;th&gt;Rust&lt;/th&gt;
&lt;th&gt;Zig&lt;/th&gt;
&lt;th&gt;Go (cgo)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;32-bit int&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;int&lt;/code&gt; / &lt;code&gt;int32_t&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;i32&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;i32&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;C.int&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;64-bit int&lt;/td&gt;
&lt;td&gt;&lt;code&gt;int64_t&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;i64&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;i64&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;int64&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;float / double&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;float&lt;/code&gt; / &lt;code&gt;double&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;f32&lt;/code&gt; / &lt;code&gt;f64&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;f32&lt;/code&gt; / &lt;code&gt;f64&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;float32&lt;/code&gt; / &lt;code&gt;float64&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;bool&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bool&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bool&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bool&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bool&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;byte buffer&lt;/td&gt;
&lt;td&gt;&lt;code&gt;uint8_t*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;*mut u8&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[*]u8&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;*byte&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C string&lt;/td&gt;
&lt;td&gt;&lt;code&gt;const char*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;*const i8&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[*c]const u8&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;*C.char&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;On the JavaScript side:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scalars&lt;/strong&gt; become &lt;code&gt;number&lt;/code&gt;. 64-bit integers can come back as &lt;code&gt;bigint&lt;/code&gt; and accept either.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pointers&lt;/strong&gt; accept &lt;strong&gt;TypedArrays&lt;/strong&gt;: pass a &lt;code&gt;Uint8Array&lt;/code&gt; for &lt;code&gt;uint8_t*&lt;/code&gt; or a &lt;code&gt;Uint32Array&lt;/code&gt; for &lt;code&gt;uint32_t*&lt;/code&gt;. Native code writes straight into your array.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;const char*&lt;/code&gt;&lt;/strong&gt; parameters and returns are plain JS strings.&lt;/li&gt;
&lt;li&gt;For manual memory there's &lt;code&gt;native.alloc(size)&lt;/code&gt;, which returns a &lt;code&gt;NativeBuffer&lt;/code&gt; with an &lt;code&gt;.address&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// @async&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;histogram_u8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;out256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;out256&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;out256&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;histogram_u8&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;loadNative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;native/histogram.c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isolation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;worker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint32Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;histogram_u8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// out is filled in place&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tip: prefer fixed-width types (&lt;code&gt;uint32_t*&lt;/code&gt; over &lt;code&gt;unsigned*&lt;/code&gt;). They make the parser's job unambiguous, and they're better C anyway.&lt;/p&gt;

&lt;h2&gt;
  
  
  A cache keyed by everything
&lt;/h2&gt;

&lt;p&gt;Compiling on every import would be unbearable, so builds are cached under &lt;code&gt;~/.relaxnative/cache&lt;/code&gt;. The key is a SHA-256 over &lt;strong&gt;everything that changes the output binary&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/cache/hash.ts (simplified)&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sourcePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;sources&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// CONTENTS, not paths&lt;/span&gt;
&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;compiler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;compiler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;includePaths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;libraryPaths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;libraries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;platform&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// e.g. win32-x64&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two bugs taught me this list. Originally only the entry file was hashed, so editing a &lt;em&gt;helper&lt;/em&gt; file in a multi-file build gave a &lt;strong&gt;false cache hit&lt;/strong&gt;: you changed code and nothing happened. Now every source's contents are hashed. And a failed compile used to leave a half-populated cache directory behind. Now a cache entry only counts once its &lt;code&gt;meta.json&lt;/code&gt; exists, and failed builds clean up after themselves.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx relaxnative cache status
npx relaxnative cache clean
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Ahead-of-time builds: no compiler in production
&lt;/h2&gt;

&lt;p&gt;Compile-on-import is lovely in development and a liability in a slim Docker image. So there's an AOT mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx relaxnative build native/add.c native/kernel.zig native/svc.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or declare targets once in &lt;code&gt;relaxnative.build.json&lt;/code&gt;:&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;"targets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"native/add.c"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"native/mathkernel/main.c"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sources"&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="s2"&gt;"native/mathkernel/helper.c"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"libraries"&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="s2"&gt;"m"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"flags"&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="s2"&gt;"-O3"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This writes the compiled libraries &lt;strong&gt;plus the parsed bindings&lt;/strong&gt; to &lt;code&gt;.relaxnative/prebuilt/&lt;/code&gt;. Ship that folder, and at runtime &lt;code&gt;loadNative()&lt;/code&gt; uses a prebuilt artifact when it matches &lt;strong&gt;the current platform and the source's current content hash&lt;/strong&gt;. No compiler, no parser work.&lt;/p&gt;

&lt;p&gt;If you edit the source after building, the hash no longer matches and it quietly falls back to compiling, which is exactly what you want in development. &lt;code&gt;RELAXNATIVE_NO_PREBUILT=1&lt;/code&gt; turns the fast path off.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three isolation modes
&lt;/h2&gt;

&lt;p&gt;Here's the uncomfortable truth about native code: &lt;strong&gt;a segfault doesn't throw, it kills the process.&lt;/strong&gt; No &lt;code&gt;try/catch&lt;/code&gt; saves you. So Relaxnative makes the blast radius a per-call choice:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3vqat1xkm3y5nqjsh9vl.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3vqat1xkm3y5nqjsh9vl.webp" alt="Three isolation modes: in-process, worker and process, trading speed for crash safety" width="800" height="410"&gt;&lt;/a&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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;loadNative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;native/kernel.c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isolation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;in-process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// fastest&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;loadNative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;native/kernel.c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isolation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;worker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;     &lt;span class="c1"&gt;// default&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;loadNative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;native/kernel.c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isolation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;    &lt;span class="c1"&gt;// safest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;in-process&lt;/code&gt;&lt;/strong&gt; calls the function directly on the JS thread. It has the lowest overhead and no safety net. Use it for trusted, hot code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;worker&lt;/code&gt;&lt;/strong&gt; (the default) sends async work to a worker-thread pool so heavy calls don't block the event loop. To keep tiny calls cheap, &lt;strong&gt;sync functions still run in-process&lt;/strong&gt;. That means worker mode is &lt;em&gt;not&lt;/em&gt; crash-safe for sync functions, and the code comments say so plainly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;process&lt;/code&gt;&lt;/strong&gt; forks a helper process and talks to it over IPC. It's the heavyweight option, and it buys you a lot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Crash containment.&lt;/strong&gt; If the native code segfaults, the helper dies, your app gets a &lt;code&gt;ProcessIsolationError&lt;/code&gt; with code &lt;code&gt;ISOLATED_PROCESS_CRASH&lt;/code&gt; (and the JS callsite that made the call), and the helper restarts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per-call timeouts.&lt;/strong&gt; An infinite loop gets the helper killed instead of hanging forever.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A best-effort memory cap.&lt;/strong&gt; The helper watches its own RSS and exits if it goes over.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permission guards.&lt;/strong&gt; Inside the helper, imports of &lt;code&gt;fs&lt;/code&gt;, &lt;code&gt;net&lt;/code&gt;/&lt;code&gt;http&lt;/code&gt;/&lt;code&gt;dns&lt;/code&gt;/&lt;code&gt;tls&lt;/code&gt;, and &lt;code&gt;child_process&lt;/code&gt; are denied unless granted. &lt;code&gt;worker_threads&lt;/code&gt;, &lt;code&gt;vm&lt;/code&gt;, &lt;code&gt;v8&lt;/code&gt; and &lt;code&gt;inspector&lt;/code&gt; are &lt;strong&gt;always&lt;/strong&gt; blocked because each one is an isolation escape hatch. Blocking is by module &lt;em&gt;family&lt;/em&gt;, so &lt;code&gt;node:fs/promises&lt;/code&gt; can't slip past a check for &lt;code&gt;fs&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All calls in &lt;code&gt;process&lt;/code&gt; mode are async, since there's an IPC boundary in the way.&lt;/p&gt;

&lt;p&gt;I'm careful about wording here, and so is the &lt;a href="https://github.com/Ravikisha/RelaxNative/blob/main/src/registry/THREAT_MODEL.md" rel="noopener noreferrer"&gt;threat model&lt;/a&gt;: this is &lt;strong&gt;defense in depth, not a sandbox.&lt;/strong&gt; Native code can make raw syscalls that no Node-level guard can see. Kernel-level sandboxing (seccomp, AppContainer, sandbox-exec) is explicitly a non-goal for now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Annotations: &lt;code&gt;@sync&lt;/code&gt;, &lt;code&gt;@async&lt;/code&gt;, &lt;code&gt;@cost&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;How does the wrapper know whether a function should return a value or a Promise? You tell it, in a comment up to &lt;strong&gt;3 lines above&lt;/strong&gt; the function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// @async&lt;/span&gt;
&lt;span class="c1"&gt;// @cost high&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;heavy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;x&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;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Annotation&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@sync&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Returns a plain value. In &lt;code&gt;worker&lt;/code&gt; mode it may run on the main thread for speed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@async&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Returns a &lt;code&gt;Promise&lt;/code&gt; and always goes through the worker in &lt;code&gt;worker&lt;/code&gt; mode.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@cost high&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Treated like &lt;code&gt;@async&lt;/code&gt;, so heavy work stays off the event loop.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You can also override per call: &lt;code&gt;loadNative(path, { config: { functionMode: { add: 'sync' }, defaultMode: 'async' } })&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmarks: where native wins (and where it loses)
&lt;/h2&gt;

&lt;p&gt;I didn't want to write a "native is 1000× faster!!" post, because it isn't, at least not always. Every FFI call has a fixed cost of a few microseconds. Native only wins when each call does enough work to pay that back.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fskjhldi0tx48vx80521u.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fskjhldi0tx48vx80521u.webp" alt="Speedup of native vs JS on a log scale: 53x for 64-bit ints, 14x buffer scan, 0.01x for a trivial add" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The numbers above come from the in-repo suites (&lt;a href="https://github.com/Ravikisha/RelaxNative/blob/main/src/benchmark.report.test.ts" rel="noopener noreferrer"&gt;&lt;code&gt;benchmark.report.test.ts&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/Ravikisha/RelaxNative/blob/main/src/benchmark.realworld.test.ts" rel="noopener noreferrer"&gt;&lt;code&gt;benchmark.realworld.test.ts&lt;/code&gt;&lt;/a&gt;), using &lt;code&gt;in-process&lt;/code&gt; isolation. They tell a clear story:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;64-bit integers: 53×.&lt;/strong&gt; JS has to use &lt;code&gt;BigInt&lt;/code&gt;, while native uses raw &lt;code&gt;u64&lt;/code&gt;. I re-ran a xorshift kernel in Rust on a different Windows machine while writing this post and got &lt;strong&gt;~74×&lt;/strong&gt; (2000 × 4000 iterations: 6.7 s in JS, 91 ms native), with results matching JS bit for bit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Raw buffers: 14×&lt;/strong&gt; for summing 1 MiB, and &lt;strong&gt;6.7×&lt;/strong&gt; for RGBA→grayscale on a 2.1 MP image.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Float-heavy loops: about 1.1–2×.&lt;/strong&gt; V8's JIT is genuinely excellent at &lt;code&gt;number&lt;/code&gt; math, so Mandelbrot and dot products barely move.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A trivial &lt;code&gt;a + b&lt;/code&gt;: 0.01×&lt;/strong&gt;, roughly 80× &lt;em&gt;slower&lt;/em&gt;. The FFI crossing costs far more than the addition, which V8 would simply inline.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The same u64 kernel across languages is a nice sanity check that it's the &lt;em&gt;workload&lt;/em&gt;, not the language, that matters:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Language&lt;/th&gt;
&lt;th&gt;Calls/s&lt;/th&gt;
&lt;th&gt;vs JS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;JS (V8, BigInt)&lt;/td&gt;
&lt;td&gt;1,945&lt;/td&gt;
&lt;td&gt;1.0×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rust&lt;/td&gt;
&lt;td&gt;28,503&lt;/td&gt;
&lt;td&gt;14.7×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Go&lt;/td&gt;
&lt;td&gt;40,560&lt;/td&gt;
&lt;td&gt;20.9×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C (&lt;code&gt;zig cc&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;42,242&lt;/td&gt;
&lt;td&gt;21.7×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zig&lt;/td&gt;
&lt;td&gt;45,304&lt;/td&gt;
&lt;td&gt;23.3×&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The rule of thumb: &lt;strong&gt;cross the boundary rarely, and do a lot of work each time.&lt;/strong&gt; Batch your data into TypedArrays and make one big call, not a million small ones.&lt;/p&gt;

&lt;p&gt;You can benchmark your own kernels against a plain-JS baseline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx relaxnative bench examples/matmul.c matmul_f32 &lt;span class="nt"&gt;--traditional&lt;/span&gt; &lt;span class="nt"&gt;--iterations&lt;/span&gt; 5 &lt;span class="nt"&gt;--warmup&lt;/span&gt; 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  RelaxRegistry and supply-chain trust
&lt;/h2&gt;

&lt;p&gt;Once loading native code is this easy, the next question is scary: &lt;em&gt;what about native code from someone else?&lt;/em&gt; An npm package can at least be sandboxed by your judgement. A native package can do anything your user account can.&lt;/p&gt;

&lt;p&gt;So Relaxnative ships a small package system, &lt;strong&gt;RelaxRegistry&lt;/strong&gt;, built with trust in mind:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx relaxnative add file:examples/registry/fast-matrix
npx relaxnative list
npx relaxnative remove fast-matrix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbyj1vcfzusso74q0g4rt.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbyj1vcfzusso74q0g4rt.webp" alt="RelaxRegistry trust levels: local, community and verified, with unsigned packages demoted to community" width="800" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each package has a &lt;code&gt;relax.json&lt;/code&gt; declaring its exports, the permissions it wants, and a &lt;strong&gt;trust level&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;local&lt;/code&gt;&lt;/strong&gt;: your own code. No prompts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;community&lt;/code&gt;&lt;/strong&gt;: third-party code. You get a warning and must consent. Elevated permissions (fs, network, spawn) are &lt;strong&gt;refused&lt;/strong&gt;, and isolation is &lt;strong&gt;forced to &lt;code&gt;process&lt;/code&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;verified&lt;/code&gt;&lt;/strong&gt;: elevated trust, but &lt;strong&gt;only&lt;/strong&gt; if a real cryptographic signature checks out. Otherwise the package is demoted to &lt;code&gt;community&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before any of that, a &lt;strong&gt;static scan&lt;/strong&gt; flags risky APIs such as &lt;code&gt;system&lt;/code&gt;, &lt;code&gt;popen&lt;/code&gt;, &lt;code&gt;exec*&lt;/code&gt;, &lt;code&gt;fork&lt;/code&gt;, &lt;code&gt;CreateProcessW&lt;/code&gt; and raw sockets. It strips comments, splices backslash line-continuations and blanks out string literals first, so &lt;code&gt;sys\&amp;lt;newline&amp;gt;tem&lt;/code&gt; or &lt;code&gt;"sy" "stem"&lt;/code&gt; can't dodge it. It's still only a heuristic, and the code says so.&lt;/p&gt;

&lt;h3&gt;
  
  
  Signing, done properly
&lt;/h3&gt;

&lt;p&gt;My first design had a &lt;code&gt;digest&lt;/code&gt; field and treated a matching digest as "verified". That's wrong, because &lt;strong&gt;anyone can recompute a hash.&lt;/strong&gt; Integrity isn't authenticity. The final design has two separate layers:&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;"trust"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"verified"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"registrySignature"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"alg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sha256"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"digest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;sha256 over canonical manifest + per-source hashes&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sources"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"add.c"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;sha256&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"keyId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"relaxnative-registry-2026"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"signature"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;base64 Ed25519 over the digest&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Integrity:&lt;/strong&gt; the &lt;code&gt;digest&lt;/code&gt; covers the manifest &lt;em&gt;and every source file's content&lt;/em&gt;. It's computed over &lt;strong&gt;canonical JSON&lt;/strong&gt; (keys sorted recursively, no whitespace), so reformatting the file can't change it. Any tampering fails the install.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authenticity:&lt;/strong&gt; an &lt;strong&gt;Ed25519&lt;/strong&gt; signature over that digest, verified against a &lt;strong&gt;pinned public key&lt;/strong&gt;. Only this grants &lt;code&gt;verified&lt;/code&gt;. Keys are bundled or provided via &lt;code&gt;RELAXNATIVE_TRUSTED_KEYS&lt;/code&gt;, and &lt;code&gt;signPackage()&lt;/code&gt; produces signatures.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Consent is &lt;strong&gt;content-pinned&lt;/strong&gt; too. Your "yes" is stored with the package's content digest in &lt;code&gt;native/registry/.trust.json&lt;/code&gt;, so if someone republishes the same &lt;code&gt;name@version&lt;/code&gt; with different bytes, you're asked again. And the low-level raw installer is deliberately &lt;strong&gt;not exported&lt;/strong&gt;. Every install goes through the trust-enforcing path, so there's no shortcut that skips the gate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Developer experience
&lt;/h2&gt;

&lt;p&gt;A few things that make day-to-day use pleasant:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tracing.&lt;/strong&gt; When a crash happens behind a worker or process boundary, the real error is easy to lose. &lt;code&gt;RELAXNATIVE_TRACE=1&lt;/code&gt; prints lifecycle events (&lt;code&gt;loadNative.begin&lt;/code&gt;, &lt;code&gt;build.done&lt;/code&gt;, &lt;code&gt;dispatch&lt;/code&gt;, &lt;code&gt;isolation.process.call&lt;/code&gt;…), and &lt;code&gt;RELAXNATIVE_TRACE_LEVEL=debug&lt;/code&gt; also prints every parsed signature.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hot reload.&lt;/strong&gt; With &lt;code&gt;RELAXNATIVE_DEV=1&lt;/code&gt;, &lt;code&gt;loadNative()&lt;/code&gt; returns a &lt;em&gt;stable proxy&lt;/em&gt; that watches the source file, rebuilds on save and swaps the implementation in place. It fingerprints the ABI (names, argument types, return types), so it knows when a change is more than a body edit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An ESM loader.&lt;/strong&gt; Run Node with &lt;code&gt;--loader relaxnative/loader&lt;/code&gt; and you can &lt;code&gt;import&lt;/code&gt; native files directly:&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;// node --loader relaxnative/loader app.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;math&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./native/add.c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It currently handles C, C++ and Rust sources, plus &lt;code&gt;relaxnative/&amp;lt;package&amp;gt;&lt;/code&gt; registry specifiers, with package names validated so &lt;code&gt;relaxnative/../../etc/passwd&lt;/code&gt; goes nowhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A native test harness.&lt;/strong&gt; Write tests &lt;em&gt;in C&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;test_add&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;      &lt;span class="c1"&gt;// 0 = pass&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;test_msg&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;                &lt;span class="c1"&gt;// NULL/"" = pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx relaxnative &lt;span class="nb"&gt;test &lt;/span&gt;native/examples &lt;span class="nt"&gt;--isolation&lt;/span&gt; process
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running tests in &lt;code&gt;process&lt;/code&gt; isolation means a segfaulting test fails that test instead of taking down the runner.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Express in five lines:&lt;/strong&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loadNative&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;relaxnative&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;native&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;loadNative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;native/loop.c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isolation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;worker&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;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/sum&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;v&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;native&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loop_sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Number&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;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;e6&lt;/span&gt;&lt;span class="p"&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;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FFI cost is the whole game.&lt;/strong&gt; Native isn't faster per se. It's faster &lt;em&gt;per unit of work&lt;/em&gt;, and only once that work dwarfs the few-microsecond crossing. The 0.01× &lt;code&gt;add&lt;/code&gt; benchmark taught me more than the 53× one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;V8 is a formidable opponent.&lt;/strong&gt; For plain float loops the JIT is within a whisker of &lt;code&gt;-O2&lt;/code&gt; C. Real wins come where JS is structurally weak: 64-bit ints and raw memory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parsing C is humbling.&lt;/strong&gt; Pointer declarators, &lt;code&gt;(void)&lt;/code&gt;, variadics and multi-word types: every edge case is a silent-corruption bug waiting to happen. "Fail fast on unknown types" became a core principle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hashes aren't signatures.&lt;/strong&gt; Separating integrity (the digest) from authenticity (Ed25519 with a pinned key) was the most important security fix in the project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Be honest about safety.&lt;/strong&gt; It's tempting to call process isolation a "sandbox". It isn't, and the docs and threat model say exactly what is and isn't protected.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Fix clang on Windows MSVC targets. It currently rejects &lt;code&gt;-fPIC&lt;/code&gt;, which is why my demo above used Rust. &lt;code&gt;zig cc&lt;/code&gt; or &lt;code&gt;cl&lt;/code&gt; work today.&lt;/li&gt;
&lt;li&gt;Cache toolchain detection so that warm loads skip probing compilers (and WSL) on every call.&lt;/li&gt;
&lt;li&gt;Bring Zig and Go to the ESM loader.&lt;/li&gt;
&lt;li&gt;Richer types: structs and callbacks.&lt;/li&gt;
&lt;li&gt;An optional hardened runtime: seccomp-bpf on Linux, AppContainer on Windows, sandbox-exec on macOS.&lt;/li&gt;
&lt;/ul&gt;

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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;my-native-app &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;my-native-app
npm init &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm pkg &lt;span class="nb"&gt;set type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;module
npm i relaxnative
npx relaxnative doctor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⭐ Star it on &lt;strong&gt;&lt;a href="https://github.com/Ravikisha/RelaxNative" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/strong&gt;, install it from &lt;strong&gt;&lt;a href="https://www.npmjs.com/package/relaxnative" rel="noopener noreferrer"&gt;npm&lt;/a&gt;&lt;/strong&gt;, and if you find a signature it can't parse or a kernel where native loses, &lt;a href="https://github.com/Ravikisha/RelaxNative/issues" rel="noopener noreferrer"&gt;open an issue&lt;/a&gt;. Those are my favourite bug reports.&lt;/p&gt;

&lt;p&gt;Happy hacking! ⚡&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>rust</category>
      <category>go</category>
    </item>
    <item>
      <title>Relaxicons: Turn Any Iconify Icon into a Native Component for 8 Frameworks</title>
      <dc:creator>Ravi Kishan</dc:creator>
      <pubDate>Mon, 05 Oct 2026 07:24:51 +0000</pubDate>
      <link>https://dev.to/ravikishan/relaxicons-turn-any-iconify-icon-into-a-native-component-for-8-frameworks-nem</link>
      <guid>https://dev.to/ravikishan/relaxicons-turn-any-iconify-icon-into-a-native-component-for-8-frameworks-nem</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; — Relaxicons is a Node.js CLI that pulls any icon from the &lt;a href="https://iconify.design" rel="noopener noreferrer"&gt;Iconify&lt;/a&gt; catalogue (200+ open-source icon sets) and writes it into your project as a real component for &lt;strong&gt;React, Next.js (RSC), Vue, Angular, Svelte, Solid, Laravel Blade or Web Components&lt;/strong&gt;. One command, one file, no runtime icon library.&lt;/p&gt;


&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; relaxicons
relaxicons init
relaxicons add lucide:home
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;🔗 &lt;a href="https://github.com/ravikisha/relaxicons" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · 📦 &lt;a href="https://www.npmjs.com/package/relaxicons" rel="noopener noreferrer"&gt;npm&lt;/a&gt; · 📚 &lt;a href="https://ravikisha.github.io/relaxicons/" rel="noopener noreferrer"&gt;Docs&lt;/a&gt; · 🔍 &lt;a href="https://ravikisha.github.io/relaxicons/icon-explorer/" rel="noopener noreferrer"&gt;Icon Explorer&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The problem: icons are weirdly annoying&lt;/li&gt;
&lt;li&gt;The idea: shadcn, but for icons&lt;/li&gt;
&lt;li&gt;A 60-second tour&lt;/li&gt;
&lt;li&gt;What happens when you run &lt;code&gt;relaxicons add&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The SVG transform pipeline (and the outline-icon trap)&lt;/li&gt;
&lt;li&gt;One prop contract, eight frameworks&lt;/li&gt;
&lt;li&gt;Caching that respects the network&lt;/li&gt;
&lt;li&gt;The small details that make a CLI pleasant&lt;/li&gt;
&lt;li&gt;Icons in CI&lt;/li&gt;
&lt;li&gt;The docs site&lt;/li&gt;
&lt;li&gt;Testing&lt;/li&gt;
&lt;li&gt;What I learned&lt;/li&gt;
&lt;li&gt;What's next&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The problem: icons are weirdly annoying
&lt;/h2&gt;

&lt;p&gt;Every frontend project hits the same wall sooner or later. You need &lt;em&gt;one&lt;/em&gt; home icon. Your options are usually:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Install a whole icon package&lt;/strong&gt; (&lt;code&gt;react-icons&lt;/code&gt;, &lt;code&gt;@mdi/js&lt;/code&gt;, &lt;code&gt;lucide-react&lt;/code&gt;…). Great until you want an icon from a &lt;em&gt;different&lt;/em&gt; set, and now you have two dependencies, two APIs and two styling conventions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use a runtime icon loader&lt;/strong&gt; that fetches SVGs from a CDN in the browser. Flexible, but now your icons depend on a network request at render time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Copy-paste the SVG&lt;/strong&gt; from a website. Fast, but you end up with hard-coded &lt;code&gt;width="24"&lt;/code&gt;, a random &lt;code&gt;fill="#000"&lt;/code&gt;, kebab-case attributes that React complains about, and zero consistency between files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these felt right to me. I wanted the icon &lt;strong&gt;in my repo&lt;/strong&gt;, as &lt;strong&gt;code I own&lt;/strong&gt;, written in &lt;strong&gt;the idiom of whatever framework I'm using&lt;/strong&gt; — and I wanted it from &lt;em&gt;any&lt;/em&gt; icon set without thinking about it.&lt;/p&gt;

&lt;p&gt;That's why I built &lt;strong&gt;Relaxicons&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The idea: shadcn, but for icons
&lt;/h2&gt;

&lt;p&gt;The mental model is close to how &lt;a href="https://ui.shadcn.com" rel="noopener noreferrer"&gt;shadcn/ui&lt;/a&gt; treats components: don't install a library, &lt;em&gt;generate the source into your project&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://iconify.design" rel="noopener noreferrer"&gt;Iconify&lt;/a&gt; already did the heavy lifting of collecting icon sets — Lucide, Material Design Icons, Tabler, Phosphor, Font Awesome, Heroicons, and hundreds more — behind a single, consistent API. Every icon has an ID like &lt;code&gt;collection:name&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lucide:home
mdi:github
tabler:brand-react
ph:rocket-launch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Relaxicons sits on top of that API. You give it an ID, and it gives you back a component file that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;has &lt;strong&gt;no width/height baked in&lt;/strong&gt; (it scales with a &lt;code&gt;size&lt;/code&gt; prop, default &lt;code&gt;1em&lt;/code&gt;),&lt;/li&gt;
&lt;li&gt;uses &lt;strong&gt;&lt;code&gt;currentColor&lt;/code&gt;&lt;/strong&gt; so it inherits your text color,&lt;/li&gt;
&lt;li&gt;exposes the &lt;strong&gt;same props in every framework&lt;/strong&gt; (&lt;code&gt;size&lt;/code&gt;, &lt;code&gt;color&lt;/code&gt;, &lt;code&gt;strokeWidth&lt;/code&gt;, &lt;code&gt;className&lt;/code&gt;/&lt;code&gt;class&lt;/code&gt;),&lt;/li&gt;
&lt;li&gt;is &lt;strong&gt;formatted with Prettier&lt;/strong&gt;, and&lt;/li&gt;
&lt;li&gt;is &lt;strong&gt;automatically exported&lt;/strong&gt; from an &lt;code&gt;index.ts&lt;/code&gt; barrel file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No runtime. No icon package. Just a file.&lt;/p&gt;

&lt;h2&gt;
  
  
  A 60-second tour
&lt;/h2&gt;

&lt;p&gt;Install the CLI globally (Node 18+):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; relaxicons
relaxicons &lt;span class="nt"&gt;--version&lt;/span&gt;   &lt;span class="c"&gt;# 1.1.2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Initialize inside your project. Relaxicons sniffs your project to figure out what you're using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;relaxicons init
&lt;span class="c"&gt;# ✔ Detected: Next.js&lt;/span&gt;
&lt;span class="c"&gt;# ? Confirm framework › Next.js&lt;/span&gt;
&lt;span class="c"&gt;# ? Where do you want to save icons? › components/ui/icons&lt;/span&gt;
&lt;span class="c"&gt;# ? Do you use TypeScript? › yes&lt;/span&gt;
&lt;span class="c"&gt;# ✔ Created relaxicons.config.json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That writes a small config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&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;"framework"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"next"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"iconPath"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"components/ui/icons"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"typescript"&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="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"schemaVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"generatedAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-10-05T00:00:00.000Z"&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;Now add icons — one, several, or a whole file of them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;relaxicons add lucide:home
relaxicons add lucide:home,star,bell          &lt;span class="c"&gt;# shared prefix shorthand&lt;/span&gt;
relaxicons add mdi:github,tabler:brand-react   &lt;span class="c"&gt;# mix collections&lt;/span&gt;
relaxicons add &lt;span class="nt"&gt;--from&lt;/span&gt; icons.txt                &lt;span class="c"&gt;# batch from a file&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And use them like any other component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HomeIcon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;StarIcon&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/ui/icons&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Nav&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;nav&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-slate-600"&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;HomeIcon&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;                         &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* inherits text color, 1em */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;StarIcon&lt;/span&gt; &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"gold"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* explicit size + color */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;nav&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Need to find an icon first? Explore from the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;relaxicons collections &lt;span class="nt"&gt;--filter&lt;/span&gt; luc
relaxicons icons lucide &lt;span class="nt"&gt;--filter&lt;/span&gt; clock &lt;span class="nt"&gt;--limit&lt;/span&gt; 10
relaxicons search arrow &lt;span class="nt"&gt;--collection&lt;/span&gt; lucide
relaxicons stats &lt;span class="nt"&gt;-c&lt;/span&gt; lucide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…or use the visual &lt;strong&gt;&lt;a href="https://ravikisha.github.io/relaxicons/icon-explorer/" rel="noopener noreferrer"&gt;Icon Explorer&lt;/a&gt;&lt;/strong&gt; on the docs site and copy the command straight from there.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happens when you run &lt;code&gt;relaxicons add&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Under the hood, &lt;code&gt;add&lt;/code&gt; is a small, linear pipeline. Here's the whole journey of &lt;code&gt;relaxicons add lucide:home&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  lucide:home
      │
      ▼
┌──────────────┐   relaxicons.config.json → framework, iconPath, typescript
│  getConfig   │   (--framework flag can override per call)
└──────┬───────┘
       ▼
┌──────────────┐   GET https://api.iconify.design/lucide/home.svg
│  fetchIcon   │   404 → fuzzy "Did you mean…?" suggestions
└──────┬───────┘
       ▼
┌──────────────┐   optional, only if svgo is installed
│  SVGO        │
└──────┬───────┘
       ▼
┌──────────────┐   strip width/height, currentColor, drop data-* attrs
│ transformSvg │   → { attrs, children }
└──────┬───────┘
       ▼
┌──────────────┐   custom template (.hbs/.ejs/.js) if present,
│  template    │   otherwise built-in react/vue/angular/svelte/…
└──────┬───────┘
       ▼
┌──────────────┐   parser picked from file extension
│  Prettier    │
└──────┬───────┘
       ▼
┌──────────────┐   HomeIcon.tsx + sorted `export * from './HomeIcon'`
│ write+barrel │
└──────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few parts of that are worth zooming into.&lt;/p&gt;

&lt;h3&gt;
  
  
  Parsing the ID
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;fetchIcon&lt;/code&gt; accepts both &lt;code&gt;lucide:home&lt;/code&gt; and &lt;code&gt;lucide/home&lt;/code&gt;, and rejects anything that isn't exactly two non-empty parts with a helpful message. It then validates that the response actually &lt;em&gt;is&lt;/em&gt; an SVG (optionally preceded by an XML prolog) before trusting it — if Iconify ever returns an HTML error page, you get &lt;code&gt;Unexpected response: not an SVG&lt;/code&gt; instead of a broken component.&lt;/p&gt;

&lt;h3&gt;
  
  
  Safe names
&lt;/h3&gt;

&lt;p&gt;Icon names on Iconify are wild. Some start with digits (&lt;code&gt;500px&lt;/code&gt;), some are JavaScript reserved words (&lt;code&gt;default&lt;/code&gt;, &lt;code&gt;class&lt;/code&gt;, &lt;code&gt;function&lt;/code&gt;), some are pure symbols. A generated component &lt;em&gt;must&lt;/em&gt; be a valid identifier, so names go through two passes:&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="nf"&gt;toPascalCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;arrow-right&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// ArrowRight&lt;/span&gt;
&lt;span class="nf"&gt;safePascal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Default&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;        &lt;span class="c1"&gt;// fine — PascalCase isn't reserved&lt;/span&gt;
&lt;span class="nf"&gt;safePascal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;500px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="c1"&gt;// Icon500px  (leading digit)&lt;/span&gt;
&lt;span class="nf"&gt;safePascal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;               &lt;span class="c1"&gt;// Icon       (nothing left after cleaning)&lt;/span&gt;
&lt;span class="nf"&gt;safeKebab&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ÅÄÖ&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;             &lt;span class="c1"&gt;// icon&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same sanitized names are reused by &lt;code&gt;relaxicons remove&lt;/code&gt;, so removing an icon always finds the file &lt;code&gt;add&lt;/code&gt; created.&lt;/p&gt;

&lt;h2&gt;
  
  
  The SVG transform pipeline (and the outline-icon trap)
&lt;/h2&gt;

&lt;p&gt;This is the most interesting file in the project: &lt;a href="https://github.com/ravikisha/relaxicons/blob/main/src/utils/transformSvg.js" rel="noopener noreferrer"&gt;&lt;code&gt;src/utils/transformSvg.js&lt;/code&gt;&lt;/a&gt;. It loads the SVG with &lt;a href="https://cheerio.js.org" rel="noopener noreferrer"&gt;cheerio&lt;/a&gt; in XML mode and does four things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Removes &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt;&lt;/strong&gt; from the root, keeping &lt;code&gt;viewBox&lt;/code&gt;, so the component can scale freely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Applies &lt;code&gt;currentColor&lt;/code&gt;&lt;/strong&gt; so icons inherit the surrounding text color.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strips noise&lt;/strong&gt; like &lt;code&gt;data-name&lt;/code&gt; / &lt;code&gt;data-style&lt;/code&gt; attributes left behind by design tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Returns a neutral representation&lt;/strong&gt; — &lt;code&gt;{ attrs, children }&lt;/code&gt; — that every framework template consumes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Step 2 sounds trivial ("just set &lt;code&gt;fill="currentColor"&lt;/code&gt; everywhere"), and that's exactly the trap I fell into first.&lt;/p&gt;

&lt;p&gt;Icon sets come in two flavours:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Style&lt;/th&gt;
&lt;th&gt;Examples&lt;/th&gt;
&lt;th&gt;How it's drawn&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Filled&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;MDI, Material Symbols, Font Awesome&lt;/td&gt;
&lt;td&gt;Shapes painted with &lt;code&gt;fill&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Outline&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Lucide, Feather, Tabler&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;fill="none"&lt;/code&gt; + &lt;code&gt;stroke&lt;/code&gt;, lines only&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you blindly add &lt;code&gt;fill="currentColor"&lt;/code&gt; to every &lt;code&gt;&amp;lt;path&amp;gt;&lt;/code&gt; in an &lt;em&gt;outline&lt;/em&gt; icon, the strokes get filled in and your crisp line icon turns into a &lt;strong&gt;solid blob&lt;/strong&gt;. So the transform first asks: &lt;em&gt;is this an outline icon?&lt;/em&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rootFillNone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$svg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fill&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rootHasStroke&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;$svg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stroke&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isOutline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rootFillNone&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;rootHasStroke&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…and only then decides, per element:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;element has a &lt;code&gt;stroke-width&lt;/code&gt; but no &lt;code&gt;stroke&lt;/code&gt; → give it &lt;code&gt;stroke="currentColor"&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;element already has its own &lt;code&gt;fill&lt;/code&gt; (even &lt;code&gt;fill="none"&lt;/code&gt;) → &lt;strong&gt;never touch it&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;outline icon, or the element itself is stroke-based → leave &lt;code&gt;fill&lt;/code&gt; unset so it inherits &lt;code&gt;none&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;otherwise, for real shapes (&lt;code&gt;path&lt;/code&gt;, &lt;code&gt;circle&lt;/code&gt;, &lt;code&gt;rect&lt;/code&gt;, &lt;code&gt;polygon&lt;/code&gt;, &lt;code&gt;polyline&lt;/code&gt;, &lt;code&gt;ellipse&lt;/code&gt;) → &lt;code&gt;fill="currentColor"&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trap had a second layer, and I only found it while writing this post. The Iconify API doesn't put Lucide's &lt;code&gt;fill="none"&lt;/code&gt; on the root at all. It wraps every path in a group:&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;svg&lt;/span&gt; &lt;span class="na"&gt;viewBox=&lt;/span&gt;&lt;span class="s"&gt;"0 0 24 24"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;g&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"none"&lt;/span&gt; &lt;span class="na"&gt;stroke=&lt;/span&gt;&lt;span class="s"&gt;"currentColor"&lt;/span&gt; &lt;span class="na"&gt;stroke-width=&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt; &lt;span class="na"&gt;stroke-linecap=&lt;/span&gt;&lt;span class="s"&gt;"round"&lt;/span&gt; &lt;span class="na"&gt;stroke-linejoin=&lt;/span&gt;&lt;span class="s"&gt;"round"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"M15 21v-8a1 1 0 0 0-1-1h-4…"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"M3 10a2 2 0 0 1 .709-1.528l7-6…"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/g&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A root-only check sees no outline, so &lt;code&gt;relaxicons add lucide:home&lt;/code&gt; produced a filled house. Worse, the group's &lt;code&gt;stroke-width="2"&lt;/code&gt; shadowed the component's &lt;code&gt;strokeWidth&lt;/code&gt; prop. The fix does two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hoist the wrapper.&lt;/strong&gt; If the root has exactly one &lt;code&gt;&amp;lt;g&amp;gt;&lt;/code&gt; child that only carries presentation attributes (&lt;code&gt;fill&lt;/code&gt;, &lt;code&gt;stroke&lt;/code&gt;, &lt;code&gt;stroke-width&lt;/code&gt;, line caps/joins), those move onto the root and the group is unwrapped. Now the root really says &lt;code&gt;fill="none" stroke="currentColor"&lt;/code&gt;, and &lt;code&gt;strokeWidth&lt;/code&gt; defaults to the icon's own &lt;code&gt;2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check ancestors, not just the root.&lt;/strong&gt; If a group can't be hoisted (say it also has a &lt;code&gt;transform&lt;/code&gt;), any element inside a &lt;code&gt;fill="none"&lt;/code&gt; or stroked group is left alone instead of being filled.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With both in place, filled icons recolor correctly &lt;em&gt;and&lt;/em&gt; outline icons stay outlines, whichever way the SVG is structured.&lt;/p&gt;

&lt;h2&gt;
  
  
  One prop contract, eight frameworks
&lt;/h2&gt;

&lt;p&gt;Every template lives in &lt;a href="https://github.com/ravikisha/relaxicons/tree/main/src/templates" rel="noopener noreferrer"&gt;&lt;code&gt;src/templates/&lt;/code&gt;&lt;/a&gt; and shares helpers from &lt;code&gt;_shared.js&lt;/code&gt;. The key design decision: &lt;strong&gt;every framework gets the same props&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;Prop&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;size&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1em&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sets &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;color&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;inherited&lt;/td&gt;
&lt;td&gt;Applied as CSS &lt;code&gt;color&lt;/code&gt; — which &lt;code&gt;currentColor&lt;/code&gt; resolves to&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;strokeWidth&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the icon's own value&lt;/td&gt;
&lt;td&gt;Overrides stroke width when passed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;className&lt;/code&gt; / &lt;code&gt;class&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Merged onto the root &lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Notice that &lt;code&gt;color&lt;/code&gt; is applied through CSS &lt;code&gt;color&lt;/code&gt;, &lt;strong&gt;not&lt;/strong&gt; by forcing a &lt;code&gt;fill&lt;/code&gt;. That one choice means &lt;code&gt;color="red"&lt;/code&gt; recolors filled icons &lt;em&gt;and&lt;/em&gt; outline icons without ever changing what kind of icon it is.&lt;/p&gt;

&lt;p&gt;Here's what that contract looks like in each ecosystem:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;React / Next.js&lt;/strong&gt; — named + default export, optional TypeScript props type, and an RSC-safe variant (&lt;code&gt;--framework next-rsc&lt;/code&gt;) with no hooks and no &lt;code&gt;'use client'&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;HomeIcon&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1em&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;strokeWidth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;IconProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;svg&lt;/span&gt; &lt;span class="na"&gt;viewBox&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"0 0 24 24"&lt;/span&gt; &lt;span class="na"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"none"&lt;/span&gt; &lt;span class="na"&gt;stroke&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"currentColor"&lt;/span&gt;
         &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;strokeWidth&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;strokeWidth&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
         &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&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="nt"&gt;path&lt;/span&gt; &lt;span class="na"&gt;d&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"…"&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="nt"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Vue&lt;/strong&gt; — a Single File Component with real typed props and &lt;code&gt;inheritAttrs: false&lt;/code&gt;, forwarding everything else via &lt;code&gt;v-bind="$attrs"&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;viewBox=&lt;/span&gt;&lt;span class="s"&gt;"0 0 24 24"&lt;/span&gt; &lt;span class="na"&gt;:width=&lt;/span&gt;&lt;span class="s"&gt;"size"&lt;/span&gt; &lt;span class="na"&gt;:height=&lt;/span&gt;&lt;span class="s"&gt;"size"&lt;/span&gt; &lt;span class="na"&gt;:stroke-width=&lt;/span&gt;&lt;span class="s"&gt;"strokeWidth"&lt;/span&gt;
       &lt;span class="na"&gt;:style=&lt;/span&gt;&lt;span class="s"&gt;"color ? &lt;/span&gt;{ color } : undefined" v-bind="$attrs"&amp;gt;
    &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"…"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Angular&lt;/strong&gt; — a standalone component with &lt;code&gt;@Input()&lt;/code&gt;s and a selector like &lt;code&gt;icon-home&lt;/code&gt;:&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="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;icon-home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;svg …&amp;gt;…&amp;lt;/svg&amp;gt;`&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HomeIcon&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1em&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="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Laravel Blade&lt;/strong&gt; — &lt;code&gt;@props([...])&lt;/code&gt; with &lt;code&gt;$attributes-&amp;gt;merge()&lt;/code&gt;, used as &lt;code&gt;&amp;lt;x-home-icon size="24" color="red" /&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Svelte&lt;/strong&gt; — exported props plus &lt;code&gt;$$restProps&lt;/code&gt;; &lt;code&gt;class&lt;/code&gt; is aliased because it's a reserved word in JS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solid&lt;/strong&gt; — JSX with &lt;code&gt;splitProps&lt;/code&gt; so known props are separated from the rest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Web Components&lt;/strong&gt; — a framework-free custom element with Shadow DOM, observing &lt;code&gt;size&lt;/code&gt;, &lt;code&gt;color&lt;/code&gt;, &lt;code&gt;stroke-width&lt;/code&gt; and &lt;code&gt;class&lt;/code&gt;:&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;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./icons/home.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;icon-home&lt;/span&gt; &lt;span class="na"&gt;size=&lt;/span&gt;&lt;span class="s"&gt;"32"&lt;/span&gt; &lt;span class="na"&gt;color=&lt;/span&gt;&lt;span class="s"&gt;"tomato"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/icon-home&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Getting the markup &lt;em&gt;idiomatic&lt;/em&gt; per framework is where most of the subtle bugs hide. A few I had to handle in &lt;code&gt;_shared.js&lt;/code&gt; and the templates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React needs &lt;strong&gt;camelCase attributes&lt;/strong&gt; (&lt;code&gt;stroke-linecap&lt;/code&gt; → &lt;code&gt;strokeLinecap&lt;/code&gt;, &lt;code&gt;class&lt;/code&gt; → &lt;code&gt;className&lt;/code&gt;, &lt;code&gt;xlink:href&lt;/code&gt; → &lt;code&gt;xlinkHref&lt;/code&gt;) — but only attribute &lt;em&gt;names&lt;/em&gt;, never path data.&lt;/li&gt;
&lt;li&gt;Angular embeds the SVG in a template literal, so backticks, backslashes and &lt;code&gt;${&lt;/code&gt; inside the markup must be &lt;strong&gt;escaped&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Web Components embed the markup as a JS string, so it goes through &lt;code&gt;JSON.stringify&lt;/code&gt; to survive quotes and newlines.&lt;/li&gt;
&lt;li&gt;Custom element names &lt;strong&gt;must contain a hyphen&lt;/strong&gt; — hence the &lt;code&gt;icon-&lt;/code&gt; prefix.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And if none of the built-ins fit your codebase, drop a &lt;code&gt;react.hbs&lt;/code&gt;, &lt;code&gt;vue.ejs&lt;/code&gt; or &lt;code&gt;svelte.js&lt;/code&gt; into a &lt;code&gt;templatesDir&lt;/code&gt; and Relaxicons will use &lt;strong&gt;your&lt;/strong&gt; template instead, passing it &lt;code&gt;{ iconId, pascal, kebab, svg, typescript }&lt;/code&gt;. Handlebars and EJS are lazy-required, so they're only needed if you actually use them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caching that respects the network
&lt;/h2&gt;

&lt;p&gt;Listing collections and searching icons means hitting Iconify's metadata endpoints a lot. &lt;a href="https://github.com/ravikisha/relaxicons/blob/main/src/utils/cache.js" rel="noopener noreferrer"&gt;&lt;code&gt;src/utils/cache.js&lt;/code&gt;&lt;/a&gt; makes that cheap and resilient:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Responses are cached as JSON in &lt;code&gt;~/.cache/relaxicons&lt;/code&gt; (override with &lt;code&gt;RELAXICONS_CACHE_DIR&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Each entry stores the &lt;strong&gt;ETag&lt;/strong&gt;; the next request sends &lt;code&gt;If-None-Match&lt;/code&gt;, and a &lt;code&gt;304 Not Modified&lt;/code&gt; just refreshes the timestamp.&lt;/li&gt;
&lt;li&gt;Entries without an ETag use a &lt;strong&gt;24-hour TTL&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Requests &lt;strong&gt;retry with backoff&lt;/strong&gt; (250 ms → 500 ms → 1 s) on network errors, &lt;code&gt;429&lt;/code&gt; and &lt;code&gt;5xx&lt;/code&gt;, and honour the server's &lt;code&gt;Retry-After&lt;/code&gt; header.&lt;/li&gt;
&lt;li&gt;If the network fails entirely, it &lt;strong&gt;falls back to stale cache&lt;/strong&gt; instead of crashing.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;RELAXICONS_OFFLINE=1&lt;/code&gt; makes the CLI run purely from a warm cache — handy on a plane, and essential for deterministic tests.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;relaxicons update-cache   &lt;span class="c"&gt;# warm everything&lt;/span&gt;
relaxicons cache-clear    &lt;span class="c"&gt;# start fresh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The small details that make a CLI pleasant
&lt;/h2&gt;

&lt;p&gt;Most of the work in a CLI isn't the happy path — it's everything around it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Did you mean…?"&lt;/strong&gt; — typo an icon name and Relaxicons loads the collection and ranks names by similarity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✖ Icon not found
Did you mean: alarm-clock, alarm-check, alarm-off?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If nothing in that collection is close, it searches &lt;em&gt;across&lt;/em&gt; collections for the nearest match.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Framework auto-detection&lt;/strong&gt; — &lt;code&gt;init&lt;/code&gt; looks for &lt;code&gt;next.config.*&lt;/code&gt;, &lt;code&gt;vite.config.*&lt;/code&gt; + a &lt;code&gt;react&lt;/code&gt;/&lt;code&gt;vue&lt;/code&gt;/&lt;code&gt;svelte&lt;/code&gt; dependency, &lt;code&gt;angular.json&lt;/code&gt;, or &lt;code&gt;composer.json&lt;/code&gt; + &lt;code&gt;artisan&lt;/code&gt;. Each match carries a confidence score and the highest wins (Astro is detected at low confidence so a docs folder never overrides your real app).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Always-sorted barrels&lt;/strong&gt; — every add appends an export and re-sorts the barrel alphabetically, preserving comment headers and the file's original line endings (CRLF stays CRLF on Windows).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Batch-friendly errors&lt;/strong&gt; — in a batch, a missing icon or an existing file doesn't abort the run; it's reported and the rest continue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Meaningful exit codes&lt;/strong&gt;, so scripts can react:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Code&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;OK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Generic error&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Config missing / invalid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fetch failed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;File already exists&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;And the usual polish:&lt;/strong&gt; &lt;code&gt;--dry-run&lt;/code&gt; to preview writes, &lt;code&gt;--quiet&lt;/code&gt; and &lt;code&gt;--no-color&lt;/code&gt; for CI logs, &lt;code&gt;--raw&lt;/code&gt; for plain SVG, &lt;code&gt;--both&lt;/code&gt; for component + cleaned SVG side by side, &lt;code&gt;doctor&lt;/code&gt; to check Node, config and Iconify reachability, and a JSON Schema (&lt;a href="https://github.com/ravikisha/relaxicons/blob/main/relaxicons.config.schema.json" rel="noopener noreferrer"&gt;&lt;code&gt;relaxicons.config.schema.json&lt;/code&gt;&lt;/a&gt;) so your editor autocompletes the config.&lt;/p&gt;

&lt;h2&gt;
  
  
  Icons in CI
&lt;/h2&gt;

&lt;p&gt;For teams, I wanted icons to be &lt;strong&gt;reproducible&lt;/strong&gt;. List the icons your app uses in a manifest:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# relaxicons.manifest
lucide:home
lucide:star
mdi:github
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…and regenerate them anywhere:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;relaxicons regenerate &lt;span class="nt"&gt;-m&lt;/span&gt; relaxicons.manifest &lt;span class="nt"&gt;--concurrency&lt;/span&gt; 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One fun bug from building this: the first version ran several &lt;code&gt;add&lt;/code&gt; commands concurrently &lt;em&gt;inside the same process&lt;/em&gt; by re-parsing the shared Commander instance. Commander keeps per-invocation state on that object, so parallel runs corrupted each other. The fix was to run each &lt;code&gt;add&lt;/code&gt; in an &lt;strong&gt;isolated child process&lt;/strong&gt; with a small worker pool — boring, but bulletproof.&lt;/p&gt;

&lt;p&gt;The repo ships a ready-made &lt;a href="https://github.com/ravikisha/relaxicons/blob/main/.github/workflows/relaxicons-regenerate.yml" rel="noopener noreferrer"&gt;GitHub Action&lt;/a&gt; that runs on changes to the manifest or config, regenerates the icons and commits the result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm i -g relaxicons&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Regenerate icons&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;relaxicons regenerate -m relaxicons.manifest&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Commit changes&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;git add -A&lt;/span&gt;
    &lt;span class="s"&gt;git diff --cached --quiet || git commit -m "chore(relaxicons): regenerate icons"&lt;/span&gt;
    &lt;span class="s"&gt;git push&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The docs site
&lt;/h2&gt;

&lt;p&gt;The documentation at &lt;strong&gt;&lt;a href="https://ravikisha.github.io/relaxicons/" rel="noopener noreferrer"&gt;ravikisha.github.io/relaxicons&lt;/a&gt;&lt;/strong&gt; is built with &lt;strong&gt;Astro 5&lt;/strong&gt;, &lt;strong&gt;React islands&lt;/strong&gt;, &lt;strong&gt;Tailwind CSS 4&lt;/strong&gt; and Radix UI primitives, and deployed to GitHub Pages by the CI workflow on every push to &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Some highlights:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://ravikisha.github.io/relaxicons/icon-explorer/" rel="noopener noreferrer"&gt;Icon Explorer&lt;/a&gt;&lt;/strong&gt; — browse collections, search icons, keep &lt;strong&gt;Favorites&lt;/strong&gt; and &lt;strong&gt;Recent&lt;/strong&gt; tabs, navigate with arrow keys + Enter, and copy an icon as a CLI command, raw SVG or data URI. It also shows per-collection stats and a top-icons carousel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Command palette&lt;/strong&gt; (built with &lt;code&gt;cmdk&lt;/code&gt;) for jumping anywhere in the docs.&lt;/li&gt;
&lt;li&gt;Copy-ready &lt;strong&gt;code tabs&lt;/strong&gt; for every framework, an animated framework marquee and a live mini demo on the home page.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Good starting points in the docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ravikisha.github.io/relaxicons/getting-started/" rel="noopener noreferrer"&gt;Getting Started&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ravikisha.github.io/relaxicons/cli/" rel="noopener noreferrer"&gt;CLI Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ravikisha.github.io/relaxicons/configuration/" rel="noopener noreferrer"&gt;Configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ravikisha.github.io/relaxicons/framework-adapters/" rel="noopener noreferrer"&gt;Framework Adapters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ravikisha.github.io/relaxicons/transform/" rel="noopener noreferrer"&gt;Transform Pipeline&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ravikisha.github.io/relaxicons/guides/advanced/" rel="noopener noreferrer"&gt;Advanced Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ravikisha.github.io/relaxicons/troubleshooting/" rel="noopener noreferrer"&gt;Troubleshooting&lt;/a&gt; · &lt;a href="https://ravikisha.github.io/relaxicons/faq/" rel="noopener noreferrer"&gt;FAQ&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;The project has &lt;strong&gt;24 Jest suites&lt;/strong&gt; covering each piece in isolation and the CLI end to end:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unit tests&lt;/strong&gt; for naming, sanitizing, path handling, framework detection, config validation, the SVG transform, and every framework template.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Golden tests&lt;/strong&gt; that snapshot generated output, so a template change can't silently alter what users get.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration tests&lt;/strong&gt; that spawn the real CLI in temp directories with &lt;code&gt;RELAXICONS_OFFLINE=1&lt;/code&gt; and fixture icons — no network, no flakiness — and assert on files written and exit codes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Windows path tests&lt;/strong&gt;, because a CLI that writes files had better work with backslashes too.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;test
&lt;/span&gt;npm run coverage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SVG is not one format, it's a family of conventions.&lt;/strong&gt; Outline vs. filled, attributes on the root vs. on a &lt;code&gt;&amp;lt;g&amp;gt;&lt;/code&gt;, &lt;code&gt;fill="none"&lt;/code&gt; meaning &lt;em&gt;"inherit nothing"&lt;/em&gt;. Normalizing icons from 200+ sets is way subtler than "replace the color", and testing against the &lt;em&gt;real&lt;/em&gt; API response (not a hand-written fixture) is what caught the &lt;code&gt;&amp;lt;g&amp;gt;&lt;/code&gt; wrapper bug.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generating code means respecting each framework's idioms.&lt;/strong&gt; It's easy to produce something that &lt;em&gt;renders&lt;/em&gt;; it's harder to produce something a React, Vue or Angular developer would actually want to commit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Caching is a UX feature.&lt;/strong&gt; ETags, TTLs, backoff and stale fallback are what make a network-backed CLI feel instant and never strand you offline.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shared mutable state bites, even in a CLI.&lt;/strong&gt; The Commander concurrency bug was a good reminder that "it's just a script" doesn't exempt you from isolation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exit codes and &lt;code&gt;--dry-run&lt;/code&gt; are documentation.&lt;/strong&gt; They tell scripts and humans exactly what happened.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Real shell completions for zsh/bash/fish (the &lt;code&gt;completion&lt;/code&gt; command is still a stub).&lt;/li&gt;
&lt;li&gt;Removing the deprecated &lt;code&gt;list&lt;/code&gt; alias in &lt;strong&gt;v2.0&lt;/strong&gt; (use &lt;code&gt;icons&lt;/code&gt; instead).&lt;/li&gt;
&lt;li&gt;More framework targets and richer custom-template examples.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're tired of juggling icon packages, give it a spin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; relaxicons
relaxicons init
relaxicons add lucide:sparkles
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⭐ Star it on &lt;strong&gt;&lt;a href="https://github.com/ravikisha/relaxicons" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/strong&gt;, grab it from &lt;strong&gt;&lt;a href="https://www.npmjs.com/package/relaxicons" rel="noopener noreferrer"&gt;npm&lt;/a&gt;&lt;/strong&gt;, and if you find an icon that renders wrong, &lt;a href="https://github.com/Ravikisha/relaxicons/issues" rel="noopener noreferrer"&gt;open an issue&lt;/a&gt; — I'd love to see it.&lt;/p&gt;

&lt;p&gt;Happy building! 🎨&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>node</category>
    </item>
    <item>
      <title>How RelaxCSS Works: Building a TailwindCSS-Like Utility Engine</title>
      <dc:creator>Ravi Kishan</dc:creator>
      <pubDate>Tue, 24 Jun 2025 05:59:38 +0000</pubDate>
      <link>https://dev.to/ravikishan/how-relaxcss-works-building-a-tailwindcss-like-utility-engine-21j6</link>
      <guid>https://dev.to/ravikishan/how-relaxcss-works-building-a-tailwindcss-like-utility-engine-21j6</guid>
      <description>&lt;h1&gt;
  
  
  Overview and Introduction
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;RelaxCSS&lt;/strong&gt; is a lightweight, Tailwind-inspired utility-first CSS engine implemented as a PostCSS plugin and CLI tool. Like Tailwind, it provides a rich set of pre-defined utility classes (e.g. &lt;code&gt;p-4&lt;/code&gt;, &lt;code&gt;bg-blue-500&lt;/code&gt;, &lt;code&gt;hover:text-white&lt;/code&gt;) and a configuration-driven design system. RelaxCSS aims to be minimal and extensible: it supports custom &lt;em&gt;theme&lt;/em&gt; values (colors, spacing, etc.), responsive and pseudo-class variants, JIT compilation of only used utilities, and a plugin API for adding new utilities. Under the hood, a “preflight” (CSS reset) is injected (similar to Tailwind’s) and directives like &lt;code&gt;@apply&lt;/code&gt; and &lt;code&gt;@relax&lt;/code&gt; in CSS enable class composition.&lt;/p&gt;

&lt;p&gt;In practice, you install RelaxCSS, write your CSS/HTML with utility classes, and run the CLI (or PostCSS plugin) to watch your files. The tool &lt;strong&gt;scans source files for class names&lt;/strong&gt; (using glob patterns and regex), generates the corresponding utility CSS on-the-fly (JIT), and writes out a final &lt;code&gt;output.css&lt;/code&gt;. The default configuration (which you can customize via &lt;code&gt;relaxcss.config.js&lt;/code&gt;) includes sensible defaults for colors, spacing, screens, etc., and even a built-in example plugin (adding a &lt;code&gt;fancy-border&lt;/code&gt; utility). Overall, RelaxCSS provides a Tailwind-like workflow—class-heavy markup and zero custom CSS—while remaining small and easy to extend.&lt;/p&gt;

&lt;h1&gt;
  
  
  Architecture Overview
&lt;/h1&gt;

&lt;p&gt;RelaxCSS consists of several major components that work together in a build pipeline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CLI/Watcher:&lt;/strong&gt; A command-line interface (&lt;code&gt;cli.ts&lt;/code&gt;/&lt;code&gt;cli-watch.ts&lt;/code&gt;) runs RelaxCSS. It uses &lt;a href="https://npmjs.com/package/glob" rel="noopener noreferrer"&gt;glob&lt;/a&gt; and &lt;a href="https://npmjs.com/package/chokidar" rel="noopener noreferrer"&gt;chokidar&lt;/a&gt; to watch source files (HTML, CSS, JS, etc.) and trigger rebuilds on changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;File Scanner (JIT Engine):&lt;/strong&gt; The CLI watches file patterns (e.g. &lt;code&gt;src/**/*.{html,js,jsx,ts,tsx,css}&lt;/code&gt;), reads each file’s content, and extracts class names with regex.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PostCSS Parser:&lt;/strong&gt; RelaxCSS is implemented as a &lt;a href="https://postcss.org/" rel="noopener noreferrer"&gt;PostCSS&lt;/a&gt; plugin. The plugin receives the CSS AST parsed from your combined stylesheet (including your &lt;code&gt;@apply&lt;/code&gt; rules).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Theme/Config:&lt;/strong&gt; User configuration (from &lt;code&gt;relaxcss.config.js&lt;/code&gt; or plugin options) is merged with the default theme/variants. This config object (colors, spacing, screens, etc.) is provided to the plugin and to any utility-generating code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Utility Generator (Plugin Logic):&lt;/strong&gt; The core plugin takes each utility class name (or &lt;code&gt;@apply&lt;/code&gt; directive) and generates the corresponding CSS declarations based on the theme config. It supports responsive prefixes (e.g. &lt;code&gt;md:&lt;/code&gt;), pseudo-classes (e.g. &lt;code&gt;hover:&lt;/code&gt;), and even arbitrary values (&lt;code&gt;bg-[#222]&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Output Generator:&lt;/strong&gt; After PostCSS transforms (including preflight injection and &lt;code&gt;@apply&lt;/code&gt; resolution), the plugin emits the final CSS. The CLI then writes this CSS to the output file (e.g. &lt;code&gt;dist/output.css&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&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%2Fj5jmgbhxbllrc52rivu6.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%2Fj5jmgbhxbllrc52rivu6.png" alt="RelaxCSS Architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this flow, the &lt;strong&gt;CLI&lt;/strong&gt; initiates file scanning (with glob and chokidar) and combines CSS and &lt;code&gt;@apply&lt;/code&gt; rules. The &lt;strong&gt;PostCSS parser&lt;/strong&gt; parses the CSS, and the &lt;strong&gt;RelaxCSS plugin&lt;/strong&gt; transforms it: injecting base styles (preflight), resolving &lt;code&gt;@apply&lt;/code&gt; by inlining utility declarations, and wrapping rules in media/pseudo selectors. The &lt;strong&gt;theme/config&lt;/strong&gt; drives which CSS values get used. Finally, the &lt;strong&gt;Output Generator&lt;/strong&gt; writes out the CSS file.&lt;/p&gt;

&lt;h1&gt;
  
  
  Theme and Configuration System
&lt;/h1&gt;

&lt;p&gt;RelaxCSS is highly configurable via a &lt;code&gt;relaxcss.config.js&lt;/code&gt; (or via plugin options). The user config can define custom &lt;strong&gt;theme values&lt;/strong&gt; (colors, spacing, fonts, etc.), &lt;strong&gt;responsive breakpoints&lt;/strong&gt;, &lt;strong&gt;variants&lt;/strong&gt; (e.g. which pseudo-classes to enable), &lt;strong&gt;plugins&lt;/strong&gt;, and more. Internally, RelaxCSS starts with a &lt;code&gt;defaultConfig&lt;/code&gt; (built-in) and merges the user’s config into it using &lt;a href="https://lodash.com/docs/#merge" rel="noopener noreferrer"&gt;lodash.merge&lt;/a&gt;:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mergedConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;defaultConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This merged config object, &lt;code&gt;mergedConfig&lt;/code&gt;, contains all theme scales. For example, the default theme includes a &lt;code&gt;screens&lt;/code&gt; section (for breakpoints) and a &lt;code&gt;spacing&lt;/code&gt; section:&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="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;screens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;640px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;md&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;768px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1024px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;xl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1280px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;px&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.25rem&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.5rem&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;…&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;transparent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;white&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#fff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#eff6ff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#dbeafe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="err"&gt;…&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1rem&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt;&lt;span class="na"&gt;lineHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.5rem&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt; &lt;span class="nx"&gt;xl&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.25rem&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt;&lt;span class="na"&gt;lineHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.75rem&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt; &lt;span class="err"&gt;…&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// etc.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Within the plugin code, CSS generation functions access these theme values. For example, when handling &lt;code&gt;max-w-&amp;lt;key&amp;gt;&lt;/code&gt; utilities, the code does:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;max-w-&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxWidth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;suffix&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;declarations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Declaration&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;max-width&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Similarly, for font sizes (&lt;code&gt;text-xl&lt;/code&gt;), it retrieves a tuple from &lt;code&gt;config.theme.fontSize&lt;/code&gt;:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fontSizeTuple&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;suffix&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fontSizeTuple&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;declarations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Declaration&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;font-size&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fontSizeTuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fontSizeTuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nx"&gt;lineHeight&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;declarations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Declaration&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;line-height&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fontSizeTuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;lineHeight&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In summary, RelaxCSS loads user settings (via &lt;code&gt;opts&lt;/code&gt; or a &lt;code&gt;relaxcss.config.js&lt;/code&gt;), merges them with defaults, and then all parts of the system read from this &lt;code&gt;mergedConfig.theme&lt;/code&gt;. The &lt;code&gt;variants&lt;/code&gt; section (e.g. which media queries and which pseudo-classes to support) also comes from the config and drives how the plugin wraps utility rules for &lt;code&gt;sm:&lt;/code&gt; or &lt;code&gt;hover:&lt;/code&gt; prefixes.&lt;/p&gt;
&lt;h1&gt;
  
  
  Utility Parser and Generator
&lt;/h1&gt;

&lt;p&gt;At the heart of RelaxCSS is the &lt;em&gt;utility parser&lt;/em&gt;, which takes a class name like &lt;code&gt;p-4&lt;/code&gt;, &lt;code&gt;bg-[#222]&lt;/code&gt;, or &lt;code&gt;md:hover:bg-blue-500&lt;/code&gt; and translates it into one or more CSS declarations. This logic lives in the function &lt;code&gt;generateUtilityCss(className, config)&lt;/code&gt; in &lt;code&gt;index.ts&lt;/code&gt;. The class name is split into a &lt;strong&gt;prefix&lt;/strong&gt; (e.g. &lt;code&gt;p&lt;/code&gt;, &lt;code&gt;bg&lt;/code&gt;, &lt;code&gt;text&lt;/code&gt;, etc.) and a &lt;strong&gt;suffix&lt;/strong&gt; (the part after the dash). A series of &lt;code&gt;if&lt;/code&gt;/&lt;code&gt;else&lt;/code&gt; and &lt;code&gt;switch&lt;/code&gt; statements handle each utility:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Spacing utilities&lt;/strong&gt; (&lt;code&gt;p-4&lt;/code&gt;, &lt;code&gt;mt-2&lt;/code&gt;, &lt;code&gt;mx-auto&lt;/code&gt;, etc.): use helper functions that look up the numeric key in &lt;code&gt;config.theme.spacing&lt;/code&gt; and emit corresponding &lt;code&gt;padding&lt;/code&gt; or &lt;code&gt;margin&lt;/code&gt; declarations. For example, &lt;code&gt;m-4&lt;/code&gt; becomes &lt;code&gt;margin: 1rem&lt;/code&gt; if &lt;code&gt;spacing[4] = "1rem"&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Size limits&lt;/strong&gt; (&lt;code&gt;max-w-lg&lt;/code&gt;, &lt;code&gt;max-h-full&lt;/code&gt;): look up in &lt;code&gt;config.theme.maxWidth&lt;/code&gt; or &lt;code&gt;maxHeight&lt;/code&gt; (from the merged config) and emit &lt;code&gt;max-width&lt;/code&gt; or &lt;code&gt;max-height&lt;/code&gt;. See above in .&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Colors and fonts&lt;/strong&gt;: for &lt;code&gt;text-&amp;lt;color&amp;gt;-&amp;lt;shade&amp;gt;&lt;/code&gt; or &lt;code&gt;bg-&amp;lt;color&amp;gt;-&amp;lt;shade&amp;gt;&lt;/code&gt;, a helper (&lt;code&gt;getColor&lt;/code&gt;) checks the nested &lt;code&gt;config.theme.colors&lt;/code&gt;. For &lt;code&gt;text-xl&lt;/code&gt;, it instead looks in &lt;code&gt;config.theme.fontSize&lt;/code&gt; as shown in .&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Importantly, RelaxCSS also supports &lt;strong&gt;arbitrary values&lt;/strong&gt; via a special parser function. A class like &lt;code&gt;bg-[#222]&lt;/code&gt; or &lt;code&gt;p-[4px]&lt;/code&gt; matches the regex &lt;code&gt;/^([a-z-]+)-\[(.+)\]$/&lt;/code&gt;. This extracts a &lt;code&gt;prefix&lt;/code&gt; and a raw &lt;code&gt;value&lt;/code&gt;. The code &lt;code&gt;parseArbitraryValue(className, config)&lt;/code&gt; (see below) directly maps certain prefixes to CSS properties:&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;parseArbitraryValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RelaxConfig&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Declaration&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// e.g. bg-[#222], p-[4px], text-[red], w-[100px], m-[1rem], etc.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arbitraryMatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;([&lt;/span&gt;&lt;span class="sr"&gt;a-z-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;-&lt;/span&gt;&lt;span class="se"&gt;\[(&lt;/span&gt;&lt;span class="sr"&gt;.+&lt;/span&gt;&lt;span class="se"&gt;)\]&lt;/span&gt;&lt;span class="sr"&gt;$/i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;arbitraryMatch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arbitraryMatch&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arbitraryMatch&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="c1"&gt;// Map prefix to CSS property&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Declaration&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;background-color&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;})];&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Declaration&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;color&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;})];&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Declaration&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border-color&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;})];&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;w&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Declaration&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;width&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;})];&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Declaration&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;height&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;})];&lt;/span&gt;
    &lt;span class="c1"&gt;// ... handle px, py, m, etc. in a similar way ...&lt;/span&gt;
    &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// fallback: treat prefix as the property name&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Declaration&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;})];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;When the PostCSS plugin encounters a utility class, it first tries &lt;code&gt;parseArbitraryValue&lt;/code&gt;. If that returns declarations, it uses them directly (for example, &lt;code&gt;bg-[#222]&lt;/code&gt; yields &lt;code&gt;background-color: #222&lt;/code&gt;). Otherwise, it falls back to the standard &lt;code&gt;generateUtilityCss&lt;/code&gt; logic for named utilities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Responsive and pseudo variants:&lt;/strong&gt; Class names can be prefixed with media queries or pseudo-classes, like &lt;code&gt;sm:&lt;/code&gt;, &lt;code&gt;md:&lt;/code&gt;, &lt;code&gt;hover:&lt;/code&gt;, &lt;code&gt;focus:&lt;/code&gt;, etc. In RelaxCSS this is handled in the plugin as well. The CLI/JIT will detect a class like &lt;code&gt;md:hover:bg-blue-500&lt;/code&gt; and enqueue it. The plugin code splits on &lt;code&gt;":"&lt;/code&gt; to see that &lt;code&gt;md&lt;/code&gt; is a responsive variant and &lt;code&gt;hover&lt;/code&gt; is a pseudo-variant, and then wraps the generated declarations accordingly. For example, &lt;code&gt;md:hover:bg-blue-500&lt;/code&gt; results in a rule inside a &lt;code&gt;@media (min-width: 768px)&lt;/code&gt; block, with selector &lt;code&gt;.md\:hover\:bg-blue-500:hover { background-color: ... }&lt;/code&gt;. (The plugin has helper code to do this, but the key point is that our design allows stacking variants in class names.)&lt;/p&gt;

&lt;p&gt;For standard utilities (without variants), the code essentially turns a class into a CSS rule of the form &lt;code&gt;.&amp;lt;class&amp;gt; { &amp;lt;declarations&amp;gt; }&lt;/code&gt;. For example, &lt;code&gt;text-xl&lt;/code&gt; would lead to:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.text-xl {
  font-size: 1.25rem; /* from theme */
  line-height: 1.75rem; /* from theme */
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Likewise, &lt;code&gt;.bg-blue-500 { background-color: #3b82f6; }&lt;/code&gt;. Arbitrary values work similarly: &lt;code&gt;.bg-\[\#222\] { background-color: #222; }&lt;/code&gt;.&lt;/p&gt;
&lt;h1&gt;
  
  
  Plugin System
&lt;/h1&gt;

&lt;p&gt;RelaxCSS provides a &lt;strong&gt;plugin API&lt;/strong&gt; so users can register additional utilities. A plugin is simply a function receiving an API object, e.g.:&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;RelaxPlugin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;addUtilities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RelaxConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Declaration&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RelaxConfig&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Within this function, a plugin typically calls &lt;code&gt;api.addUtilities(...)&lt;/code&gt; with new utility definitions. For example, the default config includes a built-in plugin that adds a &lt;code&gt;fancy-border&lt;/code&gt; utility:&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="nx"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;addUtilities&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;addUtilities&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fancy-border&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="c1"&gt;// This utility generates: border:2px dashed magenta;&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Declaration&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2px dashed magenta&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;After loading the config, RelaxCSS iterates through any &lt;code&gt;plugins&lt;/code&gt; array (if provided) and calls each plugin function. The &lt;code&gt;addUtilities&lt;/code&gt; calls aggregate into a &lt;code&gt;userUtilities&lt;/code&gt; map. Later, during CSS generation, these custom utilities are treated just like built-in ones: if a class matches &lt;code&gt;"fancy-border"&lt;/code&gt;, RelaxCSS will output the declarations given by that plugin function.&lt;/p&gt;

&lt;p&gt;This plugin mechanism allows anyone to extend RelaxCSS with their own custom shortcut classes (e.g. new color utilities, or even complex components) without modifying the core engine.&lt;/p&gt;
&lt;h1&gt;
  
  
  JIT Compilation and File Scanning
&lt;/h1&gt;

&lt;p&gt;The CLI tool (&lt;code&gt;cli-watch.ts&lt;/code&gt;) implements a &lt;strong&gt;Just-In-Time (JIT) engine&lt;/strong&gt;. Instead of generating &lt;em&gt;all possible&lt;/em&gt; utility classes, it scans your source files on-the-fly for exactly the classes you use. Key points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;File watching:&lt;/strong&gt; The CLI takes a glob pattern like &lt;code&gt;src/**/*.html&lt;/code&gt; and uses &lt;code&gt;glob.sync&lt;/code&gt; to find matching files. It then sets up a watcher with &lt;code&gt;chokidar.watch(srcGlob)&lt;/code&gt; to re-run the scan whenever any matching file changes. This makes it incremental and efficient.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Class extraction:&lt;/strong&gt; For each source file, the code reads its contents and uses a regex to find class names. For HTML/JSX/etc, it matches &lt;code&gt;class="..."&lt;/code&gt;, &lt;code&gt;className="..."&lt;/code&gt;, or Vue &lt;code&gt;:class="..."&lt;/code&gt;, etc. The regex used is:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;classRegex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;(?:&lt;/span&gt;&lt;span class="sr"&gt;class|className|:class&lt;/span&gt;&lt;span class="se"&gt;)\s&lt;/span&gt;&lt;span class="sr"&gt;*=&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;"'`&lt;/span&gt;&lt;span class="se"&gt;\{&lt;/span&gt;&lt;span class="sr"&gt;[&lt;/span&gt;&lt;span class="se"&gt;]([^&lt;/span&gt;&lt;span class="sr"&gt;"'`&lt;/span&gt;&lt;span class="se"&gt;\}\]]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;)[&lt;/span&gt;&lt;span class="sr"&gt;"'`&lt;/span&gt;&lt;span class="se"&gt;\}]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Then it splits the captured class string on whitespace. For example, in &lt;code&gt;&amp;lt;div class="text-xl p-4 hover:bg-red-500"&amp;gt;&lt;/code&gt;, it will extract &lt;code&gt;["text-xl","p-4","hover:bg-red-500"]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;CSS files are also scanned for &lt;code&gt;@apply&lt;/code&gt; directives: another regex &lt;code&gt;/@apply\s+([^;]+);/g&lt;/code&gt; pulls out any classes listed in an &lt;code&gt;@apply&lt;/code&gt; statement.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Building CSS to apply:&lt;/strong&gt; After scanning all files, the CLI builds a temporary CSS string where each found class is “applied” via &lt;code&gt;@apply&lt;/code&gt;. For example, if it found &lt;code&gt;text-lg&lt;/code&gt; and &lt;code&gt;mt-4&lt;/code&gt;, it generates:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.text-lg&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="err"&gt;@apply&lt;/span&gt; &lt;span class="err"&gt;text-lg;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.mt-4&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="err"&gt;@apply&lt;/span&gt; &lt;span class="err"&gt;mt-4;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;(It also handles variants by calling a helper &lt;code&gt;generateTailwindVariantRule&lt;/code&gt;, but ultimately it creates &lt;code&gt;@apply&lt;/code&gt; rules for each used class.) This combined CSS (plus any raw CSS content) is then fed into PostCSS with the RelaxCSS plugin.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Automatic rebuilds:&lt;/strong&gt; Thanks to &lt;code&gt;chokidar&lt;/code&gt;, any file change triggers the scan-and-build process again. This ensures the output CSS is always up-to-date with the classes in your source.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key code excerpts from &lt;code&gt;cli-watch.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Scan files for classes and @apply&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;srcGlob&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[RelaxCSS] Processing files matching: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ext&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;css&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;combinedCss&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;extractApplyClasses&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cls&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;foundClasses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileExtensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;extractClassNames&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cls&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;foundClasses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;classNameFoundClasses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;extractClassNames&lt;/code&gt; and &lt;code&gt;extractApplyClasses&lt;/code&gt; functions use regexes to find classes:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In cli-watch.ts:&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;extractClassNames&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Match class="...", className="...", etc.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;classRegex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;(?:&lt;/span&gt;&lt;span class="sr"&gt;class|className|:class&lt;/span&gt;&lt;span class="se"&gt;)\s&lt;/span&gt;&lt;span class="sr"&gt;*=&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;"'`&lt;/span&gt;&lt;span class="se"&gt;\{&lt;/span&gt;&lt;span class="sr"&gt;[&lt;/span&gt;&lt;span class="se"&gt;]([^&lt;/span&gt;&lt;span class="sr"&gt;"'`&lt;/span&gt;&lt;span class="se"&gt;\}\]]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;)[&lt;/span&gt;&lt;span class="sr"&gt;"'`&lt;/span&gt;&lt;span class="se"&gt;\}]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;classRegex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+/&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cls&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&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;// ignore Spread syntax&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;After extracting, the watcher rebuild logic looks like:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Watch for changes and rebuild&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;watcher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chokidar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;srcGlob&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;ignoreInitial&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;watcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;all&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;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filePath&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[RelaxCSS] Detected &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; in &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;. Rebuilding...`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;processFiles&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This JIT pipeline – &lt;em&gt;scan source → extract classes → generate &lt;a class="mentioned-user" href="https://dev.to/apply"&gt;@apply&lt;/a&gt; CSS → run RelaxCSS plugin&lt;/em&gt; – ensures that only used utilities end up in the final CSS. We can diagram it as:&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%2Fqapaw6z38ssifr1f78ag.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%2Fqapaw6z38ssifr1f78ag.png" alt="RelaxCSS JIT Compilation Pipeline"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Preflight and CSS Output
&lt;/h1&gt;

&lt;p&gt;By default, RelaxCSS injects a small &lt;strong&gt;preflight&lt;/strong&gt; (base reset) at the top of the CSS. This is similar to Tailwind’s Preflight and is meant to normalize browser defaults. In the plugin code, you can see it defines sections like “box-sizing”, “margin-padding”, “list-style”, etc.:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;preflightSections&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&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;box-sizing&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`*,*::before,*::after{box-sizing:border-box;}`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;margin-padding&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`body,h1,h2,h3,h4,h5,h6,p,ul,ol,li,figure,figcaption,blockquote,dl,dd{margin:0;padding:0;}`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;list-style&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`ul:not([class]),ol:not([class]){list-style:none;}`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;font-family&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`body{font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Open Sans","Helvetica Neue",sans-serif;line-height:1.5;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;}`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;media&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`img,picture,video,canvas,svg{display:block;max-width:100%;}`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;form&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0;}`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;table&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`table{border-collapse:collapse;}th,td{padding:0;}`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;These CSS snippets (with comments like &lt;code&gt;/* RelaxCSS Preflight: box-sizing */&lt;/code&gt;) are prepended to the output. The &lt;code&gt;preflight&lt;/code&gt; section of the config allows enabling/disabling parts or adding overrides, but by default all sections are included. For example, the first injected rule is &lt;code&gt;*,*::before,*::after{box-sizing:border-box;}&lt;/code&gt; (ensuring consistent box-sizing).&lt;/p&gt;

&lt;p&gt;After the plugin runs (resolving all &lt;code&gt;@apply&lt;/code&gt; rules into concrete declarations and wrapping variants), the final CSS is emitted. In &lt;code&gt;cli-watch.ts&lt;/code&gt;, this is done with PostCSS:&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="nf"&gt;postcss&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt; &lt;span class="nf"&gt;relaxcss&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="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;finalCss&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;result&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;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mkdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outFile&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;recursive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;css&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[RelaxCSS] Rebuilt: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;outFile&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[RelaxCSS] Build error:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So the &lt;strong&gt;final output&lt;/strong&gt; is a single CSS file that begins with the preflight rules, followed by your combined utilities. All &lt;code&gt;@apply&lt;/code&gt; rules have been replaced by their actual CSS declarations. For instance, if you had:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@relax&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="err"&gt;@apply&lt;/span&gt; &lt;span class="err"&gt;flex&lt;/span&gt; &lt;span class="err"&gt;bg-[#222]&lt;/span&gt; &lt;span class="py"&gt;md&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;hover&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;bg-&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;#333&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;the output might look like:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* RelaxCSS Preflight: box-sizing */&lt;/span&gt;
&lt;span class="o"&gt;*,*&lt;/span&gt;&lt;span class="nd"&gt;::before&lt;/span&gt;&lt;span class="o"&gt;,*&lt;/span&gt;&lt;span class="nd"&gt;::after&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;box-sizing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;border-box&lt;/span&gt;&lt;span class="p"&gt;;}&lt;/span&gt;
&lt;span class="c"&gt;/* RelaxCSS Preflight: margin-padding */&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;,...,&lt;/span&gt;&lt;span class="nt"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;}&lt;/span&gt;
&lt;span class="c"&gt;/* ... other preflight rules ... */&lt;/span&gt;

&lt;span class="c"&gt;/* Utility classes */&lt;/span&gt;
&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#222&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;768px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.md&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nd"&gt;:bg-&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="err"&gt;\#333\&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#333&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In the example above, &lt;code&gt;.container&lt;/code&gt; got &lt;code&gt;display:flex&lt;/code&gt; (from the &lt;code&gt;flex&lt;/code&gt; utility) and &lt;code&gt;background-color:#222&lt;/code&gt; (from &lt;code&gt;bg-[#222]&lt;/code&gt;). The &lt;code&gt;md:hover:bg-[#333]&lt;/code&gt; utility generated a media query rule for screens &lt;code&gt;&amp;gt;=768px&lt;/code&gt; with the selector &lt;code&gt;.md:hover:bg-[#333]:hover&lt;/code&gt;.&lt;/p&gt;
&lt;h1&gt;
  
  
  Example Output and Live Usage
&lt;/h1&gt;

&lt;p&gt;Suppose we have an input CSS file like &lt;code&gt;src/input.css&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* src/input.css */&lt;/span&gt;
&lt;span class="k"&gt;@relax&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;@apply&lt;/span&gt; &lt;span class="err"&gt;flex&lt;/span&gt; &lt;span class="err"&gt;bg-[#222]&lt;/span&gt; &lt;span class="py"&gt;md&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;hover&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;bg-&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;#333&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.my-box&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;@apply&lt;/span&gt; &lt;span class="err"&gt;fancy-border;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.ravi&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;@apply&lt;/span&gt; &lt;span class="err"&gt;text-2xl;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.kishan&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;@apply&lt;/span&gt; &lt;span class="err"&gt;text-3xl;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here we use &lt;code&gt;@relax;&lt;/code&gt; to trigger the plugin, and we apply several utilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;flex&lt;/code&gt;, &lt;code&gt;bg-[#222]&lt;/code&gt;, and &lt;code&gt;md:hover:bg-[#333]&lt;/code&gt; on &lt;code&gt;.container&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;fancy-border&lt;/code&gt; on &lt;code&gt;.my-box&lt;/code&gt; (this was a custom utility from the default plugin).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;text-2xl&lt;/code&gt; and &lt;code&gt;text-3xl&lt;/code&gt; on &lt;code&gt;.ravi&lt;/code&gt; and &lt;code&gt;.kishan&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Running RelaxCSS on this (&lt;code&gt;npx ts-node src/cli-watch.ts "src/**/*.{css,html,js,jsx,ts,tsx}" --out dist/output.css&lt;/code&gt;) will produce a &lt;code&gt;dist/output.css&lt;/code&gt; roughly like:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* RelaxCSS Preflight: box-sizing */&lt;/span&gt;
&lt;span class="o"&gt;*,*&lt;/span&gt;&lt;span class="nd"&gt;::before&lt;/span&gt;&lt;span class="o"&gt;,*&lt;/span&gt;&lt;span class="nd"&gt;::after&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;box-sizing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;border-box&lt;/span&gt;&lt;span class="p"&gt;;}&lt;/span&gt;
&lt;span class="c"&gt;/* RelaxCSS Preflight: margin-padding */&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;h4&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;h5&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;h6&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;ol&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;figure&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;figcaption&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;blockquote&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;dl&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;}&lt;/span&gt;
&lt;span class="c"&gt;/* ... other preflight rules ... */&lt;/span&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#222&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;768px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.md&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nd"&gt;:bg-&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="err"&gt;\#333\&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#333&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="nc"&gt;.my-box&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="nb"&gt;dashed&lt;/span&gt; &lt;span class="no"&gt;magenta&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.ravi&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.kishan&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.875rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.25rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For live usage, one might have an HTML file like:&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;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"m-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hover:bg-blue-500 hover:text-white md:hover:bg-blue-700 bg-[#222]"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Hover over me
  &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;When RelaxCSS processes this (in JIT mode), it will generate the equivalent CSS so that the button responds to hover and changes background/text color as expected.&lt;/p&gt;
&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;RelaxCSS is a compact, flexible framework for utility-first styling, suitable for frontend developers and framework authors who want Tailwind-like productivity with a smaller footprint. It leverages a &lt;strong&gt;PostCSS plugin&lt;/strong&gt; to parse utility class names (&lt;code&gt;p-4&lt;/code&gt;, &lt;code&gt;text-blue-500&lt;/code&gt;, &lt;code&gt;hover:bg-red-200&lt;/code&gt;, etc.) and emit the corresponding CSS using values from a &lt;strong&gt;theme configuration&lt;/strong&gt;. The &lt;strong&gt;CLI/JIT&lt;/strong&gt; engine watches your files and includes only the utilities you actually use, keeping the CSS minimal. The &lt;strong&gt;plugin system&lt;/strong&gt; lets you define your own utilities or copy Tailwind’s plugin approach. By supporting arbitrary values (&lt;code&gt;bg-[#222]&lt;/code&gt;), responsive prefixes (&lt;code&gt;md:&lt;/code&gt;) and variants (&lt;code&gt;hover:&lt;/code&gt;), plus a built-in preflight reset, RelaxCSS covers most needs of modern utility-based development.&lt;/p&gt;

&lt;p&gt;For advanced use, you can extend RelaxCSS by adding more functions to &lt;code&gt;generateUtilityCss&lt;/code&gt;, writing plugins with &lt;code&gt;addUtilities&lt;/code&gt;, or customizing the configuration. Because it’s just a PostCSS plugin and Node script, you could even integrate it into larger build tools or frameworks. Overall, RelaxCSS aims to be a learning-friendly, extensible alternative to Tailwind for projects where you want control over the utility engine’s internals. Users can build on this foundation – for example, adding support for more CSS features or improving performance – thanks to its clear architecture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sources:&lt;/strong&gt; The above explanations and code snippets are drawn directly from the RelaxCSS source files (e.g. &lt;code&gt;index.ts&lt;/code&gt;, &lt;code&gt;cli-watch.ts&lt;/code&gt;, &lt;code&gt;base.css&lt;/code&gt;).&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Ravikisha" rel="noopener noreferrer"&gt;
        Ravikisha
      &lt;/a&gt; / &lt;a href="https://github.com/Ravikisha/RelaxCSS" rel="noopener noreferrer"&gt;
        RelaxCSS
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A next-generation, Tailwind-like JIT CSS/PostCSS plugin with a powerful plugin system, support for arbitrary values, variants (including dark mode and RTL), efficient watch mode, and CSS variable theme support.  RelaxCSS can be used as a PostCSS plugin (recommended for most build pipelines) or as a standalone CLI tool.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;p&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/25b192c6b99c5cc9ee753bf44a208bea66ffabc7dbb0e43169dbaeae89cefcf1/68747470733a2f2f726176696b697368612e6769746875622e696f2f6173736574732f72656c61786373735f6c6f676f2e706e67"&gt;&lt;img src="https://camo.githubusercontent.com/25b192c6b99c5cc9ee753bf44a208bea66ffabc7dbb0e43169dbaeae89cefcf1/68747470733a2f2f726176696b697368612e6769746875622e696f2f6173736574732f72656c61786373735f6c6f676f2e706e67" alt="RelaxCSS Logo" width="200"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;RelaxCSS&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/12648c2ce61ec5b0cd3ac890a4e58227b4383a99d2cfc699f0f0bbc3a1db2aca/68747470733a2f2f736869656c64732e696f2f62616467652f547970655363726970742d3331373843363f6c6f676f3d54797065536372697074266c6f676f436f6c6f723d464646267374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/12648c2ce61ec5b0cd3ac890a4e58227b4383a99d2cfc699f0f0bbc3a1db2aca/68747470733a2f2f736869656c64732e696f2f62616467652f547970655363726970742d3331373843363f6c6f676f3d54797065536372697074266c6f676f436f6c6f723d464646267374796c653d666c61742d737175617265" alt="Typescript Logo"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/08c91bdd8420a2513ed7d16fd83a8b5253054e5e94c9c277d00bf28a1559d8d0/68747470733a2f2f736869656c64732e696f2f62616467652f4a6176615363726970742d4637444631453f6c6f676f3d4a617661536372697074266c6f676f436f6c6f723d303030267374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/08c91bdd8420a2513ed7d16fd83a8b5253054e5e94c9c277d00bf28a1559d8d0/68747470733a2f2f736869656c64732e696f2f62616467652f4a6176615363726970742d4637444631453f6c6f676f3d4a617661536372697074266c6f676f436f6c6f723d303030267374796c653d666c61742d737175617265" alt="JavaScript Logo"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/1504d358626062a15d1b2cd5da02d3497c67502055f18e9a13e48f46769fd688/68747470733a2f2f736869656c64732e696f2f62616467652f506f73744353532d3030303030303f6c6f676f3d506f7374435353266c6f676f436f6c6f723d464646267374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/1504d358626062a15d1b2cd5da02d3497c67502055f18e9a13e48f46769fd688/68747470733a2f2f736869656c64732e696f2f62616467652f506f73744353532d3030303030303f6c6f676f3d506f7374435353266c6f676f436f6c6f723d464646267374796c653d666c61742d737175617265" alt="PostCSS Logo"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/6b1af2dc96fa8b32f9bdc35d0f15085e6ff534810d868167c4636238015aba8c/68747470733a2f2f736869656c64732e696f2f62616467652f4e6f64652e6a732d3333393933333f6c6f676f3d4e6f64652e6a73266c6f676f436f6c6f723d464646267374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/6b1af2dc96fa8b32f9bdc35d0f15085e6ff534810d868167c4636238015aba8c/68747470733a2f2f736869656c64732e696f2f62616467652f4e6f64652e6a732d3333393933333f6c6f676f3d4e6f64652e6a73266c6f676f436f6c6f723d464646267374796c653d666c61742d737175617265" alt="Node.js Logo"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/5cfde9ac032dd6b75594ba4cddca5cd484de755ed112485d2e460895cbf747ad/68747470733a2f2f736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d626c75653f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/5cfde9ac032dd6b75594ba4cddca5cd484de755ed112485d2e460895cbf747ad/68747470733a2f2f736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d626c75653f7374796c653d666c61742d737175617265" alt="MIT License"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;A next-generation, Tailwind-like JIT CSS/PostCSS plugin with a powerful plugin system, support for arbitrary values, variants (including dark mode and RTL), efficient watch mode, and CSS variable theme support.&lt;/p&gt;

&lt;p&gt;RelaxCSS can be used as a &lt;strong&gt;PostCSS plugin&lt;/strong&gt; (recommended for most build pipelines) or as a standalone CLI tool.&lt;/p&gt;




&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;PostCSS Plugin Usage&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;RelaxCSS is a drop-in &lt;a href="https://postcss.org/" rel="nofollow noopener noreferrer"&gt;PostCSS&lt;/a&gt; plugin. It works with PostCSS v8+ and integrates with any PostCSS-based build system (Webpack, Vite, Parcel, etc).&lt;/p&gt;

&lt;div class="highlight highlight-source-js notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;// postcss.config.js&lt;/span&gt;
&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;relaxcss&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;require&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'relaxcss'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-smi"&gt;module&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;exports&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-c1"&gt;plugins&lt;/span&gt;: &lt;span class="pl-kos"&gt;[&lt;/span&gt;
    &lt;span class="pl-en"&gt;require&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'postcss-import'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-c"&gt;// must be first&lt;/span&gt;
    &lt;span class="pl-s1"&gt;relaxcss&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt;
      &lt;span class="pl-c"&gt;// custom config here&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-en"&gt;require&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'autoprefixer'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-c"&gt;// ...&lt;/span&gt;
  &lt;span class="pl-kos"&gt;]&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Supports all RelaxCSS features: JIT utilities, plugins, variants, dark mode, RTL, CSS variables, and more.&lt;/li&gt;
&lt;li&gt;Use your &lt;code&gt;relaxcss.config.js&lt;/code&gt; for custom configuration.&lt;/li&gt;
&lt;li&gt;Compatible with PostCSS v8+ and all major build…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Ravikisha/RelaxCSS" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;




&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://www.npmjs.com/package/relaxcss" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;npmjs.com&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Building a Container Runtime from Scratch with Go (MyDocker)</title>
      <dc:creator>Ravi Kishan</dc:creator>
      <pubDate>Thu, 05 Jun 2025 13:25:34 +0000</pubDate>
      <link>https://dev.to/ravikishan/building-a-container-runtime-from-scratch-with-go-mydocker-o7p</link>
      <guid>https://dev.to/ravikishan/building-a-container-runtime-from-scratch-with-go-mydocker-o7p</guid>
      <description>&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Introduction: What is a Container Runtime?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Namespaces: Isolating Processes on Linux&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Control Groups (cgroups): Managing Resources&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Project Architecture: The MyDocker Design&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command-Line Interface and Main.go&lt;/li&gt;
&lt;li&gt;Container Lifecycle (&lt;code&gt;startContainer&lt;/code&gt;, &lt;code&gt;child&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Networking Isolation (Bridge and veth)&lt;/li&gt;
&lt;li&gt;Image Handling and OCI Unpacking&lt;/li&gt;
&lt;li&gt;Volumes and Port Mappings&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Diagrams: Visualizing the Runtime&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Getting Started and Resources&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Containers are lightweight, isolated environments for running applications. Unlike virtual machines, containers share the host kernel but &lt;strong&gt;isolate&lt;/strong&gt; processes using kernel features like namespaces and cgroups. In this tutorial we’ll explore &lt;em&gt;MyDocker&lt;/em&gt;, a simple container runtime written in Go, and walk through the key pieces that make it work. We’ll explain how MyDocker uses Linux namespaces (UTS, PID, network, mount, etc.) to isolate the container’s view of the system, and how it uses cgroups to limit resources. Along the way we’ll show key code snippets (e.g. &lt;code&gt;startContainer&lt;/code&gt;, &lt;code&gt;child&lt;/code&gt;, &lt;code&gt;execContainer&lt;/code&gt;) and outline MyDocker’s architecture for CLI commands, networking, and image handling. By the end, you’ll see how MyDocker’s internals fit together, and how OCI image unpacking with tools like &lt;em&gt;umoci&lt;/em&gt; and simple mount/iptables tricks provide the functionality of &lt;code&gt;docker pull&lt;/code&gt;, &lt;code&gt;run&lt;/code&gt;, &lt;code&gt;exec&lt;/code&gt;, and more. We encourage you to check out the [MyDocker GitHub repository][22] and its [README][26] for examples and to try extending the code yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Namespaces
&lt;/h2&gt;

&lt;p&gt;Linux &lt;strong&gt;namespaces&lt;/strong&gt; provide isolation by giving a process its own “view” of system resources. For example, PID namespaces mean a process can see only processes in its own container; UTS namespaces let each container have its own hostname; mount namespaces give each container its own filesystem root; network namespaces provide separate network interfaces/iptables, and so on. In other words, namespaces prevent processes in one container from seeing or affecting those in another. This isolation is a cornerstone of container security: “namespaces are quite flexible…they can be applied individually or in groups to one or more processes”. MyDocker’s container “child” process is created with clone flags for multiple namespaces (UTS, PID, NET, mount, etc.), so it runs in isolation. The code roughly follows the pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// In main or run command:&lt;/span&gt;
&lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/proc/self/exe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"child"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SysProcAttr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;syscall&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SysProcAttr&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Cloneflags&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;syscall&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CLONE_NEWUTS&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
                &lt;span class="n"&gt;syscall&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CLONE_NEWPID&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
                &lt;span class="n"&gt;syscall&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CLONE_NEWNET&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
                &lt;span class="n"&gt;syscall&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CLONE_NEWNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c"&gt;// etc.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stdin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stderr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stdin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stderr&lt;/span&gt;
&lt;span class="n"&gt;must&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="c"&gt;// The child() function runs inside the new namespaces:&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// e.g., set hostname inside UTS namespace&lt;/span&gt;
    &lt;span class="n"&gt;syscall&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sethostname&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mydocker"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="c"&gt;// Possibly mount proc, chroot, pivot_root, etc.&lt;/span&gt;
    &lt;span class="c"&gt;// Finally exec the requested command:&lt;/span&gt;
    &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stdin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stderr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stdin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stderr&lt;/span&gt;
    &lt;span class="n"&gt;must&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;As in other “container-from-scratch” examples, this pattern uses &lt;code&gt;exec.Command("/proc/self/exe", "child", …)&lt;/code&gt; to re-invoke the same program in a new process (in new namespaces). From outside, the &lt;code&gt;run&lt;/code&gt; command spawns the namespaced child; inside the container, the &lt;code&gt;child&lt;/code&gt; function does setup (hostname, filesystem mounts, etc.) and then executes the user’s command. This effectively gives the container its own isolated environment &lt;strong&gt;separate&lt;/strong&gt; from the host.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure: Container runtime architecture. MyDocker creates a namespaced “child” process for each container, mounts a fresh root filesystem (unpacked from an OCI image), applies cgroup limits, and sets up networking (bridge &lt;code&gt;mydocker0&lt;/code&gt; and veth pair). The CLI (main.go) drives commands like &lt;code&gt;run&lt;/code&gt;, &lt;code&gt;exec&lt;/code&gt;, &lt;code&gt;pull&lt;/code&gt;, etc.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In summary, namespaces ensure that processes in MyDocker containers see only their own CPU, memory, filesystems, networks, and process list. This is one of the fundamental layers of container isolation. (MyDocker’s README also highlights this as a core feature: “Container process isolation using Linux namespaces (UTS, PID, NET, MNT)”.)&lt;/p&gt;
&lt;h2&gt;
  
  
  Control Groups (cgroups)
&lt;/h2&gt;

&lt;p&gt;While namespaces isolate &lt;em&gt;what&lt;/em&gt; a process sees, cgroups control &lt;em&gt;how much&lt;/em&gt; of a resource a process can use. A &lt;strong&gt;control group&lt;/strong&gt; (cgroup) is a Linux kernel feature that limits, accounts for, and isolates resource usage (CPU, memory, I/O, etc.) of a group of processes. MyDocker uses cgroups so that each container process has its own CPU and memory limits (as defined by CLI flags). For example, it might create a new cgroup under &lt;code&gt;/sys/fs/cgroup/cpu/mydocker/&amp;lt;id&amp;gt;&lt;/code&gt; and write the PID of the container process into it, along with any limits (like &lt;code&gt;cpu.shares&lt;/code&gt; or &lt;code&gt;memory.limit_in_bytes&lt;/code&gt;). This means the container will only get a fraction of CPU or a fixed amount of memory, protecting the host and other containers.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Cgroups are a kernel feature that allows you to partition and limit the system resources… that a group of processes can use. Think of them as virtual cages where you can corral your processes and set rules for their behavior”&lt;/em&gt;. (This quote describes cgroups in general; MyDocker uses them specifically for CPU and memory limits.)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For instance, MyDocker might contain code like:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Simplified: create a cpu cgroup for the container&lt;/span&gt;
&lt;span class="n"&gt;cgroupPath&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/sys/fs/cgroup/cpu/mydocker"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;containerID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MkdirAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cgroupPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0755&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;// write the container's PID into the cgroup.procs file&lt;/span&gt;
&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cgroupPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"cgroup.procs"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pidStr&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="m"&gt;0644&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;// optionally set limits like cpu.shares or memory.limit_in_bytes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This ensures each container is “in its own cage”. The MyDocker README emphasizes resource control: “Resource control via cgroups (CPU &amp;amp; Memory)”. By combining cgroups with namespaces, the runtime isolates both the &lt;em&gt;view&lt;/em&gt; and &lt;em&gt;resources&lt;/em&gt; of each container process, similarly to how Docker does it behind the scenes.&lt;/p&gt;
&lt;h2&gt;
  
  
  Project Architecture
&lt;/h2&gt;

&lt;p&gt;MyDocker’s source is structured simply (see [Architecture Overview][100]). At the top level we have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;main.go&lt;/code&gt; – The CLI entry point: parses commands like &lt;code&gt;run&lt;/code&gt;, &lt;code&gt;exec&lt;/code&gt;, &lt;code&gt;pull&lt;/code&gt;, etc. It calls functions like &lt;code&gt;startContainer()&lt;/code&gt; or &lt;code&gt;execContainer()&lt;/code&gt; accordingly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;cgroups/&lt;/code&gt; – Go package to set up cgroup directories and limits.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;network/&lt;/code&gt; – Go package to create a bridge (&lt;code&gt;mydocker0&lt;/code&gt;) and virtual ethernet (veth) pairs for container networking.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;helper.c&lt;/code&gt; – A small C program that is used to join existing namespaces (see below).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Other files: e.g. configuration templates, documentation.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The architecture overview in the README summarizes this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Architecture Overview: &lt;code&gt;main.go&lt;/code&gt; — The CLI and container runtime entry point; &lt;code&gt;cgroups/&lt;/code&gt; — resource limits; &lt;code&gt;network/&lt;/code&gt; — bridge networks/veth; &lt;code&gt;/var/lib/mydocker/&lt;/code&gt; — stores metadata/images”&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So when you run something like &lt;code&gt;sudo ./mydocker run -v /data:/data -p 8080:80 ubuntu:22.04 sh&lt;/code&gt;, what happens? A brief walkthrough:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CLI (&lt;code&gt;main.go&lt;/code&gt;)&lt;/strong&gt;: The program parses the &lt;code&gt;run&lt;/code&gt; command and container options (image name, mounts, ports, etc.). It likely calls a function &lt;code&gt;startContainer(containerID, command, flags...)&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;startContainer&lt;/strong&gt;: This function creates a unique container ID, sets up storage (image unpack, rootfs), sets up networking, then spawns a child process in new namespaces (using &lt;code&gt;exec.Command("/proc/self/exe", ...)&lt;/code&gt; as above). It also records container metadata (like PID, rootfs path) under &lt;code&gt;/var/lib/mydocker/&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Child process&lt;/strong&gt;: In the new namespaces, it does further initialization: e.g., performs &lt;code&gt;chroot&lt;/code&gt;/&lt;code&gt;pivot_root&lt;/code&gt; into the unpacked image root filesystem; mounts the host directory if &lt;code&gt;-v&lt;/code&gt; was given; configures networking (calls &lt;code&gt;net.SetupVeth()&lt;/code&gt; to move one end of a veth into this namespace); then finally execs the user’s command (e.g. &lt;code&gt;sh&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Networking&lt;/strong&gt;: The &lt;code&gt;network/&lt;/code&gt; code ensures there is a Linux bridge (e.g. &lt;code&gt;mydocker0&lt;/code&gt;) on the host. It creates a veth pair, moves one end into the child’s net namespace (as &lt;code&gt;eth0&lt;/code&gt;), and attaches the other end to the &lt;code&gt;mydocker0&lt;/code&gt; bridge, giving the container network access (with its own IP).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cgroups&lt;/strong&gt;: Concurrently, before or after spawning the child, MyDocker creates new cgroup entries under CPU/memory controllers and adds the child’s PID, enforcing resource limits on that container.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Image Unpacking&lt;/strong&gt;: For pulling images, MyDocker uses &lt;a href="https://github.com/opencontainers/umoci" rel="noopener noreferrer"&gt;&lt;code&gt;umoci&lt;/code&gt;&lt;/a&gt;. The &lt;code&gt;pull&lt;/code&gt; command downloads an OCI image (like Ubuntu) and uses &lt;code&gt;umoci unpack&lt;/code&gt; to extract it into a directory under &lt;code&gt;/var/lib/mydocker&lt;/code&gt;. &lt;em&gt;Umoci&lt;/em&gt; documentation explains: &lt;em&gt;“umoci unpack - Unpacks an OCI image tag into a runtime bundle”&lt;/em&gt;. In other words, MyDocker relies on umoci to convert a container image into a rootfs directory with config, just like Docker does with layered filesystems.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&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%2Fkpony5dgbndp3im94v0p.jpg" 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%2Fkpony5dgbndp3im94v0p.jpg" alt="MyDocker Architecture"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Command-Line Interface and Main.go
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;main.go&lt;/code&gt; file defines the CLI commands (&lt;code&gt;run&lt;/code&gt;, &lt;code&gt;exec&lt;/code&gt;, &lt;code&gt;ps&lt;/code&gt;, etc.) using a library like &lt;a href="https://github.com/urfave/cli" rel="noopener noreferrer"&gt;urfave/cli&lt;/a&gt;. For example, when the user runs &lt;code&gt;mydocker run ...&lt;/code&gt;, it ends up invoking something like:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;runCommandAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cli&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;imageName&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;flags&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GlobalFlags&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;containerID&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;generateID&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;startContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;containerID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;imageName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The core functions include &lt;strong&gt;&lt;code&gt;startContainer&lt;/code&gt;&lt;/strong&gt; (for &lt;code&gt;run&lt;/code&gt;) and &lt;strong&gt;&lt;code&gt;ExecContainer&lt;/code&gt;&lt;/strong&gt; (for &lt;code&gt;exec&lt;/code&gt;). In MyDocker, &lt;code&gt;startContainer&lt;/code&gt; will unpack the image if needed, set up cgroups/networks, then clone a new process.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;&lt;code&gt;execContainer&lt;/code&gt;&lt;/strong&gt; function (called by &lt;code&gt;mydocker exec&lt;/code&gt;) is also interesting. It finds the PID of an existing container process (by reading stored metadata) and then uses &lt;code&gt;exec.Command("/proc/self/exe", "exec")&lt;/code&gt; to fork a helper process that enters that container’s namespaces (via a small C helper). Part of the code might look like:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;ExecContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;containerID&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;comArray&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;getPidByContainerId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;containerID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;// Set environment variables for the helper C program:&lt;/span&gt;
    &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/proc/self/exe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"exec"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Setenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mydocker_pid"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Setenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mydocker_cmd"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stdin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stderr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stdin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stderr&lt;/span&gt;
    &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This tells the re-invoked process to run the &lt;code&gt;"exec"&lt;/code&gt; branch of &lt;code&gt;main()&lt;/code&gt;. The helper C code (in &lt;code&gt;helper.c&lt;/code&gt;) sees &lt;code&gt;mydocker_pid&lt;/code&gt;/&lt;code&gt;mydocker_cmd&lt;/code&gt; and performs &lt;code&gt;setns()&lt;/code&gt; calls to join the PID/UTS/NET namespaces of that container, then uses &lt;code&gt;system(mydocker_cmd)&lt;/code&gt; to run the desired command inside the container. (In effect, &lt;code&gt;mydocker exec&lt;/code&gt; adds your shell to the existing container’s namespaces, letting you run commands inside it.) The Chinese blog [89] illustrates this pattern clearly. The key idea is: &lt;em&gt;we fork a new process that points itself into the container’s namespaces and execs the command as if we were inside the container&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Container Lifecycle (&lt;code&gt;startContainer&lt;/code&gt;, &lt;code&gt;child&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Putting it all together, MyDocker’s container lifecycle roughly is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Start&lt;/strong&gt;: User runs &lt;code&gt;mydocker run ...&lt;/code&gt;. The Go &lt;code&gt;main.go&lt;/code&gt; calls &lt;code&gt;startContainer(...)&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Setup&lt;/strong&gt;: In &lt;code&gt;startContainer&lt;/code&gt;, MyDocker creates a directory for the container under &lt;code&gt;/var/lib/mydocker/&amp;lt;id&amp;gt;&lt;/code&gt;. It unpacks the OCI image rootfs there (if not done already), creates cgroups, sets up network (bridge/veth), and prepares the command arguments.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Clone (run)&lt;/strong&gt;: The code then does something like:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/proc/self/exe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"child"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;commandArgs&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stdin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stderr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stdin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stderr&lt;/span&gt;
&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SysProcAttr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;syscall&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SysProcAttr&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Cloneflags&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CLONE_NEWUTS&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;CLONE_NEWPID&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;CLONE_NEWNET&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;CLONE_NEWNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;UidMappings&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;GidMappings&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c"&gt;// blocks until container process exits&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This effectively forks into a &lt;strong&gt;child&lt;/strong&gt; process that will run &lt;code&gt;mydocker child ...&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Child setup&lt;/strong&gt;: In the &lt;code&gt;child()&lt;/code&gt; function inside Go, the process is now in fresh namespaces. It performs actions similar to Docker’s container init:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Calls `syscall.Chroot()` or `pivot_root()` to switch the root filesystem to the unpacked image.

- Applies mounts and volume binds (`syscall.Mount()`) for any `-v host:container` flags.

- Calls `net.SetupVeth()` to move one end of the veth into this namespace and bring up the network interface.

- Executes the container’s init process (e.g., `exec.Command("/bin/sh")`).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Run&lt;/strong&gt;: The container process (PID 1 in its PID namespace) starts and runs user code. Meanwhile, the parent Go process (still the original CLI) waits (or returns immediately if detached).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stop&lt;/strong&gt;: When the container’s main process exits (e.g. you exit the shell), the child function returns. &lt;code&gt;startContainer&lt;/code&gt; (the parent) will then do cleanup: remove cgroups, delete metadata, etc.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The code for &lt;code&gt;startContainer&lt;/code&gt; and &lt;code&gt;child&lt;/code&gt; in MyDocker is similar in spirit to many "from-scratch Docker" examples (e.g. [86]). For instance, the parent uses &lt;code&gt;exec.Command("/proc/self/exe", "child", …)&lt;/code&gt; to create the child. Inside &lt;code&gt;child&lt;/code&gt;, Go code uses syscalls (&lt;code&gt;Mount&lt;/code&gt;, &lt;code&gt;Chroot&lt;/code&gt;, &lt;code&gt;Sethostname&lt;/code&gt;, etc.) to finish setting up the namespace, then &lt;code&gt;exec.Command&lt;/code&gt; to run the actual command. Though we can’t cite the MyDocker source directly here, conceptually it follows the pattern above.&lt;/p&gt;
&lt;h3&gt;
  
  
  Networking
&lt;/h3&gt;

&lt;p&gt;By default, containers should be able to talk to each other and the outside world (on certain ports). MyDocker’s &lt;code&gt;network/&lt;/code&gt; package likely does the following (in Go, via the &lt;a href="https://github.com/vishvananda/netlink" rel="noopener noreferrer"&gt;vishvananda/netlink&lt;/a&gt; library or raw syscalls):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Ensure a Linux bridge exists (named &lt;code&gt;mydocker0&lt;/code&gt;). If not, create it with &lt;code&gt;ip link add name mydocker0 type bridge&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For each new container, create a veth pair (e.g. &lt;code&gt;veth-host&lt;/code&gt; and &lt;code&gt;veth-container&lt;/code&gt;). Move &lt;code&gt;veth-container&lt;/code&gt; into the new namespace of the child (with &lt;code&gt;netlink.LinkSetNsFd&lt;/code&gt;) and rename it to &lt;code&gt;eth0&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Bring up &lt;code&gt;eth0&lt;/code&gt; inside the container and assign it an IP (e.g. via &lt;code&gt;ip addr&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Attach &lt;code&gt;veth-host&lt;/code&gt; to the &lt;code&gt;mydocker0&lt;/code&gt; bridge and bring it up on the host.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This way, containers get an IP on the &lt;code&gt;mydocker0&lt;/code&gt; network, and host-side NAT (iptables MASQUERADE) handles outbound traffic and port mapping. MyDocker’s README mentions a &lt;em&gt;custom bridge network (&lt;code&gt;mydocker0&lt;/code&gt;) and veth pairs for network isolation&lt;/em&gt;. (In our blog, we won’t go into all the iptables details, but that’s how host ports get forwarded: the CLI probably calls &lt;code&gt;iptables -t nat&lt;/code&gt; rules so that &lt;code&gt;-p host:container&lt;/code&gt; flags forward TCP from the host port to the container’s IP:port.)&lt;/p&gt;
&lt;h3&gt;
  
  
  Image Handling and OCI Unpacking
&lt;/h3&gt;

&lt;p&gt;Container images (like &lt;code&gt;ubuntu:22.04&lt;/code&gt;) come in the OCI/Docker image format. MyDocker supports pulling and unpacking these images using the &lt;a href="https://github.com/opencontainers/umoci" rel="noopener noreferrer"&gt;&lt;code&gt;umoci&lt;/code&gt;&lt;/a&gt; tool. The &lt;code&gt;mydocker pull&lt;/code&gt; command likely shells out to &lt;code&gt;umoci pull&lt;/code&gt; or similar, then &lt;code&gt;umoci unpack&lt;/code&gt;. As &lt;a href="https://manpages.debian.org/testing/umoci/umoci-unpack.1.en.html" rel="noopener noreferrer"&gt;the umoci manual&lt;/a&gt; states: &lt;em&gt;“umoci unpack – Unpacks an OCI image tag into a runtime bundle”&lt;/em&gt;. In practice, MyDocker runs something like:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;umoci unpack &lt;span class="nt"&gt;--image&lt;/span&gt; ubuntu:22.04 /var/lib/mydocker/images/ubuntu_22.04
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This extracts the image layers and config into a directory that becomes the container’s root filesystem. MyDocker then stores this location (under &lt;code&gt;/var/lib/mydocker/&lt;/code&gt;) so that future &lt;code&gt;run&lt;/code&gt; commands can use the rootfs directly without repulling. The unpacked bundle includes &lt;code&gt;/rootfs&lt;/code&gt; with all files and a JSON config. MyDocker’s Go code then &lt;code&gt;chroot&lt;/code&gt;-es into that &lt;code&gt;/rootfs&lt;/code&gt; when starting a container.&lt;/p&gt;

&lt;p&gt;Using umoci (or a similar OCI utility) is important because it handles the layered filesystem format of images. Without overlay support, MyDocker unpacks into a single directory per image. The README cites &lt;em&gt;“Simple OCI image unpacking using &lt;code&gt;umoci&lt;/code&gt;”&lt;/em&gt; as a feature.&lt;/p&gt;
&lt;h3&gt;
  
  
  Volumes and Port Mappings
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Volumes (&lt;code&gt;-v&lt;/code&gt;)&lt;/strong&gt;: If the user specifies &lt;code&gt;-v /host/dir:/container/dir&lt;/code&gt;, MyDocker will mount a bind mount inside the container namespace. The Go code in &lt;code&gt;child()&lt;/code&gt; would do something like:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;syscall&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/host/dir"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/container/dir"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;syscall&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MS_BIND&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;after switching to the new root. This makes the host’s directory appear at the given path in the container. It relies on the mount namespace being isolated, so only the container sees the mount (the host’s filesystem is shared, but the namespace separates the mount list).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Port mappings (&lt;code&gt;-p&lt;/code&gt;)&lt;/strong&gt;: For &lt;code&gt;-p hostPort:containerPort&lt;/code&gt;, the runtime must forward network traffic. A simple approach: on the host, use &lt;code&gt;iptables&lt;/code&gt; to NAT traffic from &lt;code&gt;hostPort&lt;/code&gt; into the container’s IP and &lt;code&gt;containerPort&lt;/code&gt;. For example:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;iptables &lt;span class="nt"&gt;-t&lt;/span&gt; nat &lt;span class="nt"&gt;-A&lt;/span&gt; PREROUTING &lt;span class="nt"&gt;-p&lt;/span&gt; tcp &lt;span class="nt"&gt;--dport&lt;/span&gt; &amp;lt;hostPort&amp;gt; &lt;span class="nt"&gt;-j&lt;/span&gt; DNAT &lt;span class="nt"&gt;--to-destination&lt;/span&gt; &amp;lt;containerIP&amp;gt;:&amp;lt;containerPort&amp;gt;
iptables &lt;span class="nt"&gt;-t&lt;/span&gt; nat &lt;span class="nt"&gt;-A&lt;/span&gt; POSTROUTING &lt;span class="nt"&gt;-j&lt;/span&gt; MASQUERADE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This way, if a service inside the container listens on &lt;code&gt;containerPort&lt;/code&gt;, requests to &lt;code&gt;localhost:hostPort&lt;/code&gt; on the host will reach it. MyDocker’s implementation likely sets up such iptables rules automatically when starting the container, and removes them on stop. This achieves “port mapping” similar to Docker.&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%2Fpl9w5krg5y8h7yerw8ya.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%2Fpl9w5krg5y8h7yerw8ya.png" alt="MyDocker 1 Diagram 1"&gt;&lt;/a&gt;&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%2F34zozgijlgsgxi99yg8c.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%2F34zozgijlgsgxi99yg8c.png" alt="MyDocker 1 Diagram 2"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Diagrams
&lt;/h2&gt;

&lt;p&gt;Below are some visual aids (using PlantUML) to illustrate the architecture and isolation concepts. These diagrams are simplified schematics.&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%2Fbwoovdo7mhpzrclmrkeu.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%2Fbwoovdo7mhpzrclmrkeu.png" alt=" "&gt;&lt;/a&gt;&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%2Fkvxnt59ruasi5vwam0xb.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%2Fkvxnt59ruasi5vwam0xb.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These diagrams outline how the host CLI and services collaborate to create an isolated container process. In particular, the second diagram emphasizes that once the container process (&lt;code&gt;C&lt;/code&gt;) is created, it has its own namespace instances and cannot see the host’s unrelated processes or network stacks.&lt;/p&gt;
&lt;h2&gt;
  
  
  Getting Started and Resources
&lt;/h2&gt;

&lt;p&gt;MyDocker is intended as a learning tool to explore container internals. It “demonstrates how containerization works under the hood” and helps you understand namespaces, cgroups, and image formats. You can try it out by following the &lt;a href="https://github.com/Ravikisha/MyDocker/blob/main/README.md" rel="noopener noreferrer"&gt;README instructions&lt;/a&gt;: for example, pull an image (&lt;code&gt;mydocker pull ubuntu:22.04&lt;/code&gt;) and run it (&lt;code&gt;mydocker run -it -v /data:/data -p 8080:80 ubuntu:22.04 bash&lt;/code&gt;) as shown in the usage examples. You’ll see your process isolated (check &lt;code&gt;ps&lt;/code&gt; and hostname inside the container, and network connectivity to the bridge).&lt;/p&gt;

&lt;p&gt;We encourage you to explore the &lt;a href="https://github.com/Ravikisha/MyDocker" rel="noopener noreferrer"&gt;Project Files&lt;/a&gt; (which includes source code and examples) and even extend it. Possible exercises include adding features like Dockerfile builds, overlayfs support, or enhanced networking. By tinkering with MyDocker’s code, you’ll gain a deep understanding of what happens in every &lt;code&gt;docker run&lt;/code&gt; command. Happy hacking and containerizing!&lt;/p&gt;

&lt;p&gt;Check out the github repo:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Ravikisha" rel="noopener noreferrer"&gt;
        Ravikisha
      &lt;/a&gt; / &lt;a href="https://github.com/Ravikisha/MyDocker" rel="noopener noreferrer"&gt;
        MyDocker
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      MyDocker is a lightweight container runtime built from scratch in Go that demonstrates how containerization works under the hood — similar to Docker but in a simplified form.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/Ravikisha/MyDocker/./mydocker_docs/mydocker_banner.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FRavikisha%2FMyDocker%2F.%2Fmydocker_docs%2Fmydocker_banner.png" alt="MyDocker Banner"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🐳 MyDocker&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;MyDocker&lt;/strong&gt; is a lightweight container runtime built from scratch in Go that demonstrates how containerization works under the hood — similar to Docker but in a simplified form.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/ravikisha/mydocker" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;&lt;/p&gt;




&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🚀 Features&lt;/h2&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Container process isolation using Linux namespaces (&lt;code&gt;UTS&lt;/code&gt;, &lt;code&gt;PID&lt;/code&gt;, &lt;code&gt;NET&lt;/code&gt;, &lt;code&gt;NS&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Resource control via cgroups (CPU &amp;amp; Memory)&lt;/li&gt;
&lt;li&gt;Volume mounting (&lt;code&gt;-v host:container&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Port mapping support (&lt;code&gt;-p host:container&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Simple OCI image unpacking using &lt;code&gt;umoci&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Container image pulling, listing, and execution&lt;/li&gt;
&lt;li&gt;Custom bridge network (&lt;code&gt;mydocker0&lt;/code&gt;) and veth pairs for network isolation&lt;/li&gt;
&lt;li&gt;Command-line interface similar to Docker (&lt;code&gt;run&lt;/code&gt;, &lt;code&gt;exec&lt;/code&gt;, &lt;code&gt;ps&lt;/code&gt;, &lt;code&gt;stop&lt;/code&gt;, &lt;code&gt;pull&lt;/code&gt;, &lt;code&gt;images&lt;/code&gt;, &lt;code&gt;version&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;




&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🎯 Architecture&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/Ravikisha/MyDocker/./mydocker_docs/diagram.jpg"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FRavikisha%2FMyDocker%2F.%2Fmydocker_docs%2Fdiagram.jpg" alt="Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;📦 Installation&lt;/h2&gt;

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Requirements&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go 1.19+&lt;/li&gt;
&lt;li&gt;Root access (for namespace and networking)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;umoci&lt;/code&gt; tool installed and in &lt;code&gt;$PATH&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Linux OS (recommended: Ubuntu)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;git clone https://github.com/ravikisha/mydocker.git
&lt;span class="pl-c1"&gt;cd&lt;/span&gt; mydocker
go build -o mydocker main.go
sudo ./mydocker version&lt;/pre&gt;

&lt;/div&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Ravikisha/MyDocker" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Introducing RelaxLang: A Beginner-Friendly Programming Language</title>
      <dc:creator>Ravi Kishan</dc:creator>
      <pubDate>Thu, 16 Jan 2025 19:30:05 +0000</pubDate>
      <link>https://dev.to/ravikishan/introducing-relaxlang-a-beginner-friendly-programming-language-33i9</link>
      <guid>https://dev.to/ravikishan/introducing-relaxlang-a-beginner-friendly-programming-language-33i9</guid>
      <description>&lt;p&gt;In the vast and ever-evolving world of programming languages, creating one from scratch is a feat that blends art, science, and a touch of magic. Today, I am excited to introduce &lt;strong&gt;RelaxLang&lt;/strong&gt;, a simple yet powerful interpreted programming language. Inspired by Robert Nystrom's &lt;em&gt;Crafting Interpreters&lt;/em&gt; and the Lox programming language, RelaxLang is designed to be accessible for beginners while being feature-rich for enthusiasts who want to dive deeper into language design and implementation.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Why RelaxLang?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;RelaxLang stems from a vision to provide a lightweight, easy-to-understand programming language that serves as both a learning tool and a practical solution for basic scripting needs. Built with &lt;strong&gt;Java&lt;/strong&gt; and &lt;strong&gt;C&lt;/strong&gt;, it offers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Typing:&lt;/strong&gt; Simplifies coding by inferring variable types at runtime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;First-Class Functions:&lt;/strong&gt; Enables functional programming paradigms by treating functions as first-class citizens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Classes and Inheritance:&lt;/strong&gt; Introduces object-oriented programming with a straightforward syntax.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-In Standard Library:&lt;/strong&gt; Provides out-of-the-box utilities for string manipulation, array operations, and more.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whether you're an aspiring developer eager to learn how programming languages work or a seasoned programmer seeking an educational tool, RelaxLang caters to you.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Architecture&lt;/strong&gt;
&lt;/h3&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%2Faamtspl73ex250i3uqkc.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%2Faamtspl73ex250i3uqkc.png" alt="RelaxLang Diagram" width="800" height="493"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Key Features of RelaxLang&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. &lt;strong&gt;Dynamic Typing&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;In RelaxLang, you don’t need to worry about specifying types for variables. The interpreter takes care of it, allowing you to focus on logic and creativity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var name = "RelaxLang";  // Automatically inferred as String
var version = 1.0;       // Automatically inferred as Float
var isActive = true;     // Automatically inferred as Boolean

print(name);            // Output: RelaxLang
print(version);         // Output: 1.0
print(isActive);        // Output: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. &lt;strong&gt;First-Class Functions&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Functions are versatile in RelaxLang. They can be assigned to variables, passed as arguments, and even returned from other functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fun add(a, b) {
    return a + b;
}

var sum = add(5, 3);
print(sum);  // Output: 8

fun operate(func, x, y) {
    return func(x, y);
}

var result = operate(add, 10, 15);
print(result);  // Output: 25
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. &lt;strong&gt;Classes and Inheritance&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;RelaxLang supports object-oriented programming, making it a great tool to understand and implement OOP concepts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Animal {
    var name;

    init(name) {
        this.name = name;
    }

    fun speak() {
        print(this.name + " makes a sound.");
    }
}

class Dog &amp;lt; Animal {
    fun speak() {
        print(this.name + " barks.");
    }
}

var myDog = Dog("Buddy");
myDog.speak();  // Output: Buddy barks.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4. &lt;strong&gt;Control Flow&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;With intuitive &lt;code&gt;if-else&lt;/code&gt; statements and loops, you can control the flow of your programs effortlessly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var age = 18;

if (age &amp;lt; 18) {
    print("Minor");
} else {
    print("Adult");
}

for (var i = 0; i &amp;lt; 5; i = i + 1) {
    print(i);  // Output: 0 1 2 3 4
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;How to Get Started&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1. Prerequisites&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Ensure you have the following installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Java JDK 11 or later&lt;/strong&gt; (&lt;a href="https://www.oracle.com/java/technologies/javase-jdk11-downloads.html" rel="noopener noreferrer"&gt;Download here&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;(Optional) &lt;strong&gt;Docker&lt;/strong&gt; for a containerized setup&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;2. Installation&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Clone the Repository:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Ravikisha/RelaxLang.git
&lt;span class="nb"&gt;cd &lt;/span&gt;RelaxLang
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Compile the Source Code:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;javac src/&lt;span class="k"&gt;*&lt;/span&gt;.java
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;3. Running RelaxLang&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Using the JAR File:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;java &lt;span class="nt"&gt;-jar&lt;/span&gt; lox.jar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Using Docker:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull ravikishan63392/relaxlang:lastest
docker run &lt;span class="nt"&gt;-it&lt;/span&gt; ravikishan63392/relaxlang:lastest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;Example Usage&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;RelaxLang scripts are simple to write and execute. For instance, here’s a script &lt;code&gt;example.rl&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fun greet(name) {
    print("Hello, " + name + "!");
}

greet("World");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;java &lt;span class="nt"&gt;-jar&lt;/span&gt; lox.jar example.rl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;The Technical Journey&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;RelaxLang’s implementation involves:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Lexical Analysis:&lt;/strong&gt; Breaking down source code into tokens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parsing:&lt;/strong&gt; Constructing an Abstract Syntax Tree (AST) from tokens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interpreting:&lt;/strong&gt; Executing the AST by traversing it node by node.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Developed in &lt;strong&gt;Java&lt;/strong&gt; for platform independence and in &lt;strong&gt;C&lt;/strong&gt; for low-level optimizations, RelaxLang’s design reflects a balance between simplicity and functionality.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Resources and Contributions&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Docker Image:&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://hub.docker.com/repository/docker/ravikishan63392/relaxlang/" rel="noopener noreferrer"&gt;RelaxLang Docker Image&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;GitHub Repository:&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://github.com/Ravikisha/RelaxLang" rel="noopener noreferrer"&gt;RelaxLang on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We welcome contributions! Whether it's bug fixes, feature requests, or documentation improvements, your input makes RelaxLang better. Please check out the contributing guidelines in the repository.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Final Thoughts&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;RelaxLang is not just a programming language; it’s a journey into the heart of language design. By exploring its features, experimenting with scripts, and diving into its implementation, you can gain insights into how modern programming languages work.&lt;/p&gt;

&lt;p&gt;Give RelaxLang a try and embark on this exciting adventure. Let’s code, learn, and relax!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>tutorial</category>
      <category>learning</category>
      <category>java</category>
    </item>
    <item>
      <title>Building RelaxTube: A Scalable Video Transcoding and Streaming Application</title>
      <dc:creator>Ravi Kishan</dc:creator>
      <pubDate>Tue, 14 Jan 2025 18:34:42 +0000</pubDate>
      <link>https://dev.to/ravikishan/building-relaxtube-a-scalable-video-transcoding-and-streaming-application-3i4a</link>
      <guid>https://dev.to/ravikishan/building-relaxtube-a-scalable-video-transcoding-and-streaming-application-3i4a</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;RelaxTube is a feature-rich and scalable application designed to demonstrate the workflow of video transcoding and streaming. The project highlights the use of modern technologies like Node.js, React, Kafka, FFmpeg, MongoDB, and Docker. It efficiently processes videos by transcoding them into multiple quality levels, segmenting them for smoother streaming, and generating thumbnail previews.&lt;/p&gt;

&lt;p&gt;This blog explores the architecture, key features, tech stack, installation, and potential enhancements for RelaxTube.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Video Transcoding&lt;/strong&gt;: Converts videos into multiple quality levels (360p, 480p, 720p, 1080p) using FFmpeg.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HLS Segmentation&lt;/strong&gt;: Generates video segments for efficient HTTP Live Streaming (HLS) playback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thumbnail Generation&lt;/strong&gt;: Automatically creates thumbnail previews for each uploaded video.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch Processing&lt;/strong&gt;: Supports concurrent video processing using Kafka message queues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalable Design&lt;/strong&gt;: Built to handle increased loads and integrate with distributed systems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage and Metadata&lt;/strong&gt;: Manages video files in local storage and metadata in MongoDB.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Project Architecture
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuys5b1yhux2j8dyfjim6.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%2Fuys5b1yhux2j8dyfjim6.png" alt="Diagram" width="759" height="638"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Components
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend (React)&lt;/strong&gt;: Provides a user-friendly interface for video uploads, management, and playback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend (Node.js with Express)&lt;/strong&gt;: Handles API requests, video processing workflows, and communication with Kafka.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kafka&lt;/strong&gt;: Manages message queues for efficient batch processing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transcoding Service (FFmpeg)&lt;/strong&gt;: Handles video transcoding, segmentation, and thumbnail creation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MongoDB&lt;/strong&gt;: Stores metadata like video information, quality levels, and thumbnails.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;File Storage&lt;/strong&gt;: Stores processed video files and thumbnails locally.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Node.js&lt;/strong&gt;: Backend logic and API endpoints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React&lt;/strong&gt;: Frontend for user interaction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kafka&lt;/strong&gt;: Manages distributed message queues for scalability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FFmpeg&lt;/strong&gt;: Performs video transcoding, segmentation, and thumbnail generation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MongoDB&lt;/strong&gt;: Stores metadata and provides quick access to processed data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker&lt;/strong&gt;: Ensures easy setup and consistent environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TailwindCSS&lt;/strong&gt;: Enhances the frontend with modern styling.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Installation and Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Install &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Install &lt;a href="https://nodejs.org/" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; (v16 or higher).&lt;/li&gt;
&lt;li&gt;Clone the repository:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   git clone https://github.com/Ravikisha/RelaxTube.git
   &lt;span class="nb"&gt;cd &lt;/span&gt;RelaxTube
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Steps
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Run Docker Compose&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install Dependencies&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;cd &lt;/span&gt;frontend &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;install
   cd&lt;/span&gt; ../backend &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;install
   cd&lt;/span&gt; ../transcoding-service &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Start Services&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Backend:
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;backend
 npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Frontend:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;frontend
 npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Transcoding Service:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;transcoding-service
 npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Access the Application&lt;/strong&gt;
Open your browser and navigate to &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Upload Videos&lt;/strong&gt;: Users can upload videos through the frontend interface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Processing&lt;/strong&gt;: The backend processes the videos by:

&lt;ul&gt;
&lt;li&gt;Transcoding them to multiple quality levels.&lt;/li&gt;
&lt;li&gt;Segmenting videos for HLS playback.&lt;/li&gt;
&lt;li&gt;Generating thumbnails.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streaming&lt;/strong&gt;: Processed videos are available for streaming via the frontend.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch Processing&lt;/strong&gt;: Upload multiple videos for concurrent processing.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Screenshots
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Homepage
&lt;/h3&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%2F6ev1atpvdy5qi05ee52k.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%2F6ev1atpvdy5qi05ee52k.png" alt="Home Page" width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Video Playback
&lt;/h3&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%2Fndzn342bft8q5f205oxr.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%2Fndzn342bft8q5f205oxr.png" alt="Video Playback" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Quality Selection
&lt;/h3&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%2Fu66grti6f967yl16jw2l.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%2Fu66grti6f967yl16jw2l.png" alt="Quality" width="800" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Upload Interface
&lt;/h3&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%2Fyf9manf3dw4cqlvlkh7g.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%2Fyf9manf3dw4cqlvlkh7g.png" alt="Upload" width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Batch Upload
&lt;/h3&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%2F40imn37cy2sdk904jkbm.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%2F40imn37cy2sdk904jkbm.png" alt="Batch Upload" width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Scalability Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Batch Processing&lt;/strong&gt;: Process multiple videos simultaneously using Kafka.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distributed Workers&lt;/strong&gt;: Scale horizontally by adding workers for transcoding tasks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Load Balancing&lt;/strong&gt;: Distribute incoming requests across multiple backend servers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Storage&lt;/strong&gt;: Potential integration with AWS S3 or Google Cloud Storage for large-scale storage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring&lt;/strong&gt;: Use tools like Prometheus or Grafana for real-time monitoring and performance tracking.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Future Enhancements
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Cloud deployment for global access and scalability.&lt;/li&gt;
&lt;li&gt;Advanced analytics for tracking user interactions and video performance.&lt;/li&gt;
&lt;li&gt;User authentication and access control.&lt;/li&gt;
&lt;li&gt;Caching mechanisms for faster access to frequently requested content.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Contributing
&lt;/h2&gt;

&lt;p&gt;We welcome contributions to RelaxTube! Feel free to submit pull requests, report issues, or suggest new features.&lt;/p&gt;

&lt;h2&gt;
  
  
  License
&lt;/h2&gt;

&lt;p&gt;RelaxTube is licensed under the MIT License. See the &lt;a href="https://github.com/Ravikisha/RelaxTube/blob/main/LICENSE" rel="noopener noreferrer"&gt;LICENSE&lt;/a&gt; file for details.&lt;/p&gt;




&lt;p&gt;Start exploring RelaxTube by visiting the &lt;a href="https://github.com/Ravikisha/RelaxTube" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>mern</category>
      <category>kafka</category>
      <category>systemdesign</category>
      <category>docker</category>
    </item>
    <item>
      <title>Building Scalable Web Applications with Microfrontends: A Detailed Walkthrough of Microfrontend Blog</title>
      <dc:creator>Ravi Kishan</dc:creator>
      <pubDate>Sun, 29 Dec 2024 14:23:36 +0000</pubDate>
      <link>https://dev.to/ravikishan/building-scalable-web-applications-with-microfrontends-a-detailed-walkthrough-of-microfrontend-blog-2hlp</link>
      <guid>https://dev.to/ravikishan/building-scalable-web-applications-with-microfrontends-a-detailed-walkthrough-of-microfrontend-blog-2hlp</guid>
      <description>&lt;h4&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;In the rapidly evolving world of web development, creating scalable, maintainable, and modular applications is more important than ever. Enter &lt;strong&gt;microfrontend architecture&lt;/strong&gt;—a game-changing approach that divides a monolithic frontend into smaller, independently deployable pieces. &lt;/p&gt;

&lt;p&gt;This blog introduces &lt;strong&gt;Microfrontend Blog&lt;/strong&gt;, a real-world implementation of microfrontends built using cutting-edge technologies like &lt;strong&gt;React&lt;/strong&gt;, &lt;strong&gt;TailwindCSS&lt;/strong&gt;, &lt;strong&gt;Clerk&lt;/strong&gt;, &lt;strong&gt;Module Federation&lt;/strong&gt;, and &lt;strong&gt;Firebase Firestore&lt;/strong&gt;. Whether you're an experienced developer or just getting started with microfrontends, this project is a comprehensive guide to building modular web applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub Repository&lt;/strong&gt;: &lt;a href="https://github.com/Ravikisha/Microfrontend-Blog" rel="noopener noreferrer"&gt;Microfrontend Blog&lt;/a&gt;&lt;/p&gt;




&lt;h4&gt;
  
  
  &lt;strong&gt;Project Overview&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Microfrontend Blog&lt;/strong&gt; is a blogging platform designed to demonstrate the power of microfrontend architecture. It splits the application into five key modules:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Auth Microfrontend&lt;/strong&gt;: Handles user authentication using &lt;strong&gt;Clerk&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dashboard Microfrontend&lt;/strong&gt;: Allows users to create, edit, and manage blogs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Viewer Microfrontend&lt;/strong&gt;: Displays blogs with comment functionality.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shared Components&lt;/strong&gt;: A library of reusable components like headers, footers, and blog cards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Container&lt;/strong&gt;: Orchestrates the integration of all microfrontends.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By adopting &lt;strong&gt;Module Federation&lt;/strong&gt;, each microfrontend is developed and deployed independently, enabling seamless collaboration across teams and simplifying the scaling process.&lt;/p&gt;




&lt;h4&gt;
  
  
  &lt;strong&gt;Features&lt;/strong&gt;
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Authentication&lt;/strong&gt;: Secure login and signup with Clerk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blog Management&lt;/strong&gt;: A rich dashboard for managing blogs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blog Viewing&lt;/strong&gt;: Interactive blog display with a comments section.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsive UI&lt;/strong&gt;: Styled with &lt;strong&gt;TailwindCSS&lt;/strong&gt; for consistency across devices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: Independent deployment of microfrontends.&lt;/li&gt;
&lt;/ol&gt;




&lt;h4&gt;
  
  
  &lt;strong&gt;Technologies Used&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;React&lt;/strong&gt;: The foundation for building the UI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TailwindCSS&lt;/strong&gt;: A utility-first CSS framework for modern designs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clerk&lt;/strong&gt;: A robust authentication library.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Firebase Firestore&lt;/strong&gt;: Cloud-based database for blog storage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Module Federation&lt;/strong&gt;: Simplifies microfrontend integration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Webpack&lt;/strong&gt;: Efficient module bundler for development and production.&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  &lt;strong&gt;Architecture Diagram&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The architecture demonstrates the interaction between microfrontends, the container, and backend services:&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%2F02gyzxyvl5w700dlc6hv.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%2F02gyzxyvl5w700dlc6hv.png" alt="Microfrontend Diagram" width="800" height="511"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h4&gt;
  
  
  &lt;strong&gt;Getting Started&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;1. Prerequisites&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install &lt;strong&gt;Node.js&lt;/strong&gt; (v16+).&lt;/li&gt;
&lt;li&gt;Clone the repository:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  git clone https://github.com/Ravikisha/Microfrontend-Blog.git
  &lt;span class="nb"&gt;cd &lt;/span&gt;Microfrontend-Blog
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Install Dependencies&lt;/strong&gt;&lt;br&gt;
For each microfrontend and shared components, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &amp;lt;microfrontend-folder&amp;gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Start the Development Server&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Access the Application&lt;/strong&gt;&lt;br&gt;
Visit &lt;a href="http://localhost:3005" rel="noopener noreferrer"&gt;http://localhost:3005&lt;/a&gt; to view the application.&lt;/p&gt;




&lt;h4&gt;
  
  
  &lt;strong&gt;Screenshots&lt;/strong&gt;
&lt;/h4&gt;

&lt;h2&gt;
  
  
  Screenshots
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Home Page&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&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%2Fg1ihk0n6scjtzecwo7w2.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%2Fg1ihk0n6scjtzecwo7w2.png" alt="Home Page" width="800" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Login Page&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&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%2Fw9fm8d503ne5ayhd4vxn.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%2Fw9fm8d503ne5ayhd4vxn.png" alt="Login Page" width="682" height="683"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create Blog&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&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%2Fiob4hn96c1o8pbnyco5r.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%2Fiob4hn96c1o8pbnyco5r.png" alt="Create Blog" width="800" height="357"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;View Blog&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&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%2F6xjajfxylcpg473y4f2p.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%2F6xjajfxylcpg473y4f2p.png" alt="Content 1" width="800" height="367"&gt;&lt;/a&gt;&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%2Fscm418y6bfy6i7t2l5fv.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%2Fscm418y6bfy6i7t2l5fv.png" alt="Content 2" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  MicroFrontend Screenshots
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Auth Microfrontend&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&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%2Fyriixnzb5cdfqgpuddzu.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%2Fyriixnzb5cdfqgpuddzu.png" alt="Auth Mfe" width="800" height="358"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Dashboard Microfrontend&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&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%2Fpj3iutrlxb5591vlozm4.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%2Fpj3iutrlxb5591vlozm4.png" alt="Dashboard mfe" width="800" height="315"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Viewer Microfrontend&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&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%2F1jedmxrkmgk5vznhq4uh.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%2F1jedmxrkmgk5vznhq4uh.png" alt="Viewer Mfe" width="800" height="363"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Shared Components&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&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%2F98c5nah5y2pviu5qfa3n.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%2F98c5nah5y2pviu5qfa3n.png" alt="Shared mfe" width="800" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Container&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&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%2Fypeiuatln3m8qedzjp1o.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%2Fypeiuatln3m8qedzjp1o.png" alt="Container mfe" width="800" height="361"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h4&gt;
  
  
  &lt;strong&gt;Key Benefits of Microfrontend Architecture&lt;/strong&gt;
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Independent Development&lt;/strong&gt;: Teams can work on different microfrontends without stepping on each other's toes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: Easily scale individual modules based on demand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reusability&lt;/strong&gt;: Shared components streamline development and ensure design consistency.&lt;/li&gt;
&lt;/ol&gt;




&lt;h4&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The &lt;strong&gt;Microfrontend Blog&lt;/strong&gt; project serves as a practical example of how microfrontend architecture can simplify development and improve scalability. With technologies like &lt;strong&gt;React&lt;/strong&gt;, &lt;strong&gt;TailwindCSS&lt;/strong&gt;, and &lt;strong&gt;Module Federation&lt;/strong&gt;, developers can create robust and maintainable applications that meet modern web development demands.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explore the code and start building your modular applications today!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub Repository&lt;/strong&gt;: &lt;a href="https://github.com/Ravikisha/Microfrontend-Blog" rel="noopener noreferrer"&gt;Microfrontend Blog&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Would you like me to add more details, such as common troubleshooting tips or deeper dives into individual microfrontends?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>Introducing Stylesnap: Optimize Your CSS Like Never Before</title>
      <dc:creator>Ravi Kishan</dc:creator>
      <pubDate>Sun, 29 Dec 2024 14:04:56 +0000</pubDate>
      <link>https://dev.to/ravikishan/introducing-stylesnap-optimize-your-css-like-never-before-508f</link>
      <guid>https://dev.to/ravikishan/introducing-stylesnap-optimize-your-css-like-never-before-508f</guid>
      <description>&lt;p&gt;In the ever-evolving world of web development, efficiency and optimization are paramount. Meet &lt;strong&gt;Stylesnap&lt;/strong&gt;, a cutting-edge solution for CSS optimization that simplifies your workflow and boosts performance. Designed for developers, this handy tool minimizes your CSS files by analyzing your project’s content and retaining only the styles you truly need.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;What is Stylesnap?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Stylesnap is an NPX package tailored for modern web development. It scans your codebase—HTML, JSX, or any supported files—and generates a lightweight, optimized CSS file that eliminates unused styles. Whether you're using popular frameworks like Bootstrap, TailwindCSS, or custom CSS, Stylesnap has you covered.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Key Features&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Selective CSS Extraction&lt;/strong&gt;: Extracts only the required class names, tags, and selectors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Framework Compatibility&lt;/strong&gt;: Works seamlessly with CSS frameworks or custom styles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minification&lt;/strong&gt;: Automatically minifies the generated CSS for improved performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Configurations&lt;/strong&gt;: Offers a customizable workflow using &lt;code&gt;stylesnap.config.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Command-Line Simplicity&lt;/strong&gt;: Easy-to-use CLI for quick integration.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Why Choose Stylesnap?&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced Performance&lt;/strong&gt;: Smaller CSS files mean faster page loads and better user experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintainability&lt;/strong&gt;: Eliminates unused CSS, making your stylesheets cleaner and easier to manage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility&lt;/strong&gt;: Compatible with various frameworks and custom setups.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developer-Friendly&lt;/strong&gt;: Simple installation, intuitive CLI options, and detailed documentation.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Getting Started&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Installation&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Use npm to install Stylesnap as a development dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;stylesnap &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or run it directly with NPX:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx stylesnap
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h4&gt;
  
  
  &lt;strong&gt;Usage&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Stylesnap’s CLI makes it easy to optimize your CSS. Here’s a quick example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Initialize Configuration&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   npx stylesnap &lt;span class="nt"&gt;--init&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a &lt;code&gt;stylesnap.config.json&lt;/code&gt; file in your project.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Update Configuration&lt;/strong&gt;:
Edit the file to suit your project’s needs:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"content"&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="s2"&gt;"./src/**/*.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./src/**/*.jsx"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"css"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./src/styles.css"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./dist/optimized.css"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"minify"&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;ol&gt;
&lt;li&gt;
&lt;strong&gt;Run Stylesnap&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   npx stylesnap
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your optimized CSS will be saved at the specified output location.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Real-World Benefits&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;By using Stylesnap, you’ll see immediate improvements in your development and deployment process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Faster Load Times&lt;/strong&gt;: Reduced CSS file size enhances website speed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smaller Builds&lt;/strong&gt;: Ideal for production environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streamlined Debugging&lt;/strong&gt;: With unused CSS eliminated, debugging becomes simpler.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Links&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Repository&lt;/strong&gt;: &lt;a href="https://github.com/Ravikisha/stylesnap" rel="noopener noreferrer"&gt;https://github.com/Ravikisha/stylesnap&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NPM Package&lt;/strong&gt;: &lt;a href="https://www.npmjs.com/package/stylesnap" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/stylesnap&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Contribute&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Stylesnap is open-source, and contributions are welcome! If you encounter any issues or have ideas for improvement, feel free to open an issue or submit a pull request.&lt;/p&gt;




&lt;p&gt;Start optimizing your CSS today with Stylesnap! 🚀 Streamline your workflow, boost performance, and take your web development projects to the next level.&lt;/p&gt;

</description>
      <category>css</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>A Comprehensive Guide to Building a Single Sign-On (SSO) Gateway with Node.js</title>
      <dc:creator>Ravi Kishan</dc:creator>
      <pubDate>Sun, 22 Dec 2024 17:13:18 +0000</pubDate>
      <link>https://dev.to/ravikishan/a-comprehensive-guide-to-building-a-single-sign-on-sso-gateway-with-nodejs-4lj4</link>
      <guid>https://dev.to/ravikishan/a-comprehensive-guide-to-building-a-single-sign-on-sso-gateway-with-nodejs-4lj4</guid>
      <description>&lt;p&gt;Single Sign-On (SSO) systems have become critical in today's interconnected application ecosystems. By allowing users to log in once and access multiple applications seamlessly, SSO simplifies authentication, enhances user experience, and bolsters security. This blog dives into the implementation of an SSO Gateway using Node.js, Express, and MongoDB, guiding you through its features, architecture, setup, and best practices.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;What is a Single Sign-On Gateway?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;An SSO Gateway is a centralized authentication system where users authenticate once and gain access to multiple interconnected applications without needing to reauthenticate. The Node-SSO-Gateway project demonstrates a robust yet simple implementation of such a system.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Key Features of the Node-SSO-Gateway&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Centralized Authentication&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users log in via a single SSO server, eliminating the need for multiple logins.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Token-Based Authorization&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Secure, stateless communication between the SSO server and consumer applications via JSON Web Tokens (JWT).
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cross-Domain Session Management&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maintain seamless user sessions across multiple applications and domains.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;MongoDB Integration&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Secure storage of user credentials with robust password hashing (e.g., bcrypt).
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Dynamic Consumer App Registration&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consumer applications can dynamically register themselves with the SSO server for authentication.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Logout Functionality&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supports global and local session termination for enhanced security.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;System Architecture&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The system is divided into three primary components:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SSO Server&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The central hub that authenticates users, manages sessions, and issues JWT tokens.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Consumer Applications (Clients)&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Applications relying on the SSO server for authentication. Each client establishes a local session after verifying the token.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MongoDB&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
A database backend to securely store user data, including email and hashed passwords.  &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Architecture Diagram
&lt;/h4&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%2Fczja9mczemlqg0na73ct.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%2Fczja9mczemlqg0na73ct.png" alt="SSO Diagram" width="800" height="217"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;How Does It Work?&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;User Login&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users log in through the SSO server. Upon successful authentication, the server issues a JWT token and redirects the user to the desired consumer app.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Token Validation&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consumer apps verify the JWT token with the SSO server before granting access to protected resources.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Session Management&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Both global (SSO server) and local (consumer app) sessions are managed, ensuring secure and consistent access.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Logout&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users can log out from the SSO server, terminating the global session, or from a consumer app, terminating the local session.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Setting Up the Node-SSO-Gateway&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1. Prerequisites&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Node.js and npm installed.
&lt;/li&gt;
&lt;li&gt;MongoDB instance running (local or cloud-based).
&lt;/li&gt;
&lt;li&gt;Basic knowledge of JWT, Express, and MongoDB.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;2. Clone the Repository&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Ravikisha/Node-SSO-Gateway.git
&lt;span class="nb"&gt;cd &lt;/span&gt;Node-SSO-Gateway
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;3. Install Dependencies&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Navigate to the root directory of each component and install the required packages.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For the SSO Server&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;For Consumer Applications&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="c"&gt;# In another terminal&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;client2
npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;4. Configure MongoDB&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file in both the SSO Server and consumer apps with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;MONGODB_URI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;mongodb://localhost:27017/sso-db
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;5. Start the Applications&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Start the SSO Server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;server
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start the consumer apps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;client1
npm run dev

&lt;span class="c"&gt;# In another terminal&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;client2
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;6. Test the System&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Visit &lt;code&gt;http://localhost:3000&lt;/code&gt; to access the SSO server login page.
&lt;/li&gt;
&lt;li&gt;Successfully log in to be redirected to consumer apps (&lt;code&gt;http://localhost:3001&lt;/code&gt; and &lt;code&gt;http://localhost:3002&lt;/code&gt;).
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Adding New Consumer Applications&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create a new app following the structure of &lt;code&gt;client1&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Register the app’s domain in the SSO Server’s &lt;code&gt;allowedOrigin&lt;/code&gt; configuration.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;allowedOrigin&lt;/span&gt; &lt;span class="o"&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:3001&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3002&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3003&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Redirect authentication requests to the SSO Server.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Security Best Practices&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;HTTPS Everywhere&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use HTTPS in production to ensure encrypted communication.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Secure JWT Storage&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Store JWT securely, preferably in HTTP-only cookies, to prevent XSS attacks.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Validate Origins&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Validate consumer app origins to prevent unauthorized requests.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Password Hashing&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use strong hashing algorithms like bcrypt for storing user passwords.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Logout Functionality&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Local Logout&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Removes the session from the consumer app only.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Global Logout&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Terminates the session on the SSO Server, logging the user out from all consumer apps.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Screenshots&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Login Page
&lt;/h4&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%2Fhm0a2jqxk69erwfvczie.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%2Fhm0a2jqxk69erwfvczie.png" alt="SSO Login Page" width="800" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  SSO Server Page
&lt;/h4&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%2Ftzxr0ayl3de773y95okq.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%2Ftzxr0ayl3de773y95okq.png" alt="SSO Server Page" width="800" height="59"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  Consumer Application (Client1)
&lt;/h4&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%2Fbq5k5f1pqvcfinoir7gw.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%2Fbq5k5f1pqvcfinoir7gw.png" alt="SSO Client 1" width="800" height="129"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Consumer Application (Client2)
&lt;/h4&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%2Fyfghy9jk9t1zwqykux6c.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%2Fyfghy9jk9t1zwqykux6c.png" alt="SSO Client 2" width="800" height="142"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The Node-SSO-Gateway project offers a secure and scalable solution for centralized authentication across multiple applications. By leveraging modern web technologies like Node.js, Express, and JWT, the system ensures a seamless user experience and robust security. Whether you're building a microservices-based architecture or integrating multiple platforms, this SSO solution is a solid foundation for managing authentication effectively.  &lt;/p&gt;

&lt;p&gt;Explore the repository &lt;a href="https://github.com/Ravikisha/Node-SSO-Gateway" rel="noopener noreferrer"&gt;here&lt;/a&gt; and get started with centralized authentication today!&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>node</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Building a Feature-Rich Load Balancer in TypeScript: A Detailed Overview</title>
      <dc:creator>Ravi Kishan</dc:creator>
      <pubDate>Sun, 22 Dec 2024 16:45:02 +0000</pubDate>
      <link>https://dev.to/ravikishan/building-a-feature-rich-load-balancer-in-typescript-a-detailed-overview-1f4f</link>
      <guid>https://dev.to/ravikishan/building-a-feature-rich-load-balancer-in-typescript-a-detailed-overview-1f4f</guid>
      <description>&lt;p&gt;Load balancers are essential components of modern distributed systems, ensuring scalability, fault tolerance, and optimal resource utilization. In this blog, we’ll explore the development and capabilities of a custom &lt;strong&gt;Load Balancer Implementation in TypeScript&lt;/strong&gt;—a project that combines advanced load-balancing algorithms, health checks, self-healing mechanisms, and webhook notifications. This implementation mirrors the functionality of industry-standard tools like &lt;strong&gt;NGINX&lt;/strong&gt; and &lt;strong&gt;HAProxy&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  GitHub Repository
&lt;/h4&gt;

&lt;p&gt;You can explore the complete project on GitHub: &lt;a href="https://github.com/Ravikisha/Load-Balancer-Implementation" rel="noopener noreferrer"&gt;Load Balancer Implementation&lt;/a&gt;.&lt;/p&gt;




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

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Easy Configuration:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Configure all aspects of the load balancer through a &lt;code&gt;config.json&lt;/code&gt; file. This includes backend server details, health check intervals, and load-balancing algorithms.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Load Balancing Algorithms:&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Random:&lt;/strong&gt; Requests are sent to a randomly selected backend server.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Round-Robin:&lt;/strong&gt; Requests are distributed sequentially among backend servers.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weighted Round-Robin:&lt;/strong&gt; Backend servers are prioritized based on assigned weights.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Health Checks:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Periodic pings to backend servers ensure only healthy servers receive traffic. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Self-Healing:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Automatically attempts to recover downed servers, with a configurable success rate.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Retries and Redirects:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Failed requests are retried on alternative healthy servers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Webhook Alerts:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Notify administrators of server failures via custom webhook triggers. Alerts include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Individual server failures.&lt;/li&gt;
&lt;li&gt;Total backend server failure.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scalability:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The modular design allows for easy addition or removal of backend servers.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Project Structure
&lt;/h2&gt;

&lt;p&gt;The repository contains the following components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Backend Server Simulation:&lt;/strong&gt; Simulates multiple backend servers for load balancing.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Load Balancer Core:&lt;/strong&gt; Manages traffic, health checks, retries, and notifications.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuration File:&lt;/strong&gt; Allows users to define the behavior of the load balancer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Fdocs%2Fposter.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/.%2Fdocs%2Fposter.png" alt="Poster" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Install &lt;strong&gt;Node.js&lt;/strong&gt; and &lt;strong&gt;npm&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Clone the repository:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   git clone https://github.com/Ravikisha/Load-Balancer-Implementation.git
   &lt;span class="nb"&gt;cd &lt;/span&gt;Load-Balancer-Implementation
   npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Running the Application
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start Backend Servers:&lt;/strong&gt;
Run multiple backend servers on different ports using the command:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   npm run dev:be 8081
   npm run dev:be 8082
   npm run dev:be 8083
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Launch the Load Balancer:&lt;/strong&gt;
Start the load balancer on the specified port:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   npm run dev:lb 8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Send Requests:&lt;/strong&gt;
Use a tool like Postman or Curl to send HTTP requests to the load balancer at &lt;code&gt;http://localhost:8000&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Testing and Monitoring
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Simulate Backend Server Failures:&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kill a backend server process.&lt;/li&gt;
&lt;li&gt;Observe automatic request redirection to other healthy servers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Webhook Alerts:&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configure a webhook URL in &lt;code&gt;config.json&lt;/code&gt; for real-time alerts.&lt;/li&gt;
&lt;li&gt;Use services like &lt;a href="https://typedwebhook.tools/" rel="noopener noreferrer"&gt;Typed Webhook&lt;/a&gt; to test notifications.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Self-Healing:&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check the logs for attempts to restart failed servers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Configuration Options
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;config.json&lt;/code&gt; file governs the behavior of the load balancer. Key parameters include:&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;"lbPORT"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"_lbAlgo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rr"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"be_servers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"domain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:8081"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"weight"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"domain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:8082"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"weight"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"domain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:8083"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"weight"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"be_retries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"health_check_interval"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"send_alert_webhook"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://webhook.site/your-webhook"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"enableSelfHealing"&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;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;_lbAlgo&lt;/code&gt;&lt;/strong&gt;: Choose between &lt;code&gt;rand&lt;/code&gt;, &lt;code&gt;rr&lt;/code&gt;, or &lt;code&gt;wrr&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;be_servers&lt;/code&gt;&lt;/strong&gt;: Define backend servers and their weights.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;send_alert_webhook&lt;/code&gt;&lt;/strong&gt;: Specify a webhook URL for notifications.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;enableSelfHealing&lt;/code&gt;&lt;/strong&gt;: Enable or disable server recovery attempts.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Insights and Learning Outcomes
&lt;/h2&gt;

&lt;p&gt;Developing this load balancer provided insights into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Traffic Distribution Techniques:&lt;/strong&gt; Understanding how different algorithms impact performance and fairness.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fault Tolerance:&lt;/strong&gt; Designing systems that gracefully handle failures and recover automatically.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alerting Mechanisms:&lt;/strong&gt; Using webhooks to keep administrators informed in real-time.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuration Management:&lt;/strong&gt; Simplifying user experience through JSON-based settings.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Challenges and Future Scope
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Challenges:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Ensuring low latency during health checks and retries.&lt;/li&gt;
&lt;li&gt;Managing detached processes spawned during self-healing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Future Enhancements:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced Health Checks:&lt;/strong&gt; Add support for more complex health-check mechanisms.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSL/TLS Support:&lt;/strong&gt; Enable secure communication between clients and backend servers.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Scaling:&lt;/strong&gt; Integrate with cloud APIs to dynamically scale backend server pools.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This project demonstrates how a TypeScript-based load balancer can achieve features similar to enterprise-grade solutions like &lt;strong&gt;NGINX&lt;/strong&gt; or &lt;strong&gt;AWS ELB&lt;/strong&gt;. With robust fault tolerance, advanced load-balancing algorithms, and real-time alerting, this implementation serves as a practical example for developers looking to understand the inner workings of load balancers.&lt;/p&gt;

&lt;p&gt;Explore the project on &lt;a href="https://github.com/Ravikisha/Load-Balancer-Implementation" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, try it out, and contribute to its future enhancements!&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>cloud</category>
      <category>aws</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Introducing GitaVerse: Access Bhagavad Gita Verses Programmatically 🚀</title>
      <dc:creator>Ravi Kishan</dc:creator>
      <pubDate>Tue, 17 Dec 2024 15:55:10 +0000</pubDate>
      <link>https://dev.to/ravikishan/introducing-gitaverse-access-bhagavad-gita-verses-programmatically-53p1</link>
      <guid>https://dev.to/ravikishan/introducing-gitaverse-access-bhagavad-gita-verses-programmatically-53p1</guid>
      <description>&lt;p&gt;In the world of modern development, spiritual and literary texts can be made more accessible to developers through clean APIs and libraries. &lt;strong&gt;GitaVerse&lt;/strong&gt; is a modern TypeScript library that enables you to access, explore, and retrieve shlokas (verses) from the Bhagavad Gita with ease.&lt;/p&gt;




&lt;h2&gt;
  
  
  🌟 What is GitaVerse?
&lt;/h2&gt;

&lt;p&gt;GitaVerse is a TypeScript-based NPM library that allows developers to programmatically fetch the &lt;strong&gt;Bhagavad Gita's verses&lt;/strong&gt; (shlokas), including translations, synonyms, and original Devanagari text.&lt;/p&gt;

&lt;p&gt;The Bhagavad Gita is a profound Hindu scripture consisting of 700 verses across &lt;strong&gt;18 chapters&lt;/strong&gt;. With GitaVerse, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Retrieve individual verses based on &lt;strong&gt;Chapter&lt;/strong&gt; and &lt;strong&gt;Verse number&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Fetch all shlokas in a specific chapter.&lt;/li&gt;
&lt;li&gt;Access translations, synonyms, and meanings in a structured format.&lt;/li&gt;
&lt;li&gt;Build spiritual apps, educational tools, or study tools effortlessly.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🚀 Features of GitaVerse
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Fetch Any Shloka&lt;/strong&gt;: Get verses from any chapter with full details.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Detailed Information&lt;/strong&gt;: Includes Devanagari text, verse translations, synonyms, and multiple meanings.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Organized Data&lt;/strong&gt;: All data is structured and typed with TypeScript interfaces for ease of use.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Easy-to-Use API&lt;/strong&gt;: Clean class-based methods for developers.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Lightweight&lt;/strong&gt;: Minimal dependencies for faster integration.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;TypeScript Support&lt;/strong&gt;: Full type safety for robust development.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📥 Installation
&lt;/h2&gt;

&lt;p&gt;You can install &lt;strong&gt;GitaVerse&lt;/strong&gt; using &lt;strong&gt;npm&lt;/strong&gt; or &lt;strong&gt;yarn&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add gitaverse
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔧 How to Use GitaVerse
&lt;/h2&gt;

&lt;p&gt;Here’s a quick guide on how you can use the &lt;strong&gt;GitaVerse&lt;/strong&gt; library.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Import GitaVerse and Initialize
&lt;/h3&gt;

&lt;p&gt;Start by importing the &lt;code&gt;GitaLibrary&lt;/code&gt; class and initializing it:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gita&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GitaLibrary&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  2. Fetch Metadata About the Bhagavad Gita
&lt;/h3&gt;

&lt;p&gt;Get an overview of the Bhagavad Gita, such as the total chapters and verses:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gita&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDescription&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="cm"&gt;/*
Output:
{
  title: "Bhagavad Gita",
  description: "The Bhagavad Gita, often referred to as the Gita, is a 700-verse Hindu scripture that is part of the Indian epic Mahabharata.",
  totalChapters: 18,
  totalVerses: 700
}
*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3. Fetch All Shlokas in a Chapter
&lt;/h3&gt;

&lt;p&gt;To retrieve all the verses from a specific chapter, use &lt;code&gt;getChapter()&lt;/code&gt;:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chapter1Shlokas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gita&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getChapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;chapter1Shlokas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;shloka&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shloka&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSummary&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;
  
  
  4. Fetch a Specific Shloka
&lt;/h3&gt;

&lt;p&gt;Fetch a specific shloka using &lt;strong&gt;chapter number&lt;/strong&gt; and &lt;strong&gt;verse number&lt;/strong&gt;:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shloka&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gita&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getShloka&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shloka&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSummary&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="cm"&gt;/*
Output:
{
  chapter: "1",
  verse: "1",
  devanagari: "धृतराष्ट्र उवाच...",
  verseText: "Dhritarashtra said...",
  synonyms: "Dhritarashtra - King Dhritarashtra...",
  translation: "King Dhritarashtra inquired...",
  meaning: ["Literal meaning of the verse...", "Spiritual significance..."]
}
*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  5. Fetch All Shlokas Grouped by Chapters
&lt;/h3&gt;

&lt;p&gt;If you want to get all verses organized by chapters, use &lt;code&gt;getAllVerses()&lt;/code&gt;:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;allVerses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gita&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAllVerses&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;allVerses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;chapter&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`Chapter &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;chapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getShlokas&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; Shlokas available`&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;
  
  
  📚 API Methods Overview
&lt;/h2&gt;

&lt;p&gt;Here’s a quick overview of the available methods:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;GitaLibrary&lt;/code&gt; Methods:
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;getDescription()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Get metadata about the Gita.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;getChapter(chapter)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fetch all shlokas in a specific chapter.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;getShloka(chapter, verse)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Retrieve a specific shloka by chapter &amp;amp; verse.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;getAllVerses()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fetch all shlokas grouped by chapters.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;GitaShloka&lt;/code&gt; Methods:
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;getSummary()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Retrieve a summary of the shloka details.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;getDevanagari()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Get the Devanagari text of the verse.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;getTranslation()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Get the verse translation.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;getMeaning()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Get multiple meanings of the verse.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🛠 Use Cases
&lt;/h2&gt;

&lt;p&gt;Here are a few ideas for integrating GitaVerse into your projects:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Spiritual Apps&lt;/strong&gt;: Build apps to display Gita shlokas with translations and explanations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Study Tools&lt;/strong&gt;: Develop tools for students to explore and understand the Bhagavad Gita.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;APIs&lt;/strong&gt;: Serve Gita data through REST APIs for web or mobile apps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Personal Projects&lt;/strong&gt;: Use it for personal study and exploration of the Gita.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🌐 Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;NPM Package&lt;/strong&gt;: &lt;a href="https://www.npmjs.com/package/gitaverse" rel="noopener noreferrer"&gt;gitaverse on npm&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Repository&lt;/strong&gt;: &lt;a href="https://github.com/Ravikisha/GitaVerse/" rel="noopener noreferrer"&gt;GitaVerse on GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🤝 Contributing
&lt;/h2&gt;

&lt;p&gt;We welcome contributions! If you'd like to add features or fix issues:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fork the repository from &lt;a href="https://github.com/Ravikisha/GitaVerse/" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Create a feature branch.&lt;/li&gt;
&lt;li&gt;Submit a pull request.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For any suggestions or bugs, feel free to raise an issue.&lt;/p&gt;




&lt;h2&gt;
  
  
  📄 License
&lt;/h2&gt;

&lt;p&gt;This project is licensed under the MIT License. See the &lt;a href="https://github.com/Ravikisha/GitaVerse/blob/main/LICENSE" rel="noopener noreferrer"&gt;LICENSE&lt;/a&gt; file for more details.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✨ Final Thoughts
&lt;/h2&gt;

&lt;p&gt;With &lt;strong&gt;GitaVerse&lt;/strong&gt;, exploring the timeless wisdom of the Bhagavad Gita becomes simple and developer-friendly. Whether you're building spiritual apps, study tools, or personal projects, GitaVerse provides everything you need to programmatically access and share the Gita's teachings.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"You have the right to work, but never to the fruit of work."&lt;/em&gt;&lt;br&gt;&lt;br&gt;
— Bhagavad Gita (Chapter 2, Verse 47)&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Start Exploring the Gita Today with GitaVerse!&lt;/strong&gt; 🌟&lt;br&gt;&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/gitaverse" rel="noopener noreferrer"&gt;&lt;strong&gt;Install Now&lt;/strong&gt;&lt;/a&gt;  &lt;/p&gt;

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