<?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: Cheela Sathvik</title>
    <description>The latest articles on DEV Community by Cheela Sathvik (@sathvikcheela).</description>
    <link>https://dev.to/sathvikcheela</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%2F278125%2Fee724ef5-e0aa-4eac-a677-008ec12885fa.png</url>
      <title>DEV Community: Cheela Sathvik</title>
      <link>https://dev.to/sathvikcheela</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sathvikcheela"/>
    <language>en</language>
    <item>
      <title>Your Database Failover Doesn't Work. Ask Me How I Know.</title>
      <dc:creator>Cheela Sathvik</dc:creator>
      <pubDate>Tue, 03 Feb 2026 14:00:00 +0000</pubDate>
      <link>https://dev.to/sathvikcheela/your-database-failover-doesnt-work-ask-me-how-i-know-14jo</link>
      <guid>https://dev.to/sathvikcheela/your-database-failover-doesnt-work-ask-me-how-i-know-14jo</guid>
      <description>&lt;p&gt;Last year, our primary database went down during a critical traffic spike. We had failover configured. Or at least, we &lt;em&gt;thought&lt;/em&gt; we did.&lt;/p&gt;

&lt;p&gt;Our logic seemed solid enough on paper:&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isDown&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;switchTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;replica&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;Simple, right?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wrong.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The primary wasn't "down" in the way our code expected. It wasn't refusing connections. It was just incredibly, painfully slow. Our manual health check—a simple ping—kept succeeding, but queries were timing out.&lt;/p&gt;

&lt;p&gt;Because our health check didn't account for latency spikes, our application kept flapping between the primary and the replica. Connections piled up. The pool exhausted. The service stalled.&lt;/p&gt;

&lt;p&gt;It wasn't a crash. It was a slow, painful death by race condition.&lt;/p&gt;

&lt;p&gt;The fix? We wrote about 200 lines of manual "glue code" to handle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Timeouts&lt;/li&gt;
&lt;li&gt;  Retries&lt;/li&gt;
&lt;li&gt;  Circuit breaking&lt;/li&gt;
&lt;li&gt;  Graceful failover&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I got tired of seeing this same brittle, manual boilerplate in every service I worked on. So I decided to solve it once and for all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing OmniDB
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/sathvikc/omni-db" rel="noopener noreferrer"&gt;&lt;strong&gt;OmniDB&lt;/strong&gt;&lt;/a&gt; is a thin orchestration library for Node.js. It’s not a new database client. It doesn't try to replace Prisma, or Mongoose, or pg. It simply orchestrates the clients you already use.&lt;/p&gt;

&lt;p&gt;It handles the hard stuff automatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  ✅ &lt;strong&gt;Real Health Checks&lt;/strong&gt;: Checks that respect timeouts and latency, not just connectivity.&lt;/li&gt;
&lt;li&gt;  ✅ &lt;strong&gt;Race-Condition-Free Failover&lt;/strong&gt;: Atomic switching when things go wrong.&lt;/li&gt;
&lt;li&gt;  ✅ &lt;strong&gt;Circuit Breakers&lt;/strong&gt;: Built-in protection to stop cascading failures.&lt;/li&gt;
&lt;li&gt;  ✅ &lt;strong&gt;Graceful Shutdowns&lt;/strong&gt;: Ensuring connections close cleanly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Problem with "Do It Yourself"
&lt;/h2&gt;

&lt;p&gt;Most developers (myself included) start with something like this:&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;// ❌ The DIY Trap&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;primary&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;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PRIMARY_URL&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;replica&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;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;REPLICA_URL&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;active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ping&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;primary&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;e&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;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Primary down, using replica&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;replica&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="mi"&gt;5000&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;Why this breaks:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Flapping&lt;/strong&gt;: If the primary is unstable, you switch back and forth effectively DDOSing yourself.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;No Circuit Breaker&lt;/strong&gt;: If the replica is also stressed, you'll hammer it until it breaks too.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Request Drops&lt;/strong&gt;: Requests in flight during the switch often just fail.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The OmniDB Way
&lt;/h2&gt;

&lt;p&gt;Here is how you solve that same problem with OmniDB. It’s about 20 lines of code, and it handles all the edge cases we missed above.&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;// ✅ With OmniDB&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;Orchestrator&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;omni-db&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;db&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;Orchestrator&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;connections&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;primary&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;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PRIMARY_URL&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;replica&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;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;REPLICA_URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;failover&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;replica&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c1"&gt;// simple declarative routing&lt;/span&gt;
  &lt;span class="na"&gt;healthCheck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;30s&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;5s&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// strict timeout for checks&lt;/span&gt;
    &lt;span class="na"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&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;await&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SELECT 1&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="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;replica&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&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;await&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SELECT 1&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="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Usage:&lt;/span&gt;
&lt;span class="c1"&gt;// Automatically uses 'primary'.&lt;/span&gt;
&lt;span class="c1"&gt;// If 'primary' is unhealthy, it routes to 'replica'.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&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;primary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Resilience by Design
&lt;/h2&gt;

&lt;p&gt;OmniDB doesn't just check if a server is there; it manages the &lt;em&gt;lifecycle&lt;/em&gt; of your availability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Circuit Breakers
&lt;/h3&gt;

&lt;p&gt;If a database starts failing repeatedly, OmniDB opens the circuit. This stops your application from waiting on dead connections and allows the database time to recover. You can use the built-in simple breaker or bring your own robust solution like &lt;code&gt;opossum&lt;/code&gt; or &lt;code&gt;cockatiel&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Events
&lt;/h3&gt;

&lt;p&gt;You shouldn't have to guess what your database is doing. OmniDB emits events for everything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;db&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="s1"&gt;failover&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;primary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;backup&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="nf"&gt;alertOps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`🚨 Switched from &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; to &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;backup&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="nx"&gt;db&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="s1"&gt;recovery&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;primary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;backup&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;`✅ Recovered &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, switching back from &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;backup&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why Use OmniDB?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Zero Dependencies&lt;/strong&gt;: Just the core library. No bloat.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Scalable&lt;/strong&gt;: O(1) lookup performance, making it efficient even with hundreds of database shards/tenants.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Agnostic&lt;/strong&gt;: Works with &lt;strong&gt;Prisma&lt;/strong&gt;, &lt;strong&gt;Drizzle&lt;/strong&gt;, &lt;strong&gt;Redis&lt;/strong&gt;, &lt;strong&gt;MongoDB&lt;/strong&gt;, &lt;strong&gt;Postgres&lt;/strong&gt;, or any other client.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;TypeScript Native&lt;/strong&gt;: Full type inference. &lt;code&gt;db.get('redis')&lt;/code&gt; returns a &lt;code&gt;Redis&lt;/code&gt; client type.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Stop Writing Boilerplate
&lt;/h2&gt;

&lt;p&gt;Infrastructure code should be boring. It should be standard. And it should work.&lt;/p&gt;

&lt;p&gt;Stop wrestling with race conditions in your &lt;code&gt;setInterval&lt;/code&gt; loops. Start orchestrating.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check out the repo on GitHub:&lt;/strong&gt;&lt;br&gt;
👉 &lt;a href="https://github.com/sathvikc/omni-db" rel="noopener noreferrer"&gt;https://github.com/sathvikc/omni-db&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you've ever battled a "silent failure" in production, let me know in the comments. I'd love to hear your war stories.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>database</category>
      <category>mongodb</category>
      <category>redis</category>
    </item>
    <item>
      <title>Building a High-Performance Zip Puzzle: A Lume-JS Masterclass</title>
      <dc:creator>Cheela Sathvik</dc:creator>
      <pubDate>Tue, 23 Dec 2025 19:50:18 +0000</pubDate>
      <link>https://dev.to/sathvikcheela/building-a-high-performance-zip-puzzle-a-lume-js-masterclass-26bm</link>
      <guid>https://dev.to/sathvikcheela/building-a-high-performance-zip-puzzle-a-lume-js-masterclass-26bm</guid>
      <description>&lt;p&gt;If you’ve been on LinkedIn lately, you’ve likely seen the "Zip" puzzle. It’s a beautifully simple grid-based game where you connect numbers in a path. While the game looks simple, implementing it with high-performance reactivity, smooth visual feedback, and &lt;strong&gt;infinite background puzzle generation&lt;/strong&gt; is a great test for any front-end toolset.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live Demo:&lt;/strong&gt; &lt;a href="https://sathvikc.github.io/linkedin-zip-puzzle/" rel="noopener noreferrer"&gt;sathvikc.github.io/linkedin-zip-puzzle/&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Source Code:&lt;/strong&gt; &lt;a href="https://github.com/sathvikc/linkedin-zip-puzzle" rel="noopener noreferrer"&gt;github.com/sathvikc/linkedin-zip-puzzle&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Lume-JS Website:&lt;/strong&gt; &lt;a href="https://sathvikc.github.io/lume-js/" rel="noopener noreferrer"&gt;sathvikc.github.io/lume-js/&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  The Challenge: Beyond Manual DOM Manipulation
&lt;/h3&gt;

&lt;p&gt;In a game like Zip, every move triggers a waterfall of UI changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The cell you clicked becomes "active."&lt;/li&gt;
&lt;li&gt;A "path dot" appears.&lt;/li&gt;
&lt;li&gt;"Connector lines" must draw themselves between the current cell and the previous/next cells.&lt;/li&gt;
&lt;li&gt;The "Cells Visited" counter increments.&lt;/li&gt;
&lt;li&gt;Win detection checks if the grid is full.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Doing this manually with &lt;code&gt;document.getElementById&lt;/code&gt; is a recipe for spaghetti code.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Solution: Lume-JS &amp;amp; Ruthless Minimalism
&lt;/h3&gt;

&lt;p&gt;Lume-JS is built on the philosophy of "Ruthless Minimalism." At under 2KB, it provides a Proxy-based reactivity system that is both intuitive and powerful. Unlike VDOM-heavy frameworks, Lume-JS performs &lt;strong&gt;surgical DOM updates&lt;/strong&gt;, which is critical for a game where the UI state changes with every pixel of mouse movement.&lt;/p&gt;
&lt;h4&gt;
  
  
  1. The Reactive State (An "Antidote" to Spaghetti Code)
&lt;/h4&gt;

&lt;p&gt;Everything in the game starts with a single &lt;code&gt;state()&lt;/code&gt; object.&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;gameState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;state&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="na"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;generateInitialGrid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;elapsedSeconds&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Surgical Reactivity vs. Virtual DOM
&lt;/h4&gt;

&lt;p&gt;The magic happens in the rendering. Instead of re-rendering the whole board or diffing a heavy Virtual DOM, we use the &lt;code&gt;repeat&lt;/code&gt; addon. Each cell gets its own reactive &lt;code&gt;effect&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cellData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;el&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="nf"&gt;effect&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;pathIdx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gameState&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;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cellData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;active&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pathIdx&lt;/span&gt; &lt;span class="o"&gt;!==&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures the browser does the absolute minimum work necessary. In a 6x6 grid, when you move your mouse, only a single cell's classes are updated. No reconciliation, no complex diffing—just raw performance.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Offloading the Brain: Infinite Puzzles via Web Workers
&lt;/h4&gt;

&lt;p&gt;Generating a valid, solvable Zip puzzle is computationally expensive. To keep the UI at 60fps, I offloaded the "Brain" to a &lt;strong&gt;Web Worker&lt;/strong&gt; using Comlink. This allows for &lt;strong&gt;infinite background generation&lt;/strong&gt;—the game is already preparing your next puzzle while you're still connecting the dots on the current one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Lume-JS? The "Go-Style" Frontend
&lt;/h3&gt;

&lt;p&gt;In an era where front-end bundles are ballooning, Lume-JS proves that you don't need a massive runtime to build premium experiences. It gives you the "DX" (Developer Experience) of a major framework with the performance of vanilla JavaScript.&lt;/p&gt;

&lt;p&gt;Whether you're building a viral puzzle game or a complex enterprise dashboard, Lume-JS is a reminder that sometimes, less truly is more.&lt;/p&gt;




&lt;h3&gt;
  
  
  Resources &amp;amp; Links
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Play the Game:&lt;/strong&gt; &lt;a href="https://sathvikc.github.io/linkedin-zip-puzzle/" rel="noopener noreferrer"&gt;sathvikc.github.io/linkedin-zip-puzzle/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;View the Source Code:&lt;/strong&gt; &lt;a href="https://github.com/sathvikc/linkedin-zip-puzzle" rel="noopener noreferrer"&gt;github.com/sathvikc/linkedin-zip-puzzle&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learn Lume-JS:&lt;/strong&gt; &lt;a href="https://sathvikc.github.io/lume-js/" rel="noopener noreferrer"&gt;sathvikc.github.io/lume-js/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Join the Conversation:&lt;/strong&gt; Catch me on LinkedIn where I talk about micro-libraries and web performance!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>frontend</category>
    </item>
    <item>
      <title>I Built a 2KB React Alternative That Uses Zero Custom Syntax</title>
      <dc:creator>Cheela Sathvik</dc:creator>
      <pubDate>Sat, 29 Nov 2025 09:27:13 +0000</pubDate>
      <link>https://dev.to/sathvikcheela/i-built-a-2kb-react-alternative-that-uses-zero-custom-syntax-mpl</link>
      <guid>https://dev.to/sathvikcheela/i-built-a-2kb-react-alternative-that-uses-zero-custom-syntax-mpl</guid>
      <description>&lt;p&gt;You know what's funny? We keep inventing new ways to do the same thing: make HTML dynamic.&lt;/p&gt;

&lt;p&gt;React gave us JSX. Vue gave us &lt;code&gt;v-bind&lt;/code&gt;. Alpine gave us &lt;code&gt;x-data&lt;/code&gt;. Svelte gave us its own template syntax. Each one reinvented how we write HTML, then asked us to install build tools to compile it back into... HTML and JavaScript.&lt;/p&gt;

&lt;p&gt;What if we just used HTML and JavaScript?&lt;/p&gt;

&lt;p&gt;That's &lt;strong&gt;Lume.js&lt;/strong&gt;. I just released version 1.0.0, and it's a bet that web standards are actually good enough.&lt;/p&gt;




&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Lume.js is a &lt;strong&gt;2KB reactive framework&lt;/strong&gt; that uses only standard HTML and JavaScript. No JSX, no custom syntax, no build step required. Just &lt;code&gt;data-bind&lt;/code&gt; attributes and ES6 Proxies. It's 9-21x smaller than React/Vue/Alpine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://sathvikc.github.io/lume-js/" rel="noopener noreferrer"&gt;→ Try it in 30 seconds&lt;/a&gt;&lt;/strong&gt; | &lt;strong&gt;&lt;a href="https://github.com/sathvikc/lume-js" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/strong&gt; | &lt;strong&gt;&lt;a href="https://www.npmjs.com/package/lume-js" rel="noopener noreferrer"&gt;npm&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Entire API in 30 Seconds
&lt;/h2&gt;

&lt;p&gt;Here's a two-way bound input:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTML:&lt;/strong&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;div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Hello, &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;data-bind=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;!&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;data-bind=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Type your name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;JavaScript:&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bindDom&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;lume-js&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;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;state&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;World&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nf"&gt;bindDom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;store&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 it. No JSX. No &lt;code&gt;v-model&lt;/code&gt;. No &lt;code&gt;x-data&lt;/code&gt;. No compiler. Just &lt;code&gt;data-bind&lt;/code&gt;, which has been valid HTML since 2008.&lt;/p&gt;

&lt;p&gt;Type in the input? The span updates. Change &lt;code&gt;store.name&lt;/code&gt; in your code? The input updates. It's reactive, it's two-way, and your HTML passes validation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://sathvikc.github.io/lume-js/" rel="noopener noreferrer"&gt;→ See it working live&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Exists
&lt;/h2&gt;

&lt;p&gt;Here's the thing: 80% of websites don't need a framework. Vanilla JavaScript is powerful enough for most things. DOM manipulation? Easy. Event listeners? Simple. Animations with GSAP? Works great.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;one&lt;/em&gt; thing vanilla JS lacks is reactivity.&lt;/p&gt;

&lt;p&gt;You can write &lt;code&gt;element.textContent = count&lt;/code&gt;, but when &lt;code&gt;count&lt;/code&gt; changes, you have to remember to update the element manually. You can build dynamic forms, but you end up with spaghetti code tracking which values changed and which DOM elements need updates.&lt;/p&gt;

&lt;p&gt;That's the only real problem. Not the language. Not the DOM APIs. Just reactivity.&lt;/p&gt;

&lt;p&gt;So I built Lume to solve that one problem. Now I can use vanilla JS with reactivity everywhere:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WordPress sites where I can't install a build pipeline&lt;/li&gt;
&lt;li&gt;Shopify themes that just need a dynamic cart&lt;/li&gt;
&lt;li&gt;GSAP animations driven by reactive state&lt;/li&gt;
&lt;li&gt;Internal tools that don't need webpack&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No framework. No build step. Just JavaScript with the one missing piece added back in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Want to see real examples? &lt;a href="https://sathvikc.github.io/lume-js/#docs/tutorials/build-todo-app" rel="noopener noreferrer"&gt;Check out the Todo app&lt;/a&gt; and &lt;a href="https://sathvikc.github.io/lume-js/#docs/tutorials/build-tic-tac-toe" rel="noopener noreferrer"&gt;Tic-Tac-Toe&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What Makes This Different (And Why You Might Care)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;It's small.&lt;/strong&gt; Under 2KB gzipped for the core. That's smaller than most images on your page. React + ReactDOM is ~42KB. Vue 3 is ~18KB. Alpine.js is ~15KB. Lume is under 2KB.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It uses standards.&lt;/strong&gt; &lt;code&gt;data-*&lt;/code&gt; attributes are standard HTML5. Proxies are standard ES6. It works in HTML validators, screen readers, email templates, CMS themes—places where custom syntax breaks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No build step.&lt;/strong&gt; Drop it in via CDN and start coding. Want to use a bundler? Fine. Don't want to? Also fine. I built working examples in single HTML files because I could.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's fast.&lt;/strong&gt; No virtual DOM. No diffing. When you change &lt;code&gt;store.count&lt;/code&gt;, it directly updates &lt;code&gt;element.textContent&lt;/code&gt;. For most UIs, this is faster than frameworks that diff virtual trees.&lt;/p&gt;




&lt;h2&gt;
  
  
  What You Actually Get
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Automatic dependency tracking:&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;effect&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;lume-js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;effect&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;`Total: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quantity&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="c1"&gt;// Re-runs automatically when price or quantity changes&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;Computed values:&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;computed&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;lume-js/addons&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;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&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;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quantity&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;total&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;// Cached, updates automatically&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Efficient list rendering:&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;repeat&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;lume-js/addons&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;items&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;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;el&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;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&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="c1"&gt;// Reuses DOM elements, faster than re-rendering&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Microtask batching:&lt;/strong&gt; Update the same property 10 times? The DOM updates once. Performance without thinking.&lt;/p&gt;

&lt;p&gt;All of this in 2KB.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://sathvikc.github.io/lume-js/#examples/comprehensive" rel="noopener noreferrer"&gt;→ Play with these examples in the interactive playground&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Where It Actually Works
&lt;/h2&gt;

&lt;p&gt;Lume isn't meant to replace full frameworks for every scenario. If you need a complete application framework with extensive routing and complex state management, there are excellent options out there built for that.&lt;/p&gt;

&lt;p&gt;Lume.js works when you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reactivity on a mostly static site (blogs, marketing pages)&lt;/li&gt;
&lt;li&gt;Dynamic forms without framework overhead&lt;/li&gt;
&lt;li&gt;Something that works in WordPress, Shopify, or other restricted environments&lt;/li&gt;
&lt;li&gt;Progressive enhancement (page works with JS disabled)&lt;/li&gt;
&lt;li&gt;Prototypes where webpack feels like overkill&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of it as Knockout.js for 2025. Simple, standards-based reactivity when you don't need a full framework.&lt;/p&gt;




&lt;h2&gt;
  
  
  Install &amp;amp; Try It Now
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Via CDN (quickest way):&lt;/strong&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="nt"&gt;&amp;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;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bindDom&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;https://cdn.jsdelivr.net/npm/lume-js/src/index.js&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;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;state&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;count&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;bindDom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"store.count++"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Clicked &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;data-bind=&lt;/span&gt;&lt;span class="s"&gt;"count"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;0&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt; times&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;&lt;strong&gt;Via npm:&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;lume-js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://sathvikc.github.io/lume-js/" rel="noopener noreferrer"&gt;website&lt;/a&gt; has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live playground&lt;/strong&gt; - Test it in your browser&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step-by-step tutorials&lt;/strong&gt; - Build a Todo app and Tic-Tac-Toe&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full API docs&lt;/strong&gt; - Everything you need to know&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://sathvikc.github.io/lume-js/" rel="noopener noreferrer"&gt;→ Start building now&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Philosophy Behind It
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Standards age better than frameworks.&lt;/strong&gt; JavaScript frameworks change every few years. &lt;code&gt;data-*&lt;/code&gt; attributes have been stable since 2008. ES6 Proxies since 2015. What you build with Lume today will probably work in browsers 10 years from now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explicit beats magic.&lt;/strong&gt; Lume requires you to wrap nested objects in &lt;code&gt;state()&lt;/code&gt; explicitly. Yeah, it's more typing. But you know exactly what's reactive. No surprises when performance tanks because the framework auto-wrapped your entire Redux store.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Small and complete beats large and comprehensive.&lt;/strong&gt; I didn't add features to compete with React. I added the minimum needed for reactive UIs: state, bindings, effects, computed values, list rendering. If you need routing or global state management, use another library. Lume plays well with others.&lt;/p&gt;




&lt;h2&gt;
  
  
  What This Took
&lt;/h2&gt;

&lt;p&gt;Six months of nights and weekends. I rewrote the core three times. The first version used manual subscriptions and was too verbose. The second used automatic tracking but leaked memory. The third got it right: automatic tracking with explicit cleanup.&lt;/p&gt;

&lt;p&gt;I wrote 114 tests with full coverage. Built working examples (Todo app, Tic-Tac-Toe, multi-step forms). Made sure bundle size never exceeded 2KB. Set up a &lt;a href="https://sathvikc.github.io/lume-js/" rel="noopener noreferrer"&gt;website&lt;/a&gt; with docs and interactive tutorials.&lt;/p&gt;

&lt;p&gt;The hardest part? Figuring out what &lt;em&gt;not&lt;/em&gt; to add. Every feature request meant more bytes. More API surface. More ways to use it wrong. I said no to routing, animations, transitions, form validation, internationalization. Not because they're bad, but because they'd make the core worse.&lt;/p&gt;

&lt;p&gt;Lume does one thing: makes your HTML reactive. Everything else is optional addons or separate libraries.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Happens Next
&lt;/h2&gt;

&lt;p&gt;The core API is stable. No breaking changes planned. The &lt;code&gt;repeat&lt;/code&gt; addon is marked experimental because I want to refine its API before locking it in, but it works and it's tested.&lt;/p&gt;

&lt;p&gt;I'm considering addons for routing and form validation, but only if they stay small and standards-based. No scope creep.&lt;/p&gt;

&lt;p&gt;Mostly, I want to see what people build. If you try Lume and it doesn't fit your use case, tell me why. If you build something cool, show me. If you find a bug, open an issue.&lt;/p&gt;

&lt;p&gt;This is version 1.0 of a bet that JavaScript and HTML are good enough without reinventing them every two years.&lt;/p&gt;




&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://sathvikc.github.io/lume-js/" rel="noopener noreferrer"&gt;Try it live&lt;/a&gt;&lt;/strong&gt; - Interactive playground and tutorials&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/sathvikc/lume-js" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/strong&gt; - Source code and examples&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.npmjs.com/package/lume-js" rel="noopener noreferrer"&gt;npm&lt;/a&gt;&lt;/strong&gt; - Install it&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://sathvikc.github.io/lume-js/api/core/state.html" rel="noopener noreferrer"&gt;Full docs&lt;/a&gt;&lt;/strong&gt; - API reference&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Start with the &lt;a href="https://sathvikc.github.io/lume-js/" rel="noopener noreferrer"&gt;interactive playground&lt;/a&gt; - you'll be productive in 5 minutes.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>opensource</category>
      <category>html</category>
    </item>
  </channel>
</rss>
