<?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>Forem: Shahrad Elahi</title>
    <description>The latest articles on Forem by Shahrad Elahi (@shahrad).</description>
    <link>https://forem.com/shahrad</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F763593%2F7daebdc6-5724-4103-aaab-77a522c483b3.jpeg</url>
      <title>Forem: Shahrad Elahi</title>
      <link>https://forem.com/shahrad</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/shahrad"/>
    <language>en</language>
    <item>
      <title>A Modern, Immutable, and Zero-Dependency Library for IP Addresses in JavaScript</title>
      <dc:creator>Shahrad Elahi</dc:creator>
      <pubDate>Thu, 30 Oct 2025 04:48:13 +0000</pubDate>
      <link>https://forem.com/shahrad/a-modern-immutable-and-zero-dependency-library-for-ip-addresses-in-javascript-1g1o</link>
      <guid>https://forem.com/shahrad/a-modern-immutable-and-zero-dependency-library-for-ip-addresses-in-javascript-1g1o</guid>
      <description>&lt;h2&gt;
  
  
  The IP Address Library You've Been Waiting For
&lt;/h2&gt;

&lt;p&gt;Ever found yourself wrestling with IP addresses in a Node.js application? Maybe you're validating user input, checking if an IP belongs to a certain subnet, or just trying to convert between different formats. While there are libraries out there, many feel a bit dated or come with a baggage of dependencies.&lt;/p&gt;

&lt;p&gt;What if there was a modern, clean, and powerful way to handle this?&lt;/p&gt;

&lt;p&gt;Meet &lt;strong&gt;&lt;code&gt;@se-oss/ip-address&lt;/code&gt;&lt;/strong&gt;! It's a brand-new, zero-dependency library designed from the ground up for modern JavaScript and TypeScript development. It provides an immutable, intuitive API for both IPv4 and IPv6 addresses and CIDR ranges.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Another IP Library?
&lt;/h3&gt;

&lt;p&gt;That's a fair question. Here’s what makes &lt;code&gt;@se-oss/ip-address&lt;/code&gt; different:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Immutable API&lt;/strong&gt;: Create an IP object once, and it can't be changed. Operations like &lt;code&gt;next()&lt;/code&gt; or &lt;code&gt;previous()&lt;/code&gt; return a &lt;em&gt;new&lt;/em&gt; instance, preventing bugs from accidental modifications.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Zero Dependencies&lt;/strong&gt;: It's lightweight and secure. No need to worry about a bloated &lt;code&gt;node_modules&lt;/code&gt; folder or transitive dependency vulnerabilities.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;TypeScript First&lt;/strong&gt;: Written entirely in TypeScript, offering excellent autocompletion and type safety out of the box.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Comprehensive&lt;/strong&gt;: Handles IPv4, IPv6, and CIDR notation with a consistent, easy-to-use API.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Installation is as simple as you'd expect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm &lt;span class="nb"&gt;install&lt;/span&gt; @se-oss/ip-address
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or if you prefer npm or yarn:&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="c"&gt;# npm&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; @se-oss/ip-address

&lt;span class="c"&gt;# yarn&lt;/span&gt;
yarn add @se-oss/ip-address
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Fun Part: Code Examples
&lt;/h3&gt;

&lt;p&gt;Let's dive into what you can do with it.&lt;/p&gt;

&lt;h4&gt;
  
  
  Parsing and Validation
&lt;/h4&gt;

&lt;p&gt;The library makes it trivial to parse and validate any IP address. The &lt;code&gt;parseIP&lt;/code&gt; factory automatically detects the IP version.&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;IPv4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;IPv6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;parseIP&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;@se-oss/ip-address&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Let the factory do the work&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseIP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;192.168.1.1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Returns an IPv4 instance&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ip6&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseIP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2001:db8::1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Returns an IPv6 instance&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;ip&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="c1"&gt;// 4&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;ip6&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="c1"&gt;// 6&lt;/span&gt;

&lt;span class="c1"&gt;// Or validate without creating an instance&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;IPv4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;10.0.0.1&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Yep, a valid IPv4 address.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// It throws a specific error for invalid addresses&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;parseIP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;not.an.ip&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="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "Invalid IP address: not.an.ip"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Working with IPv4 Addresses
&lt;/h4&gt;

&lt;p&gt;Once you have an &lt;code&gt;IPv4&lt;/code&gt; instance, you can perform all sorts of checks and conversions.&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;IPv4&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;@se-oss/ip-address&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;ip&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;IPv4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;192.168.1.1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Check its type&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;ip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isPrivate&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// true&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;ip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isLoopback&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;

&lt;span class="c1"&gt;// Convert it to other formats&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;ip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBigInt&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// 3232235777n&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;ip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBytes&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// [192, 168, 1, 1]&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;ip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toArpa&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// "1.1.168.192.in-addr.arpa"&lt;/span&gt;

&lt;span class="c1"&gt;// Get the next IP (returns a new instance!)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextIp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ip&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="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;nextIp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "192.168.1.2"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  IPv6 is a First-Class Citizen
&lt;/h4&gt;

&lt;p&gt;IPv6 is just as easy, with full support for its unique features, like handling IPv4-mapped addresses.&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;IPv6&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;@se-oss/ip-address&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;ip6&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;IPv6&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2001:db8::8a2e:370:7334&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Get compressed vs. expanded address&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;ip6&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "2001:db8::8a2e:370:7334"&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;ip6&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expandedAddress&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "2001:0db8:0000:0000:0000:8a2e:0370:7334"&lt;/span&gt;

&lt;span class="c1"&gt;// Check its type&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;ip6&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isGlobalUnicast&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;

&lt;span class="c1"&gt;// Handle IPv4-mapped addresses seamlessly&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mappedIp&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;IPv6&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;::ffff:192.168.1.1&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;mappedIp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isIPv4Mapped&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ipv4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mappedIp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toIPv4&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;ipv4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "192.168.1.1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Mastering Subnets with CIDR
&lt;/h4&gt;

&lt;p&gt;Need to work with subnets? The &lt;code&gt;CIDR&lt;/code&gt; class has you covered. This is incredibly useful for network calculations.&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;CIDR&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;@se-oss/ip-address&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;cidr&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;CIDR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;10.0.0.0/24&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Get network details&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;cidr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "10.0.0.0"&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;cidr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;broadcast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "10.0.0.255"&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;cidr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "10.0.0.1" (First usable IP)&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;cidr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;last&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "10.0.0.254" (Last usable IP)&lt;/span&gt;

&lt;span class="c1"&gt;// Check if an IP falls within the range&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;cidr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;10.0.0.123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// true&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;cidr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;10.0.1.1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Under the Hood
&lt;/h3&gt;

&lt;p&gt;One of the reasons this library is so precise is its use of native &lt;code&gt;BigInt&lt;/code&gt;. This allows for accurate calculations on large 128-bit IPv6 addresses without running into floating-point limitations that can plague number-based approaches.&lt;/p&gt;

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

&lt;p&gt;Whether you're building a security tool, a network scanner, or just need to handle IP data reliably in your web application, &lt;code&gt;@se-oss/ip-address&lt;/code&gt; offers a clean, modern, and safe API to get the job done. It's lightweight, has no dependencies, and its immutable design can help you write more predictable code.&lt;/p&gt;

&lt;p&gt;Give it a try! Check out the &lt;a href="https://github.com/shahradelahi/ip-address" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt; to see the source, and don't forget to leave a star if you find it useful. We welcome contributions and feedback!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>node</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Stop Leaking Your Secrets! Secure Your Node.js Environment Variables.</title>
      <dc:creator>Shahrad Elahi</dc:creator>
      <pubDate>Fri, 29 Aug 2025 19:17:32 +0000</pubDate>
      <link>https://forem.com/shahrad/stop-leaking-your-secrets-secure-your-nodejs-environment-variables-jim</link>
      <guid>https://forem.com/shahrad/stop-leaking-your-secrets-secure-your-nodejs-environment-variables-jim</guid>
      <description>&lt;p&gt;Let's be real: we all sling secrets in &lt;code&gt;.env&lt;/code&gt; files. It's the default for a reason. You drop your &lt;code&gt;DATABASE_URL&lt;/code&gt; and &lt;code&gt;API_KEY&lt;/code&gt; in there, load them up, and you're off to the races.&lt;/p&gt;

&lt;p&gt;But have you ever stopped to think about what happens &lt;em&gt;after&lt;/em&gt; you load them into &lt;code&gt;process.env&lt;/code&gt;?&lt;/p&gt;

&lt;h3&gt;
  
  
  So, What's the Big Deal?
&lt;/h3&gt;

&lt;p&gt;When you dump everything into &lt;code&gt;process.env&lt;/code&gt;, you're essentially tossing your secrets into a global free-for-all. Every single package in your &lt;code&gt;node_modules&lt;/code&gt; black hole—and all of &lt;em&gt;their&lt;/em&gt; dependencies—can take a peek.&lt;/p&gt;

&lt;p&gt;Usually, that's fine. But in an ecosystem this massive, it only takes one sketchy dependency or one compromised package to start hoovering up your sensitive data. That nagging feeling in the back of your head? It's probably justified.&lt;/p&gt;

&lt;h3&gt;
  
  
  A "Virtual Environment" for Your Env Vars
&lt;/h3&gt;

&lt;p&gt;This exact worry is why I built &lt;a href="https://github.com/shahradelahi/process-venv" rel="noopener noreferrer"&gt;&lt;code&gt;process-venv&lt;/code&gt;&lt;/a&gt;. It's a simple idea: create a "virtual environment" for your config. Instead of exposing everything, it keeps your variables in a safe, isolated container. Only the variables you &lt;em&gt;explicitly&lt;/em&gt; mark as "shared" will ever touch &lt;code&gt;process.env&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's the payoff:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Keep Your Secrets Actually Secret&lt;/strong&gt;: Your &lt;code&gt;API_KEY&lt;/code&gt; stays tucked away, safe from prying eyes in your dependency tree.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Fail-Fast with Schema Validation&lt;/strong&gt;: Using tools you already love like Zod, Valibot, or ArkType, you can validate your env vars on startup. No more chasing down &lt;code&gt;undefined&lt;/code&gt; errors at 3 AM.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;No More Runtime Shenanigans&lt;/strong&gt;: The environment is immutable. Once it's loaded, it's locked. No accidental (or malicious) changes during runtime.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Let's See It in Action
&lt;/h3&gt;

&lt;p&gt;Here’s how easy it is to get started. First, grab the packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm &lt;span class="nb"&gt;install &lt;/span&gt;process-venv zod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(We're using Zod here, but any &lt;a href="https://standardschema.dev" rel="noopener noreferrer"&gt;Standard Schema&lt;/a&gt; validator will do.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Next, set up your environment config. I like to do this in its own file.&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/env.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createEnv&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;process-venv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;venv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createEnv&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// Define the shape of your environment variables.&lt;/span&gt;
  &lt;span class="c1"&gt;// Zod is great for this.&lt;/span&gt;
  &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;NODE_ENV&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;development&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&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="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;development&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coerce&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;default&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;span class="na"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="c1"&gt;// This will be private by default.&lt;/span&gt;
    &lt;span class="na"&gt;SHARED_SECRET&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="c1"&gt;// We'll share this one.&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="c1"&gt;// Now, tell process-venv which variables are safe to expose globally.&lt;/span&gt;
  &lt;span class="c1"&gt;// These are usually things your framework needs.&lt;/span&gt;
  &lt;span class="na"&gt;shared&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;NODE_ENV&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PORT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SHARED_SECRET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, in the rest of your app, you just import and use it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/index.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;venv&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;./env&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Things like your web framework can still access what they need.&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NODE_ENV from process.env:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// But you access everything else from the safe venv instance.&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;API_KEY from venv:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;venv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PORT from venv:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;venv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// And here's the magic: your API key is nowhere to be found globally.&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;API_KEY from process.env:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// =&amp;gt; undefined&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Your &lt;code&gt;API_KEY&lt;/code&gt; is now available to &lt;em&gt;your&lt;/em&gt; code via the &lt;code&gt;venv&lt;/code&gt; object, but it's invisible to the rest of &lt;code&gt;process.env&lt;/code&gt;. Peace of mind.&lt;/p&gt;

&lt;h3&gt;
  
  
  Give It a Spin!
&lt;/h3&gt;

&lt;p&gt;I'd be thrilled if you gave &lt;a href="https://github.com/shahradelahi/process-venv" rel="noopener noreferrer"&gt;&lt;code&gt;process-venv&lt;/code&gt;&lt;/a&gt; a try in your next project. It's a small change that can make a real difference in your app's security posture.&lt;/p&gt;

&lt;p&gt;You can find it on &lt;a href="https://www.npmjs.com/package/process-venv" rel="noopener noreferrer"&gt;npm&lt;/a&gt; and the source is on &lt;a href="https://github.com/shahradelahi/process-venv" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you dig it, a star on GitHub would be awesome! Let me know what you think in the comments. Cheers!&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>security</category>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>Solving Distributed ID Challenges with Snowflake IDs in TypeScript</title>
      <dc:creator>Shahrad Elahi</dc:creator>
      <pubDate>Wed, 27 Aug 2025 12:19:58 +0000</pubDate>
      <link>https://forem.com/shahrad/solving-distributed-id-challenges-with-snowflake-ids-in-typescript-3910</link>
      <guid>https://forem.com/shahrad/solving-distributed-id-challenges-with-snowflake-ids-in-typescript-3910</guid>
      <description>&lt;p&gt;Generating unique identifiers in distributed systems is a common headache. Traditional methods like auto-incrementing database IDs hit scaling limits, and UUIDs, while unique, lack inherent sortability. What if there was an ID that was both unique &lt;em&gt;and&lt;/em&gt; time-ordered?&lt;/p&gt;

&lt;p&gt;Here's where &lt;strong&gt;Snowflake IDs&lt;/strong&gt; come into play.&lt;/p&gt;

&lt;p&gt;Originally from Twitter, Snowflake IDs are unique, time-ordered, 64-bit identifiers perfect for high-throughput, distributed environments. Today, I want to introduce you to &lt;a href="https://github.com/shahradelahi/snowflake-sequence" rel="noopener noreferrer"&gt;&lt;code&gt;@se-oss/snowflake-sequence&lt;/code&gt;&lt;/a&gt;, a lightweight, high-performance TypeScript library that brings Snowflake IDs directly to your Node.js applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Snowflake IDs?
&lt;/h2&gt;

&lt;p&gt;Snowflake IDs solve key problems in distributed systems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Scalability:&lt;/strong&gt; Generated locally on each node, avoiding central bottlenecks.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Sortability:&lt;/strong&gt; Embeds a timestamp, so newer IDs are always greater than older ones.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Uniqueness:&lt;/strong&gt; Virtually guaranteed across your entire system.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Efficiency:&lt;/strong&gt; A compact 64-bit integer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where &lt;a href="https://github.com/shahradelahi/snowflake-sequence" rel="noopener noreferrer"&gt;&lt;code&gt;@se-oss/snowflake-sequence&lt;/code&gt;&lt;/a&gt; shines, offering a robust and easy-to-use implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Anatomy of a Snowflake ID
&lt;/h2&gt;

&lt;p&gt;A Snowflake ID is a 64-bit integer composed of three parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Timestamp (41 bits):&lt;/strong&gt; Milliseconds since a custom epoch. This enables time-based sorting.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Node ID (10 bits):&lt;/strong&gt; A unique identifier for the generating machine or process (0-1023).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Sequence (12 bits):&lt;/strong&gt; Increments for IDs generated within the same millisecond on the same node (up to 4096 per millisecond).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The library handles all the complex bitwise operations for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started with &lt;a href="https://github.com/shahradelahi/snowflake-sequence" rel="noopener noreferrer"&gt;&lt;code&gt;@se-oss/snowflake-sequence&lt;/code&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Install it with pnpm (or your preferred package manager):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm &lt;span class="nb"&gt;install&lt;/span&gt; @se-oss/snowflake-sequence
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generate and deconstruct IDs:&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;Snowflake&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;@se-oss/snowflake-sequence&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// 1. Create a new Snowflake generator instance.&lt;/span&gt;
&lt;span class="c1"&gt;//    The nodeId is crucial for uniqueness across your distributed system.&lt;/span&gt;
&lt;span class="c1"&gt;//    The epoch is optional; it defaults to Twitter's original epoch.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;snowflake&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;Snowflake&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;nodeId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Unique ID for this service instance (0-1023)&lt;/span&gt;
  &lt;span class="na"&gt;epoch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1672531200000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Optional: Jan 1, 2023, 00:00:00 UTC&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// 2. Generate a new Snowflake ID.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;snowflake&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nextId&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;`Generated ID: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;n`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Notice the 'n' for BigInt&lt;/span&gt;

&lt;span class="c1"&gt;// 3. Deconstruct the ID to inspect its components.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;deconstructed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Snowflake&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deconstruct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Deconstructed ID:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;deconstructed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="cm"&gt;/*
Output will be something like:
{
  timestamp: 1672531200000n + some_milliseconds_since_epoch,
  nodeId: 42n,
  sequence: 0n, // or higher if multiple IDs were generated in the same millisecond
  epoch: 1288834974657n // Note: deconstruct uses the DEFAULT_EPOCH for consistency
}
*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Customization and Robustness
&lt;/h2&gt;

&lt;p&gt;Configure your Snowflake generator for your environment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Node ID:&lt;/strong&gt; Assign a unique &lt;code&gt;nodeId&lt;/code&gt; (0-1023) to each service instance, perhaps via environment variables or service discovery (like &lt;a href="https://www.hashicorp.com/products/consul" rel="noopener noreferrer"&gt;Consul&lt;/a&gt; or &lt;a href="https://github.com/Netflix/eureka" rel="noopener noreferrer"&gt;Eureka&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Epoch:&lt;/strong&gt; Set a custom epoch timestamp to maximize ID lifespan or align with existing systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The library also handles edge cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Clock Backwards:&lt;/strong&gt; Throws an error if the system clock moves backward, preventing non-unique IDs.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Sequence Rollover:&lt;/strong&gt; Automatically waits for the next millisecond if more than 4096 IDs are generated in a single millisecond, ensuring uniqueness.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real-World Applications
&lt;/h2&gt;

&lt;p&gt;Snowflake IDs are ideal for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Distributed Logging:&lt;/strong&gt; Chronological sorting of logs across services.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Event Sourcing:&lt;/strong&gt; Unique and ordered event IDs.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;User-Generated Content:&lt;/strong&gt; Efficiently sort and retrieve posts, comments, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Under the Hood: The Bitwise Magic
&lt;/h2&gt;

&lt;p&gt;The efficiency of Snowflake IDs comes from clever bitwise operations that pack the timestamp, node ID, and sequence into a single 64-bit &lt;code&gt;BigInt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Imagine the 64 bits of the ID:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;[ 0 | 41-bit Timestamp | 10-bit Node ID | 12-bit Sequence ]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here's a simplified look at how it works:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Generating an ID:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Timestamp:&lt;/strong&gt; The difference between the current time and the chosen &lt;code&gt;epoch&lt;/code&gt; is calculated. This 41-bit value is shifted left by &lt;code&gt;TIMESTAMP_SHIFT&lt;/code&gt; (which is &lt;code&gt;NODE_ID_BITS + SEQUENCE_BITS = 10 + 12 = 22&lt;/code&gt; bits). This moves the timestamp to the leftmost significant position.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Node ID:&lt;/strong&gt; Your &lt;code&gt;nodeId&lt;/code&gt; (10 bits) is shifted left by &lt;code&gt;NODE_ID_SHIFT&lt;/code&gt; (which is &lt;code&gt;SEQUENCE_BITS = 12&lt;/code&gt; bits). This places the node ID in its designated 10-bit slot.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Sequence:&lt;/strong&gt; The &lt;code&gt;sequence&lt;/code&gt; number (12 bits) is added directly, occupying the rightmost 12 bits.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These three shifted values are then combined using the bitwise OR (&lt;code&gt;|&lt;/code&gt;) operator to form the final 64-bit Snowflake ID.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deconstructing an ID:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To get the components back:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Timestamp:&lt;/strong&gt; The ID is shifted right by &lt;code&gt;TIMESTAMP_SHIFT&lt;/code&gt; to isolate the timestamp, and then the &lt;code&gt;epoch&lt;/code&gt; is added back to get the absolute timestamp.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Node ID:&lt;/strong&gt; The ID is shifted right by &lt;code&gt;NODE_ID_SHIFT&lt;/code&gt; and then a bitwise AND (&lt;code&gt;&amp;amp;&lt;/code&gt;) operation with &lt;code&gt;MAX_NODE_ID&lt;/code&gt; (a mask of 10 ones) is used to extract just the 10-bit node ID.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Sequence:&lt;/strong&gt; A bitwise AND (&lt;code&gt;&amp;amp;&lt;/code&gt;) operation with &lt;code&gt;MAX_SEQUENCE&lt;/code&gt; (a mask of 12 ones) directly extracts the 12-bit sequence number.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This direct manipulation of bits is what makes Snowflake ID generation and deconstruction incredibly fast and efficient.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion &amp;amp; Call to Action
&lt;/h2&gt;

&lt;p&gt;Snowflake IDs offer a scalable, unique, and time-sortable solution for distributed ID generation. The &lt;code&gt;@se-oss/snowflake-sequence&lt;/code&gt; library provides a high-performance, pure TypeScript implementation that's easy to integrate.&lt;/p&gt;

&lt;p&gt;If you're building distributed systems, give &lt;a href="https://github.com/shahradelahi/snowflake-sequence" rel="noopener noreferrer"&gt;&lt;code&gt;@se-oss/snowflake-sequence&lt;/code&gt;&lt;/a&gt; a try!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/shahradelahi/snowflake-sequence" rel="noopener noreferrer"&gt;shahradelahi/snowflake-sequence&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Install:&lt;/strong&gt; &lt;code&gt;pnpm install @se-oss/snowflake-sequence&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>distributedsystems</category>
      <category>library</category>
      <category>snowflake</category>
    </item>
  </channel>
</rss>
