<?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: Jaison D Souza</title>
    <description>The latest articles on Forem by Jaison D Souza (@jsndz).</description>
    <link>https://forem.com/jsndz</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%2F3397579%2F0c39cc90-831a-4b1b-a696-df0fc3f7e48e.jpeg</url>
      <title>Forem: Jaison D Souza</title>
      <link>https://forem.com/jsndz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jsndz"/>
    <language>en</language>
    <item>
      <title>How HTML works? In Simple words.</title>
      <dc:creator>Jaison D Souza</dc:creator>
      <pubDate>Thu, 19 Feb 2026 18:30:52 +0000</pubDate>
      <link>https://forem.com/jsndz/how-html-works-in-simple-words-3eh1</link>
      <guid>https://forem.com/jsndz/how-html-works-in-simple-words-3eh1</guid>
      <description>&lt;p&gt;HTML is a markup language responsible for the &lt;strong&gt;structure of a web page&lt;/strong&gt;.&lt;br&gt;
The &lt;strong&gt;skeleton of a web page&lt;/strong&gt; is HTML.&lt;/p&gt;

&lt;p&gt;Instead of talking about various tags and how to use them, let us understand &lt;strong&gt;how HTML works&lt;/strong&gt;, how it renders, and how the browser displays it.&lt;/p&gt;

&lt;p&gt;When a client asks a server for a web page (this happens when you load a link), the server sends an &lt;strong&gt;HTML text file&lt;/strong&gt;.&lt;br&gt;
It is a &lt;strong&gt;plain text file&lt;/strong&gt;, nothing else.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt; My Web Page &lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt; Hello World &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The browser cannot directly render this raw text in a meaningful way.&lt;br&gt;
So it must &lt;strong&gt;convert the text into internal structures&lt;/strong&gt; that it understands.&lt;/p&gt;

&lt;p&gt;I will briefly explain the steps involved.&lt;/p&gt;


&lt;h2&gt;
  
  
  Tokenization and State Machine
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Step 1: Tokenization
&lt;/h3&gt;

&lt;p&gt;The browser reads the HTML &lt;strong&gt;character by character&lt;/strong&gt; and converts it into &lt;strong&gt;tokens&lt;/strong&gt;.&lt;br&gt;
Tokens follow a set of structured rules defined by the HTML specification.&lt;/p&gt;

&lt;p&gt;The HTML code shown earlier would be converted into tokens like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;StartTag: html&lt;/li&gt;
&lt;li&gt;StartTag: head&lt;/li&gt;
&lt;li&gt;StartTag: title&lt;/li&gt;
&lt;li&gt;Text: My Web Page&lt;/li&gt;
&lt;li&gt;EndTag: title&lt;/li&gt;
&lt;li&gt;EndTag: head&lt;/li&gt;
&lt;li&gt;StartTag: body&lt;/li&gt;
&lt;li&gt;StartTag: p&lt;/li&gt;
&lt;li&gt;Text: Hello World&lt;/li&gt;
&lt;li&gt;EndTag: p&lt;/li&gt;
&lt;li&gt;EndTag: body&lt;/li&gt;
&lt;li&gt;EndTag: html&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why is this conversion needed, and how does it happen?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This process is implemented using a &lt;strong&gt;state machine&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;The diagram shows multiple states with transitions based on characters such as &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;/&lt;/code&gt;, and text content. These transitions help the parser identify opening tags, closing tags, and text nodes.&lt;/p&gt;

&lt;p&gt;The state machine follows strict rules to convert the input stream into tokens.&lt;br&gt;
Although it may look complicated, it is essentially a series of &lt;strong&gt;conditional transitions&lt;/strong&gt; (similar to if-else logic).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why do we need tokens?&lt;/strong&gt;&lt;br&gt;
Tokens make it easier to convert the HTML into a DOM because each token clearly represents &lt;strong&gt;what kind of element it is&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  DOM, CSSOM, and Render Tree
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Step 2: Tokens → DOM
&lt;/h3&gt;

&lt;p&gt;The next step is building the &lt;strong&gt;DOM (Document Object Model)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The tokens are processed and converted into a &lt;strong&gt;tree structure&lt;/strong&gt; called the DOM.&lt;br&gt;
Each node in the tree represents an element, text node, or attribute from the HTML document.&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%2Fueuzfgtc87kowocg8p0q.gif" 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%2Fueuzfgtc87kowocg8p0q.gif" alt=" " width="486" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A hierarchical structure starting with the &lt;code&gt;html&lt;/code&gt; root node, branching into &lt;code&gt;head&lt;/code&gt; (containing &lt;code&gt;title → My Web Page&lt;/code&gt;) and &lt;code&gt;body&lt;/code&gt; (containing &lt;code&gt;p → Hello World&lt;/code&gt;).&lt;/p&gt;


&lt;h3&gt;
  
  
  Step 3: DOM + CSSOM → Render Tree
&lt;/h3&gt;

&lt;p&gt;When CSS is added, the browser parses it into another structure called the &lt;strong&gt;CSSOM (CSS Object Model)&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DOM contains &lt;strong&gt;structure and content&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;CSSOM contains &lt;strong&gt;styling rules&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The browser combines the DOM and CSSOM to build the &lt;strong&gt;Render Tree&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The Render Tree contains &lt;strong&gt;only visible elements&lt;/strong&gt; and the styles that apply to them (for example, elements with &lt;code&gt;display: none&lt;/code&gt; are excluded).&lt;/p&gt;

&lt;p&gt;The Render Tree defines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what needs to be displayed&lt;/li&gt;
&lt;li&gt;how it should be styled&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note on JavaScript:&lt;/strong&gt;&lt;br&gt;
When JavaScript modifies the DOM, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;div&amp;gt;Hello&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the browser may trigger &lt;strong&gt;layout recalculation (reflow)&lt;/strong&gt; and &lt;strong&gt;repainting&lt;/strong&gt;.&lt;br&gt;
However, &lt;strong&gt;the entire tree is not always re-rendered&lt;/strong&gt;—only the affected parts are updated when possible.&lt;/p&gt;




&lt;h2&gt;
  
  
  Layout and Paint
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 4: Layout Calculation (Reflow)
&lt;/h3&gt;

&lt;p&gt;In this step, the browser calculates the &lt;strong&gt;exact position and size&lt;/strong&gt; of each node in the Render Tree.&lt;/p&gt;

&lt;p&gt;For every node, the browser computes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;width&lt;/li&gt;
&lt;li&gt;height&lt;/li&gt;
&lt;li&gt;position&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This process is recursive and can be expensive, especially when changes affect large portions of the page.&lt;/p&gt;

&lt;p&gt;Layout calculation produces precise instructions required to generate the final visual output.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 5: Paint
&lt;/h3&gt;

&lt;p&gt;During the paint phase, the browser converts layout information into &lt;strong&gt;actual pixels&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This includes painting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;text&lt;/li&gt;
&lt;li&gt;colors&lt;/li&gt;
&lt;li&gt;borders&lt;/li&gt;
&lt;li&gt;backgrounds&lt;/li&gt;
&lt;li&gt;shadows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In simple terms:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layout → Paint → Pixels on the screen&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Optional next step (for completeness)
&lt;/h3&gt;

&lt;p&gt;Modern browsers often perform an additional step called &lt;strong&gt;Compositing&lt;/strong&gt;, where painted layers are combined and optimized (often using the GPU) before being displayed on the screen.&lt;/p&gt;




&lt;p&gt;That's all.  Thank you reading till the end. You might have a basic idea about how HTML and small part of browser works. These were my learning based on studying the working of HTML. If any mistakes are there fell free to correct me.&lt;/p&gt;

</description>
      <category>html</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Ditch JSON, Go Binary: A Simple Message Protocol</title>
      <dc:creator>Jaison D Souza</dc:creator>
      <pubDate>Sun, 24 Aug 2025 10:17:49 +0000</pubDate>
      <link>https://forem.com/jsndz/ditch-json-go-binary-a-simple-message-protocol-e6l</link>
      <guid>https://forem.com/jsndz/ditch-json-go-binary-a-simple-message-protocol-e6l</guid>
      <description>&lt;p&gt;&lt;strong&gt;Binary Message Protocol&lt;/strong&gt; — that's what I am calling this method. Sounds cool right? Well maybe not.&lt;br&gt;&lt;br&gt;
Fancy name, but it’s really just a simple method of sending data by message framing.&lt;/p&gt;


&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;In real-time applications, &lt;strong&gt;speed and efficiency are critical&lt;/strong&gt;. Sending large JSON payloads over WebSockets can add unnecessary overhead, making communication slower and more resource-intensive.  &lt;/p&gt;

&lt;p&gt;At the same time, the server needs a clear way to identify what kind of message it's receiving. For example, whether it's a request to &lt;strong&gt;join a session&lt;/strong&gt;, an &lt;strong&gt;update&lt;/strong&gt;, or some other action.  &lt;/p&gt;

&lt;p&gt;When I was building a collaboration platform with &lt;strong&gt;TypeScript&lt;/strong&gt; and &lt;strong&gt;Golang&lt;/strong&gt;, I ran into this exact problem: &lt;strong&gt;JSON was too heavy for real-time communication&lt;/strong&gt;, and I needed a faster, lighter protocol that still allowed the server to understand the type of each message.  &lt;/p&gt;


&lt;h2&gt;
  
  
  JSON Examples
&lt;/h2&gt;

&lt;p&gt;Joining:&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;"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;"join"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"payload"&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;"token"&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="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"doc_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;"..."&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;&lt;br&gt;
`&lt;/p&gt;

&lt;p&gt;Updating a document:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;json&lt;br&gt;
{&lt;br&gt;
  "type": "update",&lt;br&gt;
  "payload": { "doc_id": "abc123", "delta": [1, 0, 2, 3] }&lt;br&gt;
}&lt;br&gt;
// The delta could be very large&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Looks fine — but that's a &lt;strong&gt;lot of extra characters&lt;/strong&gt; being sent on every message.&lt;/p&gt;




&lt;h2&gt;
  
  
  Solution: Binary Message Protocol
&lt;/h2&gt;

&lt;p&gt;A simple method where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;First byte = message type&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Remaining bytes = payload&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;So instead of sending the verbose JSON above, we just send something like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
[2, 21, 1212, 1, 21, 2, 4, 243, 544, 4, 5, 67, 7]&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;2&lt;/code&gt; = message type (&lt;code&gt;join&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The rest = encoded payload&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Message Type Mapping
&lt;/h2&gt;

&lt;p&gt;Here’s an example mapping:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Byte&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;update&lt;/td&gt;
&lt;td&gt;Document update (deltas)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;join&lt;/td&gt;
&lt;td&gt;Join a document session&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;leave&lt;/td&gt;
&lt;td&gt;Leave a document session&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;ping&lt;/td&gt;
&lt;td&gt;Keep-alive / heartbeat&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;auth&lt;/td&gt;
&lt;td&gt;Authentication / validation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Encoding &amp;amp; Decoding
&lt;/h2&gt;

&lt;p&gt;This isn’t just theory — here’s how you could implement it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Encoding in Go
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;go&lt;br&gt;
func (c *Client) HandleNotification(msgType uint, message string) {&lt;br&gt;
    msgBytes := []byte(message)&lt;br&gt;
    payload := make([]byte, 1+len(msgBytes))&lt;br&gt;
    payload[0] = byte(msgType)&lt;br&gt;
    copy(payload[1:], msgBytes)&lt;br&gt;
    c.Send &amp;lt;- payload&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Decoding in TypeScript
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;ts&lt;br&gt;
function parseMessage(message: Uint8Array): {&lt;br&gt;
  type: number;&lt;br&gt;
  payload: Uint8Array;&lt;br&gt;
} {&lt;br&gt;
  const type = message[0];&lt;br&gt;
  const payload = message.slice(1);&lt;br&gt;
  return { type, payload };&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Sending as Binary over WebSocket
&lt;/h2&gt;

&lt;p&gt;In Go, you just tell the WebSocket library that you're writing &lt;strong&gt;binary messages&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;go&lt;br&gt;
func (c *Client) WritePump() {&lt;br&gt;
    for msg := range c.Send {&lt;br&gt;
        // websocket.BinaryMessage ensures data is sent as binary&lt;br&gt;
        if err := c.Conn.WriteMessage(websocket.BinaryMessage, msg); err != nil {&lt;br&gt;
            log.Println("write error:", err)&lt;br&gt;
            return&lt;br&gt;
        }&lt;br&gt;
    }&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Not JSON? Why Not Protobuf?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JSON&lt;/strong&gt; → Easy to use but heavy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protobuf&lt;/strong&gt; → Lightweight but complex.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Binary Message Protocol&lt;/strong&gt; → Minimal, custom, and just enough for real-time collaboration.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;This might not be advanced, and many senior engineers may find it straightforward, but I just wanted to share what I learned. Hopefully, you found it useful too.&lt;/p&gt;




&lt;h3&gt;
  
  
  Project
&lt;/h3&gt;

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

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`&lt;/p&gt;




</description>
    </item>
    <item>
      <title>Build a GitHub App in 5 Minutes with Probot</title>
      <dc:creator>Jaison D Souza</dc:creator>
      <pubDate>Tue, 29 Jul 2025 15:28:13 +0000</pubDate>
      <link>https://forem.com/jsndz/build-a-github-app-in-5-minutes-with-probot-pc6</link>
      <guid>https://forem.com/jsndz/build-a-github-app-in-5-minutes-with-probot-pc6</guid>
      <description>&lt;h1&gt;
  
  
  Build a GitHub App in 5 Minutes with Probot
&lt;/h1&gt;

&lt;p&gt;In this article I will show you how to build your own GitHub app in 5 minutes. You can put this in your portfolio, show a friend or just do it for fun. Without any further ado, let’s begin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;ANY code editor.&lt;/li&gt;
&lt;li&gt;Node.js installed.&lt;/li&gt;
&lt;li&gt;Little bit of programming knowledge. Just a little.&lt;/li&gt;
&lt;li&gt;Oh, and a GitHub account.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Setup the project
&lt;/h2&gt;

&lt;p&gt;Open a code editor. I will use VS Code. Then open a terminal.&lt;/p&gt;

&lt;p&gt;Run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-probot-app app_name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
`&lt;/p&gt;

&lt;p&gt;Enter the name, description, and your name. Then it will ask you to choose a template.&lt;/p&gt;

&lt;p&gt;If you’re using JavaScript, select &lt;code&gt;basic-js&lt;/code&gt;; for TypeScript, choose &lt;code&gt;basic-ts&lt;/code&gt; — which is what I'll use in this example.&lt;/p&gt;

&lt;p&gt;There are also some built-in templates like &lt;code&gt;checks&lt;/code&gt;, &lt;code&gt;deploy&lt;/code&gt;, and &lt;code&gt;git-data&lt;/code&gt;, which you can explore if you'd 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%2Fz7s76og7fgag4r7hkxzd.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%2Fz7s76og7fgag4r7hkxzd.png" alt=" " width="699" height="244"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Initialize your Smee client
&lt;/h2&gt;

&lt;p&gt;Visit &lt;a href="https://smee.io/new" rel="noopener noreferrer"&gt;https://smee.io/new&lt;/a&gt; to generate a channel and copy the URL.&lt;/p&gt;

&lt;p&gt;Open terminal and run the following command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;bash&lt;br&gt;
npm install --global smee-client&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then open &lt;code&gt;.env.example&lt;/code&gt; file and rename it to &lt;code&gt;.env&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Paste the URL from Smee in front of &lt;code&gt;WEBHOOK_PROXY_URL&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgif85h6b68hqjqhdnecq.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%2Fgif85h6b68hqjqhdnecq.png" alt=" " width="780" height="273"&gt;&lt;/a&gt;&lt;br&gt;
You might be wondering what to paste in &lt;code&gt;APP_ID&lt;/code&gt;?&lt;br&gt;
We will do that in the next step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Initialize GitHub App
&lt;/h2&gt;

&lt;p&gt;Go to: &lt;a href="https://github.com/settings/apps/new" rel="noopener noreferrer"&gt;https://github.com/settings/apps/new&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fill out the name, description, and homepage URL of your app. If you don’t have a homepage URL, just give your GitHub page.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Webhook URL&lt;/strong&gt;: Use the same &lt;code&gt;WEBHOOK_PROXY_URL&lt;/code&gt; from the previous step.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Webhook Secret&lt;/strong&gt;: Use whatever you set in your &lt;code&gt;.env&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permissions&lt;/strong&gt;: Choose permissions required for your app. If unsure, use &lt;code&gt;checks&lt;/code&gt;, &lt;code&gt;contents&lt;/code&gt;, &lt;code&gt;issues&lt;/code&gt;, &lt;code&gt;push&lt;/code&gt;, and &lt;code&gt;pull requests&lt;/code&gt;. You can change them later.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click on &lt;strong&gt;Create GitHub App&lt;/strong&gt;. You will be redirected.&lt;/p&gt;

&lt;p&gt;Copy the &lt;strong&gt;App ID&lt;/strong&gt; and paste it into your &lt;code&gt;.env&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Scroll down to the &lt;strong&gt;Private Keys&lt;/strong&gt; section.&lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;Generate a Private Key&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp1d3taapwere61qt88eh.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%2Fp1d3taapwere61qt88eh.png" alt=" " width="800" height="198"&gt;&lt;/a&gt;&lt;br&gt;
A &lt;code&gt;.pem&lt;/code&gt; file will be downloaded. Copy the file into your project folder.&lt;/p&gt;

&lt;p&gt;Rename it to &lt;code&gt;github_key.pem&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Remember to add &lt;code&gt;github_key.pem&lt;/code&gt; and &lt;code&gt;.env&lt;/code&gt; files to &lt;code&gt;.gitignore&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Paste this into the &lt;code&gt;.env&lt;/code&gt; file:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;env&lt;br&gt;
PRIVATE_KEY_PATH="./github_key.pem"&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then in terminal, open your app folder and run:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;bash&lt;br&gt;
cd app_name&lt;br&gt;
npm start&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Step: Add a Simple Feature
&lt;/h2&gt;

&lt;p&gt;You have successfully created your GitHub App. You can now modify the code to respond to events like &lt;code&gt;push&lt;/code&gt;, &lt;code&gt;pull_request&lt;/code&gt;, or &lt;code&gt;issues&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here’s an example that comments "thank you for raising the issue!" on every new issue:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`ts&lt;br&gt;
import { Probot } from "probot";&lt;/p&gt;

&lt;p&gt;export default (app: Probot) =&amp;gt; {&lt;br&gt;
  app.on("issues.opened", async (context) =&amp;gt; {&lt;br&gt;
    const issueComment = context.issue({&lt;br&gt;
      body: "thank you for raising the issue!",&lt;br&gt;
    });&lt;br&gt;
    await context.octokit.issues.createComment(issueComment);&lt;br&gt;
  });&lt;br&gt;
};&lt;br&gt;
`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That’s how you build your own GitHub App with Probot — quick and easy!&lt;/p&gt;

&lt;h2&gt;
  
  
  Check It Out
&lt;/h2&gt;

&lt;p&gt;I used this same method to build &lt;strong&gt;&lt;a href="https://github.com/jsndz/codexa" rel="noopener noreferrer"&gt;Codexa&lt;/a&gt;&lt;/strong&gt; — a GitHub Copilot-like tool for reviewing pull requests.&lt;br&gt;
Feel free to check out the code and see how it works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code&lt;/strong&gt;: &lt;a href="https://github.com/jsndz/blogs/tree/master/tutorial" rel="noopener noreferrer"&gt;github.com/jsndz/blogs/tree/master/tutorial&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Wanna connect?&lt;/strong&gt; Reach out on &lt;a href="https://www.linkedin.com/in/jaison-dsouza-414082263/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Also,&lt;/strong&gt; check out more of my &lt;a href="https://jsndz.vercel.app/" rel="noopener noreferrer"&gt;projects&lt;/a&gt; on &lt;a href="https://github.com/jsndz" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>github</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
