<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Md. Fardin Khan</title>
    <description>The latest articles on DEV Community by Md. Fardin Khan (@kporus).</description>
    <link>https://dev.to/kporus</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1175434%2Fc07de2dc-3555-4e4c-82d3-10f54f1dbffc.jpg</url>
      <title>DEV Community: Md. Fardin Khan</title>
      <link>https://dev.to/kporus</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kporus"/>
    <language>en</language>
    <item>
      <title>How We Built Chat Encryption( From First Idea to a Stable Design)</title>
      <dc:creator>Md. Fardin Khan</dc:creator>
      <pubDate>Tue, 14 Jul 2026 03:43:06 +0000</pubDate>
      <link>https://dev.to/kporus/how-we-built-chat-encryption-from-first-idea-to-a-stable-design-4e60</link>
      <guid>https://dev.to/kporus/how-we-built-chat-encryption-from-first-idea-to-a-stable-design-4e60</guid>
      <description>&lt;h1&gt;
  
  
  How We Built Chat Encryption — From First Idea to a Stable Design
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;A plain-language story of what broke, what we changed, and the architecture we ship today.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When we said &lt;strong&gt;“all messaging is encrypted,”&lt;/strong&gt; we meant something specific: our company should not be able to read your chat text from our servers. Only the people in the conversation on their own phones and browsers should unlock messages.&lt;/p&gt;

&lt;p&gt;Getting there was not a single release. It was a series of designs, real product problems, and fixes. This post walks that path from the start to the stable system we use now including the &lt;strong&gt;final architecture&lt;/strong&gt; and the main &lt;strong&gt;chat action flows&lt;/strong&gt; (login, send, receive, encrypt, re-key).&lt;/p&gt;




&lt;h2&gt;
  
  
  What “end-to-end encryption” means here
&lt;/h2&gt;

&lt;p&gt;Think of a courier delivering a lockbox.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You lock the message &lt;strong&gt;on your device&lt;/strong&gt; before it leaves.&lt;/li&gt;
&lt;li&gt;Our servers carry and store the lockbox.&lt;/li&gt;
&lt;li&gt;The other person’s device unlocks it.&lt;/li&gt;
&lt;li&gt;We never hold the private key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the &lt;strong&gt;server&lt;/strong&gt; creates the keys, the server can open every box. That is encryption &lt;em&gt;at rest&lt;/em&gt;, not end-to-end. We rejected that early. It would break the privacy promise.&lt;/p&gt;




&lt;h2&gt;
  
  
  Starting point: plaintext chat
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Before encryption&lt;/strong&gt;, messages were normal text in the database and over the wire. Chat worked well. Anyone with server or database access could read everything.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why we changed:&lt;/strong&gt; privacy protocol and user trust. Messaging content should be confidential by default.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Architecture at that time (simple):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Phone / Web  →  Server  →  Database
                (stores readable text)
                →  other devices
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 1 — First encryption design (one key per person)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What we built
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Each user generates a key pair &lt;strong&gt;on their device&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Only the &lt;strong&gt;public&lt;/strong&gt; key is uploaded.&lt;/li&gt;
&lt;li&gt;Direct messages: derive a shared secret between two people, then lock the text.&lt;/li&gt;
&lt;li&gt;Groups: each sender has a &lt;strong&gt;sender key&lt;/strong&gt; for that group. Share it with members, then lock each later message &lt;strong&gt;once&lt;/strong&gt; (same idea WhatsApp uses for groups).&lt;/li&gt;
&lt;li&gt;Server role: public-key directory + store/deliver ciphertext. No private keys.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What this looked like
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sender device                Server                    Recipient device
─────────────                ──────                    ────────────────
Create keys locally
Upload public key  ───────►  Key directory
Lock message       ───────►  Store ciphertext  ─────►  Unlock with private key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Issue we hit next
&lt;/h3&gt;

&lt;p&gt;Encryption was treated as &lt;strong&gt;required&lt;/strong&gt;. If the other person (or one group member) had never opened the new app/web, they had &lt;strong&gt;no keys&lt;/strong&gt;. Send failed. Chat looked broken for most existing users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; You cannot flip a switch to “everyone must encrypt” in a live product with old clients still in the wild.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2 — Soft rollout: encrypt if possible
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Problem
&lt;/h3&gt;

&lt;p&gt;Hard cutover blocked messaging whenever anyone lacked keys. Groups were worse: one member without keys blocked the whole send.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;If &lt;strong&gt;everyone&lt;/strong&gt; in the conversation has keys → encrypt.&lt;/li&gt;
&lt;li&gt;If &lt;strong&gt;anyone&lt;/strong&gt; is missing keys → send &lt;strong&gt;plaintext&lt;/strong&gt; and keep chat working.&lt;/li&gt;
&lt;li&gt;New clients generate and upload keys on login in the background.&lt;/li&gt;
&lt;li&gt;Never put private keys on the server to “migrate” old users (that would not be E2EE).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What users experience
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;New client ↔ new client&lt;/td&gt;
&lt;td&gt;Encrypted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New ↔ old (no keys yet)&lt;/td&gt;
&lt;td&gt;Plaintext, still delivers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Later, old user upgrades&lt;/td&gt;
&lt;td&gt;Future messages can encrypt&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Important boundary we locked later:&lt;/strong&gt; plaintext is for &lt;strong&gt;rollout&lt;/strong&gt;, not for “this group is too big.” Once keys exist, we encrypt — including large groups.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3 — Early decrypt bugs (still one device per user)
&lt;/h2&gt;

&lt;p&gt;After encryption shipped, several “Unable to decrypt” cases appeared. None were “encryption is fake”; they were edge cases in how keys were derived or loaded.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Issue (user view)&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DM fails between two people&lt;/td&gt;
&lt;td&gt;Both sides didn’t derive the same secret&lt;/td&gt;
&lt;td&gt;Align DM key agreement (identity × identity)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Can’t read your own group message after refresh&lt;/td&gt;
&lt;td&gt;Own sender key wasn’t resolved from local storage&lt;/td&gt;
&lt;td&gt;Fall back to locally stored sender key for self&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Some members never get group keys&lt;/td&gt;
&lt;td&gt;Member list used for crypto was incomplete (~paginated UI)&lt;/td&gt;
&lt;td&gt;Dedicated full member-id API for encryption&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Own DM breaks after navigating away&lt;/td&gt;
&lt;td&gt;Peer resolution sometimes treated &lt;em&gt;you&lt;/em&gt; as the peer&lt;/td&gt;
&lt;td&gt;Harden peer id; never fetch your own public bundle as the peer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; E2EE is as much about &lt;strong&gt;product edge cases&lt;/strong&gt; (reload, pagination, “my own bubble”) as about algorithms.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4 — Multi-device: phone + web for the same account
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Problem
&lt;/h3&gt;

&lt;p&gt;Same account in normal browser and Incognito (or phone + web). Send from one → &lt;strong&gt;Unable to decrypt&lt;/strong&gt; on the other.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why
&lt;/h3&gt;

&lt;p&gt;We stored &lt;strong&gt;one public key per user&lt;/strong&gt;. The second login &lt;strong&gt;overwrote&lt;/strong&gt; the first. Private keys live only in that browser. Device A cannot open a message sealed for Device B’s public key.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution (encryption version 2)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Each install gets a stable &lt;strong&gt;device id&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Server stores &lt;strong&gt;many&lt;/strong&gt; public bundles per user: &lt;code&gt;(userId, deviceId)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DMs:&lt;/strong&gt; one locked message body + small &lt;strong&gt;envelopes&lt;/strong&gt; of the message key for:

&lt;ul&gt;
&lt;li&gt;each of the peer’s devices&lt;/li&gt;
&lt;li&gt;your other devices&lt;/li&gt;
&lt;li&gt;this device (so your sent messages stay readable after reload)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Groups:&lt;/strong&gt; share the sender key to each &lt;strong&gt;member device&lt;/strong&gt;, not just each member.&lt;/li&gt;
&lt;li&gt;Cap later: &lt;strong&gt;max 5 devices&lt;/strong&gt; so fan-out stays bounded (similar to linked-device limits elsewhere).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;One message key
   ├─ lock text once → ciphertext
   ├─ envelope for peer phone
   ├─ envelope for peer web
   ├─ envelope for my phone
   └─ envelope for my web
         ↓
      Server stores ciphertext + envelopes
      (cannot open envelopes)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; “One account” in the product sense is &lt;strong&gt;many devices&lt;/strong&gt; in the crypto sense.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5 — Scale without dropping encryption (stable design)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Problem
&lt;/h3&gt;

&lt;p&gt;Privacy says all messaging is encrypted. Turning encryption off for “groups over N members” was rejected.&lt;/p&gt;

&lt;p&gt;But our group path, while &lt;em&gt;shaped&lt;/em&gt; like WhatsApp Sender Keys, still did expensive work &lt;strong&gt;on every send&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Re-share sender key wraps to everyone every message&lt;/li&gt;
&lt;li&gt;Fetch each member’s keys with &lt;strong&gt;one request per user&lt;/strong&gt; (N+1)&lt;/li&gt;
&lt;li&gt;Wasteful database work when listing keys&lt;/li&gt;
&lt;li&gt;Unbounded devices → larger and slower fan-out&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  What WhatsApp taught us (conceptually)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Once&lt;/strong&gt; (first speak / membership change): share the sender’s group secret with members’ devices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every later message:&lt;/strong&gt; lock &lt;strong&gt;once&lt;/strong&gt;; server copies the same blob to everyone.&lt;/li&gt;
&lt;li&gt;Cap linked devices.&lt;/li&gt;
&lt;li&gt;Don’t disable encryption because the group is large.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What we changed
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Change&lt;/th&gt;
&lt;th&gt;Everyday meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Distribute only when needed&lt;/td&gt;
&lt;td&gt;Heavy work on first send / new device / after join-leave; later sends stay fast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Batch key lookup&lt;/td&gt;
&lt;td&gt;One request for many members’ public keys&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Short-lived cache&lt;/td&gt;
&lt;td&gt;Don’t re-download the same public keys constantly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stop wasteful key-list side effects&lt;/td&gt;
&lt;td&gt;Listing public keys doesn’t burn one-time keys&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max 5 devices&lt;/td&gt;
&lt;td&gt;Keeps multi-device cost predictable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Always encrypt when keys exist&lt;/td&gt;
&lt;td&gt;Large groups stay encrypted&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Cost model (for engineers and curious readers):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Warm group send → cheap (lock once, upload once)&lt;/li&gt;
&lt;li&gt;Cold path (first send / rotate / new device) → more work, paid rarely&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final stable architecture
&lt;/h2&gt;

&lt;p&gt;This is the system we run today. Read it as a map of &lt;strong&gt;who does what&lt;/strong&gt;, then follow the &lt;strong&gt;action flows&lt;/strong&gt; for login, send, receive, and re-key.&lt;/p&gt;

&lt;h3&gt;
  
  
  Big picture
&lt;/h3&gt;

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

&lt;p&gt;In plain language: your device locks the words, our servers carry and file the lockbox, their device opens it. We never hold the private key.&lt;/p&gt;

&lt;h3&gt;
  
  
  System architecture — layers
&lt;/h3&gt;

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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Job&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Web and mobile apps&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;UI: thread list, message list, composer. Ask crypto to lock/unlock; never invent keys in the UI layer.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;On-device crypto service&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Create device keys, soft-rollout checks, DM envelopes, group sender keys, decrypt for history and live messages.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Realtime socket + HTTP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Socket for live send/edit/react/typing; HTTP for history, media, and the public key directory.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Backend chat service&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Auth, save messages, fan-out to members, unread and conversation previews.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Backend key directory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Store &lt;strong&gt;public&lt;/strong&gt; device keys and wrapped group secrets; signal re-key on membership change. &lt;strong&gt;Never&lt;/strong&gt; private keys.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Database&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Conversations, messages, public keys, wraps, read state, media.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Conversation model
&lt;/h3&gt;

&lt;p&gt;Every thread is a &lt;strong&gt;Group&lt;/strong&gt; — a community chat or a one-to-one DM. DMs are the same container with a DM chat type. There is no separate “Conversation” table. That keeps membership, delivery, and unread logic in one place.&lt;/p&gt;

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

&lt;p&gt;An encrypted message stores a sealed body (ciphertext), not readable text. Direct messages also store small &lt;strong&gt;device envelopes&lt;/strong&gt;. Group messages store a &lt;strong&gt;sender key id&lt;/strong&gt; so recipients know which shared secret to use.&lt;/p&gt;

&lt;h3&gt;
  
  
  Two encryption modes
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Direct message&lt;/strong&gt; — invent a one-time message key, lock the text once, put a sealed copy of that key in an envelope for each relevant device (theirs and yours).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Group&lt;/strong&gt; — share your sender key when needed; every later message from you is one locked blob for the whole group (WhatsApp-style Sender Keys).&lt;/p&gt;




&lt;h2&gt;
  
  
  Chat action flows
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Flow A — Login / device setup
&lt;/h3&gt;

&lt;p&gt;When someone opens the current app or web build while signed in, encryption sets itself up in the background. No extra button.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;What the user notices:&lt;/strong&gt; nothing dramatic — chat still works. Behind the scenes, this install published its public lock so others can encrypt to it.&lt;/p&gt;




&lt;h3&gt;
  
  
  Flow B — Send a text message (full path)
&lt;/h3&gt;

&lt;p&gt;This is the main action flow: tap Send → maybe encrypt → server stores → everyone receives → each device unlocks.&lt;/p&gt;

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

&lt;p&gt;Step by step in words:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;User taps Send.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client asks:&lt;/strong&gt; can everyone who needs to read this unlock a lockbox?

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No&lt;/strong&gt; → send plaintext (rollout only; chat must not break).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Yes&lt;/strong&gt; → DM uses envelopes; group may share a sender key, then lock once.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transport:&lt;/strong&gt; prefer realtime socket; fall back to HTTP if needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server&lt;/strong&gt; saves the message and fans it out to members in the room.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Each peer device&lt;/strong&gt; unlocks before showing the bubble (or shows plaintext / “unable to decrypt”).&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Flow C — Soft-rollout gate (decide encrypt vs plaintext)
&lt;/h3&gt;

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

&lt;p&gt;Plaintext here means “someone has not upgraded yet,” &lt;strong&gt;not&lt;/strong&gt; “this group is large.”&lt;/p&gt;




&lt;h3&gt;
  
  
  Flow D — Direct message encrypt / decrypt
&lt;/h3&gt;

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

&lt;p&gt;&lt;strong&gt;Why envelopes:&lt;/strong&gt; one locked message body; phone and web for the same account each get their own sealed copy of the message key.&lt;/p&gt;




&lt;h3&gt;
  
  
  Flow E — Group message (cold vs hot)
&lt;/h3&gt;

&lt;p&gt;Sharing a group secret with every member’s devices is expensive. We do it when needed; later messages stay cheap.&lt;/p&gt;

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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Moment&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;First encrypted send in a group (from you)&lt;/td&gt;
&lt;td&gt;Create your sender key, distribute wraps, then lock this message&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Later sends from you&lt;/td&gt;
&lt;td&gt;Reuse sender key; lock once; no redistribute&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Someone joins or leaves&lt;/td&gt;
&lt;td&gt;Server signals re-key; clients drop old local sender key; next send shares a new one&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Another member sends&lt;/td&gt;
&lt;td&gt;They use &lt;strong&gt;their&lt;/strong&gt; sender key (created on their first encrypted send)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  Flow F — Open history or a live message
&lt;/h3&gt;

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

&lt;p&gt;History and live messages use the same unlock rules. Failure shows a clear placeholder instead of garbage characters.&lt;/p&gt;




&lt;h3&gt;
  
  
  Flow G — Membership change / re-key
&lt;/h3&gt;

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

&lt;p&gt;&lt;strong&gt;Product meaning:&lt;/strong&gt; when the roster changes, chat re-locks itself so departed members should not keep reading &lt;em&gt;new&lt;/em&gt; messages under the old group secret.&lt;/p&gt;




&lt;h3&gt;
  
  
  Soft rollout vs privacy promise
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Missing keys → plaintext so chat doesn’t die during upgrade.&lt;/li&gt;
&lt;li&gt;Everyone has keys → &lt;strong&gt;always&lt;/strong&gt; encrypt, any group size.&lt;/li&gt;
&lt;li&gt;Old history before encryption → stays as it was (we don’t rewrite the past on the server).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What is / isn’t encrypted today
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Content&lt;/th&gt;
&lt;th&gt;Encrypted end-to-end?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Text when all peers have keys&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Text while someone lacks keys&lt;/td&gt;
&lt;td&gt;No (temporary rollout)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Photos / files / voice&lt;/td&gt;
&lt;td&gt;Not yet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typing, reactions, presence, group name&lt;/td&gt;
&lt;td&gt;No (delivery metadata)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Old groups: do we create sender keys up front?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;No mass migration.&lt;/strong&gt; Existing groups sit unchanged until someone with a modern client sends text &lt;strong&gt;and&lt;/strong&gt; every member has keys.&lt;/p&gt;

&lt;p&gt;Then, for &lt;strong&gt;that sender only&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a sender key (if none locally)&lt;/li&gt;
&lt;li&gt;Distribute wraps to member devices&lt;/li&gt;
&lt;li&gt;Encrypt that message&lt;/li&gt;
&lt;li&gt;Reuse the same sender key on later sends&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Other members create &lt;strong&gt;their own&lt;/strong&gt; sender key the first time &lt;em&gt;they&lt;/em&gt; send encrypted text. History from before encryption stays plaintext.&lt;/p&gt;




&lt;h2&gt;
  
  
  Decision log (what we refused and why)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tempting shortcut&lt;/th&gt;
&lt;th&gt;Why we didn’t&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Server generates keys for all users&lt;/td&gt;
&lt;td&gt;Server could read everything → not E2EE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Block send until everyone encrypts&lt;/td&gt;
&lt;td&gt;Breaks production chat during rollout&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plaintext for large groups&lt;/td&gt;
&lt;td&gt;Contradicts “all messaging is encrypted”&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One public key per account&lt;/td&gt;
&lt;td&gt;Phone + web cannot both decrypt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rebuild full Signal Protocol in one go&lt;/td&gt;
&lt;td&gt;Slower path; Sender Keys + device envelopes got us to a stable product shape&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;True E2EE is a client problem&lt;/strong&gt; as much as a server problem — private keys must stay on devices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ship a bridge&lt;/strong&gt; (encrypt-if-possible) or you will break existing users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-device is not optional&lt;/strong&gt; if people use phone and web.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scale encryption by doing expensive work rarely&lt;/strong&gt;, not by turning encryption off.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Product edge cases&lt;/strong&gt; (own messages, incomplete member lists, account switch) define whether users trust the feature.&lt;/li&gt;
&lt;/ol&gt;




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

&lt;p&gt;We started with readable messages on the server, then added locks, then learned that locks without a migration story feel like outages, then learned that one lock per account fails on a second browser, then aligned group encryption with the industry pattern: &lt;strong&gt;expensive once, cheap always&lt;/strong&gt;, without abandoning the privacy promise.&lt;/p&gt;

&lt;p&gt;The stable system today is: &lt;strong&gt;device-scoped keys, soft rollout for missing peers, WhatsApp-style group sender keys, and a server that relays sealed boxes it cannot open.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is how our chat encryption went from first idea to something we can stand behind in production.&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>softwareengineering</category>
      <category>encryption</category>
      <category>javascript</category>
    </item>
    <item>
      <title>🚀 Explore My New Interactive Portfolio and GitHub Projects! 🌟</title>
      <dc:creator>Md. Fardin Khan</dc:creator>
      <pubDate>Thu, 20 Jun 2024 15:25:38 +0000</pubDate>
      <link>https://dev.to/kporus/explore-my-new-interactive-portfolio-and-github-projects-74k</link>
      <guid>https://dev.to/kporus/explore-my-new-interactive-portfolio-and-github-projects-74k</guid>
      <description>&lt;p&gt;Hi everyone,&lt;/p&gt;

&lt;p&gt;I'm excited to share the new version of my portfolio with you! I've been working hard to improve it using Kaboom.js and Tiled software. Here’s what you can find in my new portfolio:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Interactive Projects&lt;/strong&gt;: Created with Kaboom.js.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Detailed Maps&lt;/strong&gt;: Maps designed with Tiled software.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skill Showcase&lt;/strong&gt;: My technical and soft skills.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can view my new portfolio &lt;a href="https://idyllic-empanada-3f941d.netlify.app/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you’re curious, you can also check out the older version of my portfolio &lt;a href="https://singular-mooncake-bead22.netlify.app/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I also have many projects on GitHub that you might find interesting. Feel free to explore them &lt;a href="https://github.com/KPorus" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I’d love to hear your thoughts. Reach out if you have any questions or want to connect.&lt;/p&gt;

&lt;p&gt;Thanks for checking out my work!&lt;/p&gt;

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

</description>
      <category>portfolio</category>
      <category>vite</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Client Device Detection in Next Js</title>
      <dc:creator>Md. Fardin Khan</dc:creator>
      <pubDate>Mon, 08 Apr 2024 10:52:03 +0000</pubDate>
      <link>https://dev.to/kporus/client-device-detection-in-next-js-4o9l</link>
      <guid>https://dev.to/kporus/client-device-detection-in-next-js-4o9l</guid>
      <description>&lt;p&gt;Ensuring optimal user experience across various devices is paramount in the ever-evolving web development landscape. Whether it's a smartphone, tablet, laptop, or desktop computer, each device has its own screen size, resolution, and capabilities. As web developers, one of our primary goals is to deliver content that renders seamlessly across this diverse array of devices. This is where device detection comes into play.&lt;/p&gt;

&lt;p&gt;Device detection involves identifying the type of device accessing a website, allowing developers to tailor the content and layout accordingly. By understanding the device's characteristics, such as screen size and browser capabilities, developers can optimize the presentation of their website for a superior user experience.&lt;/p&gt;

&lt;p&gt;In my recent endeavors to enhance website rendering within my Next.js projects, I delved into the realm of device detection. Despite numerous attempts using conventional methods, I found myself unable to achieve the desired results. After hours of research on Google and YouTube, I stumbled upon a game-changing solution: the &lt;a href="https://nextjs.org/docs/app/api-reference/functions/headers" rel="noopener noreferrer"&gt;Next.js Header API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Utilizing the Next.js Header API for device detection involved a series of strategic implementations. By examining user-agent strings and other relevant data, I could accurately discern the type of device accessing the website. Armed with this information, I could then tailor the website rendering to suit the specific device, whether it be a mobile phone, tablet, or desktop computer.&lt;/p&gt;

&lt;p&gt;Here's a simplified example of how this can be achieved:&lt;/p&gt;

&lt;p&gt;src/app/page.tsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { headers } from "next/headers";
import { isMobile } from "../utils/isMobile";

export default async function Home() {
  const userAgent = headers().get("user-agent") || "";
  const mobileCheck = isMobile(userAgent);

  return mobileCheck? (
      &amp;lt;div&amp;gt;Mobile Page&amp;lt;/div&amp;gt;
  ) : (
    &amp;lt;div&amp;gt;Desktop page&amp;lt;/div&amp;gt;
  );
}

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

&lt;/div&gt;



&lt;p&gt;/utils/isMobile&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// utils/isMobile.ts
export const isMobile = (userAgent: string): boolean =&amp;gt; {
  return /android.+mobile|ip(hone|[oa]d)/i.test(userAgent);
};

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

&lt;/div&gt;



&lt;p&gt;By incorporating the Next.js Header API and implementing device detection in this manner, I was able to overcome the challenges I faced and successfully optimize website rendering for different devices. This approach not only improves user experience but also demonstrates the power and versatility of Next.js in modern web development.&lt;/p&gt;

&lt;p&gt;Whether you're building a personal blog, an e-commerce platform, or a corporate website, considering device detection using Next.js Header API can significantly enhance your project's accessibility and appeal. Embrace this innovative solution and embark on a journey towards delivering exceptional user experiences across all devices.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>nextjs</category>
      <category>code</category>
      <category>programming</category>
    </item>
    <item>
      <title>Unveiling the Effects of Icons on Website Performance (part two)</title>
      <dc:creator>Md. Fardin Khan</dc:creator>
      <pubDate>Fri, 06 Oct 2023 13:24:36 +0000</pubDate>
      <link>https://dev.to/kporus/unveiling-the-effects-of-icons-on-website-performance-part-two-4h41</link>
      <guid>https://dev.to/kporus/unveiling-the-effects-of-icons-on-website-performance-part-two-4h41</guid>
      <description>&lt;p&gt;Hello and welcome back to the next part of our session. In the previous session, we delved into the impact of &lt;a href="https://react-icons.github.io/react-icons/" rel="noopener noreferrer"&gt;React Icons&lt;/a&gt; on web performance, and if you missed it, you can catch up by visiting &lt;a href="https://dev.to/kporus/unveiling-the-effects-of-icons-on-website-performance-53lm"&gt;Part One&lt;/a&gt;. Now, it's time to roll up our sleeves and explore some effective approaches to reduce page load times and enhance overall web performance.&lt;/p&gt;

&lt;p&gt;When it comes to web development, speed matters—a lot. It's not just about delivering content; it's about delivering it swiftly and efficiently. Slow-loading pages can be a major turn-off for users and can negatively affect your website's search engine rankings.&lt;/p&gt;

&lt;p&gt;So, without further ado, let's dive into the strategies and techniques I've discovered to optimize web performance and provide users with a smoother, faster experience.&lt;/p&gt;

&lt;p&gt;Before we proceed, please note that the approaches I'm about to share are based on my findings and experiences. I'm not endorsing any specific tool or method, and I'm open to learning from others. If you have a better solution or insight to offer, I encourage you to leave a comment or reach out to me via email. I'm eager to explore all available solutions and continue our collective journey toward improved web performance.&lt;/p&gt;

&lt;p&gt;Let's get started! 🚀&lt;/p&gt;

&lt;p&gt;At the outset, I opted for &lt;a href="https://ant.design/components/icon" rel="noopener noreferrer"&gt;ANT DESIGN ICONS&lt;/a&gt; when it came to using icons in my web development projects. Why, might you ask? Well, it's incredibly convenient and lightweight. Unlike some icon libraries that require you to install the entire component library, Ant Design Icons offers a more streamlined approach.&lt;/p&gt;

&lt;p&gt;With Ant Design Icons, you don't need to bloat your project with unnecessary components. Instead, you can selectively use just the icons you need. The installation process is a breeze. Just run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @ant-design/icons --save
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This minimalistic approach not only keeps your project lean but also helps optimize performance. After all, every byte matters when it comes to web performance.&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%2Fdksnuzpdg43v53j96jcq.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%2Fdksnuzpdg43v53j96jcq.png" alt="Code" width="386" height="169"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Certainly, it's important to note that it's not just the choice of icon library that matters for web performance, but also how you integrate and use those icons in your code.&lt;/p&gt;

&lt;p&gt;Efficient usage of icons can make a significant difference in loading times and resource utilization. It's not uncommon to see web developers inadvertently introduce performance bottlenecks by misusing or overloading their web pages with unnecessary icons. &lt;/p&gt;

&lt;p&gt;&lt;u&gt;&lt;strong&gt;1. Using Ant Design Icons in the Navbar:&lt;/strong&gt;&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;In my first approach, I made the strategic decision to integrate Ant Design Icons into the navigation bar of my website. Given that the navbar is a consistent element across all pages, this choice seemed natural and efficient.&lt;/p&gt;

&lt;p&gt;Icons in the navbar serve a dual purpose—they enhance both functionality and aesthetics. They offer users visual cues, which make navigation more intuitive and engaging. However, it's crucial to strike a balance and avoid overwhelming the navbar with icons that don't serve a genuine purpose.&lt;/p&gt;

&lt;p&gt;To achieve this, I followed a specific approach:&lt;/p&gt;

&lt;p&gt;*&lt;strong&gt;&lt;em&gt;Import Icons in a Separate File:&lt;/em&gt;&lt;/strong&gt;*&lt;/p&gt;

&lt;p&gt;I created a separate file for importing icons. This file &lt;br&gt;
 houses all the icons I intended to use throughout the &lt;br&gt;
 website. Importing them in one place ensures that they are &lt;br&gt;
 fetched and included only once during the build process &lt;br&gt;
 Here's a glimpse of the code:&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%2Fmglg4gqwui07hva0ngbh.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%2Fmglg4gqwui07hva0ngbh.png" alt="Code" width="800" height="568"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;*&lt;strong&gt;&lt;em&gt;Reusable Icons:&lt;/em&gt;&lt;/strong&gt;*&lt;/p&gt;

&lt;p&gt;By centralizing the icons in a single file, I made it possible to reuse these icons across multiple pages without the need to request them from Ant Design's server repeatedly. This approach significantly reduces page load times and optimizes the overall web performance.&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%2F4zd3fin01dg4qlu68g6v.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%2F4zd3fin01dg4qlu68g6v.png" alt="Code" width="800" height="348"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, this method ensures that icons are imported only once during the build process, sparing us from unnecessary server requests and benefiting the overall page load time.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;2. Use of SVG ICONS:&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;Many developers, including myself, have held the belief that using SVGs can negatively impact our web page's performance. However, over time, I've come to realize that it's not SVG themselves but rather how we use them that matters.&lt;/p&gt;

&lt;p&gt;In my code, I adopted an approach where I treated SVGs as images in Next.js. This strategy allowed me to efficiently deploy SVGs as part of my web project.&lt;/p&gt;

&lt;p&gt;Here's how I implemented it:&lt;/p&gt;

&lt;p&gt;*&lt;strong&gt;&lt;em&gt;Import SVGs as Images URL:&lt;/em&gt;&lt;/strong&gt;*&lt;br&gt;
I imported SVGs just like any other image file, as shown &lt;br&gt;
    below:&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%2F4sgumzoose5ej2l1i030.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%2F4sgumzoose5ej2l1i030.png" alt="Code" width="800" height="483"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;*&lt;strong&gt;&lt;em&gt;Use SVGs Where Needed:&lt;/em&gt;&lt;/strong&gt;*&lt;/p&gt;

&lt;p&gt;Once imported, I could use these SVGs as images in my &lt;br&gt;
   components or pages, as demonstrated in the following code &lt;br&gt;
   snippet:&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%2F55y0b5r1xw7xemk91b0p.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%2F55y0b5r1xw7xemk91b0p.png" alt="Code" width="800" height="483"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This approach made it simple to incorporate SVG wherever I &lt;br&gt;
  needed them in my web application.&lt;/p&gt;

&lt;p&gt;*&lt;strong&gt;&lt;em&gt;Optimize SVG When Required:&lt;/em&gt;&lt;/strong&gt;*&lt;/p&gt;

&lt;p&gt;While using SVGs as images, I also ensured that the SVGs &lt;br&gt;
   themselves were optimized for web use. This involved &lt;br&gt;
   optimizing their file sizes and ensuring that they didn't &lt;br&gt;
   contain unnecessary elements or attributes. This &lt;br&gt;
   optimization step is crucial for maintaining a fast-loading &lt;br&gt;
   website.&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%2F25sv664no2ceehjecw2y.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%2F25sv664no2ceehjecw2y.png" alt="Code" width="800" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In closing, I want to reiterate that these findings are a result of my exploration and experiences. Web development is a dynamic field, and there's always more to learn. There may be alternative approaches, new tools, or optimizations that I haven't encountered yet. If you come across any errors or have better solutions, please don't hesitate to share them.&lt;/p&gt;

&lt;p&gt;The beauty of our developer community lies in our collective knowledge and our willingness to help one another grow. Let's continue to push the boundaries of web performance, learn from each other, and create even faster and more efficient websites.&lt;/p&gt;

&lt;p&gt;Thank you for being a part of this journey, and let's keep the spirit of curiosity and collaboration alive in our pursuit of better web performance.&lt;/p&gt;

&lt;p&gt;Happy coding, and may your websites always load swiftly! 🚀🚀&lt;/p&gt;

</description>
      <category>performance</category>
      <category>nextjs</category>
      <category>react</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Unveiling the Effects of Icons on Website Performance</title>
      <dc:creator>Md. Fardin Khan</dc:creator>
      <pubDate>Tue, 03 Oct 2023 03:22:10 +0000</pubDate>
      <link>https://dev.to/kporus/unveiling-the-effects-of-icons-on-website-performance-53lm</link>
      <guid>https://dev.to/kporus/unveiling-the-effects-of-icons-on-website-performance-53lm</guid>
      <description>&lt;p&gt;Hello, fellow developers!&lt;/p&gt;

&lt;p&gt;Welcome to my debut blog post. If you spot any errors, kindly point them out—I'm here to learn and grow. Today, I'm excited to delve into a recent challenge I encountered while grappling with website performance.&lt;/p&gt;

&lt;p&gt;First and foremost, let me clarify that I'm not here to cast blame or impose my views on anyone. I've embarked on this writing journey to share my experience, particularly a significant hiccup I faced while crafting my portfolio website. Allow me to introduce you to my homepage—&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%2F5kop8uwyd704d9ekbxqf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5kop8uwyd704d9ekbxqf.jpg" alt="Home" width="800" height="460"&gt;&lt;/a&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%2F6ahtzl8yez7lje1605s1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ahtzl8yez7lje1605s1.jpg" alt="Home" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can observe, the homepage consists of a few text elements and a navigation bar adorned with icons. To achieve this, I employed Material-UI (MUI) and &lt;a href="https://www.npmjs.com/package/react-icons" rel="noopener noreferrer"&gt;React Icons&lt;/a&gt;. However, there's a noticeable hiccup - the page, ideally, should load swiftly, but instead, it's a bit sluggish. Even more concerning, it's transferring more data than anticipated.&lt;/p&gt;

&lt;p&gt;Let's dive deeper into these issues. After Some time I found there are many unused javascript which is coming from React icons. please see this-- &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%2F4qoexa7zmg38e75eha6j.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4qoexa7zmg38e75eha6j.jpg" alt="Network Tab" width="800" height="423"&gt;&lt;/a&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%2Fs6l4imsvhsc6r7loavrg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs6l4imsvhsc6r7loavrg.jpg" alt="Network Tab" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, as you can see, the network tab indicates an abundance of unused JavaScript that's being pulled in from React Icons. This is quite perplexing, especially when I've used only one icon on my homepage. It seems that the icons file is loading every icon in its arsenal, regardless of whether it's needed or not. Here is how I imported the icons--&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%2Fxazm1h3bajd57c7yhxgv.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxazm1h3bajd57c7yhxgv.jpg" alt="Code" width="798" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Initially, I thought I had found a solution by dynamically importing the icons as needed. However, upon inspecting the React Icons file within the node modules, it became apparent where the issue lies. Take a look at this snippet: &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%2Fqcabj2zn5moncfzjw61q.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqcabj2zn5moncfzjw61q.jpg" alt="Code" width="800" height="354"&gt;&lt;/a&gt;&lt;br&gt;
In this image, you can observe that all the "Gi" type icons are bundled together in one file. So, even if I use only one or a few icons from the "Gi" file, React Icons generates and loads the entire file, which includes all the icons it offers.&lt;/p&gt;

&lt;p&gt;This behavior undoubtedly contributes to the slower loading times and excessive data transfer that I observed.&lt;/p&gt;

&lt;p&gt;Now, let's take a look at the homepage I created without relying on React Icons:&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%2Fhgak3l9i4rezbl0z580a.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhgak3l9i4rezbl0z580a.jpg" alt="Home page" width="800" height="408"&gt;&lt;/a&gt;&lt;br&gt;
As you can see, the difference is striking. The page now loads significantly faster, and the data transfer is notably reduced compared to the previous setup.&lt;/p&gt;

&lt;p&gt;In my quest to enhance website performance, I decided to explore an alternative approach for displaying icons on my portfolio. By refraining from using React Icons and opting for a different method, I was able to achieve these promising results.&lt;/p&gt;

&lt;p&gt;Stay tuned for the exciting details!&lt;br&gt;
&lt;a href="https://dev.to/kporus/unveiling-the-effects-of-icons-on-website-performance-part-two-4h41"&gt;Unveiling the Effects of Icons on Website Performance (Part two)&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>performance</category>
      <category>react</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
