<?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: Chirag Aggarwal</title>
    <description>The latest articles on Forem by Chirag Aggarwal (@chiragagg5k).</description>
    <link>https://forem.com/chiragagg5k</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%2F963052%2F5823e752-1d03-4f78-96ae-b9beec03752f.png</url>
      <title>Forem: Chirag Aggarwal</title>
      <link>https://forem.com/chiragagg5k</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/chiragagg5k"/>
    <language>en</language>
    <item>
      <title>How we solved logging at Appwrite</title>
      <dc:creator>Chirag Aggarwal</dc:creator>
      <pubDate>Sun, 19 Apr 2026 11:56:39 +0000</pubDate>
      <link>https://forem.com/chiragagg5k/how-we-solved-logging-at-appwrite-5612</link>
      <guid>https://forem.com/chiragagg5k/how-we-solved-logging-at-appwrite-5612</guid>
      <description>&lt;p&gt;A few weeks back I came across a post by &lt;a href="https://twitter.com/boristane" rel="noopener noreferrer"&gt;@boristane&lt;/a&gt; sharing a website he made, &lt;a href="https://loggingsucks.com" rel="noopener noreferrer"&gt;loggingsucks.com&lt;/a&gt;. It caught my eye because it had been shared by my favorite tech YouTuber, &lt;a href="https://twitter.com/theo" rel="noopener noreferrer"&gt;@theo&lt;/a&gt;. Like most people, I was really inspired by the article and shared it with my team. &lt;a href="https://twitter.com/lukebsilver" rel="noopener noreferrer"&gt;@lukebsilver&lt;/a&gt;, Appwrite's Engineering Lead, was also inspired by it and decided to work on a new PHP library, &lt;code&gt;utopia-php/span&lt;/code&gt;, to fix logging throughout the Appwrite codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we had
&lt;/h2&gt;

&lt;p&gt;Before this, Appwrite used a combination of two different libraries targeting logging in two different areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;utopia-php/console&lt;/code&gt; — a very simple wrapper library around stdout logging using functions like &lt;code&gt;Console::success()&lt;/code&gt;, &lt;code&gt;Console::error()&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;utopia-php/logger&lt;/code&gt; — an adapter-based library to push error logs to monitoring systems like Sentry, AppSignal, Raygun, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Combined, these libraries served their purpose for a long time, but we often ran into problems when debugging production issues, the same ones the original article discusses in detail. I'd highly recommend going through &lt;a href="https://loggingsucks.com" rel="noopener noreferrer"&gt;that article&lt;/a&gt; first so I don't repeat it all here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our solution
&lt;/h2&gt;

&lt;p&gt;Funnily enough, the first tricky problem was deciding on a name. "Logger" was already taken, so we had to be creative. The word "Span" captured exactly what we were trying to solve: a fundamental unit of work with a named, timed operation alongside various attributes, errors, trace IDs, etc.&lt;/p&gt;

&lt;p&gt;The first step was to move away from simple log lines to &lt;strong&gt;structured logging&lt;/strong&gt;. Span enforces this by only exposing a single primary method, &lt;code&gt;add()&lt;/code&gt;, which accepts a key-value pair.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Console&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Deleting project &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$project&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (type=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$type&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, region=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$project&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'region'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Span&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'project.id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$project&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getId&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nc"&gt;Span&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'project.type'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Span&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'project.region'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$project&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'region'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This massively improved the queryability of our logs — one of the things we struggled with most when going through logs in production.&lt;/p&gt;

&lt;p&gt;We also wanted the library to be extremely simple to use. Earlier, with "logger", we had to hop through various dependency injection loops just to use it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kt"&gt;Message&lt;/span&gt; &lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kt"&gt;Document&lt;/span&gt; &lt;span class="nv"&gt;$project&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kt"&gt;Log&lt;/span&gt; &lt;span class="nv"&gt;$log&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// ← has to be injected just to add a tag&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$log&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'projectId'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$project&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getId&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="nv"&gt;$log&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'type'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'type'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="c1"&gt;// ...actual work...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With Span, it's much simpler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kt"&gt;Message&lt;/span&gt; &lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kt"&gt;Document&lt;/span&gt; &lt;span class="nv"&gt;$project&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Span&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'projectId'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$project&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getId&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="nc"&gt;Span&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'type'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'type'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="c1"&gt;// ...actual work...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why not just make the logger methods static?
&lt;/h2&gt;

&lt;p&gt;Because Appwrite's codebase leverages coroutines (via Swoole) for concurrency between requests, similar to goroutines in Go. A naive static implementation would leak state across concurrent requests. Span solves this by allowing you to choose the storage type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Span&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;setStorage&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;Storage\Coroutine&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Exporters
&lt;/h2&gt;

&lt;p&gt;To combine both logger and console capabilities, Span exposes built-in Exporters, which, as the name suggests, export the logs to not just stdout but any supported adapter. The library currently supports three:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Stdout&lt;/strong&gt;: basic usage. Dumps the output as plain JSON:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"worker.deletes"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"span.trace_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7a3f9c2b4e1d8f06"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"span.duration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.92&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"project.id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"67f3a9"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"project.type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"projects"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"project.region"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fra"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pretty&lt;/strong&gt;: JSON dumps are very useful in production where you have OpenTelemetry or other monitoring set up, but locally you just want things to be readable:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;worker.deletes · 1.92s · 7a3f9c2b

  project.id      67f3a9
  project.type    projects
  project.region  fra

  ────────────────────────────────
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Sentry&lt;/strong&gt;: since Sentry is primarily an error tracking system, Span also exposes a callable "sampler" that lets you filter which logs get exported to a particular exporter:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Span&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;addExporter&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;Sentry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dsn&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'...'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="c1"&gt;// Sampler: drop noisy expected errors, keep everything else.&lt;/span&gt;
    &lt;span class="n"&gt;sampler&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Span&lt;/span&gt; &lt;span class="nv"&gt;$span&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$span&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getError&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$error&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;ExecutorException&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nv"&gt;$error&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isPublishable&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Before and after
&lt;/h2&gt;

&lt;p&gt;One massive improvement we saw was with error logs. Before, we had very verbose and noisy errors that were often hard to make sense of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Error] Timestamp: 2026-04-17T10:32:16+00:00
[Error] Type: Utopia\Database\Exception\Timeout
[Error] Message: Query took too long
[Error] File: /usr/src/code/src/Appwrite/Cloud/Platform/Workers/Deletes.php
[Error] Line: 214
Trace: #0 /usr/src/code/app/worker.php(828): ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"worker.deletes"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"span.trace_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7a3f9c2b4e1d8f06"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"span.duration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"project.id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"67f3a9"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error.type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Utopia&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;Database&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;Exception&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;Timeout"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error.message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Query took too long"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error.file"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/usr/src/code/src/Appwrite/Cloud/Platform/Workers/Deletes.php"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error.line"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;214&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error.trace"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"file"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/usr/src/code/app/worker.php"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"line"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;828&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"function"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"action"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're writing PHP in 2026, give &lt;a href="https://github.com/utopia-php/span" rel="noopener noreferrer"&gt;utopia-php/span&lt;/a&gt; a shot. And a massive shoutout to &lt;a href="https://twitter.com/lukebsilver" rel="noopener noreferrer"&gt;@lukebsilver&lt;/a&gt;, who actually built the library. I just learned from him and wanted to share what I picked up.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>php</category>
      <category>beginners</category>
    </item>
    <item>
      <title>JStack + Appwrite: A Match Made in Heaven for Modern Web Development</title>
      <dc:creator>Chirag Aggarwal</dc:creator>
      <pubDate>Sun, 06 Jul 2025 15:27:22 +0000</pubDate>
      <link>https://forem.com/chiragagg5k/jstack-appwrite-a-match-made-in-heaven-for-modern-web-development-1cln</link>
      <guid>https://forem.com/chiragagg5k/jstack-appwrite-a-match-made-in-heaven-for-modern-web-development-1cln</guid>
      <description>&lt;p&gt;If I had a penny for each time a youtuber has launched his own tech stack, I would have 2 pennies, which isn't much but its weird that it happened twice.&lt;/p&gt;

&lt;p&gt;I am talking about &lt;a href="https://create.t3.gg/" rel="noopener noreferrer"&gt;T3 Stack&lt;/a&gt; launched a while back by everyone's favourite Theo, but recently a new player has entered the market called &lt;a href="https://jstack.app/" rel="noopener noreferrer"&gt;JStack&lt;/a&gt;, by Josh who is the lead Devrel at Upstash. To be fair, its not even that recent, but as always &lt;del&gt;I am late to the party&lt;/del&gt; I try to give a framework time to mature and gather feedback from community before giving it a shot.&lt;/p&gt;

&lt;p&gt;So, did I prefer JStack over T3 stack? Did it have more compatibility with Appwrite, my favourite backend provider? Can it be hosted on Appwrite Sites? Let's find out.&lt;/p&gt;

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

&lt;p&gt;Let's start with initialising the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bunx create-jstack-app@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Options selected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;┌   jStack CLI 
│
◇  What will your project be called?
│  testing-jstack-appwrite
│
◇  Which database ORM would you like to use?
│  None
│
◇  Should we run &lt;span class="s1"&gt;'bun install'&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;you?
│  Yes

Using: bun

✔ testing-jstack-appwrite scaffolded successfully!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's just quickly run a dev server to see what we get out of the box:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd cd &lt;/span&gt;testing-jstack-appwrite
bun dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz9c9q9ae61yzugugap9b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz9c9q9ae61yzugugap9b.png" alt="JStack landing page" width="800" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Initialising Project
&lt;/h2&gt;

&lt;p&gt;On skipping the ORM option, the stack still sets up a &lt;code&gt;/src/server&lt;/code&gt; folder with an example posts router. But it only mocks the DB using an array which does not persist:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Mocked DB&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Post&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="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="s2"&gt;Hello World&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We skipped the ORM option because Appwrite provides built-in schema management through its SDK, eliminating the need for a separate ORM layer. To get started, let's head over to &lt;a href="https://cloud.appwrite.io/" rel="noopener noreferrer"&gt;https://cloud.appwrite.io&lt;/a&gt; to set up our project. &lt;/p&gt;

&lt;p&gt;If you are using Appwrite for the first time, I highly recommend you check out our &lt;a href="https://appwrite.io/docs/quick-starts/web" rel="noopener noreferrer"&gt;Start with Web docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is a quick setup guide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new project -&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz6w0nn7x3pt9x8tott78.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz6w0nn7x3pt9x8tott78.png" alt="New project model (Appwrite)" width="800" height="521"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a new web platform and select Next.js -&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw2cvx6dkh8zdrntpy4js.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw2cvx6dkh8zdrntpy4js.png" alt="New platform screen (Appwrite)" width="800" height="333"&gt;&lt;/a&gt;    &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to project overview and grab your project's ID and region-specific endpoint:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjom1n3wjbri8qpko7z7a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjom1n3wjbri8qpko7z7a.png" alt="Project ID and endpoint (Appwrite)" width="800" height="126"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new &lt;code&gt;.env&lt;/code&gt; file in your project directory and paste in those values:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NEXT_PUBLIC_APPWRITE_PROJECT_ID=686a271700323696d223
NEXT_PUBLIC_APPWRITE_ENDPOINT=https://fra.cloud.appwrite.io/v1
NEXT_PUBLIC_APP_DOMAIN=localhost # we will change it later
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Now, let's initialise the Appwrite SDK in the project using:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;bun&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="nx"&gt;appwrite&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This covers up on how to initialize Appwrite in normal Next.js project. Now we need to configure our Appwrite databases according to the project. For this demo, let's create a &lt;code&gt;Posts&lt;/code&gt; collection to shift the mock database JStack uses as an example to Appwrite.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining Schema
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Go to the Appwrite Console &amp;gt; Databases &amp;gt; Create Database. We will call it &lt;code&gt;main&lt;/code&gt; , and keep it' ID as main as well:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frsmpij8n1yqok80pfm15.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frsmpij8n1yqok80pfm15.png" alt="Create database (Appwrite)" width="800" height="800"&gt;&lt;/a&gt;    &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Similarly, create a collection &lt;code&gt;posts&lt;/code&gt; and keep its ID as &lt;code&gt;posts&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Each document in Appwrite already has an unique ID attached to it, so the only attribute we need is &lt;code&gt;name&lt;/code&gt; for now:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcaheyx67pondngmv139t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcaheyx67pondngmv139t.png" alt="Create string attribute (Appwrite)" width="800" height="857"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lastly, you will need to define who can access your collection. To learn more about it, check out the docs for &lt;a href="https://appwrite.io/docs/advanced/platform/permissions" rel="noopener noreferrer"&gt;Appwrite Permissions&lt;/a&gt;. For now, we will set it to any:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2m4jl1939fxqa93olacw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2m4jl1939fxqa93olacw.png" alt="Create permissions" width="800" height="191"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Syncing Types
&lt;/h2&gt;

&lt;p&gt;That's it, we are all set with configuration on the Appwrite Console. Now let's set it up in our project. I will also take the help of the Appwrite CLI to help me set up things faster. You can learn more about how to install it by following the installation docs.&lt;/p&gt;

&lt;p&gt;Once done, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;appwrite init project

? How would you like to start? Link directory to an existing project
? Choose your organization 67610b8ee51f147ca943
? Choose your Appwrite project. &lt;span class="o"&gt;[&lt;/span&gt;object Object]
✓ Success: Project successfully linked. Details are now stored &lt;span class="k"&gt;in &lt;/span&gt;appwrite.json file.
Would you like to pull all resources from project you just linked? Yes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once done, let's utilize the last Types Generation feature to sync our defined types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;appwrite types src/types       

ℹ Info: Detected language: ts
ℹ Info: Directory: src/types does not exist, creating...
ℹ Info: Found 1 collections: posts
ℹ Info: Found 1 attributes across all collections
ℹ Info: Added types to src/types/appwrite.d.ts
✓ Success: Generated types &lt;span class="k"&gt;for &lt;/span&gt;all the listed collections
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result will look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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;type&lt;/span&gt; &lt;span class="nx"&gt;Models&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;appwrite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * This file is auto-generated by the Appwrite CLI. 
 * You can regenerate it by running `appwrite types -l ts src/types`.
 */&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Document&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&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="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Obviously pretty small for now, but a really helpful feature once the project expands and more collections are defined.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Code
&lt;/h2&gt;

&lt;p&gt;Final steps are to connect the Appwrite backend with our tech stack. For that let's create a simple &lt;code&gt;appwrite.ts&lt;/code&gt; file in &lt;code&gt;src/lib&lt;/code&gt; folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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;Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Databases&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;appwrite&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;client&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setEndpoint&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;NEXT_PUBLIC_APPWRITE_ENDPOINT&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProject&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;NEXT_PUBLIC_APPWRITE_PROJECT_ID&lt;/span&gt;&lt;span class="o"&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;databases&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;Databases&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;databases&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we can modify the original &lt;code&gt;post-router.ts&lt;/code&gt; file to use the defined database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;publicProcedure&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../jstack&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;databases&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/lib/appwrite&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Posts&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/types/appwrite&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ID&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;appwrite&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;DATABASE_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;main&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;POSTS_COLLECTION_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;posts&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;postRouter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;router&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;recent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;publicProcedure&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="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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;databases&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listDocuments&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Posts&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;DATABASE_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;POSTS_COLLECTION_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;superjson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;at&lt;/span&gt;&lt;span class="p"&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="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;

  &lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;publicProcedure&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;input&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;object&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="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;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mutation&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="nx"&gt;input&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;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;databases&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createDocument&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Posts&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;DATABASE_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;POSTS_COLLECTION_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="nf"&gt;unique&lt;/span&gt;&lt;span class="p"&gt;(),&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="nx"&gt;input&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="k"&gt;return&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;superjson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&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;And done! Now your JStack application is using Appwrite as its backend provider.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Start the dev server if not already by running:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;bun&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="nx"&gt;dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Your application should have started on: &lt;a href="http://localhost:3000/" rel="noopener noreferrer"&gt;http://localhost:3000/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Create a new post.&lt;/li&gt;
&lt;li&gt;You should be able to see it in recent posts:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foy9htyvp77qqct8grhzf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foy9htyvp77qqct8grhzf.png" alt="Recent posts image" width="800" height="463"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Also, the data should be visible in your Appwrite Console:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foce30jvc16lb80e7v9qu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foce30jvc16lb80e7v9qu.png" alt="Appwrite console showing data" width="800" height="152"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying your application
&lt;/h2&gt;

&lt;p&gt;Until recently, to deploy your Next.js application, you had pretty low choices. But no more &lt;a href="https://appwrite.io/products/sites" rel="noopener noreferrer"&gt;Appwrite Sites&lt;/a&gt;. Now, you can have your backend and frontend hosted on Appwrite.&lt;/p&gt;

&lt;p&gt;Check out these docs on how to get started with Sites - &lt;a href="https://appwrite.io/docs/advanced/self-hosting/sites" rel="noopener noreferrer"&gt;https://appwrite.io/docs/advanced/self-hosting/sites&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's deploy your application using Sites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to Appwrite Console &amp;gt; Sites &amp;gt; Create Site.&lt;/li&gt;
&lt;li&gt;You can upload a tar file directly, or connect to a GitHub repository (I prefer the GitHub option for automatic deployments).&lt;/li&gt;
&lt;li&gt;Select the repository:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe6ww9m9mb2z7w8hc5ggk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe6ww9m9mb2z7w8hc5ggk.png" alt="Selecting repository screen" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can keep all the settings as the default ones, just make sure to upload the environment variables we defined earlier:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwsthkangby5vgqfnntio.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwsthkangby5vgqfnntio.png" alt="Add environment variables screen" width="800" height="212"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Depending on the domain you are assigned / plan to use, you also need to update the &lt;code&gt;APP_DOMAIN&lt;/code&gt; variable we defined earlier. For me I will keep it:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_APP_DOMAIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;jstack&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;appwrite&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appwrite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;network&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Click on deploy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And done! Your application should be live 🎉&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmfxrz2dfa7nhwu26n93o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmfxrz2dfa7nhwu26n93o.png" alt="Deployment successful screenshot" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can checkout the demo application here - &lt;a href="https://jstack-appwrite-template.appwrite.network/" rel="noopener noreferrer"&gt;https://jstack-appwrite-template.appwrite.network/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Let's start by answering the question the blog began with: Do I prefer JStack over T3 Stack? I'm sorry, Theo, but I do.&lt;/p&gt;

&lt;p&gt;JStack solves the fundamental problems I have always had with Next.js:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using &lt;a href="https://hono.dev/" rel="noopener noreferrer"&gt;Hono&lt;/a&gt; instead of Next.js's inbuilt convention for defining API routes.&lt;/li&gt;
&lt;li&gt;Using &lt;a href="https://tanstack.com/" rel="noopener noreferrer"&gt;TanStack&lt;/a&gt; query out of the box. Trust me, you should start now if you are not using it.&lt;/li&gt;
&lt;li&gt;Type safe and uses &lt;a href="https://zod.dev/" rel="noopener noreferrer"&gt;Zod&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most noticeable difference between T3 Stack and JStack is how light they are, mainly due to the inclusion of the tRPC protocol in T3 Stack. Although JStack also uses tRPC, it seems like a much simpler implementation of it. Most projects do not require the complexity tRPC adds, and in my opinion it makes the code 10x more complicated to maintain.&lt;/p&gt;

&lt;p&gt;So, give JStack a shot if you are starting with a new project (or want to spend a weekend migrating your existing stack to it). Huge shoutout to &lt;a href="https://www.youtube.com/@joshtriedcoding" rel="noopener noreferrer"&gt;Josh&lt;/a&gt; for creating this wonderful stack. And lastly, give Appwrite a chance to be your next all in one cloud platform, both for your backend and frontend needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;JStack - &lt;a href="https://jstack.app/" rel="noopener noreferrer"&gt;https://jstack.app/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Appwrite Docs - &lt;a href="https://appwrite.io/docs" rel="noopener noreferrer"&gt;https://appwrite.io/docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Github repository - &lt;a href="https://github.com/ChiragAgg5k/jstack-appwrite-template" rel="noopener noreferrer"&gt;https://github.com/ChiragAgg5k/jstack-appwrite-template&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>Creating Knowledge bases using MindsDB</title>
      <dc:creator>Chirag Aggarwal</dc:creator>
      <pubDate>Wed, 25 Jun 2025 03:35:39 +0000</pubDate>
      <link>https://forem.com/chiragagg5k/creating-knowledge-bases-using-mindsdb-1a33</link>
      <guid>https://forem.com/chiragagg5k/creating-knowledge-bases-using-mindsdb-1a33</guid>
      <description>&lt;p&gt;Whenever we think we knowledge base, what is the first thing that comes to our mind? &lt;/p&gt;

&lt;p&gt;For me it had always been a &lt;strong&gt;library&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Hundreds of thousands of meticulously organised lines of pure knowledge. In digital form, this knowledge is what we call as data. The internet is filled with data, and with the arrival of AI harnessing its power has become easier than ever before.&lt;/p&gt;

&lt;p&gt;But what if you wanted your own library, &lt;em&gt;your own knowledge base&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;In this blog, we will discuss how you can do just that, and use this library of yours to ask anything you would like using simple natural language. We will create a knowledge base of various research papers, ask it some complex questions and for fun, stress test the hell out of it.&lt;/p&gt;

&lt;p&gt;So let’s begin!&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a knowledge base
&lt;/h2&gt;

&lt;p&gt;As an example lets create &lt;strong&gt;Scholar Map&lt;/strong&gt;, an AI-powered research assistant where you can store any research paper and query for them in simple natural language.&lt;/p&gt;

&lt;p&gt;To get started, first setup mindsdb self-hosted instance by following these docs - &lt;a href="https://docs.mindsdb.com/setup/self-hosted/docker" rel="noopener noreferrer"&gt;https://docs.mindsdb.com/setup/self-hosted/docker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Make sure the instance is available on &lt;a href="http://127.0.0.1:47334/" rel="noopener noreferrer"&gt;&lt;code&gt;http://127.0.0.1:47334&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clone the repository:
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Install &lt;code&gt;uv&lt;/code&gt; package manager if not already by following these &lt;a href="https://docs.astral.sh/uv/getting-started/installation/" rel="noopener noreferrer"&gt;installation docs&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sync up dependencies:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv &lt;span class="nb"&gt;sync&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Start the application using:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv run main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│  Scholar Map                                                                                                                                                                  │
╰───────────────────────────────────────────────────────────────── Research Paper Knowledge Management System ──────────────────────────────────────────────────────────────────╯
Connecting to MindsDB...
Attempting to connect to MindsDB server...
Connection established successfully!
Setting up research papers knowledge base...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script will automatically run the configuration code and setup knowledge base.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/4ZksrrIPWp4"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

</description>
    </item>
    <item>
      <title>From student to full-time Platform Engineer at Appwrite</title>
      <dc:creator>Chirag Aggarwal</dc:creator>
      <pubDate>Sat, 21 Jun 2025 14:52:08 +0000</pubDate>
      <link>https://forem.com/chiragagg5k/from-student-to-full-time-platform-engineer-at-appwrite-49ci</link>
      <guid>https://forem.com/chiragagg5k/from-student-to-full-time-platform-engineer-at-appwrite-49ci</guid>
      <description>&lt;h2&gt;
  
  
  TLDR
&lt;/h2&gt;

&lt;p&gt;For those who are not really interested in reading some random university student’s story, here is a short TLDR. I worked at Appwrite as an Engineering Intern for 6 months and just got offered a full-time position as a Platform Engineer, while still being in University for another year :D&lt;/p&gt;

&lt;p&gt;The story ahead covers how while drowning in a sea of desperation a light of hope changed everything for me, how my experience was working for a fully remote OSS company, and the challenges I faced while working in PHP, a language I had never touched before this :p&lt;/p&gt;




&lt;h2&gt;
  
  
  Pre-Interview
&lt;/h2&gt;

&lt;p&gt;Back in September-November 2024, I was kind of at the lowest point of my engineering journey yet. I had concluded my last internship around August when the project I was working on abruptly closed, and since then I was on a constant hunt for my next one.&lt;/p&gt;

&lt;p&gt;Silence. From all the mediums I tried  - LinkedIn, Upwork, AngelList, cold DMs, and what not.&lt;/p&gt;

&lt;p&gt;The thing is that once you start “working”, although it was an unpaid one, it’s pretty hard to go back to doing… nothing. “Nothing” is the wrong word I guess, I was still working on OSS, building projects, and trying to learn new things. But if someone asked what I was up to nowadays… i drew a blank.&lt;/p&gt;

&lt;p&gt;Then one day I was just hanging out on Discord and saw a notification from a bright red server I usually didn’t check much. Hey, it’s another job opening, so I applied like usual. Another month passed, silence again. But then I saw an email from Emma, our People’s person at Appwrite.&lt;/p&gt;

&lt;p&gt;“We wanna have a chat with you.”&lt;/p&gt;

&lt;p&gt;This was a very unusual email for me. Usually, companies like to give an assignment for the first round, but here it was a direct meeting scheduled… so I already knew something was different this time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Interview(s)
&lt;/h2&gt;

&lt;p&gt;Of course, I am not allowed to share the entire interview experience without getting into a call with Emma after this is published. So, I just want to share one question that has stuck with me since then,&lt;/p&gt;

&lt;p&gt;“Looking at your resume, you don’t seem to have much if any experience with PHP. And Appwrite’s entire backend is in PHP. Will you be able to handle this?” - Torsten, Product Engineer at Appwrite.&lt;/p&gt;

&lt;p&gt;Stunned. Before going to the interview I did see the codebase was written in PHP. I had never touched it before. No contributions, No issues filed. So I assumed the position I was applying for might have nothing related to this codebase… maybe a new project altogether… right? Nope. &lt;/p&gt;

&lt;p&gt;My answer? It was somewhere along the lines of “I will figure it out, trust me, bro”.&lt;/p&gt;

&lt;p&gt;Very bad answer I know. But it was the best I could come up with. After the interview, I went on a grind. Reading the codebase, running it, and understanding its architecture (in that process I even wrote an article - &lt;a href="https://dev.to/chiragagg5k/architecture-patterns-for-beginners-mvc-mvp-and-mvvm-2pe7"&gt;Architecture Patterns for Beginners: MVC, MVP, and MVVM&lt;/a&gt;). Long story short I tried to learn as much about Appwrite’s codebase as was physically possible in that timeframe from the next interview scheduled.&lt;/p&gt;

&lt;p&gt;And Tada~ It worked. I got the offer!&lt;/p&gt;

&lt;h2&gt;
  
  
  Experience
&lt;/h2&gt;

&lt;p&gt;Working at Appwrite is unlike working in any other place. From the first day on, even though you are an Intern, you are never treated like one. I was introduced to the entire codebase in my first week and assigned to issues not from the pending log, but actual production issues that users were facing.&lt;/p&gt;

&lt;p&gt;You can message anyone. At any point.&lt;/p&gt;

&lt;p&gt;Work on any issue that you like.&lt;/p&gt;

&lt;p&gt;There is a padding issue you saw on the website? Knock yourself out and raise the PR.&lt;/p&gt;

&lt;p&gt;The beautiful thing about Appwrite being open source is that you could do this from the very start. It’s just now I could bug anyone on the team more freely if I was stuck on any issue.&lt;/p&gt;

&lt;p&gt;It’s hard to summarise how much work I did in the past 6 months, but here are some notable ones:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;200+ PRs merged in the Appwrite organization’s repositories, including main, website, SDK, MCP, etc. repositories.&lt;/li&gt;
&lt;li&gt;Uptime monitoring for the &lt;a href="https://appwrite.io/docs/tooling/assistant" rel="noopener noreferrer"&gt;Appwrite Assistant&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Adding a monthly limit to the number of free Phone OTPs allowed.&lt;/li&gt;
&lt;li&gt;Fixing Amazon and Slack OAuth adapters. Add Figma OAuth adapter.&lt;/li&gt;
&lt;li&gt;Making several changes to SDKs and making releases.&lt;/li&gt;
&lt;li&gt;Adding Types generation to Appwrite CLI.&lt;/li&gt;
&lt;li&gt;Worked on the DevKeys feature in the latest Appwrite release 1.7&lt;/li&gt;
&lt;li&gt;Added 2 blogs on the website - self-hosting using coolify and announcement for &lt;a href="https://appwrite.io/blog/author/chirag-aggarwal" rel="noopener noreferrer"&gt;DevKeys&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Taking leadership on the &lt;a href="https://github.com/appwrite/synapse" rel="noopener noreferrer"&gt;Synapse&lt;/a&gt; project, operating system gateway for remote serverless environments.&lt;/li&gt;
&lt;li&gt;Adding new phone OTP adapter - Inforu, which reduces pricing for phone OTPs for Israeli users by 11x.&lt;/li&gt;
&lt;li&gt;and… a lot more.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Honestly looking back at it, I never realized I worked on so much. It feels like I had just joined Appwrite yesterday. &lt;/p&gt;

&lt;h2&gt;
  
  
  Thank You
&lt;/h2&gt;

&lt;p&gt;At last, I wanna thank the entire Appwrite team for treating me like part of the team since day one, and for giving me this opportunity. Let’s build like a team of hundreds_&lt;/p&gt;




&lt;p&gt;&lt;em&gt;You can check out my profile to learn more about me - &lt;a href="https://www.chiragaggarwal.tech/" rel="noopener noreferrer"&gt;https://www.chiragaggarwal.tech/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Hit me up on any socials if you have any doubts, I am always up for a chat :D&lt;/em&gt;&lt;/p&gt;

</description>
      <category>career</category>
    </item>
    <item>
      <title>Automate anything - Making research analysis effortless</title>
      <dc:creator>Chirag Aggarwal</dc:creator>
      <pubDate>Sat, 14 Jun 2025 05:13:48 +0000</pubDate>
      <link>https://forem.com/chiragagg5k/automate-anything-making-research-analysis-effortless-250a</link>
      <guid>https://forem.com/chiragagg5k/automate-anything-making-research-analysis-effortless-250a</guid>
      <description>&lt;p&gt;Starting with a research project can be overwhelming.&lt;/p&gt;

&lt;p&gt;There are so many data points to consider, so many hours of reading to do, and within all that chaos, the hardest piece of the puzzle to find is a &lt;strong&gt;starting point&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I faced this first hand when last year I had to work on multiple papers to earn a single credit point for my engineering degree. Unfortunately why universities force this pointless system is not the spotlight of today’s discussion.&lt;/p&gt;

&lt;p&gt;Instead, we are going to discuss how you can cheat on this mundane activity using Runner H.&lt;/p&gt;

&lt;p&gt;The article will redefine how you interact with AI, helping you put together analysis, execution, summarisation and integration with a single prompt.&lt;/p&gt;

&lt;p&gt;So, let’s dive in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Researcher’s Dilemma
&lt;/h2&gt;

&lt;p&gt;Whenever you start with a research project, the first question that comes to mind is: &lt;strong&gt;"Has this been researched before?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Answering this question is crucial for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Avoiding duplication of work&lt;/li&gt;
&lt;li&gt;Finding gaps in the existing study&lt;/li&gt;
&lt;li&gt;Not claiming something as noble when it has already been done before&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;However, doing this is a very manual process, and requires hours and hours of find papers, reading them and doing accurate analysis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Meet Runner H
&lt;/h2&gt;

&lt;p&gt;Ever tried using Perplexity or ChatGPT in research mode? &lt;/p&gt;

&lt;p&gt;Think of Runner H as that, but on &lt;strong&gt;steroids&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Runner H is an advanced AI-powered web automation tool that lets you perform multi-step online tasks using natural language instructions. It seamlessly integrates with services like Slack, Notion, Gmail, and Excel, enabling you to create complex workflows, no coding experience required.&lt;/p&gt;

&lt;p&gt;For our purpose, we can use Runner H to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Quickly identify similar research papers with a Google Scholar scan.&lt;/li&gt;
&lt;li&gt;Assess similarities between them and your topic using AI.&lt;/li&gt;
&lt;li&gt;Scan the internet to find gaps between the existing work.&lt;/li&gt;
&lt;li&gt;Export the findings in a structured format.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The prompt
&lt;/h2&gt;

&lt;p&gt;Below, I have crafted a prompt that you can copy and paste into Runner H, replace with the topic you need to research, and voila~, see the magic unfold:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Analyse if my research idea, {YOUR_RESEARCH_IDEA}, has been previously explored. Search Google Scholar for similar research papers. For each, extract the title, authors, publication date, abstract, journal/conference, and similarity percentage to my idea, and note any research gaps mentioned or left open. Create an Excel file summarising all findings.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Just replace &lt;code&gt;{YOUR_RESEARCH_IDEA}&lt;/code&gt; with the idea you want to research on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Let’s try researching on a topic:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“The impact of generative AI tools on student learning outcomes in higher education”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/kFZjj8X33F0"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;So Runner H after doing all the analysis and hard work for us was able to generate a structured output. Unfortunately, even though prompt specifically asks for Excel format, most of the times for me it generated a PDF format for me. Still Runner H is still in early phases and hopefully will be improved in future by the team.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what makes Runner H different?
&lt;/h2&gt;

&lt;p&gt;One of the most fascinating differentiations I found in Runner H compared to other agentic tools was its ability to search, summarise and synthesize as well. Instead of just dumping in raw results, it evaluates the relevance of each paper, highlights the overlaps and gaps in the study, and presents it in an actionable format.&lt;/p&gt;

&lt;p&gt;Using Runner H has completely transformed my approach to starting a research topic. It has bridged me to the starting point where I used to struggle the most. For students, academic professionals, and anyone doing any sort of research work, Runner H is a game changer.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Happy researching! If you have questions or want to share your own experiences with Runner H, drop a comment below.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>runnerhchallenge</category>
      <category>ai</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Vibe coding an Email Ticket Automater using Postmark</title>
      <dc:creator>Chirag Aggarwal</dc:creator>
      <pubDate>Sat, 31 May 2025 02:44:00 +0000</pubDate>
      <link>https://forem.com/chiragagg5k/vibe-coding-an-email-ticket-automater-using-postmark-l11</link>
      <guid>https://forem.com/chiragagg5k/vibe-coding-an-email-ticket-automater-using-postmark-l11</guid>
      <description>&lt;p&gt;This is a submission for the &lt;a href="https://dev.to/challenges/postmark"&gt;Postmark Challenge: Inbox Innovators&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;Support tickets…&lt;/p&gt;

&lt;p&gt;Nobody really loves either writing or much worse reading them. And managing them is much much worse than managing my laundry, and that is a really high bar to pass.&lt;/p&gt;

&lt;p&gt;So, in a world where we all are writing and summarising emails for the sake of maintaining formality, automating support tickets seems like the logical next step.&lt;/p&gt;

&lt;p&gt;And sure there are companies that do this… not really going to name them, but my vision here was to just create something that takes the unorganized text and convert it to organized boxes, while still being pretty to look at… &lt;em&gt;cough&lt;/em&gt; Jira &lt;em&gt;cough.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Meet EmailTicket. Firstly hoping that marks are not being deducted for the lack of naming creativity, it's here to do exactly what it says. Create tickets based on emails. Sounds simple right? Well kind of… but with some headaches.&lt;/p&gt;

&lt;p&gt;Historically, when creating tickets you would have to ask the user a bunch of information like whether it is a billing issue, a bug, or feedback, when did the issue start, etc. &lt;/p&gt;

&lt;p&gt;After creation, you would have to manually keep track of information like how urgent is it. Has the ticket been closed or is it still in progress? etc. etc.&lt;/p&gt;

&lt;p&gt;You know… the boring stuff.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyg0bvs81e953d8r4bu37.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyg0bvs81e953d8r4bu37.png" alt="Ticket Modal"&gt;&lt;/a&gt;&lt;br&gt;Image captured during the pre-AI times (just kidding it was created using ChatGPT)
  &lt;/p&gt;




&lt;p&gt;But with AI, we no longer need to take care of that stuff. Just give it a random block of text and out comes structured beauty (It’s like a dream come true for data scientists honestly).&lt;/p&gt;

&lt;p&gt;This is pretty much what Email Ticket does for now. It’s highly inspired by platforms like HelpScout (an amazing tool btw do check it out) and in the future can extend a lot more if good guys like the ones from Postmark support it :D&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/yvApeUgQcVs"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Checkout the live link here - &lt;a href="https://email-ticket-automator.vercel.app/" rel="noopener noreferrer"&gt;https://email-ticket-automator.vercel.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If your emails are stuck on processing/waiting, It’s highly likely that I ran out of the 100 free emails. So… don’t sweat too much about it 😅&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Repository
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ChiragAgg5k" rel="noopener noreferrer"&gt;
        ChiragAgg5k
      &lt;/a&gt; / &lt;a href="https://github.com/ChiragAgg5k/email-ticket-automator" rel="noopener noreferrer"&gt;
        email-ticket-automator
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      AI-powered helpdesk platform leveraging email-parsing by Postmark
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;📧 Email Ticket&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A modern, AI-powered helpdesk platform that transforms email support into an organized ticket management system. Built with React, TypeScript, Postmark, and Appwrite for seamless customer support experiences.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/ChiragAgg5k/email-ticket-automator/blob/main/assets/banner-cropped.png?raw=true"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FChiragAgg5k%2Femail-ticket-automator%2Fraw%2Fmain%2Fassets%2Fbanner-cropped.png%3Fraw%3Dtrue" alt="Email Ticket Dashboard"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🏹 Quick Start&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Prerequisites&lt;/h3&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Node.js 18+ and npm&lt;/li&gt;
&lt;li&gt;Postmark account for email parsing&lt;/li&gt;
&lt;li&gt;Appwrite account for backend services&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Installation&lt;/h3&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Clone the repository&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;git clone https://github.com/ChiragAgg5k/email-ticket-automator.git
&lt;span class="pl-c1"&gt;cd&lt;/span&gt; email-ticket-automator&lt;/pre&gt;

&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Install dependencies&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;bun i &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; or npm install&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Configure Appwrite&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create an Appwrite project at &lt;a href="https://cloud.appwrite.io" rel="nofollow noopener noreferrer"&gt;cloud.appwrite.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Update the configuration in &lt;code&gt;src/lib/appwrite.ts&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight highlight-source-ts notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-s1"&gt;client&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;setEndpoint&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;"YOUR_APPWRITE_ENDPOINT"&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-s1"&gt;client&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;setProject&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;"YOUR_PROJECT_ID"&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Start the development server&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;bun dev&lt;/pre&gt;

&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Open your browser&lt;/strong&gt;
Navigate to &lt;code&gt;http://localhost:8080&lt;/code&gt; to see the application&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🛠️ Tech Stack&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Frontend&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;React&lt;/strong&gt; - Modern React with hooks and functional components&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TypeScript&lt;/strong&gt; - Type-safe development experience&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vite&lt;/strong&gt; - Fast build tool and development server&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailwind CSS&lt;/strong&gt; - Utility-first CSS framework&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;shadcn/ui&lt;/strong&gt; - High-quality, accessible UI components&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Backend &amp;amp; Services&lt;/h3&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ChiragAgg5k/email-ticket-automator" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;So most of the application is vibe-coded using Lovable. Was it because I am lazy? Probably yes. But that’s not the exact reason. In my opinion tools like Lovable, V0, Firebase Studio (god there are so many now), etc. are perfectly fine to use to get an initial MVP of your idea up and running.&lt;/p&gt;

&lt;p&gt;And in a world where AI is dominating the entire development process, not utilizing these tools is just slowing you down.&lt;/p&gt;

&lt;p&gt;So let’s talk about the 10% of coding I actually did.&lt;/p&gt;

&lt;p&gt;The first was integration with a database. Or more specifically a Backend as a Service because who codes their own backend nowadays? So naturally I went with Appwrite. Lovable refused to do this integration, but thankfully Appwrite is extremely easy to set up. I used it to implement Authentication flow, as well as Database for ticket storing and retrieval.&lt;/p&gt;

&lt;p&gt;Next was the start of the application, Postmark. Postmark made the entire process of receiving an email, parsing it into JSON, and receiving it just via an API call so easy, I forgot dealing with emails was such an annoying task.&lt;/p&gt;

&lt;p&gt;Firstly, I needed to A) Either get inbound domain forwarding setup, or B) Get my account approved to be able to send emails to the default inbound email address with no domain restrictions. I tried both techniques and luckily got my account approved in 2 days!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flid9dtnuzzd6gktuziv5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flid9dtnuzzd6gktuziv5.png" alt="Postmark Email"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Not so luckily I was never able to set my inbound domain even tho I had my MX record set properly and could verify it using &lt;a href="https://www.whatsmydns.net/" rel="noopener noreferrer"&gt;https://www.whatsmydns.net/&lt;/a&gt; (You can check my comment here complaining about it - &lt;a href="https://dev.to/chiragagg5k/comment/2o6hi"&gt;https://dev.to/chiragagg5k/comment/2o6hi&lt;/a&gt;). So something to note down @Postmark team.&lt;/p&gt;

&lt;p&gt;To utilize the API seamlessly without ever needing to touch a single line of actual backend code, I came up with this flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Appwrite triggers a “create” document/ticket event.&lt;/li&gt;
&lt;li&gt;The event triggers a function that then calls the Postmark’s API for sending an inbound email.&lt;/li&gt;
&lt;li&gt;Postmark listens to the inbound email and triggers an email parsing flow.&lt;/li&gt;
&lt;li&gt;After parsing is done it returns the output to a webhook URL which is just an Appwrite function.&lt;/li&gt;
&lt;li&gt;The Appwrite function finally processes the parsed content and stores it back to the database.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqsmi3ogtpgd07jqm5k9g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqsmi3ogtpgd07jqm5k9g.png" alt="Flow Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally time for structured outputs. Almost all LLMs offer a way to generate structured outputs now in their APIs. Here are some docs I found for this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://docs.perplexity.ai/guides/structured-outputs" rel="noopener noreferrer"&gt;https://docs.perplexity.ai/guides/structured-outputs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://platform.openai.com/docs/guides/structured-outputs?api-mode=responses" rel="noopener noreferrer"&gt;https://platform.openai.com/docs/guides/structured-outputs?api-mode=responses&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.anthropic.com/en/docs/test-and-evaluate/strengthen-guardrails/increase-consistency" rel="noopener noreferrer"&gt;https://docs.anthropic.com/en/docs/test-and-evaluate/strengthen-guardrails/increase-consistency&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;and on and on…&lt;/p&gt;

&lt;p&gt;(a small plug would be to check this repo I worked on which allows you to use any LLM with structured outputs and consistent syntax in PHP - &lt;a href="https://github.com/utopia-php/agents" rel="noopener noreferrer"&gt;https://github.com/utopia-php/agents&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;You can check the &lt;a href="https://github.com/ChiragAgg5k/email-ticket-automator/blob/main/functions/email-parsed-webhook/src/main.js" rel="noopener noreferrer"&gt;repository code&lt;/a&gt; itself to see which one I picked because I might have changed it by the time you are reading it :p&lt;/p&gt;

&lt;p&gt;That’s it then. Let me know in the comments how was your experience using EmailTicket Automater. You can reach out to me on any of my social media links if you have any queries or just wanna have a casual talk. A big shoutout to Postmark for arranging this contest and letting me have fun with their platform, as well as my company Appwrite for supporting the application’s backend :D&lt;/p&gt;

&lt;p&gt;Bye!&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>postmarkchallenge</category>
      <category>webdev</category>
      <category>api</category>
    </item>
    <item>
      <title>Focus on the product, not the tech stack</title>
      <dc:creator>Chirag Aggarwal</dc:creator>
      <pubDate>Wed, 14 May 2025 16:48:53 +0000</pubDate>
      <link>https://forem.com/chiragagg5k/focus-on-the-product-not-the-tech-stack-15d</link>
      <guid>https://forem.com/chiragagg5k/focus-on-the-product-not-the-tech-stack-15d</guid>
      <description>&lt;p&gt;Recently I got this DM,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdnfiao9st34jlhfpw28.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdnfiao9st34jlhfpw28.png" alt="Twitter DM" width="788" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;“Which tech stack should I learn?”&lt;/p&gt;

&lt;p&gt;“Should I use Next.js or Svelte?”&lt;/p&gt;

&lt;p&gt;“Is Python better for the backend than node?”&lt;/p&gt;

&lt;p&gt;I am sure we have asked or been asked questions like this several times in our tech journeys. As someone who is just starting out, I think it seems like a very important thing to ask. You don’t wanna waste your time learning a technology that might become worthless soon? Or isn’t fast enough? or isn’t the “industry standard”… right?&lt;/p&gt;

&lt;p&gt;Or should it matter?&lt;/p&gt;

&lt;h2&gt;
  
  
  Languages are just tools
&lt;/h2&gt;

&lt;p&gt;Back in 2003 when Facebook was originally founded, its backend was written in PHP. Was it the lack of options? You can say so. Back then they certainly didn’t have a plethora of frameworks or hell even languages to choose from. But what about now? Realistically PHP should be dead by now…&lt;/p&gt;

&lt;p&gt;Right?&lt;/p&gt;

&lt;p&gt;But if you look at the &lt;a href="https://kinsta.com/php-market-share/" rel="noopener noreferrer"&gt;statistics by Kinsta&lt;/a&gt;, around 79.2% of the internet still relies on PHP to some degree. Okay, but that number has to be declining for sure!&lt;/p&gt;

&lt;p&gt;But wait...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiytuwpkuplv3pxtq2ypn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiytuwpkuplv3pxtq2ypn.png" alt="PHP Trend Chart" width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nope, it has been on a steady increase since 2011, peaking at 80.6% in 2015, and maintaining a steady line.&lt;/p&gt;

&lt;p&gt;But how?&lt;/p&gt;

&lt;p&gt;It’s because language is just a tool. It does not matter how many new bleeding edge languages enter the market increasing the performance metrics by some fractions of seconds, as long as a &lt;del&gt;tool&lt;/del&gt; language sufficiently fulfills its job, it will stay relevant. PHP has done a great job at that. It’s constantly evolving as well, something which is direly required to stay alive in the software world.&lt;/p&gt;

&lt;p&gt;So next time if someone asks you “Which language should I choose?”, ask them two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Which language are you more comfortable with?&lt;/li&gt;
&lt;li&gt;Do the other languages provide a set of features more beneficial for your use case? Even if so are they worth the effort to learn? (arguments like uh it's 0.001sec faster should not be relevant)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  It’s OK to not upgrade
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmggrfh7nqkijd465dn8r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmggrfh7nqkijd465dn8r.png" alt="Updating dependencies meme" width="800" height="420"&gt;&lt;/a&gt;&lt;br&gt;Image from: &lt;a href="https://foreverealize.me/posts/how-to-update-dependencies/" rel="noopener noreferrer"&gt;https://foreverealize.me/posts/how-to-update-dependencies/&lt;/a&gt;
  &lt;/p&gt;

&lt;p&gt;I was once asked, “Why is your website still at Next version 13 when 15 has arrived?”&lt;/p&gt;

&lt;p&gt;To which I ask, why does it matter? Sure software is meant to be ever-evolving, but that doesn’t necessarily mean it's a good idea to always hop on the upgrade bandwagon without looking at the consequences.&lt;/p&gt;

&lt;p&gt;This in this case will be a complete re-write since Next 15 introduces a ton of breaking changes.&lt;/p&gt;

&lt;p&gt;And it's OK not to upgrade every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Judge a product by its usefulness, not complexity
&lt;/h2&gt;

&lt;p&gt;A lot of people especially those building projects just for improving their resume will try to make them extremely complex. It will be a wobbly mess of high-end sounding technologies like SSR, TRPC, GraphQL, Kubernetes, Redis, etc.&lt;/p&gt;

&lt;p&gt;Sure I do understand the thinking behind this, it does show your ability to work with complex technologies.&lt;/p&gt;

&lt;p&gt;But in the age of AI and the really fast-moving pace of technology, it's pretty trivial for someone to learn technologies on the go and incorporate them into their project. Real engineering will always be that “&lt;strong&gt;solves a problem, not create one&lt;/strong&gt;”. Solving problems always requires asking questions first:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Does your project really need TRPC or GraphQL? Why not just use REST like everyone does bruh?&lt;/li&gt;
&lt;li&gt;Do I really need Kubernetes for those 5 concurrent connections?&lt;/li&gt;
&lt;li&gt;Does my really interactive website need SSR where then each button click will be a server action and take ages to process any action?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ikoimzgzcyvgo9c1ot8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ikoimzgzcyvgo9c1ot8.png" alt="Tutorial hell meme" width="506" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And please, stop building clones. It does not matter: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how many services you use in it&lt;/li&gt;
&lt;li&gt;how much knowledge you gained from creating it&lt;/li&gt;
&lt;li&gt;how complex the project was to make&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The YouTube clone you made by following a random Youtuber’s 8-hour-long guide is not going to help you in any way.&lt;/p&gt;

&lt;p&gt;Quoting &lt;a href="https://www.youtube.com/@t3dotgg" rel="noopener noreferrer"&gt;Theo&lt;/a&gt; (idk where he said tho):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To build a great product, you need to first be a customer&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you want project ideas, look around you. Try to solve problems you face every day. If you just try looking, you WILL find many.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;This blog is a summary of my (I admit very short-lived) experience of working in tech till now. I always tried not to treat tech as something I specialize in, but as a tool that helps me solve problems. &lt;/p&gt;

&lt;p&gt;I started off my journey in web with a simple problem, I just wanted a website of my own because it would be cool :D&lt;/p&gt;

&lt;p&gt;Then a simple problem gave birth to more problems with a chain reaction ongoing, to me finding myself working with PHP, something I would have never imagined doing in a million years before. &lt;/p&gt;

&lt;p&gt;So…. that’s it. Keep building and showcasing your work, and most importantly, have fun at it!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Debugging with Source Maps: A Comprehensive Guide</title>
      <dc:creator>Chirag Aggarwal</dc:creator>
      <pubDate>Sun, 09 Mar 2025 18:44:24 +0000</pubDate>
      <link>https://forem.com/chiragagg5k/debugging-with-source-maps-a-comprehensive-guide-3dhp</link>
      <guid>https://forem.com/chiragagg5k/debugging-with-source-maps-a-comprehensive-guide-3dhp</guid>
      <description>&lt;p&gt;We all have been there, working on a new feature for 10+ hours straight, and everything is going well. You build your project and push the code to production. And boom, a new production error alert! Everyone in your team - whether at a company or a hackathon - starts to look for someone to blame. Found it; it was from you. But none of your test suites resulted in an error. Everything with the code itself looks excellent.&lt;/p&gt;

&lt;p&gt;You check the logs. The error is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Uncaught Error: Cannot &lt;span class="nb"&gt;read &lt;/span&gt;property &lt;span class="s1"&gt;'xyz'&lt;/span&gt; of undefined at app.min.js:1:45678
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You think to yourself, what the heck is &lt;code&gt;app.min.js:1:45678&lt;/code&gt; supposed to mean? There was no file like that in the entire source code? Your file was called &lt;code&gt;app.js&lt;/code&gt;. And it's 45678 characters long! That's impossible to debug!! Still, you try to open the file and potentially find the root cause of the error. It's a mess. The entire file is filled with random gibberish you are unable to understand. What should you do?&lt;/p&gt;

&lt;p&gt;Now, this is where Source Maps come into play. Source Maps allow you to map the minified code in your production environment, &lt;em&gt;aka the random gibberish you just saw&lt;/em&gt;, with the actual source code, allowing you to pinpoint the root cause of the error in your source code and debug it effectively.&lt;/p&gt;

&lt;p&gt;In this blog, we will detail what source maps are, why and how they are created, and give some tips on effectively using source maps to debug your code. Let's dive in!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why is source code minified?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Before we delve into Source Maps, let's first decode what happened to your clean, formatted and linked source code and why it looks nothing like it on the browser.&lt;/p&gt;

&lt;p&gt;The simple answer is minification.&lt;/p&gt;

&lt;p&gt;Minification is the process of converting your source code into production-ready code without changing any of its functionality. This is typically done by the bundler you are using, such as Webpack. To learn more about bundlers, you can check out this awesome &lt;a href="https://snipcart.com/blog/javascript-module-bundler" rel="noopener noreferrer"&gt;guide on Javascript bundlers&lt;/a&gt; by &lt;a href="https://snipcart.com/" rel="noopener noreferrer"&gt;Snipcart&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Simply put, bundlers optimise your source code by stripping out whitespaces, comments, and redundant code and even removing or renaming variables for shorter alternatives. This makes your code super efficient and much smaller in size.&lt;/p&gt;

&lt;p&gt;Why does this happen?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Improved load times&lt;/strong&gt; - Smaller file sizes lead to better website loading times.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Obfuscation—&lt;/strong&gt;Although it won't make your code entirely illegible, it does make it harder for regular users to understand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Browser Performance&lt;/strong&gt; - The code is altered in a way that's easy for browser engines to parse.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is an example of what a minified React app code looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fykp4yriiyci828833oct.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fykp4yriiyci828833oct.png" alt="Bundle.js file containing minified code" width="800" height="276"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;bundle.js file created by Webpack on building a simple React app, even the text is overflowing from the terminal screenshot!&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What are source maps?
&lt;/h2&gt;

&lt;p&gt;Source maps are files whose names end with &lt;code&gt;.map&lt;/code&gt; and that map the minified code to your actual source code. Examples of such files can be &lt;code&gt;example.min.js.map&lt;/code&gt; or for css, &lt;code&gt;styles.css.map&lt;/code&gt;. They are explicitly generated only by build tools like Webpack, Vite, Rollup, Parcel etc. Since source maps are only required for debugging purposes, these tools usually have the option to generate source maps off by default. For example to enable it in Webpack, you can do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// add this to your package.json file&lt;/span&gt;
&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scripts&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;build:dev&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;webpack --mode development --devtool source-map&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;or add it to your &lt;code&gt;webpack.config.js&lt;/code&gt;  file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;devtool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;source-map&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// ...rest of your config&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A source map includes crucial information on how the mapping is done, including the actual source file name, the content it includes, various variable name the source code has, name of the minified code file etc.&lt;/p&gt;

&lt;p&gt;Here is a format of how a typical source map file looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mappings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AAAA,SAAQA,MAAMA,QAAQ,OAAO;AAC7B,SAAQC...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sources&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sourcesContent&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;import React from 'react';&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;import { createRoot } from 'react-dom/...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;names&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;React&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;createRoot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;setCount&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;useState&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;version&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bundle.js.map&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The most important section here is &lt;code&gt;mappings&lt;/code&gt;. This uses a special kind of encoding called &lt;a href="https://developer.chrome.com/blog/sourcemaps#base64-vlq-and-keeping-the-source-map-small" rel="noopener noreferrer"&gt;VLQ base 64 encoded string&lt;/a&gt; to map the lines and locations to compiled file and its corresponding original file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visualising source maps
&lt;/h2&gt;

&lt;p&gt;"Okay, great!" I hear you saying. "How is this actually helpful? I still can't read the source maps and manually decode the mappings."&lt;/p&gt;

&lt;p&gt;That's a great question! This brings me to the main highlight of this blog—source map visualisers. These tools allow you to see the mappings in a visual manner to locate and debug the problem effectively. There are many source map visualisers on the market, but today, we will be focusing on Sokra &amp;amp; Paulirish's source map visualization. You can find the source code for this on their &lt;a href="https://github.com/sokra/source-map-visualization/" rel="noopener noreferrer"&gt;Github Repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is a side-by-side comparison of how your code (on the right-hand side) can look like a jumbled mess when minified (on the left-hand side). However, the colour-coded mapping of the visualiser helps us map these two codes by hovering over them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmpgftukud1078hx2iui4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmpgftukud1078hx2iui4.png" alt="Comparison between minified code and source code" width="800" height="335"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Let’s create a simple React app and play around with it’s sourcemaps!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start with creating a project directory:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;my-project
&lt;span class="nb"&gt;cd &lt;/span&gt;my-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Init a new project:
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Add the following dependencies into &lt;code&gt;package.json&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"react-counter-app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Simple React Counter App"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"webpack serve --mode development"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"webpack --mode production"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"echo &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Error: no test specified&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; &amp;amp;&amp;amp; exit 1"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"react"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^18.2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"react-dom"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^18.2.0"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@babel/core"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^7.23.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@babel/preset-env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^7.23.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@babel/preset-react"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^7.22.15"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"babel-loader"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^9.1.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"css-loader"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^6.8.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"html-webpack-plugin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^5.5.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"style-loader"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^3.3.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"webpack"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^5.88.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"webpack-cli"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^5.1.4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"webpack-dev-server"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.15.1"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create a &lt;code&gt;src/index.js&lt;/code&gt; file with following React code:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/index.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&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;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createRoot&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;react-dom/client&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./styles.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useState&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;increment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decrement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"app"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Counter: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Increment&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;decrement&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Decrement&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// New React 18 createRoot API&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&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;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createRoot&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;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Add styling by adding a &lt;code&gt;src/styles.css&lt;/code&gt; file:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* src/styles.css */&lt;/span&gt;
&lt;span class="nc"&gt;.app&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Arial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;500px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#4CAF50&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text-decoration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;inline-block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#45a049&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Now define the webpack config by creating a &lt;code&gt;webpack.config.js&lt;/code&gt; file in the root folder:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// webpack.config.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&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;HtmlWebpackPlugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;html-webpack-plugin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./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="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&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="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dist&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bundle.js&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;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.(&lt;/span&gt;&lt;span class="sr"&gt;js|jsx&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/node_modules/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;babel-loader&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;presets&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;@babel/preset-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;@babel/preset-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;css$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;use&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;style-loader&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;css-loader&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&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;HtmlWebpackPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./public/index.html&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;devServer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;static&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;directory&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;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public&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;port&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;open&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;extensions&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;.js&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;.jsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Now you can start the application by running:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;webpack serve &lt;span class="nt"&gt;--mode&lt;/span&gt; development
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is how it should look (very basic i know :D):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdpawfyjl38iit5x40seg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdpawfyjl38iit5x40seg.png" alt="Basic UI Image" width="800" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find the source maps using your browser's dev tools. The format can look different depending on the browser you are using. Here, I am using Zen, but the format should look similar for all browsers.&lt;/p&gt;

&lt;p&gt;You can do so by right-clicking anywhere on the page and clicking on &lt;strong&gt;Inspect Element&lt;/strong&gt;. Then, go to the &lt;strong&gt;Sources&lt;/strong&gt; section of your browser and find the source file. Here on Zen, it's available in the debugger section since it's mainly used for debugging purposes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F55ye3ujrmwuhjw9o62zo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F55ye3ujrmwuhjw9o62zo.png" alt="Showing source map in dev tools" width="800" height="592"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, you can load this in the &lt;a href="https://sokra.github.io/source-map-visualization/" rel="noopener noreferrer"&gt;source-map-visualization&lt;/a&gt;. It will look something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F241myprsrlt92gf2a25b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F241myprsrlt92gf2a25b.png" alt="Showing a visualization of source map" width="800" height="592"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On right you can skip all the React code and skip to the section that contains just your code. On hovering over each section of your code you will see exactly which part of the minified code it maps to!&lt;/p&gt;

&lt;p&gt;It can look pretty confusing at first, but try hovering over various elements in the UI and you will see how intuitive it actually is. For eg. in this example code,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;----&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;t&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Counter: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;....&lt;/span&gt; &lt;span class="c1"&gt;// so on&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hovering over &lt;code&gt;React.useState&lt;/code&gt; reveals that it maps to a &lt;code&gt;createElement&lt;/code&gt; in the minified code. So our bundler, Webpack, in this case, optimised our code by directly converting our state into a javascript element and directly modifying it in subsequent code. This makes our application much, much more performant and reduces the file sizes the browser has to load!&lt;/p&gt;

&lt;h2&gt;
  
  
  Security Considerations
&lt;/h2&gt;

&lt;p&gt;While creating the example app, you may have noticed we had to explicitly add the flag &lt;code&gt;--mode development&lt;/code&gt; to the Webpack run command. This is because source maps are supposed to be used for debugging purposes only, and can lead to security concerns when used in production, including:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concern&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Mitigation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Exposing Source Code&lt;/td&gt;
&lt;td&gt;Source maps reveal your original code, including comments and logic&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;hidden-source-map&lt;/code&gt; or &lt;code&gt;nosources-source-map&lt;/code&gt; in production&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IP Protection&lt;/td&gt;
&lt;td&gt;Intellectual property may be exposed via full source maps&lt;/td&gt;
&lt;td&gt;Deploy source maps to secure, authenticated location&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File Size&lt;/td&gt;
&lt;td&gt;Source maps can be large, affecting download performance&lt;/td&gt;
&lt;td&gt;Generate maps only in development, or serve separately&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server Configuration&lt;/td&gt;
&lt;td&gt;CORS issues may prevent source map loading&lt;/td&gt;
&lt;td&gt;Configure proper &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; headers&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There are also tools like &lt;strong&gt;Sentry&lt;/strong&gt; or &lt;strong&gt;Rollbar&lt;/strong&gt; which use your source maps for better error reports without violating any of the security concerns. Tools like these are considered best practise for production environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Source maps are a mind-blowing feature that lets you map your source code precisely to the minified code loaded by your browsers, which is generated by bundlers like Webpack for performance and speed. We explored how debugging can be made easy using this feature and tools like source map visualisers to aid in the process.&lt;/p&gt;

&lt;p&gt;The web is built on top of layers and layers of abstractions done by tools like bundlers, but when things go catastrophically wrong, we might discover that these abstractions are not always hundred percent perfect, and hence, we need to take out our tools, look under the hood, and find the fix ourselves.&lt;/p&gt;

&lt;p&gt;To learn more about package managers like NPM, Bun, PNPM, and yarn, you can check out my other article, &lt;a href="https://www.chiragaggarwal.tech/blog/mastering-npm-a-comprehensive-guide-to-package-management" rel="noopener noreferrer"&gt;Mastering npm: A Comprehensive Guide to Package Management&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;Thanks to these fantastic references by the Google Chrome dev team that helped me learn about source maps myself and in writing this article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/devtools/javascript/source-maps" rel="noopener noreferrer"&gt;Debug your original code instead of deployed with source maps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=FIYkjjFYvoI" rel="noopener noreferrer"&gt;What are source maps? #DevToolsTips&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=SkUcO4ML5U0&amp;amp;t=241s" rel="noopener noreferrer"&gt;Using source maps in DevTools #DevToolsTips&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Writing Event-Driven Serverless Code to Build Scalable Applications</title>
      <dc:creator>Chirag Aggarwal</dc:creator>
      <pubDate>Sun, 26 Jan 2025 17:12:20 +0000</pubDate>
      <link>https://forem.com/chiragagg5k/writing-event-driven-serverless-code-to-build-scalable-applications-2mol</link>
      <guid>https://forem.com/chiragagg5k/writing-event-driven-serverless-code-to-build-scalable-applications-2mol</guid>
      <description>&lt;p&gt;Serverless isn't just trendy—it's rewriting how software scales.  &lt;/p&gt;

&lt;p&gt;Netflix streams billions of hours without servers. Coca-Cola automates workflows without infrastructure. Figma and T-Mobile ditch downtime. What do they know that you don't?  &lt;/p&gt;

&lt;p&gt;The secret? Event-driven serverless code. It's the backbone of apps that scale instantly, cut costs, and survive traffic spikes. No servers. No guesswork. Just code that reacts.  &lt;/p&gt;

&lt;p&gt;This isn't hype—it's a blueprint. Ready to build smarter? Let's break down how event-driven serverless turns scalability from a challenge into a reflex.  &lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Brief Intro to Serverless&lt;/strong&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Spoiler alert: servers are still there.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are multiple definitions for this term online, often filled with complex jargon. The best way I like to define it is:&lt;br&gt;&lt;br&gt;
&lt;em&gt;A "fashion" of deploying your code where YOU don't have to think about the servers running your code.&lt;/em&gt;  &lt;/p&gt;

&lt;p&gt;Let's take an example:  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F884rktyfom0qj4zwatzm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F884rktyfom0qj4zwatzm.png" alt="Serverless Deployment Diagram" width="800" height="998"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;Take Bob. He built &lt;em&gt;mytrashcode.com&lt;/em&gt; but panicked at "server setup." He's a developer, not a sysadmin. Instead, he uploaded his code to a cloud provider. They handled security, scaling, and traffic—his site went live. No late-night server meltdowns. No panic during traffic surges. Done.  &lt;/p&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;Why Can't I Manage My Own Servers?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Managing your own servers usually takes one of two paths. You either run physical hardware—like turning an old laptop into a DIY server—or rent a Virtual Private Server (VPS) from providers like DigitalOcean Droplets, Azure VMs, or AWS Lightsail. These fall under IaaS (Infrastructure as a Service), where the cloud company provides the bare-metal infrastructure, but the rest—updates, scaling, security—is entirely up to you.  &lt;/p&gt;

&lt;p&gt;Does this mean self-managing servers is impossible?  &lt;/p&gt;

&lt;p&gt;Not at all. Plenty of teams still do it. But managing your own servers comes with a lot of... challenges, including:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Knowing how to manage &lt;strong&gt;infrastructure&lt;/strong&gt;/hardware.
&lt;/li&gt;
&lt;li&gt;Setting up &lt;strong&gt;auto-scaling&lt;/strong&gt; and downscaling.
&lt;/li&gt;
&lt;li&gt;Periodically applying &lt;strong&gt;system patches&lt;/strong&gt; and updates to avoid exposing vulnerabilities.
&lt;/li&gt;
&lt;li&gt;Configuring proxies, SSL certificate generation, &lt;strong&gt;network settings&lt;/strong&gt;, etc.
&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;Dividing Your Code into Functions&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Serverless code doesn't need to be monolithic, i.e., all code doesn't need to be in the same place. It can be a collection of bite-sized, event-triggered functions.  &lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Function&lt;/strong&gt; is nothing but a set of code that performs a specific task. When writing your entire code serverless, you'll find that you can divide your code into various functions, each handling a specific part of your application. Let's understand this more deeply with an example:  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frc9zdithhna5sjs2gup4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frc9zdithhna5sjs2gup4.png" alt="Functions Diagram" width="800" height="533"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;When Bob first logs into &lt;em&gt;mytrashcode.com&lt;/em&gt; as a new user, the system triggers a "send welcome email" function before redirecting him. Subsequent logins bypass this function entirely, routing him straight to the dashboard. This separation serves a critical purpose—while 99% of users interact solely with the dashboard, isolating secondary functions (like email triggers) enables independent scaling.  &lt;/p&gt;

&lt;p&gt;Though trivial in this example, the cost implications compound dramatically at scale. Each decoupled function operates on its own resource allocation curve—high-frequency features like dashboard access demand consistent infrastructure, while one-time actions (welcome emails) can scale down during inactive periods. This modular approach prevents overprovisioning for rarely triggered events, even before considering complex systems with hundreds of interdependent functions.  &lt;/p&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;Where to Deploy???&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Okay, so just a quick recap—we now know:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Deploying serverless is great!
&lt;/li&gt;
&lt;li&gt;Dividing your code into functions is modular and scalable.
&lt;/li&gt;
&lt;li&gt;Functions can be triggered by events.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, where do you deploy this architecture? Leading platforms like AWS Lambda, Azure Functions, and Google Cloud Functions support it, but we'll focus on Appwrite Functions.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl9sqdus26z0ygxclj0ms.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl9sqdus26z0ygxclj0ms.png" alt="Function Deployment Options" width="800" height="297"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;Appwrite, an open-source Backend-as-a-Service (BaaS), bundles authentication, databases, storage, and serverless functions into a single toolkit. This tight integration streamlines deployment—instead of managing fragmented cloud services, Appwrite centralizes backend logic, letting you deploy event-driven functions with minimal overhead. For developers prioritizing simplicity without sacrificing scalability, this unified approach reduces operational friction significantly.  &lt;/p&gt;

&lt;p&gt;So, let's deploy our function!  &lt;/p&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;Deploying Your First Function&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Before writing code, set up your backend on Appwrite:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://appwrite.io/" rel="noopener noreferrer"&gt;appwrite.io&lt;/a&gt; and register or log in.
&lt;/li&gt;
&lt;li&gt;Create an organization (if new).
&lt;/li&gt;
&lt;li&gt;Create a new project.
&lt;/li&gt;
&lt;li&gt;Copy your &lt;strong&gt;Project ID&lt;/strong&gt; for later use.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, let's simulate a server-side project using the &lt;code&gt;node-appwrite&lt;/code&gt; package:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a project directory:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;my-project  
&lt;span class="nb"&gt;cd &lt;/span&gt;my-project  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Install the &lt;a href="https://appwrite.io/docs/tooling/command-line/installation" rel="noopener noreferrer"&gt;Appwrite CLI&lt;/a&gt; and initialize your project:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init &lt;span class="nt"&gt;-y&lt;/span&gt;  
appwrite init  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Install dependencies:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;dotenv node-appwrite  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Create your function using the Appwrite CLI:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;appwrite init &lt;span class="k"&gt;function&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For the runtime, I selected &lt;strong&gt;Node 20&lt;/strong&gt;, but you can choose any runtime.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write your main function in &lt;code&gt;src/main.js&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;dotenv&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Users&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node-appwrite&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;dotenv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&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;client&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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cloud.appwrite.io/v1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProject&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;PROJECT_ID&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;users&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;Users&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&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;account&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;Account&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&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;main&lt;/span&gt; &lt;span class="o"&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;await&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test-user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test@test.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test@123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createEmailPasswordSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test@test.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test@123&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="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Add a &lt;code&gt;start&lt;/code&gt; script in &lt;code&gt;package.json&lt;/code&gt; to run &lt;code&gt;node src/main.js&lt;/code&gt;.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file with the required environment variables.  &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This function simulates a new user creation and login, logging the session details.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Replace the email IDs with actual emails to receive the email.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpa9qh5cp756w6a5jpjrt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpa9qh5cp756w6a5jpjrt.png" alt="Functions Architecture" width="800" height="419"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;Now, let's set up the function logic. Navigate to &lt;code&gt;functions/your-function&lt;/code&gt; where your function resides.  &lt;/p&gt;

&lt;p&gt;For this demo, we'll use &lt;a href="https://resend.com" rel="noopener noreferrer"&gt;Resend&lt;/a&gt; to send emails:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install the &lt;code&gt;resend&lt;/code&gt; package:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;resend  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/main.js&lt;/code&gt; with this code:
&lt;/li&gt;
&lt;/ul&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;Resend&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;resend&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// https://appwrite.io/docs/advanced/platform/events&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&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;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;log&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;resend&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;Resend&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;RESEND_API_KEY&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;resend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello@yourdomain.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hi, its nice to meet you!&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="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;Email sent successfully&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Email sent successfully&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You need to set up an account on Resend to get the API Key. Resend also requires you to connect to your own domain to send emails. You can read more about it on the &lt;a href="https://resend.com/docs/introduction" rel="noopener noreferrer"&gt;Resend docs&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;Now, let's push the created function to the console using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;appwrite push functions  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final step is to set up the event that connects the two pieces of code together using the &lt;code&gt;users.*.create&lt;/code&gt; event:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the Appwrite console and navigate to your created project.
&lt;/li&gt;
&lt;li&gt;Navigate to the Functions tab.
&lt;/li&gt;
&lt;li&gt;You should see your newly created function there—click on it.
&lt;/li&gt;
&lt;li&gt;Go to its settings and under the Events section.
&lt;/li&gt;
&lt;li&gt;Add a new event to trigger this function: &lt;code&gt;users.*.create&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsb7etulqcgb31sx5at2t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsb7etulqcgb31sx5at2t.png" alt="Appwrite Console showing Events" width="800" height="263"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And... voila! Your program is done. If everything is set up correctly, running your main script should send the newly created user an invitation email. Try it using:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In conclusion, serverless architecture is more than just a passing trend—it's a transformative approach to building and scaling modern applications.  &lt;/p&gt;

&lt;p&gt;Platforms like Appwrite further simplify the process, offering a unified backend solution that integrates seamlessly with serverless functions. Whether you're a solo developer like Bob or part of a larger team, adopting serverless can turn scalability from a daunting challenge into an effortless reflex.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjnuiov1eikg0u26hgpyt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjnuiov1eikg0u26hgpyt.png" alt="Conclusion Image" width="800" height="493"&gt;&lt;/a&gt; &lt;/p&gt;




&lt;p&gt;&lt;em&gt;Thanks for reading!&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;You can also connect with me here: &lt;a href="https://www.chiragaggarwal.tech/" rel="noopener noreferrer"&gt;https://www.chiragaggarwal.tech/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>serverless</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Architecture Patterns for Beginners: MVC, MVP, and MVVM</title>
      <dc:creator>Chirag Aggarwal</dc:creator>
      <pubDate>Fri, 27 Dec 2024 20:22:17 +0000</pubDate>
      <link>https://forem.com/chiragagg5k/architecture-patterns-for-beginners-mvc-mvp-and-mvvm-2pe7</link>
      <guid>https://forem.com/chiragagg5k/architecture-patterns-for-beginners-mvc-mvp-and-mvvm-2pe7</guid>
      <description>&lt;p&gt;Building software can be complex.&lt;/p&gt;

&lt;p&gt;You might not have to think much about it when building your side project, but production software differs.&lt;/p&gt;

&lt;p&gt;It can require multiple components, all of which if not handled correctly can lead to chaos.&lt;/p&gt;

&lt;p&gt;But it doesn't need to be this complex. In today's article we will be delving into the world of architectural patterns, and discuss some divides your software into 3 simple components, each focusing on related tasks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architectural patterns
&lt;/h2&gt;

&lt;p&gt;Whenever we are talking about architectural patterns in software design, the first ones to top the list include architectures like client-server, layered, monolithic, microkernel, even-driven, etc. These patterns are concerned with overall system architecture, including multiple applications, services, servers, etc.&lt;/p&gt;

&lt;p&gt;However, MVP, MVC, and MVVM focus on organizing code within a single application by separating data, user interface, and logic. These are a subset of architecture patterns that focus on the overall system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftsnn1y32wzy0gz5bnl4z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftsnn1y32wzy0gz5bnl4z.png" alt="Client-Server Architecture vs MVC" width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  MVC, MVP, and MVVM
&lt;/h2&gt;

&lt;p&gt;For the sake of keeping the blog readable and not exceeding the word length, we will focus on just the architectural patterns that organize the code within a single application, namely:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Model-View-Controller&lt;/li&gt;
&lt;li&gt;Model-View-Presenter&lt;/li&gt;
&lt;li&gt;Model-View-ViewModel&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Clearly, all three models have two components fixed, i.e. the Model and the View. So let's first discuss them in detail before coming to each of the architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  Model
&lt;/h3&gt;

&lt;p&gt;The model consists of all the code that is related to &lt;strong&gt;data&lt;/strong&gt; present in the software. It's the layer for communication of the database and network layers with the rest of the application. Its main responsibilities include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Handle data and business logic.&lt;/li&gt;
&lt;li&gt;Encapsulate the application's data and the rules governing access to that data.&lt;/li&gt;
&lt;li&gt;Handling data structures.&lt;/li&gt;
&lt;li&gt;Performing CRUD (Create, Read, Update, and Delete) operations on data.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyacza08pqkbmgb5ae9cf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyacza08pqkbmgb5ae9cf.png" alt="Functioning of Model layer" width="800" height="696"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  View
&lt;/h3&gt;

&lt;p&gt;View is pretty much the front end of your application or everything that the user will be able to see and interact with. It's also known as the User Interface (UI) of your application. Its responsibilities include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Handle non-business logic and purely presentational logic.&lt;/li&gt;
&lt;li&gt;Present the data provided by other layers to the user.&lt;/li&gt;
&lt;li&gt;Receive user input and forward it to other layers.&lt;/li&gt;
&lt;li&gt;May or may communicate directly with the Model layer.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Model-View-Controller (MVC) Architecture
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft34ojxv1pyae6kogh33t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft34ojxv1pyae6kogh33t.png" alt="Model-View-Controller Architecture" width="573" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we have an understanding of what Model and View layers do, let's take a look at individual architectural patterns. &lt;/p&gt;

&lt;p&gt;Starting with MVC, it uses a &lt;strong&gt;Controller&lt;/strong&gt; layer that communicates with both the Model and View layers.&lt;/p&gt;

&lt;p&gt;It's main responsibilities of the controller include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Manipulating data through the Model layer.&lt;/li&gt;
&lt;li&gt;Receive instructions, aka the UI, from the View layer.&lt;/li&gt;
&lt;li&gt;Update the View with changes defined due to control logic.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here, although the View layer cannot directly interact with the Model layer, it can however receive updates based on changes in the data. Hence all three layers are connected to each other in some form, with the controller being the main component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Model-View-Presenter (MVP) Architecture
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhw9i30c4jrun2ryzxup8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhw9i30c4jrun2ryzxup8.png" alt="Model-View-Presenter Architecture" width="800" height="285"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, the Presenter layer assumes the functionality of the "middle-man" between the Model and View layers and handles all the communication between them. There is no communication at all between the Model and View layers directly.&lt;/p&gt;

&lt;p&gt;Its responsibilities include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Update the UI or the View layer based on user actions.&lt;/li&gt;
&lt;li&gt;Update the data or Model layer based on code logic.&lt;/li&gt;
&lt;li&gt;Handle much of the business logic that would be otherwise handled in the controller in MVC architecture.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Model-View-ViewModel (MVVM) Architecture
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr7ik37i57yt9vbx70z7c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr7ik37i57yt9vbx70z7c.png" alt="Model-View-ViewModel Architecture" width="800" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This architecture at first glance is almost identical to MVP architecture. But there are some key differences between them:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Multiple views can be mapped to a single ViewModel layer.&lt;/li&gt;
&lt;li&gt;It uses data binding between the ViewModel layer and the View layer, making it more event-driven.&lt;/li&gt;
&lt;li&gt;There is no concept of User Interface in this architecture. The View layer represents the actions of the user, not the interface.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Side by Side comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;MVC&lt;/th&gt;
&lt;th&gt;MVP&lt;/th&gt;
&lt;th&gt;MVVM&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Full Name&lt;/td&gt;
&lt;td&gt;Model-View-Controller&lt;/td&gt;
&lt;td&gt;Model-View-Presenter&lt;/td&gt;
&lt;td&gt;Model-View-ViewModel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Separation of Concerns&lt;/td&gt;
&lt;td&gt;Basic&lt;/td&gt;
&lt;td&gt;Better&lt;/td&gt;
&lt;td&gt;Best&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data Flow&lt;/td&gt;
&lt;td&gt;Two-way&lt;/td&gt;
&lt;td&gt;One-way&lt;/td&gt;
&lt;td&gt;One-way with data binding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;View-Logic Relationship&lt;/td&gt;
&lt;td&gt;Many-to-one&lt;/td&gt;
&lt;td&gt;One-to-one&lt;/td&gt;
&lt;td&gt;Many-to-one&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Testability&lt;/td&gt;
&lt;td&gt;Hard&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;Best&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maintenance&lt;/td&gt;
&lt;td&gt;Hard&lt;/td&gt;
&lt;td&gt;Easy&lt;/td&gt;
&lt;td&gt;Easy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learning Curve&lt;/td&gt;
&lt;td&gt;Easy&lt;/td&gt;
&lt;td&gt;Easy&lt;/td&gt;
&lt;td&gt;Harder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Performance&lt;/td&gt;
&lt;td&gt;Can be slower due to tight coupling&lt;/td&gt;
&lt;td&gt;Better performance with looser coupling&lt;/td&gt;
&lt;td&gt;Smooth performance, especially for complex UIs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UI Updates&lt;/td&gt;
&lt;td&gt;Controller updates View&lt;/td&gt;
&lt;td&gt;Presenter updates View&lt;/td&gt;
&lt;td&gt;ViewModel updates View through data binding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dependency on UI Framework&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Low or no dependency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scalability&lt;/td&gt;
&lt;td&gt;Suitable for small-scale projects&lt;/td&gt;
&lt;td&gt;Good for simple and complex projects&lt;/td&gt;
&lt;td&gt;Ideal for large, data-heavy apps&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;But which is the most popular you might ask? All of them are equally popular architectures being used according to the company's respective requirements for a product. Some companies adopting these different architectures are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;MVC: StackOverflow, GoDaddy, Visual Studio website
Dell&lt;/li&gt;
&lt;li&gt;MVP: Google (for some Android apps)&lt;/li&gt;
&lt;li&gt;MVVM: Apple (for some iOS apps using SwiftUI), Angular framework, Vue.js framework&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Also, many companies use a mix of these architectures depending on the specific needs of each project or product. The choice of architecture often depends on factors such as the complexity of the application, the development team's expertise, and the specific requirements of the project.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This article covered the basics of architectural patterns, from how overall architecture is designed to how a single application can be further divided into three components for better management and scalability.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MVC, with its straightforward approach, remains popular for web applications.&lt;/li&gt;
&lt;li&gt;MVP builds upon MVC's foundation, offering improved testability and a cleaner separation of concerns.&lt;/li&gt;
&lt;li&gt;MVVM, the most recent of the three, has gained significant traction in modern application development.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is no clear winner between them and each pattern offers unique advantages and is suited to different projects and development scenarios. As the software development landscape continues to evolve, we may see further refinements of these patterns or the emergence of new architectures altogether.&lt;/p&gt;

&lt;p&gt;Want to learn more about the architectural patterns discussed? Here are some references I found helpful:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.geeksforgeeks.org/android-architecture-patterns/" rel="noopener noreferrer"&gt;https://www.geeksforgeeks.org/android-architecture-patterns/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.masaischool.com/blog/comparing-software-architecture-patterns/" rel="noopener noreferrer"&gt;https://www.masaischool.com/blog/comparing-software-architecture-patterns/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.apptension.com/blog-posts/mvc-vs-mvvm-vs-mvp" rel="noopener noreferrer"&gt;https://www.apptension.com/blog-posts/mvc-vs-mvvm-vs-mvp&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>performance</category>
      <category>architecture</category>
    </item>
    <item>
      <title>My Hackfrost Journey: Navigating Development Challenges with Daytona</title>
      <dc:creator>Chirag Aggarwal</dc:creator>
      <pubDate>Thu, 05 Dec 2024 16:11:31 +0000</pubDate>
      <link>https://forem.com/chiragagg5k/my-hackfrost-journey-navigating-development-challenges-with-daytona-hdc</link>
      <guid>https://forem.com/chiragagg5k/my-hackfrost-journey-navigating-development-challenges-with-daytona-hdc</guid>
      <description>&lt;h2&gt;
  
  
  The Winter of Tech Innovation
&lt;/h2&gt;

&lt;p&gt;As the crisp winter winds swept across India, the tech community buzzed with excitement. Hackfrost, a hackathon organized by the dynamic WeMakeDevs community—founded by the renowned tech educator Kunal Kushwaha—promised to be more than just another coding competition. This 48-hour virtual event was set to challenge developers, foster innovation, and bring together a diverse group of tech enthusiasts from across the country.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5tpogusxub7v18mw2cec.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5tpogusxub7v18mw2cec.png" alt="Hackfrost Cover Image" width="800" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Allure of the Challenge
&lt;/h2&gt;

&lt;p&gt;When I first stumbled upon the hackathon announcement, it was the prize lineup that immediately caught my eye—a treasure trove that would make any developer's heart race:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Latest MacBook Pro&lt;/li&gt;
&lt;li&gt;High-end Dell Monitor&lt;/li&gt;
&lt;li&gt;Sleek iPad&lt;/li&gt;
&lt;li&gt;Compact M4 Mac Mini&lt;/li&gt;
&lt;li&gt;Premium Keychron Keyboards&lt;/li&gt;
&lt;li&gt;An assortment of exclusive tech swag&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But this wasn't just a simple giveaway. The competition had a unique twist: every project needed to incorporate Kestra, an open-source orchestration tool that was gaining significant traction in the developer community. What seemed like a constraint at first quickly transformed into an exciting opportunity for innovation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Team Formation: A Community-Driven Approach
&lt;/h2&gt;

&lt;p&gt;My journey began in the vibrant corridors of Quira, an open-source community that has been my technical home for quite some time. Networking has always been more than just collecting contact information—it's about finding passionate individuals who complement your skills and share your vision.&lt;/p&gt;

&lt;p&gt;I was fortunate to connect with an incredible team:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;K Om Senapati&lt;/strong&gt;: A brilliant problem solver with a knack for backend architecture&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Juanita&lt;/strong&gt;: A frontend wizard with an eye for user experience&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chelsea&lt;/strong&gt;: Our team's DevOps expert who understands the intricacies of cloud infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our diversity was our strength. Each of us brought unique perspectives and skills to the table, transforming a potential challenge into an opportunity for collaborative innovation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Development Environment Dilemma
&lt;/h2&gt;

&lt;p&gt;Any developer who has worked on a team project knows the pain of environment setup. It's a time-consuming process typically involving:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Endless configuration scripts&lt;/li&gt;
&lt;li&gt;Dependency version conflicts&lt;/li&gt;
&lt;li&gt;Complex environment variable management&lt;/li&gt;
&lt;li&gt;Hours of synchronization between team members&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where Daytona emerged as our unexpected hero. What would traditionally take days was reduced to mere minutes. The tool's ability to streamline development environments was nothing short of revolutionary for our team.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0dylirv94hune4s3bynf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0dylirv94hune4s3bynf.png" alt="Daytona Thumbnail" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Development Container Configuration with Daytona
&lt;/h3&gt;

&lt;p&gt;To ensure a consistent development environment, we leveraged Daytona's powerful configuration capabilities. Here's a step-by-step guide to setting up Daytona for our project:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Install Daytona&lt;/strong&gt;: You can find the instructions specific to your OS on their website &lt;a href="https://www.daytona.io/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create Devcontainer Configuration&lt;/strong&gt;&lt;br&gt;
We crafted a detailed devcontainer configuration to standardize our development environment:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Flow Forge Development Container"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"dockerfile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Dockerfile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".."&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"customizations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"vscode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"settings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="nl"&gt;"terminal.integrated.shell.linux"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/bin/sh"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="nl"&gt;"eslint.enable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="nl"&gt;"prettier.resolveGlobalModules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"extensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="s2"&gt;"esbenp.prettier-vscode"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="s2"&gt;"dbaeumer.vscode-eslint"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="s2"&gt;"ms-vscode.vscode-typescript-tslint"&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Add a Provider&lt;/strong&gt;: We opted for a cloud provider due to low-spec configurations on some of our teammates' systems. Specifically, due to an abundance of Azure credits, we chose Azure using:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   daytona provider &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Running the Project&lt;/strong&gt;: After pushing our devcontainer to the project repo, we can start the environment easily with:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   daytona create https://github.com/ChiragAgg5k/flow-forge &lt;span class="nt"&gt;--devcontainer-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;.devcontainer/devcontainer.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Feedback and Reflections&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While traditional development environments often feel like navigating a maze of configurations, Daytona emerged as a breath of fresh air. Its intuitive approach to setting up development environments was nothing short of revolutionary for our team. &lt;/p&gt;

&lt;p&gt;Key Observations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity&lt;/strong&gt;: What traditionally took hours of manual configuration was reduced to a few command-line interactions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency&lt;/strong&gt;: Every team member's environment was identical, eliminating the notorious "it works on my machine" syndrome.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility&lt;/strong&gt;: The tool seamlessly handled different development setups, from local machines to cloud-based environments.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cloud-Powered Development
&lt;/h3&gt;

&lt;p&gt;Given my modest MacBook's specifications, we decided to leverage cloud computing. Daytona's seamless Azure integration was a game-changer. With just a few clicks, I added Azure as our cloud provider, and suddenly, our entire development ecosystem was accessible, consistent, and performant.&lt;/p&gt;

&lt;p&gt;The magic of Daytona wasn't just in its simplicity, but in its ability to democratize development environments. Teammates with varying hardware could now collaborate effortlessly, breaking down technological barriers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecting the GitHub Workflow Manager
&lt;/h2&gt;

&lt;p&gt;Our project aimed to solve a real-world problem: simplifying GitHub workflow management using Kestra's powerful orchestration capabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Technical Architecture
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend&lt;/strong&gt;: Next.js, chosen for its server-side rendering and robust ecosystem&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orchestration&lt;/strong&gt;: Kestra, running on an Azure VM&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication &amp;amp; Backend&lt;/strong&gt;: Appwrite, providing a flexible Backend-as-a-Service solution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We implemented basic authentication to interact with the Kestra instance, allowing users to define, monitor, and execute complex workflows with unprecedented ease.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Seamless GitHub workflow creation&lt;/li&gt;
&lt;li&gt;Real-time workflow status tracking&lt;/li&gt;
&lt;li&gt;Customizable workflow templates&lt;/li&gt;
&lt;li&gt;Secure authentication mechanisms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhdblxgqij2hp93upccg9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhdblxgqij2hp93upccg9.png" alt="Kestra Worfklow Thumbnail" width="800" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond the Competition
&lt;/h2&gt;

&lt;p&gt;While the prize table remained unclaimed by our team, the true value of Hackfrost transcended material rewards. We had:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learned cutting-edge technologies&lt;/li&gt;
&lt;li&gt;Practiced collaborative development&lt;/li&gt;
&lt;li&gt;Solved a tangible industry problem&lt;/li&gt;
&lt;li&gt;Strengthened our professional network&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Daytona's Impact&lt;/strong&gt;: The development tool didn't just simplify our setup—it transformed how we think about collaborative coding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Tech competitions are rarely about winning. They're about growth, learning, and pushing technological boundaries. Our Hackfrost journey exemplified this philosophy—a testament to the power of community, innovation, and the right tools.&lt;/p&gt;

&lt;p&gt;To Daytona, Kestra, and the entire WeMakeDevs community: Thank you for creating spaces where innovation thrives.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Check out the live project &lt;a href="https://flow-forge-iota.vercel.app/" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For more information about me, checkout my &lt;a href="https://www.chiragaggarwal.tech/" rel="noopener noreferrer"&gt;Portfolio&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>hackathon</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>How a Viral Tweet Landed Me Multiple Job Interviews</title>
      <dc:creator>Chirag Aggarwal</dc:creator>
      <pubDate>Thu, 21 Nov 2024 04:39:59 +0000</pubDate>
      <link>https://forem.com/chiragagg5k/how-a-viral-tweet-landed-me-multiple-job-interviews-49oo</link>
      <guid>https://forem.com/chiragagg5k/how-a-viral-tweet-landed-me-multiple-job-interviews-49oo</guid>
      <description>&lt;p&gt;We all enjoy using social media. In today's digital world, it’s nearly impossible to find someone who doesn’t. Social platforms wield immense power—capable of making someone famous overnight. However, such power has its downsides. Today, I’ll share how one casual tweet (or X, as it’s now called) turned my luck around and landed me multiple internship interviews when I was struggling to get any.&lt;/p&gt;




&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;Hi, I’m &lt;strong&gt;Chirag Aggarwal&lt;/strong&gt;, a 3rd-year B.Tech CSE student at a tier-3 university in India. Like many in my situation, I was struggling to secure an internship, despite:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Two previous internship experiences
&lt;/li&gt;
&lt;li&gt;Multiple solid projects
&lt;/li&gt;
&lt;li&gt;A portfolio website
&lt;/li&gt;
&lt;li&gt;A CGPA of &lt;strong&gt;9.71&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;And much more
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the same time, I was practicing &lt;strong&gt;DSA (Data Structures and Algorithms)&lt;/strong&gt; daily. Although not always required for internships, I was targeting companies like &lt;strong&gt;Amazon, Google, Microsoft, and Goldman Sachs&lt;/strong&gt;, where DSA knowledge is crucial.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Tweet
&lt;/h2&gt;

&lt;p&gt;One day, I realized I had completed &lt;strong&gt;400 problems on LeetCode&lt;/strong&gt;. Normally, this would be a moment of pride—a milestone to share on LinkedIn and celebrate. But instead of feeling accomplished, I was disappointed. Despite my constant effort, I felt unrewarded. So, I vented my frustration on Twitter:  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzmnenwiv3wt9g9kwhld4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzmnenwiv3wt9g9kwhld4.png" alt="Tweet Screenshot" width="800" height="757"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;When I posted it, I didn’t expect much. I often tweeted random thoughts, and this felt like just another one of them. But, as you can see from the numbers above, it was anything but ordinary.  &lt;/p&gt;

&lt;p&gt;Soon, my phone started buzzing... and it didn’t stop. Thousands of people joined the conversation.  &lt;/p&gt;




&lt;h2&gt;
  
  
  The Reactions
&lt;/h2&gt;

&lt;p&gt;The responses to my tweet generally fell into three categories:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Struggling comrades&lt;/strong&gt; who empathized and shared similar struggles.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Critics&lt;/strong&gt; who blamed me for focusing on DSA instead of development.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supporters&lt;/strong&gt; who offered genuine help and advice.
&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Struggling Comrades
&lt;/h3&gt;

&lt;p&gt;The first category overwhelmed me. I was shocked to see so many talented individuals facing the same struggles. It felt like the entire industry was filled with people like me—working hard and still not seeing results.  &lt;/p&gt;

&lt;p&gt;Here’s one response that really stood out:  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3w57w6pccvqh9s5em8o6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3w57w6pccvqh9s5em8o6.png" alt="Tweet Screenshot" width="800" height="546"&gt;&lt;/a&gt;  &lt;/p&gt;




&lt;h3&gt;
  
  
  Critics
&lt;/h3&gt;

&lt;p&gt;This was, unsurprisingly, the largest group. Due to the viral nature of my tweet, many people jumped to conclusions and shared similar critiques:  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxpeuf2ijpgw156lohov2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxpeuf2ijpgw156lohov2.png" alt="Critique 1" width="800" height="129"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq7ev2m9hvs9e2serhlex.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq7ev2m9hvs9e2serhlex.png" alt="Critique 2" width="800" height="133"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvbk1uvvdh445907fvjjl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvbk1uvvdh445907fvjjl.png" alt="Critique 3" width="678" height="202"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;(Thanks, Rohan. Really appreciated that last one! 😅)  &lt;/p&gt;

&lt;p&gt;Most critics suggested I focus on &lt;strong&gt;projects&lt;/strong&gt; and &lt;strong&gt;development&lt;/strong&gt; instead of just DSA. Ironically, that’s exactly what I’d been doing for a long time. I’ve always enjoyed development more than solving DSA problems, contributing to open source, and building amazing stuff.  &lt;/p&gt;

&lt;p&gt;Still, I understood their perspective. If I saw someone only doing DSA without focusing on development, I might have left a similar comment.  &lt;/p&gt;




&lt;h3&gt;
  
  
  Supporters
&lt;/h3&gt;

&lt;p&gt;This was my favorite category. Although smaller, it was still more support than I’d ever expected. These tweets genuinely lifted my spirits:  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fabh1uz9orz3b5aj9oklp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fabh1uz9orz3b5aj9oklp.png" alt="Support 1" width="800" height="513"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff60jqfj5z8zontvfhrw2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff60jqfj5z8zontvfhrw2.png" alt="Support 2" width="800" height="147"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsjybual8uj4npeqmcid8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsjybual8uj4npeqmcid8.png" alt="Support 3" width="756" height="392"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;These words reminded me that I was on the right track and just needed to keep pushing forward.  &lt;/p&gt;




&lt;h2&gt;
  
  
  What Happened Next?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;I got calls. Emails. Offers.&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;The viral tweet brought me &lt;strong&gt;visibility&lt;/strong&gt;—a crucial factor in landing interviews. I had a few rounds with different companies, but in the end, I accepted an offer that didn’t even require a formal interview. After an introductory call and a basic assignment, I was handed the offer letter.  &lt;/p&gt;

&lt;p&gt;This happened thanks to one person:  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0hw2yrmswr4vlczauvb4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0hw2yrmswr4vlczauvb4.png" alt="Thank You Teja" width="800" height="226"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;(Thanks a lot, Teja!)  &lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I wish I had a concrete lesson or formula to share, but this journey was a rollercoaster sparked by one lucky tweet.  &lt;/p&gt;

&lt;p&gt;If there’s one takeaway, it’s this:  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Be active on social media. Build in public. Share your creations, passions, and energy with the world.&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;Luck favors those who are ready to take advantage of it.  &lt;/p&gt;




&lt;h3&gt;
  
  
  Check out my portfolio: &lt;a href="https://www.chiragaggarwal.tech" rel="noopener noreferrer"&gt;chiragaggarwal.tech&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Feel free to reach out if you want to discuss anything!  &lt;/p&gt;

</description>
      <category>twitter</category>
      <category>interview</category>
      <category>beginners</category>
      <category>career</category>
    </item>
  </channel>
</rss>
