<?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: Sai Praveen Sanapalli</title>
    <description>The latest articles on DEV Community by Sai Praveen Sanapalli (@saipraveen446).</description>
    <link>https://dev.to/saipraveen446</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%2F3807369%2Ff073a29f-7463-4a70-86b5-66c28d1f20f1.jpeg</url>
      <title>DEV Community: Sai Praveen Sanapalli</title>
      <link>https://dev.to/saipraveen446</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/saipraveen446"/>
    <language>en</language>
    <item>
      <title>CDN Explained: How Content Delivery Networks Work — A Complete Beginner's Guide</title>
      <dc:creator>Sai Praveen Sanapalli</dc:creator>
      <pubDate>Wed, 12 Aug 2026 20:48:35 +0000</pubDate>
      <link>https://dev.to/saipraveen446/cdn-explained-how-content-delivery-networks-work-a-complete-beginners-guide-3pkp</link>
      <guid>https://dev.to/saipraveen446/cdn-explained-how-content-delivery-networks-work-a-complete-beginners-guide-3pkp</guid>
      <description>&lt;p&gt;If you've ever wondered how websites deliver content quickly to users around the world, a Content Delivery Network (CDN) is a big part of the answer.&lt;/p&gt;

&lt;p&gt;But how does a CDN actually work? How does it route users to nearby servers, cache content, and reduce the load on the origin server?&lt;/p&gt;

&lt;p&gt;This post breaks down what a CDN actually is, how it works under the hood, its architecture, real-world examples, and why modern websites rely on CDNs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;What is a CDN?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Why Is a CDN Needed?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How Does a CDN Work?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CDN Architecture&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Key Components of a CDN&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What Content Does a CDN Deliver?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CDN for JavaScript, APIs, and Dynamic Websites&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Caching Strategies&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Real-World Examples&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Popular CDN Providers&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Benefits of Using a CDN&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Challenges and Limitations&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When Should You Use a CDN?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How to Check Which CDN a Site Uses&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  What is a CDN?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Content Delivery Network (CDN)&lt;/strong&gt; is a globally distributed network of servers that delivers content to users from a location close to them, instead of routing every request to a single origin server.&lt;/p&gt;

&lt;p&gt;Instead of every user request traveling all the way to your &lt;strong&gt;origin server&lt;/strong&gt; (the main server hosting your website), a CDN stores &lt;strong&gt;cached copies&lt;/strong&gt; of your content on servers spread across the world — called &lt;strong&gt;edge servers&lt;/strong&gt; or &lt;strong&gt;Points of Presence (PoPs)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Almost every large website today uses some form of CDN to improve performance, reduce origin-server load, handle traffic spikes, and provide additional security.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Without CDN:  User (India) → Origin Server (USA)
With CDN:     User (India) → CDN Edge (near India) → Origin (only if needed)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Why CDN is Needed
&lt;/h2&gt;

&lt;p&gt;Imagine your app is hosted on a single server in Mumbai, and users come from Hyderabad, Delhi, London, New York, and Tokyo. Every single request — no matter where it originates — has to travel all the way to Mumbai and back.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hyderabad ─┐
Delhi ─────┤
London ────┼──→ Mumbai Origin
New York ──┤
Tokyo ─────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The farther a user is from the origin, the more &lt;strong&gt;latency&lt;/strong&gt; (network delay) is introduced. A CDN's job is to place cacheable content closer to users so this round trip shrinks dramatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  How a CDN Works (Step by Step)
&lt;/h2&gt;

&lt;p&gt;Let's trace a real request for &lt;code&gt;https://example.com/logo.png&lt;/code&gt; from start to finish.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. DNS Resolution
&lt;/h3&gt;

&lt;p&gt;The user enters a URL such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://example.com/logo.png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The browser performs a DNS lookup for &lt;code&gt;example.com&lt;/code&gt;. If the website uses a CDN, DNS directs the request toward the CDN network rather than sending it directly to the origin server.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. User Request Reaches the CDN
&lt;/h3&gt;

&lt;p&gt;The request travels from the user's device through their ISP (such as Airtel, Jio, ACT, BSNL) and across the internet toward a suitable CDN Point of Presence (PoP).&lt;/p&gt;

&lt;p&gt;CDNs use technologies such as &lt;strong&gt;Anycast routing&lt;/strong&gt; or &lt;strong&gt;GeoDNS&lt;/strong&gt; to route users to an appropriate edge location — often one that is geographically or network-wise close to them.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Edge Server Checks the Cache
&lt;/h3&gt;

&lt;p&gt;Once the request reaches the CDN edge server, the CDN checks whether the requested content — &lt;code&gt;/logo.png&lt;/code&gt; in this case — is already cached. There are two possible outcomes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cache Hit&lt;/strong&gt; — if &lt;code&gt;/logo.png&lt;/code&gt; is already available in the edge cache, the CDN immediately returns it to the user.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cache Miss&lt;/strong&gt; — if the content is not available in the edge cache, the CDN sends a request to the origin server.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. CDN Fetches Content from the Origin
&lt;/h3&gt;

&lt;p&gt;The origin server is the actual server where the website's content is stored.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User
  ↓
ISP
  ↓
CDN Edge Server
  ↓
Origin Server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The origin server returns &lt;code&gt;logo.png&lt;/code&gt; to the CDN edge server.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. CDN Caches the Content
&lt;/h3&gt;

&lt;p&gt;The CDN stores the returned content in its edge cache according to the configured cache rules and TTL (Time to Live). The response is then sent to the user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Origin Server
      ↓
CDN Edge Server
      ↓
    User
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Subsequent Requests
&lt;/h3&gt;

&lt;p&gt;When another user requests the same &lt;code&gt;logo.png&lt;/code&gt; and is routed to an edge location that already has the object cached, the CDN can serve it directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User
  ↓
ISP
  ↓
CDN Edge
  ↓
Cached logo.png
  ↓
User
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The origin server does not need to be contacted for every request.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Cache Expiration
&lt;/h3&gt;

&lt;p&gt;Cached content has a TTL that determines how long the CDN should consider the cached object fresh. Once the TTL expires, the CDN may need to contact the origin server again to obtain a fresh version, depending on the CDN's caching and revalidation configuration.&lt;/p&gt;




&lt;h2&gt;
  
  
  CDN Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                        USERS
                          |
                          v
                         DNS
                          |
                          v
                         ISP
                          |
                          v
                 CDN / EDGE LOCATION
                          |
                   Cache Hit?
                    /         \
                 Yes            No
                  |              |
                  v              v
                USER          ORIGIN
                                 |
                                 v
                          LOAD BALANCER
                                 |
                        +--------+--------+
                        |                 |
                   APP SERVER        APP SERVER
                        |                 |
                        +--------+--------+
                                 |
                              DATABASE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you remember only one diagram from this whole post, remember this one — it's the backbone of every CDN explanation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Components of a CDN
&lt;/h2&gt;

&lt;p&gt;It helps to know the individual pieces that make up a CDN and work together on every request.&lt;/p&gt;

&lt;h3&gt;
  
  
  a. Origin Server
&lt;/h3&gt;

&lt;p&gt;The original source of truth — where your actual website/app files live.&lt;/p&gt;

&lt;h3&gt;
  
  
  b. Edge Servers (PoPs — Points of Presence)
&lt;/h3&gt;

&lt;p&gt;Servers distributed across multiple geographic locations that cache and serve content to nearby users.&lt;/p&gt;

&lt;h3&gt;
  
  
  c. DNS Routing / Anycast
&lt;/h3&gt;

&lt;p&gt;Determines which edge server should handle a given user's request — usually the geographically nearest or least congested one.&lt;/p&gt;

&lt;h3&gt;
  
  
  d. Cache Layer
&lt;/h3&gt;

&lt;p&gt;Stores static (and sometimes dynamic) content temporarily so it doesn't need to be re-fetched from the origin every time.&lt;/p&gt;

&lt;h3&gt;
  
  
  e. Load Balancer
&lt;/h3&gt;

&lt;p&gt;Distributes incoming traffic across multiple servers to prevent overload and ensure high availability.&lt;/p&gt;

&lt;h3&gt;
  
  
  f. Origin Shield
&lt;/h3&gt;

&lt;p&gt;An additional caching layer between edge servers and the origin, reducing the number of direct requests that hit your origin server.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Content a CDN Delivers
&lt;/h2&gt;

&lt;p&gt;A CDN isn't just for JavaScript files. It commonly handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Static content&lt;/strong&gt;: images, CSS, JavaScript, fonts, PDFs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic content&lt;/strong&gt;: personalized pages, API responses (via dynamic content acceleration)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streaming media&lt;/strong&gt;: video/audio (YouTube, Netflix use CDNs heavily)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Software downloads&lt;/strong&gt;: large files like game updates, installers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web applications&lt;/strong&gt;: full websites via edge computing (e.g., Cloudflare Workers, Vercel Edge Functions)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  CDN for JavaScript, APIs, and Dynamic Websites
&lt;/h2&gt;

&lt;h3&gt;
  
  
  CDN for JavaScript
&lt;/h3&gt;

&lt;p&gt;This is where the term "JavaScript CDN" often causes confusion.&lt;/p&gt;

&lt;p&gt;Consider Bootstrap. Instead of hosting it yourself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/assets/bootstrap.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;you can load it from a CDN instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.example.com/bootstrap.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The JavaScript file is hosted and distributed through the CDN provider's infrastructure. Popular libraries are commonly distributed this way — jQuery, React, Bootstrap, and countless others are all available via public CDNs like jsDelivr or cdnjs.&lt;/p&gt;

&lt;p&gt;It's worth being precise about what's actually happening here: the CDN is &lt;strong&gt;not&lt;/strong&gt; "executing" your JavaScript. It is simply &lt;strong&gt;delivering the JavaScript file&lt;/strong&gt; to the browser — the browser is the one that executes it. The CDN's job ends the moment the file is handed off.&lt;/p&gt;

&lt;h3&gt;
  
  
  CDN for APIs
&lt;/h3&gt;

&lt;p&gt;A common myth is that CDNs only work for static sites. Not true — CDNs can also sit in front of APIs.&lt;/p&gt;

&lt;p&gt;A CDN can route static assets to cache while sending dynamic requests straight to the origin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    CDN
                     |
          +----------+----------+
          |                     |
    Static files          Dynamic requests
   (/assets/*.js)          (/api/login)
          |                     |
          v                     v
        Cache                Origin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Take an endpoint like &lt;code&gt;/api/products&lt;/code&gt;. Suppose the product list only changes every 5 minutes — you might configure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Cache-Control: public, max-age=300
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now many users can be served the cached response instead of hitting your backend on every single request.&lt;/p&gt;

&lt;p&gt;But this should &lt;strong&gt;only&lt;/strong&gt; be done when serving a cached response is actually safe — meaning the response is identical for everyone requesting it. Never blindly cache personalized API responses like &lt;code&gt;/api/profile&lt;/code&gt;, &lt;code&gt;/api/cart&lt;/code&gt;, or &lt;code&gt;/api/orders&lt;/code&gt;; doing so risks leaking one user's data to another.&lt;/p&gt;




&lt;h2&gt;
  
  
  Caching Strategies
&lt;/h2&gt;

&lt;p&gt;CDNs use different caching strategies depending on the content type:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Strategy&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Example Use Case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pull CDN&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Content is cached only after the first user request&lt;/td&gt;
&lt;td&gt;Blogs, general websites&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Push CDN&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You manually upload content to the CDN in advance&lt;/td&gt;
&lt;td&gt;Large media files, software releases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Time-based expiry (TTL)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Content is cached for a fixed duration&lt;/td&gt;
&lt;td&gt;Static assets like logos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cache invalidation/purge&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Manually clearing cache when content updates&lt;/td&gt;
&lt;td&gt;After a website deployment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Stale-while-revalidate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Serves old cached content while fetching a fresh copy in background&lt;/td&gt;
&lt;td&gt;News sites, high-traffic pages&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  Cache Hit vs Cache Miss
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Cache hit&lt;/strong&gt; — the requested content already exists at the edge, so it's returned immediately with no origin involved.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cache miss&lt;/strong&gt; — the content isn't cached yet, so the edge server fetches it from the origin (or another cache tier), caches it, and then serves it — meaning the next request for that same object is likely to be a hit.&lt;/p&gt;

&lt;h3&gt;
  
  
  TTL, Cache Invalidation, and Cache Busting
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;TTL (Time to Live)&lt;/strong&gt; controls how long an object stays cached before it's considered stale and needs to be refreshed from the origin.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cache invalidation / purging&lt;/strong&gt; lets you manually clear a cached object — useful right after deploying a new version of a file the CDN is still serving an old copy of.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cache busting&lt;/strong&gt; is a common alternative: changing the filename whenever content changes (e.g. &lt;code&gt;app.a82f91.js&lt;/code&gt; → &lt;code&gt;app.91bc72.js&lt;/code&gt;) so the CDN and browser treat it as a brand-new resource, avoiding stale-cache issues entirely.&lt;/p&gt;

&lt;h3&gt;
  
  
  Browser Cache vs CDN Cache
&lt;/h3&gt;

&lt;p&gt;These are two separate caching layers that work together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser Cache               CDN Cache
└── lives on the user's     └── lives across CDN edge
    own device                  locations worldwide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the browser already has a resource cached locally, it may skip the network entirely. If it does need to fetch it, that request then hits the CDN cache layer next — before ever reaching your origin.&lt;/p&gt;

&lt;h3&gt;
  
  
  DNS Alone Is Not a CDN
&lt;/h3&gt;

&lt;p&gt;A common misunderstanding: pointing &lt;code&gt;example.com → 1.2.3.4&lt;/code&gt; in DNS does &lt;strong&gt;not&lt;/strong&gt; create a CDN. DNS only tells clients where/how to reach a service — you still need an actual distributed CDN network behind that configuration. Typically your domain is set up with a CNAME (or provider-specific equivalent) pointing to a CDN-provided hostname, e.g.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;www.example.com  →  d123example.cloudfront.net
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Netflix&lt;/strong&gt;: Uses its own CDN (Open Connect) to cache movies/shows on servers close to ISPs, ensuring smooth streaming without buffering.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;E-commerce sites (Amazon, Flipkart)&lt;/strong&gt;: Serve product images and static assets via CDN so pages load fast during high-traffic sales events.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;News websites&lt;/strong&gt;: Use CDNs to handle massive traffic spikes when breaking news goes viral, without crashing the origin server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: Uses a CDN (jsDelivr, Fastly) to serve raw files and package assets globally.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gaming platforms&lt;/strong&gt;: Use CDNs to distribute large game updates/patches quickly to millions of users worldwide.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Popular CDN Providers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cloudflare&lt;/strong&gt; — widely used, offers free tier, strong security features (DDoS protection, WAF)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Akamai&lt;/strong&gt; — one of the oldest and largest CDN providers, used by enterprises&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amazon CloudFront&lt;/strong&gt; — integrated with AWS services&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fastly&lt;/strong&gt; — known for real-time purging and developer-friendly edge computing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Cloud CDN&lt;/strong&gt; — integrated with Google Cloud Platform&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;jsDelivr&lt;/strong&gt; — popular free CDN for open-source JS/CSS libraries and npm packages&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Benefits of Using a CDN
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Faster load times&lt;/strong&gt; — content served from nearby edge servers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced origin server load&lt;/strong&gt; — fewer direct requests hit your main server&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved scalability&lt;/strong&gt; — handles traffic spikes gracefully&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better reliability/uptime&lt;/strong&gt; — if one edge server fails, traffic reroutes to another&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced security&lt;/strong&gt; — many CDNs offer DDoS protection, bot mitigation, and SSL/TLS termination&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SEO benefits&lt;/strong&gt; — page speed is a ranking factor for search engines&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bandwidth cost savings&lt;/strong&gt; — cached content reduces data transfer from the origin&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Challenges and Limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cache invalidation complexity&lt;/strong&gt; — ensuring users don't see stale/outdated content&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost&lt;/strong&gt; — can get expensive at very high traffic volumes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic content limitations&lt;/strong&gt; — not all CDNs handle personalized/dynamic content well&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging difficulty&lt;/strong&gt; — issues can be harder to trace since content isn't always coming from your origin&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vendor lock-in&lt;/strong&gt; — switching CDN providers can require configuration changes&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  When Should You Use a CDN?
&lt;/h2&gt;

&lt;p&gt;You should seriously consider a CDN if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your website/app has users spread across different geographic regions&lt;/li&gt;
&lt;li&gt;You serve a lot of static assets (images, videos, JS/CSS bundles)&lt;/li&gt;
&lt;li&gt;You expect high or unpredictable traffic (product launches, sales, viral content)&lt;/li&gt;
&lt;li&gt;You want to improve page speed/SEO performance&lt;/li&gt;
&lt;li&gt;You need extra protection against DDoS attacks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even small projects and personal blogs benefit from free-tier CDNs like Cloudflare.&lt;/p&gt;

&lt;p&gt;Less critical for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; Small internal tools
&lt;span class="p"&gt;-&lt;/span&gt; Very low traffic
&lt;span class="p"&gt;-&lt;/span&gt; Purely private/dynamic requests
&lt;span class="p"&gt;-&lt;/span&gt; Users concentrated right next to the origin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  How to Check Which CDN a Site Uses
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Browser DevTools:&lt;/strong&gt; open Network tab, reload the page, inspect a resource's response headers. Cloudflare, for example, often exposes headers like &lt;code&gt;cf-cache-status&lt;/code&gt; and &lt;code&gt;server: cloudflare&lt;/code&gt;; other providers have their own signatures.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;curl:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-I&lt;/span&gt; https://example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for headers like &lt;code&gt;cache-control&lt;/code&gt;, &lt;code&gt;age&lt;/code&gt;, and &lt;code&gt;server&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DNS lookup:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dig example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;CNAME&lt;/code&gt; pointing to something like &lt;code&gt;*.cloudfront.net&lt;/code&gt; is a strong clue about which CDN is in use.&lt;/p&gt;

&lt;p&gt;Note: the exact physical data center a request was served from usually isn't discoverable from public headers — CDN routing is dynamic, and providers generally don't expose exact building/server-level detail.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;A CDN is a &lt;strong&gt;globally distributed network of servers&lt;/strong&gt; that sits between your users and your origin server, caching and delivering content from the location closest to each user — instead of routing every request across the world to a single origin.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The core flow to remember:&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;User → DNS → ISP → CDN Edge Location → Cache Hit/Miss → Origin (if needed)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On a &lt;strong&gt;cache hit&lt;/strong&gt;, the edge server answers directly. On a &lt;strong&gt;cache miss&lt;/strong&gt;, it fetches from the origin, caches the response according to its TTL, and serves future requests from cache — until that TTL expires or the content is invalidated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What makes this work, pulled from the post:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Components&lt;/strong&gt; — origin server, edge servers/PoPs, DNS/Anycast routing, cache layer, load balancer, and origin shield all work together on every request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What gets delivered&lt;/strong&gt; — not just JavaScript: images, CSS, fonts, video, downloads, and even API responses and full dynamic apps via edge computing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Caching strategies&lt;/strong&gt; — pull vs push CDNs, TTL-based expiry, manual invalidation/purging, and cache busting (renaming files) all exist to balance freshness against performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not just static sites&lt;/strong&gt; — CDNs can safely accelerate APIs too, as long as cacheable responses are the same for every user; personalized endpoints should never be cached this way.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DNS alone isn't a CDN&lt;/strong&gt; — you need an actual distributed CDN network behind your domain, not just a DNS record.
&lt;strong&gt;Why it matters:&lt;/strong&gt; faster load times, less load on your origin, better resilience during traffic spikes, built-in DDoS/WAF protection from most providers, and a real SEO benefit since page speed affects ranking. The trade-offs are mainly cache-invalidation complexity, cost at scale, and slightly harder debugging.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're building anything with users spread across regions, or expecting unpredictable traffic, a CDN isn't optional anymore — it's a baseline part of modern web architecture, and even a free tier (like Cloudflare) is worth adding to a small project.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Have you set up a CDN for one of your own projects? Drop the provider you used (and what tripped you up) in the comments — I'd love to hear it.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>cdn</category>
      <category>webdev</category>
      <category>networking</category>
      <category>devops</category>
    </item>
    <item>
      <title>PostgreSQL Replication: The Complete Guide to Read Replicas, Architecture, and Setup</title>
      <dc:creator>Sai Praveen Sanapalli</dc:creator>
      <pubDate>Tue, 11 Aug 2026 18:22:49 +0000</pubDate>
      <link>https://dev.to/saipraveen446/postgresql-replication-the-complete-guide-to-read-replicas-architecture-and-setup-4f9o</link>
      <guid>https://dev.to/saipraveen446/postgresql-replication-the-complete-guide-to-read-replicas-architecture-and-setup-4f9o</guid>
      <description>&lt;p&gt;Replication is one of those topics that every backend engineer eventually has to deal with — usually right when the primary database starts sweating under load, or right after an outage nobody wants to repeat. This guide walks through everything you need to know about PostgreSQL replication: what it is, why you need it, how it actually works under the hood, and how to configure it yourself, step by step.&lt;/p&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;What Is a Read Replica?&lt;/li&gt;
&lt;li&gt;Why Read Replicas Are Needed&lt;/li&gt;
&lt;li&gt;Primary vs Replica: Key Differences&lt;/li&gt;
&lt;li&gt;How Replication Works&lt;/li&gt;
&lt;li&gt;Replication Flow&lt;/li&gt;
&lt;li&gt;Synchronous, Asynchronous &amp;amp; Semi-Synchronous Replication&lt;/li&gt;
&lt;li&gt;Replication Lag &amp;amp; Monitoring&lt;/li&gt;
&lt;li&gt;Types of Replication in PostgreSQL&lt;/li&gt;
&lt;li&gt;PostgreSQL Replication Architecture&lt;/li&gt;
&lt;li&gt;Replication Components — Detailed Breakdown&lt;/li&gt;
&lt;li&gt;Checking PostgreSQL Activity and Storage&lt;/li&gt;
&lt;li&gt;Primary Server Configuration&lt;/li&gt;
&lt;li&gt;Replica Server Configuration&lt;/li&gt;
&lt;li&gt;Setting Up a Replica (Local &amp;amp; Remote)&lt;/li&gt;
&lt;li&gt;Verifying and Testing Replication&lt;/li&gt;
&lt;li&gt;Summary&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  What Is a Read Replica?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;read replica&lt;/strong&gt; is a live, continuously-updated copy of your primary PostgreSQL database that accepts &lt;strong&gt;read-only queries&lt;/strong&gt;. It is not a static backup — it stays in near real-time sync with the primary by receiving and replaying the stream of changes the primary produces.&lt;/p&gt;

&lt;p&gt;Any attempt to run &lt;code&gt;INSERT&lt;/code&gt;, &lt;code&gt;UPDATE&lt;/code&gt;, or &lt;code&gt;DELETE&lt;/code&gt; on a replica will fail with an error like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERROR: cannot execute INSERT in a read-only transaction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is by design. The replica exists purely to serve reads, while all writes continue to go through the primary.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Read Replicas Are Needed
&lt;/h2&gt;

&lt;p&gt;As an application grows, a single database instance becomes a bottleneck and a single point of failure. Read replicas solve several real problems at once:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Read/write separation&lt;/strong&gt; – offload &lt;code&gt;SELECT&lt;/code&gt;-heavy traffic away from the primary so writes aren't competing for resources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High availability &amp;amp; failover&lt;/strong&gt; – a replica can be promoted to primary if the original server goes down.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backup offloading&lt;/strong&gt; – run &lt;code&gt;pg_dump&lt;/code&gt; or backup jobs against a replica instead of hammering the primary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time reporting/analytics&lt;/strong&gt; – dashboards and BI tools can query a replica without impacting production traffic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Geographic distribution&lt;/strong&gt; – place replicas closer to users in different regions to reduce read latency.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Primary vs Replica: Key Differences
&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;Primary Server&lt;/th&gt;
&lt;th&gt;Replica Server&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Writes (&lt;code&gt;INSERT&lt;/code&gt;/&lt;code&gt;UPDATE&lt;/code&gt;/&lt;code&gt;DELETE&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Allowed&lt;/td&gt;
&lt;td&gt;Blocked (read-only)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reads (&lt;code&gt;SELECT&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Allowed&lt;/td&gt;
&lt;td&gt;Allowed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Generates WAL&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No — it receives WAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Role&lt;/td&gt;
&lt;td&gt;Source of truth&lt;/td&gt;
&lt;td&gt;Follower, replays changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pg_is_in_recovery()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Returns &lt;code&gt;false&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Returns &lt;code&gt;true&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Config flag&lt;/td&gt;
&lt;td&gt;Normal instance&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;hot_standby = on&lt;/code&gt;, has &lt;code&gt;standby.signal&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Can be promoted&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;Can be promoted to primary during failover&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  How Replication Works
&lt;/h2&gt;

&lt;p&gt;Every change made to a PostgreSQL database — an insert, update, delete, or schema change — is first written to the &lt;strong&gt;Write-Ahead Log (WAL)&lt;/strong&gt; before it's applied to the actual data files. This is a core durability mechanism in PostgreSQL, and replication piggybacks directly on it.&lt;/p&gt;

&lt;p&gt;In physical replication:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The primary writes every change as a WAL record.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;WAL sender process&lt;/strong&gt; on the primary streams these WAL records to the replica.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;WAL receiver process&lt;/strong&gt; on the replica receives the records and writes them to its own WAL.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;startup process&lt;/strong&gt; on the replica continuously replays the WAL, applying the same changes to its local data files.&lt;/li&gt;
&lt;li&gt;The replica's data converges to match the primary, typically within milliseconds to seconds.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because the replica is replaying the exact same WAL as the primary, it ends up as a faithful copy — including indexes, table structures, and data.&lt;/p&gt;




&lt;h2&gt;
  
  
  Replication Flow
&lt;/h2&gt;

&lt;p&gt;A simplified view of the data flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client Write Request
        |
        v
  Primary Server  --&amp;gt; WAL Generated --&amp;gt; WAL Sender Process
        |                                      |
        |                              (streams over network)
        |                                      v
        |                              WAL Receiver Process (Replica)
        |                                      |
        |                                      v
        |                              Replica WAL written locally
        |                                      |
        |                                      v
        |                         Startup Process replays WAL
        |                                      |
        |                                      v
        |                         Replica data files updated
        v
  Client Read Request ----------&amp;gt; Can be served by Primary OR Replica
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Synchronous, Asynchronous &amp;amp; Semi-Synchronous Replication
&lt;/h2&gt;

&lt;p&gt;PostgreSQL supports three modes that control &lt;strong&gt;how strictly the primary waits for a replica before confirming a write&lt;/strong&gt;:&lt;/p&gt;

&lt;h3&gt;
  
  
  Asynchronous Replication (default)
&lt;/h3&gt;

&lt;p&gt;The primary commits a transaction and returns success to the client immediately, without waiting for the replica to confirm it received or applied the WAL. This is fast, but there's a small risk: if the primary crashes right after commit, the very latest transactions might not have reached the replica yet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Synchronous Replication
&lt;/h3&gt;

&lt;p&gt;The primary waits for at least one designated &lt;strong&gt;synchronous standby&lt;/strong&gt; to confirm it has received (and optionally flushed) the WAL before acknowledging the commit to the client. This guarantees zero data loss for that transaction but adds latency, since every commit is gated on network round-trip time to the replica.&lt;/p&gt;

&lt;p&gt;Configured via:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;synchronous_standby_names&lt;/span&gt; = &lt;span class="s1"&gt;'replica1'&lt;/span&gt;
&lt;span class="n"&gt;synchronous_commit&lt;/span&gt; = &lt;span class="n"&gt;on&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Semi-Synchronous Replication
&lt;/h3&gt;

&lt;p&gt;A middle ground: the primary waits for confirmation that the WAL has been &lt;strong&gt;received&lt;/strong&gt; by at least one replica (not necessarily applied/flushed to disk), balancing durability and performance. PostgreSQL's &lt;code&gt;synchronous_commit&lt;/code&gt; parameter has several levels (&lt;code&gt;remote_write&lt;/code&gt;, &lt;code&gt;remote_apply&lt;/code&gt;, &lt;code&gt;on&lt;/code&gt;, &lt;code&gt;local&lt;/code&gt;, &lt;code&gt;off&lt;/code&gt;) that let you fine-tune exactly how much guarantee you want versus how much latency you're willing to accept.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Data Loss Risk&lt;/th&gt;
&lt;th&gt;Write Latency&lt;/th&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Asynchronous&lt;/td&gt;
&lt;td&gt;Small window possible&lt;/td&gt;
&lt;td&gt;Lowest&lt;/td&gt;
&lt;td&gt;Reporting replicas, general read scaling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Semi-synchronous&lt;/td&gt;
&lt;td&gt;Very low&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;Balanced HA setups&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Synchronous&lt;/td&gt;
&lt;td&gt;None (for that replica)&lt;/td&gt;
&lt;td&gt;Highest&lt;/td&gt;
&lt;td&gt;Financial/critical systems requiring zero data loss&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Replication Lag &amp;amp; Monitoring
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Replication lag&lt;/strong&gt; is the delay between a change happening on the primary and that same change being visible on the replica. Some lag is normal and expected in asynchronous replication — the goal is to keep it small and to catch it if it grows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check connected replicas (run on primary)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client_addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sync_state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;write_lag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flush_lag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;replay_lag&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_stat_replication&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Count active replicas
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;count&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="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_stat_replication&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Check replication lag in time (run on replica)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;pg_last_xact_replay_timestamp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;replication_lag&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Check replication slots
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;slot_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;slot_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;active&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_replication_slots&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Check WAL retained per slot
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;slot_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;pg_size_pretty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pg_wal_lsn_diff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pg_current_wal_lsn&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;restart_lsn&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;wal_retained&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_replication_slots&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Check WAL directory size
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;pg_size_pretty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;size&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_ls_waldir&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Check WAL receiver status (run on replica)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_stat_wal_receiver&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why monitoring matters:&lt;/strong&gt; if a replica falls too far behind and its replication slot retains too much WAL, the primary's disk can fill up. Persistent high lag is usually a sign of network issues, an underpowered replica, or heavy write volume outpacing the replica's replay speed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Types of Replication in PostgreSQL
&lt;/h2&gt;

&lt;p&gt;PostgreSQL supports a few distinct approaches, each suited to different needs:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Streaming replication&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Physical&lt;/td&gt;
&lt;td&gt;Real-time binary replication of the WAL. The replica is a byte-for-byte copy of the primary. Most common choice for standard read replicas — simple, reliable, keeps the whole database in sync automatically.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Logical replication&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Logical&lt;/td&gt;
&lt;td&gt;Table-level replication of data changes via logical decoding of WAL. Enables selective replication, cross-version replication, and CDC pipelines (Debezium, Kafka).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;WAL file shipping&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Physical&lt;/td&gt;
&lt;td&gt;Periodic shipping of completed WAL segments instead of continuous streaming — an older, higher-lag, file-based approach still seen in some legacy setups.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cascading replication&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Physical&lt;/td&gt;
&lt;td&gt;Replicas stream WAL to &lt;em&gt;other&lt;/em&gt; replicas instead of all pulling from the primary directly — reduces load on the primary when many replicas are needed.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  PostgreSQL Replication Architecture
&lt;/h2&gt;

&lt;p&gt;A typical production architecture looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 +--------------------+
                 |   Primary Server   |
                 |   (Read + Write)   |
                 +---------+----------+
                            | WAL Streaming
        +-------------------+-------------------+
        v                   v                   v
 +--------------+   +--------------+   +--------------+
 | Read Replica |   | Read Replica |   | Read Replica |
 |      1       |   |      2       |   |      3       |
 | (Read only)  |   | (Read only)  |   | (Read only)  |
 +--------------+   +--------------+   +--------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reads get distributed across replicas (often via a load balancer, connection pooler like PgBouncer, or application-level routing), while all writes are funneled to the single primary.&lt;/p&gt;




&lt;h2&gt;
  
  
  Replication Components — Detailed Description
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&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;&lt;strong&gt;WAL (Write-Ahead Log)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sequential log of every change made to the database, written before the change is applied to data files. Forms the basis of both crash recovery and replication.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;WAL Sender&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A process on the primary, spawned per connected replica, that reads WAL and streams it over the network.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;WAL Receiver&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A process on the replica that receives streamed WAL from the primary and writes it locally.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Startup Process (Replay)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;On the replica, continuously reads the locally-written WAL and applies (replays) the changes to data files.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Replication Slot&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A primary-side bookmark that ensures WAL isn't removed until the corresponding replica has consumed it — prevents replicas from falling irrecoverably behind, but can cause disk bloat if a replica disconnects for a long time.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;pg_stat_replication&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A system view on the primary showing real-time status of every connected replica (lag, state, sync mode).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;standby.signal&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A marker file in the replica's data directory indicating it should start in standby (replica) mode.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;hot_standby&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A setting that allows the replica to serve read-only queries while it's replaying WAL, instead of being completely inaccessible.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;pg_basebackup&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The utility used to take a full physical copy of the primary's data directory as the starting point for a new replica.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Replication User&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A dedicated PostgreSQL role with the &lt;code&gt;REPLICATION&lt;/code&gt; privilege used exclusively for streaming WAL — never for application queries.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Checking PostgreSQL Activity and Storage
&lt;/h2&gt;

&lt;p&gt;Before setting up replication, it's good practice to understand your primary's current load and size.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connections and active queries
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;count&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="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_stat_activity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;usename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;application_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;count&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="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_stat_activity&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;usename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;application_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;usename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_stat_activity&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'active'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;SHOW&lt;/span&gt; &lt;span class="n"&gt;max_connections&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;count&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="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_stat_activity&lt;/span&gt; &lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="k"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;datname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;count&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="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_stat_activity&lt;/span&gt; &lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;datname&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;usename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;count&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="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_stat_activity&lt;/span&gt; &lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;usename&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Database size
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;datname&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;database_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;pg_size_pretty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pg_database_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datname&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="k"&gt;size&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_database&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;pg_database_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Top 20 largest tables
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;schemaname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;relname&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="k"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;pg_size_pretty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pg_total_relation_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;relid&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;total_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;pg_size_pretty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pg_relation_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;relid&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;table_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;pg_size_pretty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pg_indexes_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;relid&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;index_size&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_catalog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pg_statio_user_tables&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;pg_total_relation_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;relid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Primary Server Configuration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Locate the configuration file
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ubuntu (PostgreSQL 14):&lt;/strong&gt; &lt;code&gt;/etc/postgresql/14/main/postgresql.conf&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mac (Homebrew, PostgreSQL 14):&lt;/strong&gt; &lt;code&gt;/opt/homebrew/var/postgresql@14/postgresql.conf&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ubuntu (PostgreSQL 15):&lt;/strong&gt; &lt;code&gt;/etc/postgresql/15/main/postgresql.conf&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Check current replication-related settings
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SHOW&lt;/span&gt; &lt;span class="n"&gt;wal_level&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SHOW&lt;/span&gt; &lt;span class="n"&gt;max_wal_senders&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SHOW&lt;/span&gt; &lt;span class="n"&gt;wal_keep_size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SHOW&lt;/span&gt; &lt;span class="n"&gt;max_replication_slots&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;setting&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_settings&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'%wal%'&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'%replication%'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Update &lt;code&gt;postgresql.conf&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;wal_level&lt;/span&gt; = &lt;span class="n"&gt;replica&lt;/span&gt;
&lt;span class="n"&gt;max_wal_senders&lt;/span&gt; = &lt;span class="m"&gt;10&lt;/span&gt;
&lt;span class="n"&gt;max_replication_slots&lt;/span&gt; = &lt;span class="m"&gt;10&lt;/span&gt;
&lt;span class="n"&gt;wal_keep_size&lt;/span&gt; = &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;GB&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;wal_level = replica&lt;/code&gt; enables enough WAL detail for streaming replication.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;max_wal_senders&lt;/code&gt; caps how many replicas can connect simultaneously.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;max_replication_slots&lt;/code&gt; caps how many replication slots can exist.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;wal_keep_size&lt;/code&gt; keeps a buffer of WAL on disk so a temporarily disconnected replica can catch up.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Configure &lt;code&gt;pg_hba.conf&lt;/code&gt; to allow replica connections
&lt;/h3&gt;

&lt;p&gt;Local testing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;host&lt;/span&gt;    &lt;span class="n"&gt;replication&lt;/span&gt;     &lt;span class="n"&gt;replicator&lt;/span&gt;      &lt;span class="m"&gt;127&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;1&lt;/span&gt;/&lt;span class="m"&gt;32&lt;/span&gt;            &lt;span class="n"&gt;md5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;host&lt;/span&gt;    &lt;span class="n"&gt;replication&lt;/span&gt;     &lt;span class="n"&gt;all&lt;/span&gt;             &lt;span class="m"&gt;127&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;1&lt;/span&gt;/&lt;span class="m"&gt;32&lt;/span&gt;            &lt;span class="n"&gt;scram&lt;/span&gt;-&lt;span class="n"&gt;sha&lt;/span&gt;-&lt;span class="m"&gt;256&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remote replica (example IP &lt;code&gt;192.168.1.50&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;host&lt;/span&gt;    &lt;span class="n"&gt;replication&lt;/span&gt;     &lt;span class="n"&gt;replicator&lt;/span&gt;      &lt;span class="m"&gt;192&lt;/span&gt;.&lt;span class="m"&gt;168&lt;/span&gt;.&lt;span class="m"&gt;1&lt;/span&gt;.&lt;span class="m"&gt;50&lt;/span&gt;/&lt;span class="m"&gt;32&lt;/span&gt;         &lt;span class="n"&gt;md5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Reload / restart PostgreSQL
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart postgresql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;pg_reload_conf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Create the replication user
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;rolname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rolreplication&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rolcanlogin&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_roles&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;ROLE&lt;/span&gt; &lt;span class="n"&gt;replicator&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;REPLICATION&lt;/span&gt; &lt;span class="n"&gt;LOGIN&lt;/span&gt; &lt;span class="n"&gt;PASSWORD&lt;/span&gt; &lt;span class="s1"&gt;'your_secure_password'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Permission&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;LOGIN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Can connect to the database&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;REPLICATION&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Can stream WAL files&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Replica Server Configuration
&lt;/h2&gt;

&lt;p&gt;Enable hot standby mode so the replica can serve read queries while replaying WAL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;hot_standby&lt;/span&gt; = &lt;span class="n"&gt;on&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also confirm a &lt;code&gt;standby.signal&lt;/code&gt; file exists in the replica's data directory — this is what tells PostgreSQL to start the instance as a standby rather than a primary. &lt;code&gt;pg_basebackup&lt;/code&gt; with the &lt;code&gt;-R&lt;/code&gt; flag creates this automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  Setting Up a Replica (Local &amp;amp; Remote)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Local Replica (Same Server)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create data directory&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; ~/pg_replica
&lt;span class="nb"&gt;chmod &lt;/span&gt;700 ~/pg_replica

&lt;span class="c"&gt;# Take a base backup from the primary&lt;/span&gt;
pg_basebackup &lt;span class="nt"&gt;-h&lt;/span&gt; 127.0.0.1 &lt;span class="nt"&gt;-D&lt;/span&gt; ~/pg_replica &lt;span class="nt"&gt;-U&lt;/span&gt; replicator &lt;span class="nt"&gt;-P&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt;

&lt;span class="c"&gt;# Change the replica's port to avoid conflicts&lt;/span&gt;
nano ~/pg_replica/postgresql.conf
port &lt;span class="o"&gt;=&lt;/span&gt; 5433
hot_standby &lt;span class="o"&gt;=&lt;/span&gt; on

&lt;span class="c"&gt;# Start the replica&lt;/span&gt;
pg_ctl &lt;span class="nt"&gt;-D&lt;/span&gt; ~/pg_replica start

&lt;span class="c"&gt;# Stop the replica&lt;/span&gt;
pg_ctl &lt;span class="nt"&gt;-D&lt;/span&gt; ~/pg_replica stop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Remote Replica (Different Server)
&lt;/h3&gt;

&lt;p&gt;Make sure the primary allows remote replication (&lt;code&gt;pg_hba.conf&lt;/code&gt; entry + firewall port 5432 open).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# On the replica server&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; ~/pg_replica
&lt;span class="nb"&gt;chmod &lt;/span&gt;700 ~/pg_replica

&lt;span class="c"&gt;# Base backup from the remote primary&lt;/span&gt;
pg_basebackup &lt;span class="nt"&gt;-h&lt;/span&gt; &amp;lt;PRIMARY_IP&amp;gt; &lt;span class="nt"&gt;-D&lt;/span&gt; ~/pg_replica &lt;span class="nt"&gt;-U&lt;/span&gt; replicator &lt;span class="nt"&gt;-P&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt;

&lt;span class="c"&gt;# Configure postgresql.conf&lt;/span&gt;
port &lt;span class="o"&gt;=&lt;/span&gt; 5432
hot_standby &lt;span class="o"&gt;=&lt;/span&gt; on

&lt;span class="c"&gt;# Start the replica&lt;/span&gt;
pg_ctl &lt;span class="nt"&gt;-D&lt;/span&gt; ~/pg_replica start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; If &lt;code&gt;pg_ctl: command not found&lt;/code&gt;, locate your PostgreSQL binaries with:&lt;/p&gt;


&lt;pre class="highlight shell"&gt;&lt;code&gt;which psql
&lt;span class="nb"&gt;sudo &lt;/span&gt;find / &lt;span class="nt"&gt;-name&lt;/span&gt; pg_ctl 2&amp;gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Typical path: &lt;code&gt;/usr/lib/postgresql/14/bin/pg_ctl&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Verifying and Testing Replication
&lt;/h2&gt;

&lt;h3&gt;
  
  
  On the primary — confirm the replica is connected
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_stat_replication&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  On the replica — confirm it's in recovery (standby) mode
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;pg_is_in_recovery&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;-- should return true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Test that writes are blocked on the replica
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;replication_test&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'test'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;-- ERROR: cannot execute INSERT in a read-only transaction&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Test that data actually replicates
&lt;/h3&gt;

&lt;p&gt;On primary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;test_table&lt;/span&gt; &lt;span class="k"&gt;VALUES&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="s1"&gt;'test'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On replica:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;test_table&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- The row should appear here almost immediately&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;read replica&lt;/strong&gt; is a live, read-only copy of your primary database kept in sync via WAL.&lt;/li&gt;
&lt;li&gt;Replication exists to &lt;strong&gt;scale reads, enable high availability, offload backups, and support real-time reporting&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;PostgreSQL supports &lt;strong&gt;physical (streaming)&lt;/strong&gt;, &lt;strong&gt;logical&lt;/strong&gt;, and &lt;strong&gt;WAL file-shipping&lt;/strong&gt; replication.&lt;/li&gt;
&lt;li&gt;Replication can run in &lt;strong&gt;asynchronous, synchronous, or semi-synchronous&lt;/strong&gt; modes, trading off latency against durability guarantees.&lt;/li&gt;
&lt;li&gt;Core components — &lt;strong&gt;WAL, WAL sender/receiver, replication slots, and the startup/replay process&lt;/strong&gt; — work together to keep replicas in sync.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;pg_stat_replication&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;pg_stat_wal_receiver&lt;/code&gt;&lt;/strong&gt;, and &lt;strong&gt;&lt;code&gt;pg_replication_slots&lt;/code&gt;&lt;/strong&gt; are your primary tools for monitoring health and lag.&lt;/li&gt;
&lt;li&gt;Setup is largely the same across PostgreSQL 14 and 15, on Ubuntu or macOS, for local or remote replicas: configure the primary (&lt;code&gt;wal_level&lt;/code&gt;, &lt;code&gt;max_wal_senders&lt;/code&gt;, &lt;code&gt;pg_hba.conf&lt;/code&gt;, replication role), configure the replica (&lt;code&gt;hot_standby&lt;/code&gt;, &lt;code&gt;standby.signal&lt;/code&gt;), take a base backup with &lt;code&gt;pg_basebackup -R&lt;/code&gt;, and verify with &lt;code&gt;pg_stat_replication&lt;/code&gt; / &lt;code&gt;pg_is_in_recovery()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Replication is foundational to running PostgreSQL reliably at scale — once you understand the WAL-driven mechanics behind it, the rest (sync modes, monitoring, failover) all falls into place naturally.&lt;/p&gt;




</description>
      <category>readreplica</category>
      <category>postgres</category>
      <category>database</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>40+ Best Chrome Extensions Every Developer Should Know in 2026</title>
      <dc:creator>Sai Praveen Sanapalli</dc:creator>
      <pubDate>Fri, 31 Jul 2026 15:58:53 +0000</pubDate>
      <link>https://dev.to/saipraveen446/40-best-chrome-extensions-every-developer-should-know-in-2026-59g</link>
      <guid>https://dev.to/saipraveen446/40-best-chrome-extensions-every-developer-should-know-in-2026-59g</guid>
      <description>&lt;p&gt;If you're a developer, your browser is basically your second IDE. The right set of Chrome extensions can save you hours every week — from debugging React state to picking the perfect hex code to testing APIs without leaving the tab.&lt;/p&gt;

&lt;p&gt;I put together this list of the extensions I rely on (and a few community favorites), organized by category, with a quick description of what each one actually does.&lt;/p&gt;




&lt;h2&gt;
  
  
  Frontend Development &amp;amp; UI Design
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Extension&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;&lt;strong&gt;React Developer Tools&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Inspect the React component tree, view props/state in real time, and profile render performance. A must-have for any React project.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Vue.js Devtools&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The Vue equivalent of React DevTools — inspect components, Vuex/Pinia state, events, and routing.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Angular DevTools&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Debug Angular apps by exploring the component tree, checking change detection, and profiling performance.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Redux DevTools&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Time-travel through Redux state changes, inspect dispatched actions, and debug your app's state management.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Wappalyzer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Instantly detect what technologies a website is built with — frameworks, CMS, analytics tools, hosting, and more.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;WhatFont&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Click any text on a page to instantly see its font family, size, weight, and color.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ColorZilla&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;An advanced color picker and eyedropper with gradient generator and CSS color analysis tools.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;VisBug&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;An open-source design tool that lets you edit any live webpage's layout, spacing, and typography directly in the browser.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dimensions&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Measure distances, padding, and margins on any webpage by hovering over elements.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SVG Gobbler&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Find, extract, and export every SVG, icon, and image on a page in one click.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CSS Viewer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;See the computed CSS styles of any element just by clicking on it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Eye Dropper&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A simple, fast color picker that grabs the exact hex/RGB value of any pixel on your screen.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Window Resizer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Quickly resize your browser window to test responsive designs at common device resolutions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Page Ruler&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Draw a ruler over any part of a webpage to measure exact pixel dimensions.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  API Development &amp;amp; Testing
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Extension&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;&lt;strong&gt;Postman Interceptor&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Captures browser requests (including cookies) and syncs them into Postman for accurate API testing.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Talend API Tester&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A lightweight tool for sending REST/SOAP requests and inspecting responses without leaving Chrome.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Requestly&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Intercept, modify, redirect, and mock HTTP requests — great for testing edge cases and API mocking.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RESTED&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A minimalist REST client for quickly firing off API requests and viewing formatted responses.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;WebSocket DevTools&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Monitor and debug WebSocket connections and messages in real time.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GraphQL Network Inspector&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Inspect GraphQL queries, mutations, and responses directly in your browser's dev tools panel.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Swagger Viewer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Render and preview OpenAPI/Swagger specs as interactive, readable documentation.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;JSON Formatter&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Automatically pretty-prints raw JSON responses in the browser, making them readable and collapsible.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fake Filler&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Auto-fills forms with realistic dummy data — handy for quickly testing form validation and flows.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mobile Simulator&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Emulate different mobile devices and screen sizes to test responsive and mobile-first designs.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Debugging &amp;amp; Performance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Extension&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;&lt;strong&gt;Lighthouse&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Google's built-in auditing tool for performance, accessibility, SEO, and best practices scoring.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Web Vitals&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Displays Core Web Vitals (LCP, FID/INP, CLS) for any page you visit, in real time.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reactime&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A time-travel debugger for React that visualizes state changes and component re-renders over time.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Screen Capture &amp;amp; Recording
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Extension&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;&lt;strong&gt;Screenity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A free, open-source screen recorder with annotation tools, webcam overlay, and no watermarks.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GoFullPage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Capture a full-page screenshot of any website in one click, including content below the fold.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Loom&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Record quick video walkthroughs of your screen and camera — great for bug reports and async updates.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🚀 Productivity &amp;amp; Workflow
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Extension&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;&lt;strong&gt;OneTab&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Convert all your open tabs into a single list to save memory and declutter your browser instantly.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Session Buddy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Save, organize, and restore groups of browser tabs and sessions whenever you need them.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Workona&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A tab and workspace manager that organizes tabs into projects for better focus.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Raindrop.io&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A powerful bookmark manager with tags, collections, and full-text search for saved links.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Todoist&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Manage your to-do lists and tasks directly from the browser toolbar.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Clockify&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Track time spent on tasks and projects right from your browser.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Momentum&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Replaces your new tab page with a personal dashboard featuring goals, to-dos, and inspiration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Grammarly&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AI-powered writing assistant that checks grammar, tone, and clarity as you type — including in code comments and docs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Muzli&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A curated feed of design inspiration, articles, and trends shown on your new tab page.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Octotree&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Adds a file-tree sidebar to GitHub repositories for easier code navigation.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Toby&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Organize and share collections of tabs across projects and teams.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Perplexity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;An AI-powered search assistant that gives sourced, conversational answers directly in your browser.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Monica AI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;An all-in-one AI copilot for chat, writing, summarization, and translation while browsing.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sider AI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A sidebar AI assistant that summarizes pages, chats with PDFs, and helps with writing across any site.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




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

&lt;p&gt;You don't need all 40+ of these installed at once — that'll just slow your browser down. Pick a handful from each category based on your actual stack and workflow.&lt;/p&gt;

&lt;p&gt;What extensions made your list that aren't here? Drop them in the comments 👇&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>chrome</category>
      <category>productivity</category>
      <category>tools</category>
    </item>
    <item>
      <title>AWS Fundamentals to Services: A Beginner's Guide to Global Infrastructure and Core Services</title>
      <dc:creator>Sai Praveen Sanapalli</dc:creator>
      <pubDate>Thu, 30 Jul 2026 17:20:48 +0000</pubDate>
      <link>https://dev.to/saipraveen446/aws-fundamentals-to-services-a-beginners-guide-to-global-infrastructure-and-core-services-2h77</link>
      <guid>https://dev.to/saipraveen446/aws-fundamentals-to-services-a-beginners-guide-to-global-infrastructure-and-core-services-2h77</guid>
      <description>&lt;p&gt;If you're starting your cloud journey, AWS can feel overwhelming — &lt;strong&gt;200+ services&lt;/strong&gt;, cryptic acronyms, and a global footprint spanning dozens of regions. This guide breaks it down into three digestible parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;AWS Global Infrastructure — the foundation&lt;/li&gt;
&lt;li&gt;AWS Service Categories — the building blocks&lt;/li&gt;
&lt;li&gt;What beginners should learn first — and in what order&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's dive in.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. AWS Global Infrastructure — The Foundation
&lt;/h2&gt;

&lt;p&gt;Before touching a single service, it's worth understanding &lt;strong&gt;where&lt;/strong&gt; AWS actually runs. Everything sits on top of three core concepts: Regions, Availability Zones, and Edge Locations.&lt;/p&gt;

&lt;h3&gt;
  
  
  🌍 What is an AWS Region?
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;Region&lt;/strong&gt; is a physical geographic location where AWS operates multiple data centers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use cases:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Deploy applications closer to users for lower latency&lt;/li&gt;
&lt;li&gt;✅ Meet data residency and compliance requirements&lt;/li&gt;
&lt;li&gt;✅ Disaster recovery across regions&lt;/li&gt;
&lt;li&gt;✅ Global application deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🏢 What is an Availability Zone (AZ)?
&lt;/h3&gt;

&lt;p&gt;An &lt;strong&gt;Availability Zone&lt;/strong&gt; is one or more isolated data centers within a Region. Each AZ has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⚡ Independent Power&lt;/li&gt;
&lt;li&gt;❄️ Independent Cooling&lt;/li&gt;
&lt;li&gt;🔗 Independent Networking&lt;/li&gt;
&lt;li&gt;🔒 High-speed Private Links&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example — Mumbai Region (&lt;code&gt;ap-south-1&lt;/code&gt;):&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;AZ-A  &amp;lt;——&amp;gt;  AZ-B  &amp;lt;——&amp;gt;  AZ-C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use cases:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ High Availability&lt;/li&gt;
&lt;li&gt;✅ Fault Tolerance&lt;/li&gt;
&lt;li&gt;✅ Business Continuity&lt;/li&gt;
&lt;li&gt;✅ Production Workloads&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A common pattern: a &lt;strong&gt;Load Balancer&lt;/strong&gt; sits in front of EC2 instances spread across AZ-A and AZ-B.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 If one AZ fails, your application keeps running in another AZ.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  🌐 What are Edge Locations?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Edge Locations&lt;/strong&gt; are AWS Points of Presence used by CDN and networking services — mainly powering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Amazon CloudFront&lt;/li&gt;
&lt;li&gt;AWS Global Accelerator&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use cases:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Faster content delivery&lt;/li&gt;
&lt;li&gt;✅ Reduced latency&lt;/li&gt;
&lt;li&gt;✅ Global caching&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; A website hosted in the Mumbai Region is accessed by users from Hyderabad, Chennai, Singapore, and London. CloudFront caches content at the nearest edge location instead of fetching every request all the way back to Mumbai.&lt;/p&gt;

&lt;h3&gt;
  
  
  📊 AWS Global Infrastructure by the Numbers (2024)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Count&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🌐 Regions&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;39&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🏢 Availability Zones&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;123&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📡 Edge Locations &amp;amp; Points of Presence&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;700+&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  2. AWS Service Categories &amp;amp; Main Services
&lt;/h2&gt;

&lt;p&gt;AWS has 200+ services, but they cluster into a manageable set of categories. Here's the map:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Key Services&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🖥️ &lt;strong&gt;Compute&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;EC2, Lambda, ECS, EKS, Fargate, Elastic Beanstalk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;💾 &lt;strong&gt;Storage&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;S3, EBS, EFS, FSx, AWS Backup&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;RDS, Aurora, DynamoDB, ElastiCache, Redshift&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🌐 &lt;strong&gt;Networking &amp;amp; CDN&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;VPC, Route 53, ELB, CloudFront, Transit Gateway&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔐 &lt;strong&gt;Security &amp;amp; Identity&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;IAM, KMS, Secrets Manager, WAF, Shield, GuardDuty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📩 &lt;strong&gt;Notifications &amp;amp; Messaging&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;SES, SNS, SQS, EventBridge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📈 &lt;strong&gt;Monitoring &amp;amp; Observability&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;CloudWatch, CloudTrail, AWS Config, X-Ray&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⚙️ &lt;strong&gt;Automation &amp;amp; Serverless&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Lambda, Systems Manager, Step Functions, EventBridge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔁 &lt;strong&gt;DevOps &amp;amp; CI/CD&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;CodeCommit, CodeBuild, CodeDeploy, CodePipeline, CloudFormation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🧠 &lt;strong&gt;AI / ML &amp;amp; Generative AI&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;SageMaker, Bedrock, Rekognition, Textract, Comprehend&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📊 &lt;strong&gt;Analytics &amp;amp; Big Data&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Athena, Glue, EMR, Kinesis, QuickSight&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;☁️ &lt;strong&gt;Migration &amp;amp; Hybrid Cloud&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;DMS, Application Migration Service (MGN), DataSync, Storage Gateway&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🏛️ &lt;strong&gt;Management &amp;amp; Governance&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Organizations, Control Tower, Trusted Advisor, Service Catalog&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔍 &lt;strong&gt;Search &amp;amp; Integration&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;OpenSearch Service, API Gateway, AppSync&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🛡️ &lt;strong&gt;Disaster Recovery &amp;amp; Backup&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;AWS Backup, Elastic Disaster Recovery (DRS), S3 Glacier&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Yes, this list can feel like alphabet soup at first — but notice how each category maps to a real-world engineering need: run code, store data, secure access, monitor systems, automate ops, and so on.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. AWS Services Every Beginner Should Learn First
&lt;/h2&gt;

&lt;p&gt;Instead of trying to learn everything at once, focus on this core set:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🔒 &lt;strong&gt;IAM&lt;/strong&gt; – Identity &amp;amp; Access Management&lt;/li&gt;
&lt;li&gt;🖥️ &lt;strong&gt;EC2&lt;/strong&gt; – Virtual Servers&lt;/li&gt;
&lt;li&gt;🪣 &lt;strong&gt;S3&lt;/strong&gt; – Object Storage&lt;/li&gt;
&lt;li&gt;🌐 &lt;strong&gt;VPC&lt;/strong&gt; – Networking Foundation&lt;/li&gt;
&lt;li&gt;🗄️ &lt;strong&gt;RDS&lt;/strong&gt; – Managed Databases&lt;/li&gt;
&lt;li&gt;⚖️ &lt;strong&gt;Elastic Load Balancer&lt;/strong&gt; – Traffic Distribution&lt;/li&gt;
&lt;li&gt;🌍 &lt;strong&gt;Route 53&lt;/strong&gt; – DNS &amp;amp; Domain Management&lt;/li&gt;
&lt;li&gt;📈 &lt;strong&gt;CloudWatch&lt;/strong&gt; – Monitoring &amp;amp; Alerts&lt;/li&gt;
&lt;li&gt;📧 &lt;strong&gt;SES&lt;/strong&gt; – Email Service&lt;/li&gt;
&lt;li&gt;⚡ &lt;strong&gt;Lambda&lt;/strong&gt; – Serverless Computing&lt;/li&gt;
&lt;li&gt;🌐 &lt;strong&gt;CloudFront&lt;/strong&gt; – Content Delivery Network&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🗺️ Recommended Learning Path
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Regions &amp;amp; AZs → IAM → EC2 → S3 → VPC → RDS → ELB → Route 53 → CloudWatch → SES → Lambda → CloudFront
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This order isn't arbitrary — it mirrors how a real application gets built: understand &lt;em&gt;where&lt;/em&gt; things run, secure access, stand up compute, add storage, network it together, attach a database, load-balance and route traffic, monitor it, and finally add serverless + CDN for scale.&lt;/p&gt;




&lt;h2&gt;
  
  
  💡 Key Takeaway
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Understanding &lt;strong&gt;Regions&lt;/strong&gt; and &lt;strong&gt;Availability Zones&lt;/strong&gt; first helps you design applications that are highly available, scalable, secure, and cost-effective on AWS.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Whether you're a System Administrator, DevOps Engineer, Cloud Engineer, or Solutions Architect, mastering these fundamentals will help you understand &lt;strong&gt;80–90% of real-world AWS deployments&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  ⭐ Final Thought
&lt;/h3&gt;

&lt;p&gt;Learn the foundation. Build with confidence. Scale without limits. That's the power of AWS!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
      <category>devops</category>
      <category>cloudcomputing</category>
    </item>
    <item>
      <title>Getting Started with Frappe Framework: From Basics to Architecture &amp; Internals</title>
      <dc:creator>Sai Praveen Sanapalli</dc:creator>
      <pubDate>Thu, 30 Jul 2026 15:39:30 +0000</pubDate>
      <link>https://dev.to/saipraveen446/getting-started-with-frappe-framework-from-basics-to-architecture-internals-ph0</link>
      <guid>https://dev.to/saipraveen446/getting-started-with-frappe-framework-from-basics-to-architecture-internals-ph0</guid>
      <description>&lt;p&gt;If you've ever wondered how ERPNext, HRMS, Helpdesk, and dozens of other production-grade business apps got built so fast — the answer is &lt;strong&gt;Frappe&lt;/strong&gt;. It's a metadata-driven, low-code &lt;em&gt;and&lt;/em&gt; full-code Python framework that handles the boring-but-critical 80% (auth, permissions, forms, REST APIs, workflows, reports) so you can focus on actual business logic.&lt;/p&gt;

&lt;p&gt;While learning Frappe, and turned them into this single guide. It's split into three parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Core Concepts&lt;/strong&gt; — what Frappe is, how to set it up, and how apps/sites are structured&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Development Essentials&lt;/strong&gt; — the day-to-day toolkit: controllers, hooks, ORM, scripts, reports, APIs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Framework Internals&lt;/strong&gt; — what actually happens under the hood, from request to response&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's dive in.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 1: Core Concepts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is Frappe?
&lt;/h3&gt;

&lt;p&gt;Frappe is an open-source, metadata-driven, low-code/full-code Python framework for building modern business applications. It bundles database management, forms, auth, role-based permissions, workflows, automation, reports, and REST APIs out of the box — so you're not reinventing the wheel for every project.&lt;/p&gt;

&lt;p&gt;It's the engine behind ERP, CRM, HRMS, Helpdesk, Manufacturing, Healthcare, Education, and many other custom business solutions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Before you install Bench (Frappe's CLI), make sure you have:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Requirement&lt;/th&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OS&lt;/td&gt;
&lt;td&gt;Ubuntu 22.04 LTS+ / macOS / Linux&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;3.11+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node.js&lt;/td&gt;
&lt;td&gt;20+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Yarn&lt;/td&gt;
&lt;td&gt;1.22.x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;PostgreSQL 14+ / MariaDB 10.6+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Redis&lt;/td&gt;
&lt;td&gt;6+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Git&lt;/td&gt;
&lt;td&gt;latest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;wkhtmltopdf&lt;/td&gt;
&lt;td&gt;for PDF generation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bench CLI&lt;/td&gt;
&lt;td&gt;official CLI tool&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Installing Bench
&lt;/h3&gt;

&lt;p&gt;Bench is the official CLI tool used to set up and manage Frappe instances (technically called &lt;em&gt;benches&lt;/em&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip3 &lt;span class="nb"&gt;install &lt;/span&gt;frappe-bench
bench init my-bench
&lt;span class="nb"&gt;cd &lt;/span&gt;my-bench
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Bench Directory Structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-bench/
├── apps/            # Installed apps
├── sites/           # Sites (databases)
├── config/          # Config files
├── logs/            # Logs
├── sites/assets/     # Public assets
└── Procfile          # Process configuration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating an App
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bench new-app my_app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This scaffolds a full app structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my_app/
├── my_app/
│   ├── doctype/      # Custom DocTypes
│   ├── report/       # Report scripts
│   ├── page/         # Custom pages
│   ├── api/          # API endpoints
│   ├── utils/        # Utility functions
│   ├── www/          # Public web assets (CSS, JS, images)
│   ├── hooks.py       # App hooks &amp;amp; overrides
│   ├── patches.txt    # Patches for migrations
│   └── modules.txt    # List of modules in the app
├── tests/             # Unit &amp;amp; integration tests
├── README.md
├── requirements.txt
└── setup.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating a Site
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bench new-site site.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every site gets its own isolated structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sites/site.local/
├── site_config.json   # DB, email, redis config
├── public/             # Public files (assets, uploads)
├── private/            # Private files (backups, keys)
└── logs/               # Site-specific logs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key idea: &lt;strong&gt;each site has its own database, configuration, and files&lt;/strong&gt; — this is what enables Frappe's multi-tenancy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing an App into a Site
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bench &lt;span class="nt"&gt;--site&lt;/span&gt; site.local install-app my_app
bench &lt;span class="nt"&gt;--site&lt;/span&gt; site.local migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This installs the app in the site and creates the necessary tables, assets, roles, and permissions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Modules &amp;amp; DocTypes
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;module&lt;/strong&gt; groups related functionality within an app (e.g., Accounts, HR, Selling, Buying).&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;DocType&lt;/strong&gt; is the fundamental building block of Frappe — it defines the structure and behavior of data, and is rendered automatically into forms, lists, and reports.&lt;/p&gt;

&lt;p&gt;Types of DocTypes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Regular DocType&lt;/strong&gt; — a standard doctype with its own database table&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single&lt;/strong&gt; — a doctype with only one record (e.g., global settings)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Child Table&lt;/strong&gt; — a table nested inside a parent DocType&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Submittable DocType&lt;/strong&gt; — supports workflow states (submit/cancel)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Virtual DocType&lt;/strong&gt; — not stored in the DB; used for calculated/reporting data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom DocType&lt;/strong&gt; — created by developers for custom requirements&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Common Bench Commands
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bench start&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start all services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bench stop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stop all services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bench restart&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Restart all services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bench new-site &amp;lt;site&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a new site&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bench get-app &amp;lt;app&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Download an app&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bench install-app &amp;lt;app&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Install app in a site&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bench migrate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run database migrations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bench update&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Update apps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bench --site &amp;lt;site&amp;gt; console&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Open the site console&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bench --site &amp;lt;site&amp;gt; backup&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Backup a site&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bench list-apps&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List installed apps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bench list-sites&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List all sites&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Notable Frappe Features
&lt;/h3&gt;

&lt;p&gt;Authentication (Login, OAuth, LDAP, 2FA, Social Login), granular role-based permissions, dynamic form &amp;amp; list views, a REST API out of the box, workflow &amp;amp; automation engine, integrated Email/SMS/WhatsApp, background jobs &amp;amp; scheduler, built-in reports &amp;amp; dashboards, secure file management, multi-tenancy, and full extensibility — all under the MIT license.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 2: Development Essentials
&lt;/h2&gt;

&lt;p&gt;Once your app and site are set up, here's the toolkit you'll actually use day-to-day.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Controllers &amp;amp; Methods
&lt;/h3&gt;

&lt;p&gt;DocTypes ship with a Python controller class where you hook into the document lifecycle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;before_insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;before_save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;before_submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;on_update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;on_submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;on_cancel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;after_insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;on_trash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These give you precise control over what happens at every stage of a document's life.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Users, Roles &amp;amp; Permissions
&lt;/h3&gt;

&lt;p&gt;Frappe's permission system is deep: &lt;br&gt;
Users &amp;amp; Roles,&lt;br&gt;
Role Permission Manager, &lt;br&gt;
Permission Levels (0–3), &lt;br&gt;
User Permissions, &lt;br&gt;
Document Permissions, &lt;br&gt;
Permission Query Conditions, &lt;br&gt;
Field-Level Permissions, &lt;br&gt;
Share &amp;amp; Assign, &lt;br&gt;
conditional (if-based) rules,&lt;br&gt;
User/Role Profiles.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Hooks
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;hooks.py&lt;/code&gt; is where an app declares itself to the framework. Key hooks include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;doc_events&lt;/code&gt; → document event handlers&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;scheduler_events&lt;/code&gt; → background scheduled jobs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;override_whitelisted_methods&lt;/code&gt; → override REST API methods&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;override_doctype_class&lt;/code&gt; → replace a DocType's controller&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;doctype_js&lt;/code&gt; → customize form behavior&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;app_include_js/css&lt;/code&gt; &amp;amp; &lt;code&gt;web_include_js/css&lt;/code&gt; → load Desk/Website assets&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;jinja&lt;/code&gt; → custom template methods&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fixtures&lt;/code&gt; → export app customizations&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;permission_query_conditions&lt;/code&gt; → custom list permissions&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;on_login&lt;/code&gt; / &lt;code&gt;on_logout&lt;/code&gt; → authentication hooks&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  4. Database, ORM &amp;amp; Query
&lt;/h3&gt;

&lt;p&gt;Frappe gives you multiple layers to work with data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frappe ORM (&lt;code&gt;frappe.db&lt;/code&gt;, &lt;code&gt;get_doc&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Query Builder (&lt;code&gt;frappe.qb&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Raw SQL when you need it&lt;/li&gt;
&lt;li&gt;Database transactions (commit/rollback)&lt;/li&gt;
&lt;li&gt;Indexes &amp;amp; performance tuning&lt;/li&gt;
&lt;li&gt;Full-text search&lt;/li&gt;
&lt;li&gt;Support for both MariaDB and PostgreSQL&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  5. Scripts
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Client Script (JS)&lt;/strong&gt; — form events, field validation, UI customization, API calls&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server Script (Python)&lt;/strong&gt; — business logic, scheduled tasks, event-based logic&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;System Console&lt;/strong&gt; — execute Python/JS, debug &amp;amp; test, developer tools&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  6. Reports
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Query Report&lt;/strong&gt; — drag-and-drop fields, filters, groups, aggregations, charts &amp;amp; pivot&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Script Report&lt;/strong&gt; — custom Python logic with dynamic data&lt;/li&gt;
&lt;li&gt;Reports support charts, pivots, indicators, export (Excel/CSV/PDF), scheduling &amp;amp; sharing&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  7. Print Formats
&lt;/h3&gt;

&lt;p&gt;Build documents using Jinja templates — supports HTML/PDF output, dynamic data, company letterheads, custom styles, and watermarks/signatures.&lt;/p&gt;
&lt;h3&gt;
  
  
  8. Jinja Templates
&lt;/h3&gt;

&lt;p&gt;Jinja is the templating engine at the heart of Frappe's UI — used in Print Formats, Email Templates, Web Pages, and List/Form Views. Supports variables, filters, control statements, inheritance, and macros/includes.&lt;/p&gt;
&lt;h3&gt;
  
  
  9. REST APIs &amp;amp; Webhooks
&lt;/h3&gt;

&lt;p&gt;Every DocType gets REST endpoints automatically — list, get, create, update, delete, with filtering, pagination, and field selection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /api/resource/Customer?fields=["name","email"]&amp;amp;filters=["disabled",0]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Webhooks let you fire real-time notifications on document events, triggered securely and reliably.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. Document APIs &amp;amp; Methods
&lt;/h3&gt;

&lt;p&gt;Common patterns you'll use constantly in server scripts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;frappe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new_doc&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="n"&gt;frappe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_doc&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="n"&gt;frappe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_list&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="n"&gt;frappe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_all&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="n"&gt;frappe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_cached_doc&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="n"&gt;frappe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="n"&gt;frappe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete_doc&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;

&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reload&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;db_set&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  11. Desk
&lt;/h3&gt;

&lt;p&gt;The modern workspace for your team: role-based desk, custom workspaces, modules, shortcuts, notifications, to-do/kanban/calendar views, real-time updates, search &amp;amp; filters, and custom fields/views.&lt;/p&gt;

&lt;h3&gt;
  
  
  12. Workflows
&lt;/h3&gt;

&lt;p&gt;Automate business processes with workflow states, transitions, state-based permissions, transition conditions, approve/reject actions, email/notification triggers, multi-level approvals, and role-based access.&lt;/p&gt;

&lt;h3&gt;
  
  
  13. Profiling, Monitoring &amp;amp; Logging
&lt;/h3&gt;

&lt;p&gt;Built-in profiler, &lt;br&gt;
request profiling, &lt;br&gt;
error logs, &lt;br&gt;
background job logs, &lt;br&gt;
scheduler logs, &lt;br&gt;
slow query analysis, &lt;br&gt;
performance monitoring, &lt;br&gt;
site health monitoring — essential for debugging in production.&lt;/p&gt;
&lt;h3&gt;
  
  
  14. Social Logins &amp;amp; OAuth
&lt;/h3&gt;

&lt;p&gt;Out of the box: Google Login, GitHub Login, LDAP Authentication, OAuth 2.0 Providers, SAML Authentication, OpenID Connect (OIDC), and custom OAuth providers.&lt;/p&gt;
&lt;h3&gt;
  
  
  15. Fixtures
&lt;/h3&gt;

&lt;p&gt;Fixtures allow you to export customizations from one site and ship them with your application.&lt;br&gt;
Custom Fields&lt;br&gt;
Property Setters&lt;br&gt;
Client Scripts&lt;br&gt;
Server Scripts&lt;br&gt;
Print Formats&lt;br&gt;
Workspaces&lt;br&gt;
Reports&lt;br&gt;
Roles&lt;br&gt;
Notification Templates&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;fixtures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Custom Field&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Property Setter&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Client Script&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Export fixtures:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bench export-fixtures
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt; &lt;br&gt;
these fourteen building blocks are what let teams ship scalable, secure business applications &lt;em&gt;faster&lt;/em&gt; — with real-time integrations, automation, and enterprise-grade security baked in.&lt;/p&gt;


&lt;h2&gt;
  
  
  Part 3: Framework Internals — What Happens Under the Hood
&lt;/h2&gt;

&lt;p&gt;This is the part that made Frappe click for me — understanding the actual architecture behind the abstractions.&lt;/p&gt;
&lt;h3&gt;
  
  
  Request Lifecycle
&lt;/h3&gt;

&lt;p&gt;Every request flows through a clear, layered pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser
   ↓
Nginx
   ↓
Gunicorn
   ↓
Frappe Framework
   ↓
Authentication
   ↓
Permission Check
   ↓
Controller (Python)
   ↓
Business Logic
   ↓
ORM / Query Builder
   ↓
PostgreSQL / MariaDB
   ↓
Response (JSON / HTML)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Browser&lt;/strong&gt; — user makes a request&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nginx&lt;/strong&gt; — handles static files, SSL, and reverse proxying&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gunicorn&lt;/strong&gt; — WSGI server that receives the request&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frappe Framework&lt;/strong&gt; — routes the request to the application&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication&lt;/strong&gt; — user is authenticated (session/token/OAuth)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permission Check&lt;/strong&gt; — permissions are validated&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Controller (Python)&lt;/strong&gt; — request is handled by the appropriate controller&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Business Logic&lt;/strong&gt; — application logic is executed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ORM / Query Builder&lt;/strong&gt; — database operations (ORM or Query Builder)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PostgreSQL / MariaDB&lt;/strong&gt; — data is read from or written to the database&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Response (JSON / HTML)&lt;/strong&gt; — response is sent back to the browser&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Redis (In-Memory Store)
&lt;/h3&gt;

&lt;p&gt;Redis is the central storage for queues, cache, sessions, locks, and realtime events. It handles: cache, session storage, the Redis Queue (RQ), pub/sub for realtime events, job metadata, distributed locks, rate limiting, and background job status.&lt;/p&gt;

&lt;h3&gt;
  
  
  Background Jobs (RQ)
&lt;/h3&gt;

&lt;p&gt;RQ (Redis Queue) manages asynchronous tasks so users don't wait around for long-running operations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;frappe.enqueue(...)
   ↓
RQ Creates Job
   ↓
Redis Queue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Typical background jobs: email, SMS, WhatsApp, notifications, report generation, PDF generation, import/export, webhook calls, API sync, and scheduler jobs. &lt;strong&gt;Jobs are stored in Redis, and workers fetch and execute them.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Workers
&lt;/h3&gt;

&lt;p&gt;Workers are long-running Python processes that monitor Redis queues, fetch jobs, and execute them asynchronously. There are three tiers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Queue&lt;/th&gt;
&lt;th&gt;Worker&lt;/th&gt;
&lt;th&gt;Examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Short Queue&lt;/td&gt;
&lt;td&gt;Worker (Short)&lt;/td&gt;
&lt;td&gt;Notifications, email, SMS, small updates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Default Queue&lt;/td&gt;
&lt;td&gt;Worker (Default)&lt;/td&gt;
&lt;td&gt;Business logic, API calls, data processing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Long Queue&lt;/td&gt;
&lt;td&gt;Worker (Long)&lt;/td&gt;
&lt;td&gt;Reports, imports, exports, PDF, AI jobs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Important: &lt;strong&gt;without running workers, queued jobs remain in Redis and are never executed.&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;The scheduler checks scheduled events defined in &lt;code&gt;hooks.py&lt;/code&gt;, creates background jobs, and places them into Redis queues:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hooks.py (scheduler_events)
   ↓
Scheduler Process (bench schedule)
   ↓
Checks Schedule
   ↓
Calls frappe.enqueue()
   ↓
Redis Queue (RQ)
   ↓
Worker
   ↓
Execute Task
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Schedule types supported: Hourly, Daily, Weekly, Monthly, and Cron (custom).&lt;/p&gt;

&lt;p&gt;Crucially: &lt;strong&gt;the scheduler never executes jobs itself — it only enqueues them.&lt;/strong&gt; Actual execution is always the worker's job.&lt;/p&gt;

&lt;h3&gt;
  
  
  Realtime (Socket.IO)
&lt;/h3&gt;

&lt;p&gt;Realtime communication between server and clients — live notifications, progress bars, desk updates, and chat/collaboration — all powered by Socket.IO and Redis Pub/Sub.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authentication &amp;amp; Session
&lt;/h3&gt;

&lt;p&gt;Handles user authentication and session management: session management, API keys, token authentication (REST API), OAuth/social login, and role-based access — supporting multiple authentication methods.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cache
&lt;/h3&gt;

&lt;p&gt;Caching improves performance and reduces database load, via Redis cache, metadata cache, session cache, and document cache — for frequently accessed data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Monitoring &amp;amp; Logging
&lt;/h3&gt;

&lt;p&gt;Tools to monitor performance, errors, and system health: Error Log DocType, system logs (bench logs), slow query logs, background job logs, scheduler logs, &lt;code&gt;bench doctor&lt;/code&gt; (health check), and the built-in profiler.&lt;/p&gt;

&lt;h3&gt;
  
  
  Database Layer
&lt;/h3&gt;

&lt;p&gt;Handles all database operations and provides an abstraction over SQL: PostgreSQL/MariaDB support, Frappe ORM, Query Builder, transactions (commit/rollback), row-level locking, indexes &amp;amp; performance, and migrations (&lt;code&gt;bench migrate&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Frappe Queue Management Architecture — Two Flows
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;A. User-Triggered Flow&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;User Click / Action (Generate Report, Send Email, etc.)
   ↓
frappe.enqueue() — Add job to queue
   ↓
Redis Queue (RQ) — Job stored in Redis
   ↓
Routed to Short / Default / Long Queue
   ↓
Worker executes the background job
   ↓
Database updated / Notification sent
   ↓
Job Completed (result stored or sent back)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;B. Scheduled Layer&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;Time Reached (as per schedule)
   ↓
Scheduler Process (bench schedule) checks hooks.py Schedule Events
   ↓
Calls frappe.enqueue() — creates background job
   ↓
Redis Queue (RQ)
   ↓
Worker
   ↓
Execute Scheduled Task
   ↓
Job Completed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example scheduled events: hourly tasks, daily reports, weekly cleanups, monthly jobs, custom cron jobs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common Bench Commands (Internals-Focused)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&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;&lt;code&gt;bench start&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start all services (web, worker, scheduler, etc.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bench stop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stop all services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bench restart&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Restart all services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bench status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check status of all services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bench worker&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start worker for default queue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bench worker --queue short&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start worker for short queue (fast tasks)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bench worker --queue long&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start worker for long queue (heavy tasks)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bench schedule&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start scheduler process&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bench migrate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run database migrations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bench doctor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check bench health and system status&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bench show-pending-jobs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show pending jobs in all queues&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bench purge-jobs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Purge completed/failed jobs from queues&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bench backup&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a backup of the site&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bench console&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Open Frappe console&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Official Resources
&lt;/h2&gt;

&lt;p&gt;Frappe Official Website: &lt;a href="https://frappe.io/" rel="noopener noreferrer"&gt;https://frappe.io/&lt;/a&gt;&lt;br&gt;
Frappe Framework Documentation: &lt;a href="https://docs.frappe.io/framework" rel="noopener noreferrer"&gt;https://docs.frappe.io/framework&lt;/a&gt;&lt;br&gt;
ERPNext Documentation: &lt;a href="https://docs.erpnext.com" rel="noopener noreferrer"&gt;https://docs.erpnext.com&lt;/a&gt;&lt;br&gt;
Frappe GitHub Repository: &lt;a href="https://github.com/frappe/frappe" rel="noopener noreferrer"&gt;https://github.com/frappe/frappe&lt;/a&gt;&lt;br&gt;
ERPNext GitHub Repository: &lt;a href="https://github.com/frappe/erpnext" rel="noopener noreferrer"&gt;https://github.com/frappe/erpnext&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Frappe's real power isn't any single feature — it's how metadata (DocTypes), events (hooks), and infrastructure (Redis, RQ, workers, scheduler) compose together into a cohesive system. Once you understand the request lifecycle and the queue architecture, the rest of the framework — controllers, permissions, workflows, reports — starts to feel like straightforward configuration on top of a solid foundation.&lt;/p&gt;

&lt;p&gt;If you're building your first Frappe app, my suggestion: &lt;br&gt;
start with &lt;code&gt;bench new-app&lt;/code&gt;, &lt;br&gt;
get a simple DocType working end-to-end (form → hook → API), &lt;br&gt;
go read about workers and the scheduler. &lt;br&gt;
The internals will make a lot more sense once you've felt the "front door" of the framework first.&lt;/p&gt;

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

&lt;p&gt;&lt;em&gt;If this was useful, drop a comment with what you're building on Frappe — always curious to see what people ship with it.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>erpnext</category>
      <category>frappe</category>
      <category>frappeframework</category>
    </item>
    <item>
      <title>Complete WhatsApp Cloud API Setup Guide (2026) – From Facebook Account to Production Integration</title>
      <dc:creator>Sai Praveen Sanapalli</dc:creator>
      <pubDate>Mon, 22 Jun 2026 20:08:44 +0000</pubDate>
      <link>https://dev.to/saipraveen446/complete-whatsapp-cloud-api-setup-guide-2026-from-facebook-account-to-production-integration-3ff0</link>
      <guid>https://dev.to/saipraveen446/complete-whatsapp-cloud-api-setup-guide-2026-from-facebook-account-to-production-integration-3ff0</guid>
      <description>&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%2F8fofglo0apn1m7uoh4n1.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%2F8fofglo0apn1m7uoh4n1.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
WhatsApp has become one of the most important communication channels for businesses worldwide. With Meta's WhatsApp Cloud API, developers can integrate WhatsApp messaging directly into their applications without managing their own WhatsApp infrastructure.&lt;/p&gt;

&lt;p&gt;However, many developers find the initial setup confusing because multiple Meta components are involved:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Facebook Account&lt;/li&gt;
&lt;li&gt;Facebook Page&lt;/li&gt;
&lt;li&gt;Meta Business Portfolio&lt;/li&gt;
&lt;li&gt;Meta Developer Account&lt;/li&gt;
&lt;li&gt;Meta App&lt;/li&gt;
&lt;li&gt;WhatsApp Business Account (WABA)&lt;/li&gt;
&lt;li&gt;System User&lt;/li&gt;
&lt;li&gt;Access Tokens&lt;/li&gt;
&lt;li&gt;Webhooks&lt;/li&gt;
&lt;li&gt;Message Templates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This guide walks through the complete end-to-end setup process, from creating the required Meta assets to sending production WhatsApp messages through the Cloud API.&lt;/p&gt;


&lt;h1&gt;
  
  
  What You Will Build
&lt;/h1&gt;

&lt;p&gt;By the end of this guide, you will have:&lt;/p&gt;

&lt;p&gt;✅ Verified Meta Business Portfolio&lt;/p&gt;

&lt;p&gt;✅ Meta Developer Account&lt;/p&gt;

&lt;p&gt;✅ Meta App with WhatsApp Product&lt;/p&gt;

&lt;p&gt;✅ WhatsApp Business Account (WABA)&lt;/p&gt;

&lt;p&gt;✅ Verified Production Phone Number&lt;/p&gt;

&lt;p&gt;✅ Permanent Access Token&lt;/p&gt;

&lt;p&gt;✅ Webhook Configuration&lt;/p&gt;

&lt;p&gt;✅ Approved Message Templates&lt;/p&gt;

&lt;p&gt;✅ Production-Ready WhatsApp Cloud API Integration&lt;/p&gt;


&lt;h1&gt;
  
  
  WhatsApp Cloud API Architecture
&lt;/h1&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Facebook Account
        │
        ▼
Facebook Page
        │
        ▼
Meta Business Portfolio
        │
        ▼
Meta App 
        │
        ▼
WhatsApp Business Account (WABA)
        │
        ▼
Phone Number
        │
        ▼
Cloud API
        │
        ▼
Your Application
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  1: Prerequisites
&lt;/h1&gt;

&lt;p&gt;Before starting, ensure the following are available:&lt;/p&gt;
&lt;h2&gt;
  
  
  Required
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Personal Facebook Account&lt;/li&gt;
&lt;li&gt;Facebook Page&lt;/li&gt;
&lt;li&gt;Business Name&lt;/li&gt;
&lt;li&gt;Business Email Address&lt;/li&gt;
&lt;li&gt;Business Website&lt;/li&gt;
&lt;li&gt;Business Verification Documents (GST Certificate, Certificate of Incorporation, Udyam/MSME Certificate, Business PAN, or other valid business proof)&lt;/li&gt;
&lt;li&gt;Mobile Number for WhatsApp (preferably a new number, should not be banned/restricted, and ideally not used with unofficial WhatsApp tools)&lt;/li&gt;
&lt;li&gt;Debit/Credit Card (for billing setup)&lt;/li&gt;
&lt;li&gt;Domain Name and HTTPS-enabled Public Server (for webhook configuration)&lt;/li&gt;
&lt;/ul&gt;


&lt;h1&gt;
  
  
  2. Facebook Account Creation and Facebook Page Linking
&lt;/h1&gt;

&lt;p&gt;Before setting up a Meta Business Portfolio or WhatsApp Business Platform, you must have:&lt;/p&gt;
&lt;h2&gt;
  
  
  Facebook Personal Account
&lt;/h2&gt;

&lt;p&gt;A Facebook Personal Account is the standard Facebook user account used to access:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Meta Business Portfolio (Business Manager)&lt;/li&gt;
&lt;li&gt;Meta Business Suite&lt;/li&gt;
&lt;li&gt;Meta Developer Portal&lt;/li&gt;
&lt;li&gt;WhatsApp Business Platform&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No special configuration is required. A normal Facebook account is sufficient.&lt;/p&gt;
&lt;h3&gt;
  
  
  Recommended
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Verify email address&lt;/li&gt;
&lt;li&gt;Verify mobile number&lt;/li&gt;
&lt;li&gt;Enable Two-Factor Authentication (2FA)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Meta may consider the trust level and history of the Facebook account during business verification and account reviews.&lt;/p&gt;


&lt;h2&gt;
  
  
  Facebook Page
&lt;/h2&gt;

&lt;p&gt;A Facebook Page represents your business or brand on Meta platforms.&lt;/p&gt;

&lt;p&gt;A WhatsApp Business Account (WABA) is typically linked to a Facebook Page for business identity and management purposes.&lt;/p&gt;
&lt;h3&gt;
  
  
  Recommended Page Information
&lt;/h3&gt;

&lt;p&gt;Configure the following details on the Facebook Page:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Page Name (Business/Brand Name)&lt;/li&gt;
&lt;li&gt;Profile Picture (Company Logo)&lt;/li&gt;
&lt;li&gt;Cover Photo&lt;/li&gt;
&lt;li&gt;Business Description&lt;/li&gt;
&lt;li&gt;Business Website&lt;/li&gt;
&lt;li&gt;Business Email Address&lt;/li&gt;
&lt;li&gt;Business Phone Number&lt;/li&gt;
&lt;li&gt;Business Address (Optional)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These details help establish business identity and may assist during review and verification processes.&lt;/p&gt;


&lt;h2&gt;
  
  
  Scenario 1: No Facebook Account and No Facebook Page Exist
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Step 1: Create a Facebook Personal Account
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to Facebook.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create New Account&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Enter your personal details.&lt;/li&gt;
&lt;li&gt;Verify your email address and mobile number.&lt;/li&gt;
&lt;li&gt;Complete your profile information.&lt;/li&gt;
&lt;li&gt;Enable Two-Factor Authentication (2FA).&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Step 2: Create a Facebook Page
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Log in to your Facebook account.&lt;/li&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Pages&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create New Page&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Enter:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Page Name&lt;/li&gt;
&lt;li&gt;Category&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Description&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add a profile picture and cover image.&lt;/li&gt;
&lt;li&gt;Publish the page.&lt;/li&gt;
&lt;li&gt;Facebook Personal Account created.&lt;/li&gt;
&lt;li&gt;Facebook Page created.&lt;/li&gt;
&lt;li&gt;The Facebook account automatically becomes the Page Admin.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Scenario 2: Facebook Account Exists, but No Facebook Page Exists
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Step 1: Log in to Facebook
&lt;/h3&gt;

&lt;p&gt;Use the existing Facebook account that will manage the business assets.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 2: Create a Facebook Page
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Pages&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create New Page&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Enter:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Page Name&lt;/li&gt;
&lt;li&gt;Category&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Description&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add a profile picture and cover image.&lt;/li&gt;
&lt;li&gt;Publish the page.&lt;/li&gt;
&lt;li&gt;Existing Facebook Account is used.&lt;/li&gt;
&lt;li&gt;New Facebook Page is created.&lt;/li&gt;
&lt;li&gt;The Facebook account becomes the Page Admin.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Scenario 3: Facebook Account Exists and Facebook Page Already Exists
&lt;/h2&gt;

&lt;p&gt;In this scenario, the Facebook Page is already owned or managed by another user or organization.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1: Create or Use Your Facebook Account
&lt;/h3&gt;

&lt;p&gt;Use the Facebook account that will be used for Meta Business Portfolio and WhatsApp Business Platform setup.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 2: Existing Page Admin Grants Access
&lt;/h3&gt;

&lt;p&gt;The current Page Admin must:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the Facebook Page.&lt;/li&gt;
&lt;li&gt;Navigate to:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Settings → Page Access
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Add New&lt;/strong&gt; under Facebook Access.&lt;/li&gt;
&lt;li&gt;Search for the user's Facebook profile.&lt;/li&gt;
&lt;li&gt;Send the invitation.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Step 3: Accept the Invitation
&lt;/h3&gt;

&lt;p&gt;The invited user must:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open Facebook notifications.&lt;/li&gt;
&lt;li&gt;Review the Page access invitation.&lt;/li&gt;
&lt;li&gt;Accept the invitation.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;The user's Facebook account is linked to the existing Facebook Page.&lt;/li&gt;
&lt;li&gt;The user can manage the Page according to the permissions granted by the Page Admin.&lt;/li&gt;
&lt;/ul&gt;


&lt;h1&gt;
  
  
  3. Create Meta Business Portfolio and Complete Business Verification
&lt;/h1&gt;
&lt;h2&gt;
  
  
  Create Business Portfolio
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Go to:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://business.facebook.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Log in using your Facebook account.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create Account&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Enter:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Business Name&lt;/li&gt;
&lt;li&gt;Business Email&lt;/li&gt;
&lt;li&gt;Your Name

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Submit&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This creates your Meta Business Portfolio (formerly Business Manager).&lt;/p&gt;


&lt;h2&gt;
  
  
  Link Business Assets
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Link Facebook Page
&lt;/h3&gt;

&lt;p&gt;Navigate to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Business Settings → Accounts → Pages
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Existing Facebook Page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a New Facebook Page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Optional assets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instagram Account&lt;/li&gt;
&lt;li&gt;Ad Account&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Confirm Business Email
&lt;/h2&gt;

&lt;p&gt;Meta sends a verification email to the business email address.&lt;/p&gt;

&lt;p&gt;Open the email and confirm ownership.&lt;/p&gt;




&lt;h2&gt;
  
  
  Complete Business Verification
&lt;/h2&gt;

&lt;p&gt;Navigate to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Business Settings → Security Center
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click &lt;strong&gt;Start Verification&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Legal Business Name&lt;/li&gt;
&lt;li&gt;Business Address&lt;/li&gt;
&lt;li&gt;Business Phone Number&lt;/li&gt;
&lt;li&gt;Business Website (recommended)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Upload supporting documents such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Certificate of Incorporation&lt;/li&gt;
&lt;li&gt;GST Registration Certificate&lt;/li&gt;
&lt;li&gt;Udyam (MSME) Registration&lt;/li&gt;
&lt;li&gt;Business License&lt;/li&gt;
&lt;li&gt;Utility Bill or Bank Statement (if requested)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Verify Contact Information
&lt;/h2&gt;

&lt;p&gt;Meta may ask to verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Business Email&lt;/li&gt;
&lt;li&gt;Business Phone Number&lt;/li&gt;
&lt;li&gt;Domain Ownership (if website is provided)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Verification Status
&lt;/h3&gt;

&lt;p&gt;Track verification from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Business Settings → Security Center
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Business verification typically takes between &lt;strong&gt;1 and 7 days&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  4. Create Meta Developer Account and Meta App
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Go to:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://developers.facebook.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Log in using your Facebook account.&lt;/li&gt;
&lt;li&gt;Accept the Meta Developer Terms.&lt;/li&gt;
&lt;li&gt;Complete email verification if prompted.&lt;/li&gt;
&lt;li&gt;Navigate to:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;My Apps → Create App
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Select &lt;strong&gt;Business&lt;/strong&gt; as the app type.&lt;/li&gt;
&lt;li&gt;Enter:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;App Name&lt;/li&gt;
&lt;li&gt;Contact Email&lt;/li&gt;
&lt;li&gt;Business Portfolio

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Create App&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Add WhatsApp Product
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open the newly created app.&lt;/li&gt;
&lt;li&gt;Click:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Add Product → WhatsApp → Set Up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Meta provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Test WhatsApp Business Account (WABA)&lt;/li&gt;
&lt;li&gt;Test Phone Number&lt;/li&gt;
&lt;li&gt;Temporary Access Token&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  These resources are intended for development and testing purposes. You can immediately test WhatsApp Cloud API requests before configuring production assets.
&lt;/h2&gt;

&lt;h1&gt;
  
  
  5. Add Production Phone Number
&lt;/h1&gt;

&lt;p&gt;Navigate to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://developers.facebook.com
Developer Console → Select App → WhatsApp → API Setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click &lt;strong&gt;Add Phone Number&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Business Name&lt;/li&gt;
&lt;li&gt;Display Name&lt;/li&gt;
&lt;li&gt;Business Category&lt;/li&gt;
&lt;li&gt;Phone Number&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Complete verification using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SMS OTP&lt;/li&gt;
&lt;li&gt;Voice Call OTP&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Important Notes
&lt;/h2&gt;

&lt;p&gt;The phone number:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Must not already be registered with a personal WhatsApp account&lt;/li&gt;
&lt;li&gt;Must not already be registered with WhatsApp Business App&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the number is already registered with WhatsApp, it must be migrated before it can be used with WhatsApp Cloud API.&lt;/p&gt;

&lt;p&gt;After successful verification:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Phone number is associated with the WABA&lt;/li&gt;
&lt;li&gt;Meta reviews the display name&lt;/li&gt;
&lt;li&gt;Application can use the number through Cloud API&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  6. Check Display Name Status
&lt;/h1&gt;

&lt;p&gt;Navigate to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Business Settings → Accounts → WhatsApp Accounts → Phone Numbers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WhatsApp Manager → Phone Numbers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Display Name Status:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Approved&lt;/li&gt;
&lt;li&gt;Pending Review&lt;/li&gt;
&lt;li&gt;Rejected&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only approved display names can be used for production messaging.&lt;/p&gt;

&lt;p&gt;If rejected, update and resubmit the display name.&lt;/p&gt;




&lt;h1&gt;
  
  
  7. WhatsApp Business Account (WABA)
&lt;/h1&gt;

&lt;p&gt;A WhatsApp Business Account (WABA) is the container that manages all WhatsApp Business Platform assets.&lt;/p&gt;

&lt;p&gt;Meta typically creates or associates a WABA during the onboarding process when a production phone number is added.&lt;/p&gt;

&lt;p&gt;Manage WABA from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Business Settings → Accounts → WhatsApp Accounts&lt;/li&gt;
&lt;li&gt;WhatsApp Manager&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  WABA Management Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Business Information
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;WABA Name&lt;/li&gt;
&lt;li&gt;Business Portfolio&lt;/li&gt;
&lt;li&gt;Business Details&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Phone Numbers
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Add or Remove Phone Numbers&lt;/li&gt;
&lt;li&gt;Display Name Status&lt;/li&gt;
&lt;li&gt;Quality Rating&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Message Templates
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create Templates&lt;/li&gt;
&lt;li&gt;Submit Templates for Approval&lt;/li&gt;
&lt;li&gt;View Template Status&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Users &amp;amp; Permissions
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Add Admins&lt;/li&gt;
&lt;li&gt;Assign Access&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Messaging Limits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;View Messaging Limits&lt;/li&gt;
&lt;li&gt;Monitor Quality Rating&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Billing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Payment Method&lt;/li&gt;
&lt;li&gt;Billing Information&lt;/li&gt;
&lt;li&gt;Usage and Charges&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  8. Create a System User
&lt;/h1&gt;

&lt;p&gt;Navigate to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://business.facebook.com
Business Settings → Users → System Users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Add&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Enter a name&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Admin System User&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;System Users are used for server-to-server authentication and generating permanent access tokens for API Integratios.&lt;/p&gt;




&lt;h1&gt;
  
  
  9. Assign Assets to the System User
&lt;/h1&gt;

&lt;p&gt;Select the System User.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Assign Assets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assign:&lt;/p&gt;

&lt;h3&gt;
  
  
  WhatsApp Business Account (WABA)
&lt;/h3&gt;

&lt;p&gt;Permissions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;whatsapp_business_management&lt;/li&gt;
&lt;li&gt;whatsapp_business_messaging&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Meta App
&lt;/h3&gt;

&lt;p&gt;Permissions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full Control (Recommended)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Save changes.&lt;/p&gt;




&lt;h1&gt;
  
  
  10. Generate a Permanent Access Token
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Open the System User.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Generate New Token&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select the Meta App.&lt;/li&gt;
&lt;li&gt;Select permissions:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;whatsapp_business_management&lt;/li&gt;
&lt;li&gt;whatsapp_business_messaging

&lt;ol&gt;
&lt;li&gt;Generate the token.&lt;/li&gt;
&lt;li&gt;Securely store it.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This permanent access token is used by your application to access the WhatsApp Cloud API in production.&lt;/p&gt;




&lt;h1&gt;
  
  
  11. Configure Billing
&lt;/h1&gt;

&lt;p&gt;Navigate to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WhatsApp Manager → Billing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Payment Method&lt;/li&gt;
&lt;li&gt;Billing Information&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Billing allows you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add payment methods&lt;/li&gt;
&lt;li&gt;View conversation charges&lt;/li&gt;
&lt;li&gt;Monitor usage and costs&lt;/li&gt;
&lt;li&gt;Manage billing information&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  12. Configure Webhooks
&lt;/h1&gt;

&lt;p&gt;Navigate to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://developers.facebook.com
Developer Console → Your App → WhatsApp → Configuration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configure:&lt;/p&gt;

&lt;h3&gt;
  
  
  Callback URL
&lt;/h3&gt;

&lt;p&gt;The endpoint that receives webhook events from Meta.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://yourdomain.com/api/method/whatsapp.webhook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Verify Token
&lt;/h3&gt;

&lt;p&gt;Custom secret token used during webhook verification.&lt;/p&gt;

&lt;h3&gt;
  
  
  Subscribe to Webhook Fields
&lt;/h3&gt;

&lt;p&gt;Recommended:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;messages&lt;/li&gt;
&lt;li&gt;message_status&lt;/li&gt;
&lt;li&gt;message_template_status_update&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Webhook Use Cases
&lt;/h2&gt;

&lt;p&gt;Receive:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Incoming Messages&lt;/li&gt;
&lt;li&gt;Delivery Reports&lt;/li&gt;
&lt;li&gt;Read Receipts&lt;/li&gt;
&lt;li&gt;Message Status Updates&lt;/li&gt;
&lt;li&gt;Template Status Updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Webhook configuration is required for two-way messaging and real-time event processing.&lt;/p&gt;




&lt;h1&gt;
  
  
  13. Create Message Templates
&lt;/h1&gt;

&lt;p&gt;Navigate to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WhatsApp Manager → Message Templates
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create templates for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OTP Messages&lt;/li&gt;
&lt;li&gt;Welcome Messages&lt;/li&gt;
&lt;li&gt;Notifications&lt;/li&gt;
&lt;li&gt;Payment Reminders&lt;/li&gt;
&lt;li&gt;Appointment Reminders&lt;/li&gt;
&lt;li&gt;Marketing Campaigns&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;After creating a template:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select the template category (Marketing, Utility, Authentication).&lt;/li&gt;
&lt;li&gt;Configure the message content and variables.&lt;/li&gt;
&lt;li&gt;Submit the template for Meta review.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Template Status
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Pending &lt;/li&gt;
&lt;li&gt;Approved&lt;/li&gt;
&lt;li&gt;Rejected&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Template approval typically takes from a few minutes to several hours, although it may take longer in some cases.&lt;/p&gt;

&lt;p&gt;Only approved templates can be used to initiate conversations.&lt;/p&gt;




&lt;h1&gt;
  
  
  14. Test WhatsApp API Integration
&lt;/h1&gt;

&lt;p&gt;Use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Phone Number ID&lt;/li&gt;
&lt;li&gt;Permanent Access Token&lt;/li&gt;
&lt;/ul&gt;




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

&lt;h3&gt;
  
  
  Postman Testing
&lt;/h3&gt;

&lt;p&gt;Postman Collection:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.postman.com/meta/whatsapp-business-platform/collection" rel="noopener noreferrer"&gt;https://www.postman.com/meta/whatsapp-business-platform/collection&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Phone Number ID&lt;/li&gt;
&lt;li&gt;Permanent Access Token&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the most common method used for API testing and troubleshooting.&lt;/p&gt;




&lt;h3&gt;
  
  
  Application/API Integration Testing
&lt;/h3&gt;

&lt;p&gt;Integrate the WhatsApp Cloud API into your application and test using your application code.&lt;/p&gt;

&lt;p&gt;Examples: Python, Node.js,Java&lt;/p&gt;

&lt;p&gt;Validate complete end-to-end integration.&lt;/p&gt;




&lt;h2&gt;
  
  
  Test the Following APIs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Send Message API
&lt;/h3&gt;

&lt;p&gt;Send a basic text message.&lt;/p&gt;

&lt;h3&gt;
  
  
  Template Message API
&lt;/h3&gt;

&lt;p&gt;Send an approved template.&lt;/p&gt;

&lt;h3&gt;
  
  
  Media Message API
&lt;/h3&gt;

&lt;p&gt;Send:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Images&lt;/li&gt;
&lt;li&gt;Documents&lt;/li&gt;
&lt;li&gt;Audio&lt;/li&gt;
&lt;li&gt;Video&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Verify Integration
&lt;/h2&gt;

&lt;p&gt;Confirm:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Messages are delivered successfully.&lt;/li&gt;
&lt;li&gt;Incoming messages are received.&lt;/li&gt;
&lt;li&gt;Webhooks are triggered correctly.&lt;/li&gt;
&lt;li&gt;Delivery status updates are received.&lt;/li&gt;
&lt;li&gt;Read receipts are received.&lt;/li&gt;
&lt;li&gt;Template messages are delivered successfully.&lt;/li&gt;
&lt;li&gt;Media messages are delivered successfully.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Resolve any API, webhook, permission, or configuration issues before moving to production.&lt;/p&gt;




&lt;h1&gt;
  
  
  15. Go Live
&lt;/h1&gt;

&lt;p&gt;After all configurations are complete and verified, your WhatsApp Cloud API integration is ready for production use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Go-Live Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✓ Business Verification Completed&lt;/li&gt;
&lt;li&gt;✓ Approved Display Name&lt;/li&gt;
&lt;li&gt;✓ Verified Production Phone Number&lt;/li&gt;
&lt;li&gt;✓ Approved Message Templates&lt;/li&gt;
&lt;li&gt;✓ Permanent Access Token Generated&lt;/li&gt;
&lt;li&gt;✓ Webhooks Configured and Working&lt;/li&gt;
&lt;li&gt;✓ Billing Configured&lt;/li&gt;
&lt;li&gt;✓ API Integration Tested Successfully&lt;/li&gt;
&lt;li&gt;✓ Required Users and Permissions Configured&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once the checklist is complete, the WhatsApp Business Platform can be used for production messaging.&lt;/p&gt;




&lt;h1&gt;
  
  
  16. Production Integration Credentials Reference
&lt;/h1&gt;

&lt;p&gt;After completing the WhatsApp Cloud API setup, collect and securely store the following credentials.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Credential&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Required For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;App ID&lt;/td&gt;
&lt;td&gt;Unique identifier of the Meta App&lt;/td&gt;
&lt;td&gt;API management and token generation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;App Secret&lt;/td&gt;
&lt;td&gt;Secret key associated with the Meta App&lt;/td&gt;
&lt;td&gt;Server-to-server authentication and security operations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Business Portfolio ID (Business Manager ID)&lt;/td&gt;
&lt;td&gt;Identifier of the Meta Business Portfolio&lt;/td&gt;
&lt;td&gt;Business asset management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WhatsApp Business Account ID (WABA ID)&lt;/td&gt;
&lt;td&gt;Identifier of the WhatsApp Business Account&lt;/td&gt;
&lt;td&gt;Template management and account management APIs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Phone Number ID&lt;/td&gt;
&lt;td&gt;Identifier of the WhatsApp-enabled phone number&lt;/td&gt;
&lt;td&gt;Sending messages through Cloud API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Permanent Access Token&lt;/td&gt;
&lt;td&gt;Authentication token generated for the System User&lt;/td&gt;
&lt;td&gt;All production API requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verify Token&lt;/td&gt;
&lt;td&gt;Custom token configured during webhook setup&lt;/td&gt;
&lt;td&gt;Webhook verification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Webhook Callback URL&lt;/td&gt;
&lt;td&gt;Public HTTPS endpoint that receives Meta events&lt;/td&gt;
&lt;td&gt;Incoming messages and status updates&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h1&gt;
  
  
  Resources 👍
&lt;/h1&gt;

&lt;p&gt;Meta WhatsApp Business Platform Documentation&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.facebook.com/documentation/business-messaging/whatsapp/overview" rel="noopener noreferrer"&gt;https://developers.facebook.com/documentation/business-messaging/whatsapp/overview&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Postman Collection&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.postman.com/meta/whatsapp-business-platform/collection" rel="noopener noreferrer"&gt;https://www.postman.com/meta/whatsapp-business-platform/collection&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Setting up WhatsApp Cloud API involves several Meta services, including Business Portfolio, WABA, Developer Apps, System Users, Access Tokens, and Webhooks. While the onboarding process may initially seem complex, once configured correctly, it provides a scalable and reliable platform for integrating WhatsApp messaging into business applications.&lt;/p&gt;

&lt;p&gt;Following this guide will help you move from a simple Facebook account to a fully production-ready WhatsApp Cloud API integration.&lt;/p&gt;

</description>
      <category>whatsappcloudapi</category>
      <category>metawhatsapp</category>
      <category>meta</category>
      <category>whatsapp</category>
    </item>
    <item>
      <title># 🚀 70+ VS Code Extensions Every Developer Should Know</title>
      <dc:creator>Sai Praveen Sanapalli</dc:creator>
      <pubDate>Fri, 05 Jun 2026 19:02:20 +0000</pubDate>
      <link>https://dev.to/saipraveen446/-70-vs-code-extensions-every-developer-should-know-3b47</link>
      <guid>https://dev.to/saipraveen446/-70-vs-code-extensions-every-developer-should-know-3b47</guid>
      <description>&lt;p&gt;Visual Studio Code is one of the most popular code editors among developers. While VS Code is powerful out of the box, the right extensions can significantly improve productivity, code quality, debugging, collaboration, and workflow management.&lt;/p&gt;

&lt;p&gt;Here are 70+ useful VS Code extensions categorized by use case.&lt;/p&gt;




&lt;h2&gt;
  
  
  🐍 Python &amp;amp; Data Science
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Python&lt;/strong&gt; – Official Python support with debugging, IntelliSense, linting, and environment management.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pylance&lt;/strong&gt; – Fast IntelliSense, type checking, and auto-import suggestions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ruff&lt;/strong&gt; – Extremely fast Python linter and formatter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Black Formatter&lt;/strong&gt; – Automatically formats Python code consistently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flake8&lt;/strong&gt; – Enforces coding standards and detects issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;isort&lt;/strong&gt; – Organizes and sorts imports automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python Test Explorer&lt;/strong&gt; – Run and manage tests directly in VS Code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Jupyter&lt;/strong&gt; – Create and run notebooks inside VS Code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Indent Rainbow&lt;/strong&gt; – Makes indentation levels easier to read.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🌐 Web &amp;amp; Frontend Development
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ES7+ React/Redux Snippets&lt;/strong&gt; – Speed up React development with ready-made snippets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailwind CSS IntelliSense&lt;/strong&gt; – Autocomplete and validation for Tailwind CSS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prettier&lt;/strong&gt; – Automatically formats code on save.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTML CSS Support&lt;/strong&gt; – Improves HTML and CSS IntelliSense.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSS Peek&lt;/strong&gt; – Jump directly to CSS definitions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto Rename Tag&lt;/strong&gt; – Renames paired HTML tags automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto Close Tag&lt;/strong&gt; – Inserts closing tags automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live Server&lt;/strong&gt; – Launch local projects with live reload.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live Share&lt;/strong&gt; – Collaborate with teammates in real time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Jest&lt;/strong&gt; – Run and debug Jest tests directly.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🗄️ Databases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SQLTools&lt;/strong&gt; – Connect to and query multiple databases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PostgreSQL&lt;/strong&gt; – Browse and run PostgreSQL queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MongoDB for VS Code&lt;/strong&gt; – Explore collections and execute queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQLite Viewer&lt;/strong&gt; – Open SQLite databases directly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prisma&lt;/strong&gt; – IntelliSense and formatting for Prisma schemas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rainbow CSV&lt;/strong&gt; – Makes CSV files easier to read and analyze.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔀 Git &amp;amp; GitHub
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitLens&lt;/strong&gt; – Advanced Git insights and history tracking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Git Graph&lt;/strong&gt; – Visualize branches and commit history.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Pull Requests&lt;/strong&gt; – Review and manage pull requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Actions&lt;/strong&gt; – View workflow runs and statuses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Codespaces&lt;/strong&gt; – Launch cloud development environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Repositories&lt;/strong&gt; – Browse repositories without cloning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Settings Sync&lt;/strong&gt; – Synchronize settings and extensions across devices.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ✅ Code Quality &amp;amp; Formatting
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ESLint&lt;/strong&gt; – JavaScript and TypeScript linting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Lens&lt;/strong&gt; – Displays errors directly inline.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SonarQube for IDE&lt;/strong&gt; – Detects bugs, vulnerabilities, and code smells.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better Comments&lt;/strong&gt; – Organize comments using visual highlights.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Spell Checker&lt;/strong&gt; – Finds spelling mistakes in code and documentation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DotENV&lt;/strong&gt; – Syntax highlighting for environment files.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔌 API Testing &amp;amp; Debugging
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Thunder Client&lt;/strong&gt; – Lightweight API testing inside VS Code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;REST Client&lt;/strong&gt; – Execute HTTP requests from text files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Turbo Console Log&lt;/strong&gt; – Generate console logs instantly.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ☁️ DevOps &amp;amp; Cloud
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Docker&lt;/strong&gt; – Manage containers and images.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remote SSH&lt;/strong&gt; – Develop directly on remote servers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dev Containers&lt;/strong&gt; – Open projects inside containers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kubernetes&lt;/strong&gt; – Manage clusters and workloads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Terraform&lt;/strong&gt; – Infrastructure as Code support.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;YAML&lt;/strong&gt; – Validation and IntelliSense for YAML files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS Toolkit&lt;/strong&gt; – Access AWS services directly from VS Code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Makefile Tools&lt;/strong&gt; – Work efficiently with Makefiles.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📝 Documentation &amp;amp; Diagrams
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Markdown All in One&lt;/strong&gt; – Productivity tools for Markdown editing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Markdown Preview Enhanced&lt;/strong&gt; – Rich Markdown preview and exports.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mermaid Charts&lt;/strong&gt; – Create flowcharts and diagrams with Mermaid.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Draw.io Integration&lt;/strong&gt; – Build architecture and workflow diagrams.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CodeSnap&lt;/strong&gt; – Create beautiful code screenshots.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;vscode-pdf&lt;/strong&gt; – View PDFs without leaving VS Code.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ⚡ Productivity &amp;amp; Workflow
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Path IntelliSense&lt;/strong&gt; – Auto-complete file paths.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project Manager&lt;/strong&gt; – Quickly switch between projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bookmarks&lt;/strong&gt; – Save important code locations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Todo Tree&lt;/strong&gt; – Organize TODO and FIXME comments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JSON Crack&lt;/strong&gt; – Visualize JSON structures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Peacock&lt;/strong&gt; – Color-code workspaces.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pomodoro Timer&lt;/strong&gt; – Stay focused with timed work sessions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WakaTime&lt;/strong&gt; – Track coding activity automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VSCodeVim&lt;/strong&gt; – Vim keybindings for VS Code users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One Dark Pro&lt;/strong&gt; – Popular developer-friendly theme.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Material Icon Theme&lt;/strong&gt; – Beautiful file and folder icons.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Color Highlight&lt;/strong&gt; – Preview colors directly in code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Paste JSON as Code&lt;/strong&gt; – Generate typed models from JSON instantly.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💡 Pro Tip
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Choose extensions based on your workflow, not popularity.&lt;/li&gt;
&lt;li&gt;Too many extensions can impact performance and increase resource usage.&lt;/li&gt;
&lt;li&gt;Keep your setup lean, fast, and productive. 🚀&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  What are your favorite VS Code extensions?
&lt;/h3&gt;

&lt;p&gt;Drop your recommendations in the comments and help other developers discover useful tools.&lt;/p&gt;

&lt;p&gt;Happy Coding! 💻&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>extensions</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title># AWS SES Setup Guide: Domain Verification, SMTP Configuration, DKIM, SPF &amp; DMARC</title>
      <dc:creator>Sai Praveen Sanapalli</dc:creator>
      <pubDate>Wed, 03 Jun 2026 18:55:53 +0000</pubDate>
      <link>https://dev.to/saipraveen446/-aws-ses-setup-guide-domain-verification-smtp-configuration-dkim-spf-dmarc-273j</link>
      <guid>https://dev.to/saipraveen446/-aws-ses-setup-guide-domain-verification-smtp-configuration-dkim-spf-dmarc-273j</guid>
      <description>&lt;p&gt;Email delivery is a critical component of modern applications. Whether you're sending OTPs, transactional notifications, account alerts, invoices, or marketing campaigns, reliable email delivery is essential.&lt;/p&gt;

&lt;p&gt;In this guide, we'll walk through the complete setup of Amazon Simple Email Service (AWS SES), including domain verification, DKIM, SPF, DMARC, SMTP credentials, and production access.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is AWS SES?
&lt;/h2&gt;

&lt;p&gt;Amazon Simple Email Service (AWS SES) is a cloud-based email service that enables businesses and developers to send and receive emails securely and at scale.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Cost-effective email delivery&lt;/li&gt;
&lt;li&gt;High deliverability&lt;/li&gt;
&lt;li&gt;SMTP and API support&lt;/li&gt;
&lt;li&gt;Easy integration with applications&lt;/li&gt;
&lt;li&gt;Reputation monitoring&lt;/li&gt;
&lt;li&gt;Scalable infrastructure&lt;/li&gt;
&lt;li&gt;Security through SPF, DKIM, and DMARC&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Step 1: Before You Start
&lt;/h1&gt;

&lt;p&gt;Before configuring AWS SES, complete the following prerequisites.&lt;/p&gt;

&lt;h3&gt;
  
  
  Login to AWS Console
&lt;/h3&gt;

&lt;p&gt;Sign in to your AWS account and select the correct region.&lt;/p&gt;

&lt;h3&gt;
  
  
  Select AWS Region
&lt;/h3&gt;

&lt;p&gt;For users in India, use:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Asia Pacific (Mumbai) – ap-south-1&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Important:&lt;br&gt;
SMTP credentials are region-specific.&lt;br&gt;
For SMTP and SMS credential generation, it is recommended to use the Mumbai (ap-south-1) region.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Create Identity Using Your Domain
&lt;/h3&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alerts.yourcompany.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AWS SES uses this domain identity for email authentication and reputation management.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 2: Create Domain Identity
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Open AWS Console&lt;/li&gt;
&lt;li&gt;Search for SES&lt;/li&gt;
&lt;li&gt;Open Amazon Simple Email Service&lt;/li&gt;
&lt;li&gt;Navigate to Verified Identities&lt;/li&gt;
&lt;li&gt;Click Create Identity&lt;/li&gt;
&lt;li&gt;Select Identity Type → Domain&lt;/li&gt;
&lt;li&gt;Enter your domain&lt;/li&gt;
&lt;/ol&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alerts.yourcompany.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Enable Easy DKIM&lt;/li&gt;
&lt;li&gt;Click Create Identity&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;AWS SES will generate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TXT record for domain verification&lt;/li&gt;
&lt;li&gt;Three DKIM CNAME records&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Step 3: Configure DNS Records
&lt;/h1&gt;

&lt;p&gt;Add the records generated by SES to your DNS provider.&lt;/p&gt;

&lt;h2&gt;
  
  
  TXT Record (Domain Verification)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Type: TXT
Value: amazonses-verification-token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  DKIM Records
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Type: CNAME
Count: 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AWS provides these automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  SPF Record
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Type: TXT

Value:
v=spf1 include:amazonses.com -all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SPF authorizes Amazon SES to send emails on behalf of your domain.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 4: Route 53 Configuration (Optional)
&lt;/h1&gt;

&lt;p&gt;If your domain is hosted in Route 53:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open Route 53&lt;/li&gt;
&lt;li&gt;Select Hosted Zone&lt;/li&gt;
&lt;li&gt;Add TXT verification record&lt;/li&gt;
&lt;li&gt;Add DKIM CNAME records&lt;/li&gt;
&lt;li&gt;Save changes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;DNS propagation generally completes within:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;5–15 minutes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Step 5: Configure Custom MAIL FROM Domain
&lt;/h1&gt;

&lt;p&gt;Using a custom MAIL FROM domain improves deliverability and branding.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mail.alerts.yourcompany.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Navigate to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SES → Verified Identities → Domain → MAIL FROM Domain
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Use Custom MAIL FROM Domain
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add MX Record
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Type: MX

Value:
10 feedback-smtp.ap-south-1.amazonses.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add SPF Record
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Type: TXT

Value:
v=spf1 include:amazonses.com -all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Step 6: Create Configuration Set (Optional but Recommended for monitoring)
&lt;/h1&gt;

&lt;p&gt;Configuration Sets help monitor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deliverability&lt;/li&gt;
&lt;li&gt;Bounce rates&lt;/li&gt;
&lt;li&gt;Complaint rates&lt;/li&gt;
&lt;li&gt;Reputation metrics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open SES&lt;/li&gt;
&lt;li&gt;Navigate to Configuration Sets&lt;/li&gt;
&lt;li&gt;Click Create Configuration Set&lt;/li&gt;
&lt;li&gt;Enter a name&lt;/li&gt;
&lt;/ol&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alerts-config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Enable Reputation Metrics&lt;/li&gt;
&lt;li&gt;Attach SNS or CloudWatch event destinations&lt;/li&gt;
&lt;/ol&gt;




&lt;h1&gt;
  
  
  Step 7: Request Production Access
&lt;/h1&gt;

&lt;p&gt;New AWS SES accounts start in Sandbox Mode.&lt;/p&gt;

&lt;p&gt;Sandbox restrictions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can only send to verified email addresses&lt;/li&gt;
&lt;li&gt;Limited sending quotas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To move to production:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open SES Dashboard&lt;/li&gt;
&lt;li&gt;Select Request Production Access&lt;/li&gt;
&lt;li&gt;Fill in:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Use Case: Transactional Emails
Email Type: Transactional
Website: https://yourcompany.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Approval typically takes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2–24 hours
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Step 8: Create SMTP Credentials
&lt;/h1&gt;

&lt;p&gt;Navigate to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SES → SMTP Settings
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Create SMTP Credentials
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AWS creates an IAM user and generates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SMTP Username&lt;/li&gt;
&lt;li&gt;SMTP Password&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  SMTP Endpoint (Mumbai Region)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Host:
email-smtp.ap-south-1.amazonaws.com

Port:
587

Encryption:
TLS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Important
&lt;/h3&gt;

&lt;p&gt;Always use the SMTP endpoint that matches the region where credentials were generated.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 9: Test Email Delivery
&lt;/h1&gt;

&lt;p&gt;You can test email delivery using:&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 1
&lt;/h3&gt;

&lt;p&gt;SMTP integration from your application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 2
&lt;/h3&gt;

&lt;p&gt;AWS SES test email functionality.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 3
&lt;/h3&gt;

&lt;p&gt;Python Boto3 SDK.&lt;/p&gt;

&lt;p&gt;After receiving the email:&lt;/p&gt;

&lt;p&gt;Open Gmail → Show Original&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SPF: PASS
DKIM: PASS
DMARC: PASS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Step 10: Configure DMARC
&lt;/h1&gt;

&lt;p&gt;DMARC adds an additional layer of protection against email spoofing.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Type: TXT

Host:
_dmarc.alerts.yourcompany.com

Value:
v=DMARC1; p=none; rua=mailto:admin@yourcompany.com;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After monitoring reports, you can move from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;p=none
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;p=quarantine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and eventually&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;p=reject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;for stronger protection.&lt;/p&gt;




&lt;h1&gt;
  
  
  Email Deliverability Best Practices
&lt;/h1&gt;

&lt;h3&gt;
  
  
  Warm Up New Domains
&lt;/h3&gt;

&lt;p&gt;Start with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10–20 emails per day
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and gradually increase volume.&lt;/p&gt;

&lt;h3&gt;
  
  
  Maintain Low Bounce Rates
&lt;/h3&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bounce Rate &amp;lt; 5%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Maintain Low Complaint Rates
&lt;/h3&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Complaint Rate &amp;lt; 0.1%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Send Multipart Emails
&lt;/h3&gt;

&lt;p&gt;Always send:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTML version&lt;/li&gt;
&lt;li&gt;Plain text version&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Monitor Reputation Dashboard
&lt;/h3&gt;

&lt;p&gt;Review:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Delivery rates&lt;/li&gt;
&lt;li&gt;Bounce rates&lt;/li&gt;
&lt;li&gt;Complaint rates&lt;/li&gt;
&lt;li&gt;Reputation status&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;regularly.&lt;/p&gt;




&lt;h1&gt;
  
  
  High-Level Email Flow
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application
      ↓
AWS SES
      ↓
Domain Verification
      ↓
SPF + DKIM + DMARC
      ↓
Recipient Inbox
      ↓
High Deliverability
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;AWS SES provides a reliable, scalable, and cost-effective solution for sending transactional and notification emails. By properly configuring Domain Verification, DKIM, SPF, DMARC, Custom MAIL FROM, and SMTP credentials, you can significantly improve email deliverability and protect your domain reputation.&lt;/p&gt;

&lt;p&gt;If you're building SaaS platforms, ERP systems, notification services, fintech applications, or customer communication platforms, AWS SES is one of the most efficient email delivery services available today.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>awsses</category>
      <category>cloud</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
