<?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: Ratnesh Maurya</title>
    <description>The latest articles on DEV Community by Ratnesh Maurya (@ratneshmaurya).</description>
    <link>https://dev.to/ratneshmaurya</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F946642%2F39f469a9-49d8-4330-86f1-033a225ed39f.png</url>
      <title>DEV Community: Ratnesh Maurya</title>
      <link>https://dev.to/ratneshmaurya</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ratneshmaurya"/>
    <language>en</language>
    <item>
      <title>Go 1.26.2 Released: Security Fixes, Regression Patches, and an Upgrade Playbook</title>
      <dc:creator>Ratnesh Maurya</dc:creator>
      <pubDate>Thu, 09 Apr 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/ratneshmaurya/go-1262-released-security-fixes-regression-patches-and-an-upgrade-playbook-1ebo</link>
      <guid>https://dev.to/ratneshmaurya/go-1262-released-security-fixes-regression-patches-and-an-upgrade-playbook-1ebo</guid>
      <description>&lt;p&gt;# Go 1.26.2 Released: Security Fixes, Regression Patches, and an Upgrade Playbook&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.ratnesh-maurya.com%2Fimages%2Fblog%2Fgo-1-26-2-release-overview.svg" 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%2Fblog.ratnesh-maurya.com%2Fimages%2Fblog%2Fgo-1-26-2-release-overview.svg" alt="Go 1.26.2 Released: Security Fixes, Regression Patches, and an Upgrade Playbook" width="1600" height="900"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Go 1.26.2 Released: Security Fixes, Regression Patches, and an Upgrade Playbook
&lt;/h1&gt;

&lt;p&gt;Go 1.26.2 was released on &lt;strong&gt;2026-04-07&lt;/strong&gt; as a patch release focused on security and stability.&lt;/p&gt;

&lt;p&gt;If you are running Go 1.26.x in production, this is the kind of release you should evaluate quickly.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
Go 1.26.2 includes security fixes to the &lt;code&gt;go&lt;/code&gt; command, compiler, and the &lt;code&gt;archive/tar&lt;/code&gt;, &lt;code&gt;crypto/tls&lt;/code&gt;, &lt;code&gt;crypto/x509&lt;/code&gt;, &lt;code&gt;html/template&lt;/code&gt;, and &lt;code&gt;os&lt;/code&gt; packages, plus bug fixes across the &lt;code&gt;go&lt;/code&gt; command, &lt;code&gt;go fix&lt;/code&gt;, compiler, linker, runtime, &lt;code&gt;net&lt;/code&gt;, &lt;code&gt;net/http&lt;/code&gt;, and &lt;code&gt;net/url&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.ratnesh-maurya.com%2Fimages%2Fblog%2Fgo-1-26-2-release-overview.svg" 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%2Fblog.ratnesh-maurya.com%2Fimages%2Fblog%2Fgo-1-26-2-release-overview.svg" alt="Go 1.26.2 release at a glance" width="1600" height="900"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR (beginner + technical)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If you are on &lt;strong&gt;1.26.0&lt;/strong&gt; or &lt;strong&gt;1.26.1&lt;/strong&gt;, plan an upgrade to &lt;strong&gt;1.26.2&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;If your service is internet-facing, treat this as high priority because security-sensitive packages were patched.&lt;/li&gt;
&lt;li&gt;Verify checksums before installation.&lt;/li&gt;
&lt;li&gt;Roll out with canary + SLO guardrails, not a full one-shot deployment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  If you are new: what does "1.26.2" mean?
&lt;/h2&gt;

&lt;p&gt;Go versions follow a &lt;code&gt;major.minor.patch&lt;/code&gt; pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;1&lt;/code&gt; = major line&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;26&lt;/code&gt; = minor release line&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;2&lt;/code&gt; = patch release&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Patch releases are usually about &lt;strong&gt;fixing behavior&lt;/strong&gt;, not adding new language features.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this patch matters technically
&lt;/h2&gt;

&lt;p&gt;Go 1.26 introduced important runtime and toolchain changes. Point releases like 1.26.2 are where real-world regressions and security backports get addressed.&lt;/p&gt;

&lt;p&gt;Use this release as both a security update and a reliability update.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Area&lt;/th&gt;
&lt;th&gt;Patch focus in 1.26.2&lt;/th&gt;
&lt;th&gt;Practical risk if delayed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;crypto/tls&lt;/code&gt;, &lt;code&gt;crypto/x509&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Security hardening and correctness fixes&lt;/td&gt;
&lt;td&gt;TLS/cert path issues at trust boundaries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;html/template&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Security-related fixes&lt;/td&gt;
&lt;td&gt;Potential template safety exposure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;cmd/go&lt;/code&gt;, &lt;code&gt;go fix&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Toolchain reliability fixes&lt;/td&gt;
&lt;td&gt;Slow/hanging CI or broken automation flows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compiler/linker/runtime&lt;/td&gt;
&lt;td&gt;Regression and crash fixes&lt;/td&gt;
&lt;td&gt;Build or runtime instability in production&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;net&lt;/code&gt;, &lt;code&gt;net/http&lt;/code&gt;, &lt;code&gt;net/url&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Networking correctness fixes&lt;/td&gt;
&lt;td&gt;Subtle request/routing/parsing behavior regressions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Deep look at the Go1.26.2 milestone
&lt;/h2&gt;

&lt;p&gt;Using the public GitHub milestone API for &lt;code&gt;Go1.26.2&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Milestone state: &lt;code&gt;closed&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Open issues: &lt;code&gt;0&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Closed issues: &lt;code&gt;31&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What the issue distribution tells us
&lt;/h3&gt;

&lt;p&gt;From a title/label scan of closed issues, the cluster is practical and production-facing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CVE-related titles: &lt;code&gt;10&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Security backport-labeled titles: &lt;code&gt;8&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Compiler/runtime-labeled items: &lt;code&gt;10&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cmd/go&lt;/code&gt;-labeled items: &lt;code&gt;1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Testing-labeled items: &lt;code&gt;2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Documentation/backport consistency items: &lt;code&gt;4&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the normal fingerprint of a mature patch release: security + high-impact regressions + release-quality cleanup.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security and CVE signal
&lt;/h3&gt;

&lt;p&gt;The milestone shows clear CVE and security backport activity, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/golang/go/issues/78428" rel="noopener noreferrer"&gt;#78428&lt;/a&gt; &lt;code&gt;security: fix CVE-2026-32283 [1.26 backport]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/golang/go/issues/78426" rel="noopener noreferrer"&gt;#78426&lt;/a&gt; &lt;code&gt;security: fix CVE-2026-32282 [1.26 backport]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/golang/go/issues/78424" rel="noopener noreferrer"&gt;#78424&lt;/a&gt; &lt;code&gt;security: fix CVE-2026-27144 [1.26 backport]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/golang/go/issues/78422" rel="noopener noreferrer"&gt;#78422&lt;/a&gt; &lt;code&gt;security: fix CVE-2026-27140 [1.26 backport]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/golang/go/issues/78362" rel="noopener noreferrer"&gt;#78362&lt;/a&gt; &lt;code&gt;crypto/x509 ... (CVE-2026-32280)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/golang/go/issues/78360" rel="noopener noreferrer"&gt;#78360&lt;/a&gt; &lt;code&gt;crypto/x509 ... (CVE-2026-32281)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br&gt;
Even without changing your app code, patching core trust-boundary packages (&lt;code&gt;tls&lt;/code&gt;, &lt;code&gt;x509&lt;/code&gt;, templates, and toolchain) reduces real production risk.&lt;br&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Regression fixes you may actually notice
&lt;/h3&gt;

&lt;p&gt;Representative examples from the milestone:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/golang/go/issues/78058" rel="noopener noreferrer"&gt;#78058&lt;/a&gt;: &lt;code&gt;cmd/go&lt;/code&gt; cache trim could block for 20+ minutes on macOS.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/golang/go/issues/78111" rel="noopener noreferrer"&gt;#78111&lt;/a&gt;: &lt;code&gt;net/url&lt;/code&gt; parsing regression affecting MongoDB multi-host connection strings.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/golang/go/issues/78041" rel="noopener noreferrer"&gt;#78041&lt;/a&gt;: runtime crash on Windows in 1.26.0/1.26.1.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/golang/go/issues/78239" rel="noopener noreferrer"&gt;#78239&lt;/a&gt;: linker panic on darwin/arm64.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/golang/go/issues/78191" rel="noopener noreferrer"&gt;#78191&lt;/a&gt;: &lt;code&gt;cmd/fix&lt;/code&gt; panic in edge cases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Beginner translation: these are exactly the kinds of bugs that become random CI failures, odd runtime crashes, or flaky production behavior.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.ratnesh-maurya.com%2Fimages%2Fblog%2Fgo-1-26-2-milestone-breakdown.svg" 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%2Fblog.ratnesh-maurya.com%2Fimages%2Fblog%2Fgo-1-26-2-milestone-breakdown.svg" alt="Go 1.26.2 milestone breakdown" width="1600" height="900"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Download artifacts and checksum verification
&lt;/h2&gt;

&lt;p&gt;Official download page: &lt;a href="https://go.dev/dl/" rel="noopener noreferrer"&gt;go.dev/dl&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Selected Go 1.26.2 artifacts from the official download feed:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Artifact&lt;/th&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;th&gt;SHA256&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;go1.26.2.src.tar.gz&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Source&lt;/td&gt;
&lt;td&gt;33 MB&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2e91ebb6947a96e9436fb2b3926a8802efe63a6d375dffec4f82aa9dbd6fd43b&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;go1.26.2.linux-amd64.tar.gz&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Linux x86-64&lt;/td&gt;
&lt;td&gt;64 MB&lt;/td&gt;
&lt;td&gt;&lt;code&gt;990e6b4bbba816dc3ee129eaeaf4b42f17c2800b88a2166c265ac1a200262282&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;go1.26.2.darwin-arm64.pkg&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;macOS Apple Silicon&lt;/td&gt;
&lt;td&gt;63 MB&lt;/td&gt;
&lt;td&gt;&lt;code&gt;5daa0b7ba59f703c5b6be2bd48437062224fd9244160e8e73a1c9f7eb8a11784&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;go1.26.2.darwin-amd64.pkg&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;macOS Intel&lt;/td&gt;
&lt;td&gt;66 MB&lt;/td&gt;
&lt;td&gt;&lt;code&gt;5eab5ad8943e7666554fddd72ecbcbe64cf8f04197d6e06486fbb395b779fd8d&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;go1.26.2.windows-amd64.msi&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Windows x86-64&lt;/td&gt;
&lt;td&gt;59 MB&lt;/td&gt;
&lt;td&gt;&lt;code&gt;84826eca833548bb2beabe7429052eaaec18faa902fde723898d906b42e59a73&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Why checksum verification matters: it confirms the artifact you downloaded is exactly what Go published.&lt;/p&gt;

&lt;p&gt;Example verification (macOS/Linux shell):&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;-LO&lt;/span&gt; https://go.dev/dl/go1.26.2.linux-amd64.tar.gz
shasum &lt;span class="nt"&gt;-a&lt;/span&gt; 256 go1.26.2.linux-amd64.tar.gz
&lt;span class="c"&gt;# expected: 990e6b4bbba816dc3ee129eaeaf4b42f17c2800b88a2166c265ac1a200262282&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Production-safe upgrade playbook
&lt;/h2&gt;

&lt;p&gt;&lt;br&gt;
If your team has no formal release process yet, just follow the steps in order and keep a rollback version ready.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
  &lt;br&gt;
    Use Go 1.26.2 explicitly in CI images, local dev environments, and build containers. Avoid implicit latest tags.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```dockerfile
FROM golang:1.26.2-alpine
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;br&gt;
  &lt;br&gt;
    Validate what your runner is actually using before tests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```bash
go version
go env GOTOOLCHAIN GOOS GOARCH
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;br&gt;
  &lt;br&gt;
    Start with your existing suite, then add race detection for services that handle concurrency heavily.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```bash
go test ./...
go test ./... -race
go vet ./...
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;br&gt;
  &lt;br&gt;
    Execute &lt;code&gt;govulncheck&lt;/code&gt; and compare findings against your previous baseline.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```bash
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;br&gt;
  &lt;br&gt;
    Add focused tests for URL parsing, HTTP handling, TLS handshakes, and cert verification in critical flows.&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
    Canary first, then staged rollout with explicit SLO gates (error rate, latency, crash loops, build stability).&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
    Preserve the previous working toolchain image/tag so rollback is a fast switch, not a rebuild.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.ratnesh-maurya.com%2Fimages%2Fblog%2Fgo-1-26-2-upgrade-flow.svg" 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%2Fblog.ratnesh-maurya.com%2Fimages%2Fblog%2Fgo-1-26-2-upgrade-flow.svg" alt="Go 1.26.2 upgrade flow" width="1600" height="900"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Copy-paste CI gate (practical baseline)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

go version
go &lt;span class="nb"&gt;env &lt;/span&gt;GOTOOLCHAIN GOOS GOARCH

go &lt;span class="nb"&gt;test&lt;/span&gt; ./...
go &lt;span class="nb"&gt;test&lt;/span&gt; ./... &lt;span class="nt"&gt;-race&lt;/span&gt;
go vet ./...

govulncheck ./...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Should you upgrade now?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Upgrade now (high priority):&lt;/strong&gt; internet-facing services, heavy TLS/cert usage, or strict security posture.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Upgrade soon (scheduled):&lt;/strong&gt; internal services on 1.26.0/1.26.1.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plan migration path:&lt;/strong&gt; older major line users that need broader compatibility testing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Read more
&lt;/h2&gt;

&lt;p&gt;&lt;br&gt;
  The canonical summary of packages touched in 1.26.2.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
  Understand what 1.26 introduced so you can interpret which 1.26.2 fixes are stabilization backports.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
  Official binaries, source tarball, and checksums for every platform.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
  Closed issue set showing exactly what was backported into the patch.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
  Guidance on govulncheck, vulnerability database, and release security policy.&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Data provenance
&lt;/h2&gt;

&lt;p&gt;This article and its visuals are based on:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Official Go release notes and release history.&lt;/li&gt;
&lt;li&gt;Official Go download index and checksums.&lt;/li&gt;
&lt;li&gt;Public GitHub milestone API data for &lt;code&gt;Go1.26.2&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The embedded images in this post are custom summary visuals created from those public sources.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://blog.ratnesh-maurya.com/blog/Go-1-26-2-Released-Security-Fixes-Regression-Patches-and-Upgrade-Playbook" rel="noopener noreferrer"&gt;https://blog.ratnesh-maurya.com/blog/Go-1-26-2-Released-Security-Fixes-Regression-Patches-and-Upgrade-Playbook&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>go</category>
    </item>
    <item>
      <title>cursor-claude-personas: Give Your AI Coding Assistant a Domain Expert Brain in 30 Seconds</title>
      <dc:creator>Ratnesh Maurya</dc:creator>
      <pubDate>Sat, 21 Mar 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/ratneshmaurya/cursor-claude-personas-give-your-ai-coding-assistant-a-domain-expert-brain-in-30-seconds-1i67</link>
      <guid>https://dev.to/ratneshmaurya/cursor-claude-personas-give-your-ai-coding-assistant-a-domain-expert-brain-in-30-seconds-1i67</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.amazonaws.com%2Fuploads%2Farticles%2Fh9idn723xynbf6xlj7ys.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh9idn723xynbf6xlj7ys.png" alt="cursor-claude-personas: Give Your AI Coding Assistant a Domain Expert Brain in 30 Seconds" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  cursor-claude-personas: Give Your AI Coding Assistant a Domain Expert Brain in 30 Seconds
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; — &lt;code&gt;cursor-claude-personas&lt;/code&gt; is a free, open-source collection of 38 role-based AI persona packs for Claude Code, Cursor, and VS Code. Copy one folder into your project, reopen your editor, and your AI assistant instantly behaves like a seasoned specialist — whether that's a senior Python developer, a DevOps engineer, a security expert, or a UI/UX designer.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Problem: Generic AI Gives Generic Code
&lt;/h2&gt;

&lt;p&gt;You have Claude Code or Cursor open. You ask it to add an endpoint. It writes something that works — but it doesn't know your preferred framework patterns, it doesn't follow your domain conventions, and it certainly doesn't remember that you care deeply about SQL index hygiene or GraphQL schema design.&lt;/p&gt;

&lt;p&gt;The usual fix is a long system prompt you paste in every time. Or a &lt;code&gt;.cursorrules&lt;/code&gt; file you spend hours writing. Or endless back-and-forth corrections.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;cursor-claude-personas solves this with a dead-simple copy-paste.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is cursor-claude-personas?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/ratnesh-maurya/cursor-claude-personas" rel="noopener noreferrer"&gt;cursor-claude-personas&lt;/a&gt; is a GitHub repository containing &lt;strong&gt;38 ready-made persona packs&lt;/strong&gt; for AI coding tools. Each persona is a folder with two hidden subdirectories:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;senior-python-developer/
├── .claude/
│ ├── rules/ ← always-on instructions Claude Code reads at session start
│ └── skills/ ← auto-triggered skill docs for specific tasks
└── .cursor/
    ├── rules/ ← always-on instructions Cursor reads at session start
    └── skills/ ← auto-triggered skill docs for specific tasks

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

&lt;/div&gt;



&lt;p&gt;When you copy &lt;code&gt;.claude/&lt;/code&gt; or &lt;code&gt;.cursor/&lt;/code&gt; (or both) into the root of your project, your editor loads those configs automatically. No slash commands. No system prompts. The persona is live the moment you start a new chat session.&lt;/p&gt;

&lt;h3&gt;
  
  
  Supported tools
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What to copy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Claude Code&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.claude/&lt;/code&gt; folder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cursor&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.cursor/&lt;/code&gt; folder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;VS Code&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.claude/&lt;/code&gt; folder (when using Claude-based extensions)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  How to Use It — Step by Step
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Clone the repo
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/ratnesh-maurya/cursor-claude-personas.git

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

&lt;/div&gt;



&lt;p&gt;You only need to clone it once. Keep it around as your personal AI persona library.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Pick the persona that matches your current work
&lt;/h3&gt;

&lt;p&gt;Browse the table in the next section or visit the &lt;a href="https://ratnesh-maurya.github.io/cursor-claude-personas/" rel="noopener noreferrer"&gt;GitHub Pages site&lt;/a&gt; to filter by technology or tag.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Copy the persona into your project
&lt;/h3&gt;

&lt;p&gt;Navigate to your cloned copy and run:&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;# Claude Code only&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; cursor-claude-personas/senior-python-developer/.claude /path/to/your-project/

&lt;span class="c"&gt;# Cursor only&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; cursor-claude-personas/senior-python-developer/.cursor /path/to/your-project/

&lt;span class="c"&gt;# Both tools&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; cursor-claude-personas/senior-python-developer/.claude /path/to/your-project/
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; cursor-claude-personas/senior-python-developer/.cursor /path/to/your-project/

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

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;senior-python-developer&lt;/code&gt; with any persona slug from the list below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Reopen your editor or start a new session
&lt;/h3&gt;

&lt;p&gt;Claude Code and Cursor reload configuration at session start. From that point on, the AI follows the persona's rules, applies its skills automatically, and behaves as a domain expert — without you typing a single extra word.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bonus: Enable the auto-skill router
&lt;/h3&gt;

&lt;p&gt;Each persona includes a special rule file called &lt;code&gt;rules--auto-skill-router.mdc&lt;/code&gt; (&lt;code&gt;.mdc&lt;/code&gt; is the Cursor/Claude rule file format — it is just Markdown with optional YAML frontmatter). This rule tells the AI to automatically select the right skill doc based on what you're working on — so you never need to type &lt;code&gt;/skill&lt;/code&gt; commands manually.&lt;/p&gt;

&lt;p&gt;It is already included when you copy the persona folders. No extra steps required.&lt;/p&gt;




&lt;h2&gt;
  
  
  All 38 Personas
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Persona&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;3d-frontend-developer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Three.js, WebGL, 3D UI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ai-agent-developer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;LLM agents, tool use, orchestration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ai-ml-engineer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Model training, pipelines, MLOps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;azure-developer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Azure services, ARM/Bicep, AKS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;blockchain-web3-developer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Smart contracts, DeFi, Web3 tooling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;blog-website-developer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Content sites, CMS, static generators&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;data-engineer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pipelines, dbt, Spark, warehouses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;devops-cloud-engineer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CI/CD, Kubernetes, IaC, observability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ecommerce-specialist&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Shopify, WooCommerce, checkout flows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fullstack-saas-mvp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Rapid SaaS prototyping, full-stack&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;functional-programming&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Haskell, Clojure, FP patterns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;game-developer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unity, Godot, game loops&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;health-tech-developer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;FHIR, HL7, medical data systems&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;legal-finance-analyst&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Contracts, compliance, financial models&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;marketing-automation&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Email, CRM integrations, analytics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mobile-developer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;React Native, Flutter, iOS/Android&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;n8n-automation-specialist&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;n8n workflows, low-code automation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;odoo-erp-specialist&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Odoo modules, ERP customization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;open-source-maintainer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;OSS governance, reviews, releases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;platform-integrations&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;APIs, webhooks, third-party services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;product-manager&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Roadmaps, specs, user stories&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;qa-testing-engineer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Test strategy, automation, coverage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;saas-startup-founder&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;GTM, metrics, early-stage decisions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;security-engineer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Threat modeling, hardening, audits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;senior-dotnet-developer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;C#, ASP.NET Core, Azure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;senior-elixir-developer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Elixir, Phoenix, OTP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;senior-frontend-developer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;React, TypeScript, frontend architecture&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;senior-golang-developer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Go, microservices, concurrency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;senior-java-developer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Java, Spring Boot, enterprise patterns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;senior-python-developer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Python, APIs, automation, data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;senior-rust-developer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Rust, systems programming, WASM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;seo-specialist&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Technical SEO, Core Web Vitals, schema&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;system-architect&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Service boundaries, scalability, design&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;system-designer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Low-level system design, algorithms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;technical-writer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Docs, onboarding, API clarity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ui-ux-designer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Design systems, accessibility, UX&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;voice-ai-developer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Voice interfaces, TTS, STT, ASR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;wordpress-specialist&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;WordPress, WooCommerce, theme dev&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Not sure where to start? Try &lt;code&gt;senior-python-developer&lt;/code&gt; or &lt;code&gt;senior-frontend-developer&lt;/code&gt; — both are polished starting points that work for a wide range of projects.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Makes This Different From a &lt;code&gt;.cursorrules&lt;/code&gt; File?
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;.cursorrules&lt;/code&gt; file (a single plain-text file at the project root) you write yourself usually contains two or three paragraphs of general instructions. Cursor also supports a &lt;code&gt;.cursor/rules/&lt;/code&gt; directory of individual rule files for more granular control. Both are fine for broad guidance, but neither gives your AI assistant real domain depth out of the box.&lt;/p&gt;

&lt;p&gt;cursor-claude-personas packs in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multiple focused rule files&lt;/strong&gt; — each covering a specific concern (schema design, security, pagination, query patterns, etc.) rather than one sprawling blob of text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skill documents&lt;/strong&gt; — structured reference files that are automatically surfaced when the AI detects it needs them, without you prompting it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Both tool formats simultaneously&lt;/strong&gt; — the same expertise loads whether you are using Claude Code, Cursor, or VS Code Copilot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero prompt engineering on your part&lt;/strong&gt; — you copy two folders and you are done.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key design principle is &lt;strong&gt;depth over breadth&lt;/strong&gt; : one sharp specialist beats five vague generalists.&lt;/p&gt;




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

&lt;p&gt;Imagine you are building a Python REST API with PostgreSQL. You copy in the &lt;code&gt;senior-python-developer&lt;/code&gt; persona. From that point on, when you write a query, the AI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Warns you against &lt;code&gt;WHERE id IN (SELECT ...)&lt;/code&gt; and rewrites it as &lt;code&gt;WHERE id = ANY(ARRAY[...])&lt;/code&gt; with a note about the 10× speedup.&lt;/li&gt;
&lt;li&gt;Adds &lt;code&gt;WHERE deleted_at IS NULL&lt;/code&gt; partial indexes automatically when it sees soft-delete columns.&lt;/li&gt;
&lt;li&gt;Flags missing foreign key indexes before you even run &lt;code&gt;EXPLAIN ANALYZE&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Enforces proper connection pool limits and prepared statement patterns.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of that required you to type a single instruction. It was all encoded in the rules and skills you copied in.&lt;/p&gt;




&lt;h2&gt;
  
  
  How the Folder Structure Works Under the Hood
&lt;/h2&gt;

&lt;p&gt;Each persona ships with two kinds of config files:&lt;/p&gt;

&lt;h3&gt;
  
  
  Rules (&lt;code&gt;rules/&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Rules are always-on markdown files the editor reads at the start of every session. They define the persona's defaults, code style, anti-patterns to avoid, and domain-specific best practices. They are named with a &lt;code&gt;rules--&lt;/code&gt; prefix so they sort together and are easy to identify.&lt;/p&gt;

&lt;h3&gt;
  
  
  Skills (&lt;code&gt;skills/&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Skill documents are structured markdown files with YAML frontmatter. The auto-skill router rule tells the AI to load the relevant skill when it detects you are working on a related task. For example, if you start writing an index migration, the SQL indexing skill is surfaced automatically. If you start wiring up an authentication flow, the auth skill fires.&lt;/p&gt;

&lt;p&gt;This means the AI pulls in deep, specific guidance exactly when it is relevant — not all at once, cluttering its context.&lt;/p&gt;




&lt;h2&gt;
  
  
  Switching Personas Mid-Project
&lt;/h2&gt;

&lt;p&gt;You can swap personas at any time. Just delete the existing &lt;code&gt;.claude/&lt;/code&gt; and &lt;code&gt;.cursor/&lt;/code&gt; folders in your project and copy in a different persona. Reopen your session and the new persona is live.&lt;/p&gt;

&lt;p&gt;You can even mix rules from multiple personas manually if you know what you are doing, but most of the time a single focused persona is all you need.&lt;/p&gt;




&lt;h2&gt;
  
  
  Contributing a New Persona
&lt;/h2&gt;

&lt;p&gt;The project is open source under the MIT license and welcomes contributions. If you want to add a new persona:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fork the repository.&lt;/li&gt;
&lt;li&gt;Create a new folder named after the role (e.g., &lt;code&gt;data-science-researcher&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Add matching &lt;code&gt;.claude/&lt;/code&gt; and &lt;code&gt;.cursor/&lt;/code&gt; subdirectories with rules and skills.&lt;/li&gt;
&lt;li&gt;Make sure the two directories are in sync — the parity check in &lt;code&gt;CONTRIBUTING.md&lt;/code&gt; validates this.&lt;/li&gt;
&lt;li&gt;Open a pull request.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;See &lt;a href="//CONTRIBUTING.md"&gt;CONTRIBUTING.md&lt;/a&gt; for branch naming conventions, commit message format, and the full persona checklist.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where to Get It
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub repository&lt;/strong&gt; : &lt;a href="https://github.com/ratnesh-maurya/cursor-claude-personas" rel="noopener noreferrer"&gt;https://github.com/ratnesh-maurya/cursor-claude-personas&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Pages site&lt;/strong&gt; (browse and filter personas): &lt;a href="https://ratnesh-maurya.github.io/cursor-claude-personas/" rel="noopener noreferrer"&gt;https://ratnesh-maurya.github.io/cursor-claude-personas/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;License&lt;/strong&gt; : MIT — free for personal and commercial use.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If it saves you time, star the repo. It helps other developers discover it.&lt;/p&gt;




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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;What it is&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;38 role-based AI persona packs for Claude Code, Cursor, and VS Code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;What it does&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Shapes your AI coding assistant into a domain specialist — instantly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;How to install&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Clone the repo, copy one persona folder, reopen your editor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Time to set up&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Under 30 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free and open source (MIT)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Requires&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Claude Code, Cursor, or VS Code with Copilot&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Clone it, copy a persona, and ship better code.&lt;/p&gt;

</description>
      <category>toolinganddx</category>
    </item>
    <item>
      <title>Chrome 144 Introduces the &lt;geolocation&gt; Element: Declarative Location Access for Modern Web Apps</title>
      <dc:creator>Ratnesh Maurya</dc:creator>
      <pubDate>Tue, 24 Feb 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/ratneshmaurya/chrome-144-introduces-the-element-declarative-location-access-for-modern-web-apps-29ie</link>
      <guid>https://dev.to/ratneshmaurya/chrome-144-introduces-the-element-declarative-location-access-for-modern-web-apps-29ie</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.amazonaws.com%2Fuploads%2Farticles%2Fq7lva3dib1x9h3dx1mg7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq7lva3dib1x9h3dx1mg7.png" alt="Chrome 144 Introduces the &amp;lt;geolocation&amp;gt; Element: Declarative Location Access for Modern Web Apps" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Chrome 144 Introduces the &lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt; Element: Declarative Location Access for Modern Web Apps
&lt;/h1&gt;

&lt;p&gt;Chrome 144 introduces a new declarative &lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt; HTML element that changes how web applications request location access. Instead of calling &lt;code&gt;navigator.geolocation.getCurrentPosition()&lt;/code&gt; imperatively from JavaScript, developers can now place a browser-controlled element directly in the DOM.&lt;/p&gt;

&lt;p&gt;This post is for frontend engineers, platform engineers, and privacy-conscious developers who want to understand how this new model works and whether they should migrate.&lt;/p&gt;

&lt;p&gt;By the end of this article, you'll understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What the &lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt; element is&lt;/li&gt;
&lt;li&gt;How it works internally&lt;/li&gt;
&lt;li&gt;How it compares to the traditional Geolocation API&lt;/li&gt;
&lt;li&gt;How to implement it with proper fallback support&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why Chrome Introduced &lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Historically, location access was triggered via JavaScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geolocation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCurrentPosition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This caused several problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Permission prompts appearing on page load&lt;/li&gt;
&lt;li&gt;Users denying requests due to poor timing&lt;/li&gt;
&lt;li&gt;Quiet permission blocking by browsers&lt;/li&gt;
&lt;li&gt;Complicated permission state handling in code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt; element solves this by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requiring explicit user interaction&lt;/li&gt;
&lt;li&gt;Providing a visible, browser-controlled UI&lt;/li&gt;
&lt;li&gt;Reducing boilerplate permission code&lt;/li&gt;
&lt;li&gt;Improving recovery from previously denied states&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Chrome origin trials showed measurable improvements in successful permission grants and recovery rates.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is the &lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt; Element?
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt; element is part of the WICG "Permission Elements" proposal. It acts as a declarative wrapper around the existing Geolocation API.&lt;/p&gt;

&lt;p&gt;It renders as a browser-controlled button such as:&lt;/p&gt;

&lt;p&gt;When clicked:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The browser shows the location permission dialog.&lt;/li&gt;
&lt;li&gt;If granted, it dispatches a &lt;code&gt;location&lt;/code&gt; event.&lt;/li&gt;
&lt;li&gt;The element exposes either:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;position&lt;/code&gt; (success)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;error&lt;/code&gt; (failure)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Attributes Explained
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;autolocate&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Automatically attempts to retrieve location when inserted into the DOM — &lt;strong&gt;only if permission was already granted&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;geolocation&lt;/span&gt; &lt;span class="na"&gt;autolocate&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/geolocation&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;It does not trigger surprise permission prompts.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;code&gt;watch&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Continuously tracks position updates, similar to &lt;code&gt;watchPosition()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;geolocation&lt;/span&gt; &lt;span class="na"&gt;watch&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/geolocation&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Without &lt;code&gt;watch&lt;/code&gt;, it behaves like &lt;code&gt;getCurrentPosition()&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;code&gt;accuracymode&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Controls precision level.&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;geolocation&lt;/span&gt; &lt;span class="na"&gt;accuracymode=&lt;/span&gt;&lt;span class="s"&gt;"precise"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/geolocation&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Possible values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;"approximate"&lt;/code&gt; (default)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;"precise"&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When set to &lt;code&gt;"precise"&lt;/code&gt;, the browser may:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Change icon (crosshair instead of pin)&lt;/li&gt;
&lt;li&gt;Update label text&lt;/li&gt;
&lt;li&gt;Request higher accuracy internally&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Basic Implementation
&lt;/h2&gt;

&lt;p&gt;Minimal example:&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;geolocation&lt;/span&gt; &lt;span class="na"&gt;onlocation=&lt;/span&gt;&lt;span class="s"&gt;"handleLocation(event)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/geolocation&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleLocation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;longitude&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Location:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;No permission logic required.&lt;/p&gt;

&lt;p&gt;The browser handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Permission prompts&lt;/li&gt;
&lt;li&gt;Recovery dialogs&lt;/li&gt;
&lt;li&gt;Error states&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Adding Progressive Enhancement (Fallback)
&lt;/h2&gt;

&lt;p&gt;You must support non-Chrome browsers.&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;geolocation&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"geo"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"fallback-btn"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Use my location
  &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/geolocation&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;HTMLGeolocationElement&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;geo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;geo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;geo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;location&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;geo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;geo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fallback-btn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geolocation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCurrentPosition&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This ensures compatibility across browsers.&lt;/p&gt;




&lt;h2&gt;
  
  
  Browser UI Behavior
&lt;/h2&gt;

&lt;p&gt;When clicked, Chrome displays the standard location permission dialog:&lt;/p&gt;

&lt;p&gt;If previously denied, Chrome shows a recovery prompt:&lt;/p&gt;

&lt;p&gt;This makes permission recovery significantly easier compared to manual browser settings navigation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Styling Restrictions (Security Guardrails)
&lt;/h2&gt;

&lt;p&gt;To prevent abuse or clickjacking, Chrome enforces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Minimum size&lt;/li&gt;
&lt;li&gt;Opacity must remain &lt;code&gt;1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;No negative margins&lt;/li&gt;
&lt;li&gt;No deceptive transforms&lt;/li&gt;
&lt;li&gt;Enforced contrast ratio&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can style it, but you cannot make it invisible or misleading.&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 css"&gt;&lt;code&gt;&lt;span class="nt"&gt;geolocation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;But you cannot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hide it&lt;/li&gt;
&lt;li&gt;Make it 1px wide&lt;/li&gt;
&lt;li&gt;Overlay fake UI elements&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt; vs &lt;code&gt;navigator.geolocation&lt;/code&gt;
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Traditional API&lt;/th&gt;
&lt;th&gt;&lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Permission Trigger&lt;/td&gt;
&lt;td&gt;Script-based&lt;/td&gt;
&lt;td&gt;User-click only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Boilerplate Code&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Minimal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recovery Flow&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;Built-in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Styling Control&lt;/td&gt;
&lt;td&gt;Full&lt;/td&gt;
&lt;td&gt;Guard-railed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Privacy Model&lt;/td&gt;
&lt;td&gt;Developer-controlled&lt;/td&gt;
&lt;td&gt;Browser-mediated&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  When Should You Use It?
&lt;/h2&gt;

&lt;p&gt;Use &lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt; if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need a simple "Use my location" feature&lt;/li&gt;
&lt;li&gt;You want better permission recovery&lt;/li&gt;
&lt;li&gt;You want reduced code complexity&lt;/li&gt;
&lt;li&gt;You care about user trust and privacy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stick to the traditional API if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need fine-grained timing control&lt;/li&gt;
&lt;li&gt;You require silent background tracking&lt;/li&gt;
&lt;li&gt;You are building real-time geo-heavy apps (ride-sharing, logistics dashboards)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Production Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Feature-detect &lt;code&gt;HTMLGeolocationElement&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Provide a JS fallback&lt;/li&gt;
&lt;li&gt;Avoid using &lt;code&gt;autolocate&lt;/code&gt; unnecessarily&lt;/li&gt;
&lt;li&gt;Test denied → recovery flows&lt;/li&gt;
&lt;li&gt;Validate UX on mobile devices&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;The &lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt; element is a significant shift toward declarative permission handling on the web. It reduces developer complexity while improving privacy, trust, and user experience.&lt;/p&gt;

&lt;p&gt;For simple location-based features, it should become the default pattern in Chrome-supported environments.&lt;/p&gt;

&lt;p&gt;However, since it's currently Chrome-specific and incubating, production systems must still include fallback support.&lt;/p&gt;

&lt;p&gt;If you're building modern web applications and care about privacy-first UX, this is worth adopting early — but do it responsibly with progressive enhancement.&lt;/p&gt;

</description>
      <category>webdev</category>
    </item>
    <item>
      <title>Five Caching Strategies Every Backend Dev Should Know</title>
      <dc:creator>Ratnesh Maurya</dc:creator>
      <pubDate>Tue, 24 Feb 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/ratneshmaurya/five-caching-strategies-every-backend-dev-should-know-3oi8</link>
      <guid>https://dev.to/ratneshmaurya/five-caching-strategies-every-backend-dev-should-know-3oi8</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.amazonaws.com%2Fuploads%2Farticles%2Famt5t4xtt52vqpks3enp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Famt5t4xtt52vqpks3enp.png" alt="Five Caching Strategies Every Backend Dev Should Know" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Five Caching Strategies Every Backend Dev Should Know
&lt;/h1&gt;

&lt;p&gt;If you build backend systems, you eventually run into &lt;strong&gt;caching&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Someone says “just put Redis in front of it” and suddenly your app is faster… until you start seeing stale data, cache misses, and weird bugs when you deploy.&lt;/p&gt;

&lt;p&gt;This post explains &lt;strong&gt;five core caching strategies&lt;/strong&gt; in plain language:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cache-Aside&lt;/li&gt;
&lt;li&gt;Read-Through&lt;/li&gt;
&lt;li&gt;Write-Through&lt;/li&gt;
&lt;li&gt;Write-Back&lt;/li&gt;
&lt;li&gt;Write-Around&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You’ll see &lt;strong&gt;how each one works&lt;/strong&gt; , &lt;strong&gt;what can go wrong&lt;/strong&gt; , and &lt;strong&gt;when to use it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A cache is just a faster, smaller copy of some data. The hard part is &lt;strong&gt;keeping that copy useful&lt;/strong&gt; : when to fill it, when to read from it, and when to update or skip it.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Cache-Aside (Lazy Loading)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Idea:&lt;/strong&gt; The application talks to the cache and the database. It “checks the cache first, then falls back to the DB” and fills the cache on a miss.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;If the key is in the cache (a hit), just return it. Super fast.

If the key is missing, the app queries the database instead.

The app stores the result in the cache and returns it to the user.

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why people love it&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simple and flexible&lt;/strong&gt; : logic lives in your code; you control what goes in the cache.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resilient&lt;/strong&gt; : if the cache dies, the app can still read from the DB (just slower).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory-efficient&lt;/strong&gt; : only data that is actually read gets cached.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What can go wrong&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;first&lt;/strong&gt; request for a key is slow (cold cache).&lt;/li&gt;
&lt;li&gt;If the DB is updated &lt;strong&gt;outside&lt;/strong&gt; your code path (e.g. admin tool, another service), the cache can serve &lt;strong&gt;stale data&lt;/strong&gt; until TTL expires or you manually invalidate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When to use&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Great default for &lt;strong&gt;read-heavy&lt;/strong&gt; apps (blogs, product catalogs, many dashboards).&lt;/li&gt;
&lt;li&gt;When you’re just adding caching to an existing codebase and want full control.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Read-Through
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Idea:&lt;/strong&gt; The application pretends the &lt;strong&gt;cache is the main database&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It calls the cache for every read. On a miss, the &lt;strong&gt;cache layer itself&lt;/strong&gt; fetches from the DB, stores the result, and returns it.&lt;/p&gt;

&lt;p&gt;With &lt;strong&gt;Cache-Aside&lt;/strong&gt; , your app code calls both cache and DB. With &lt;strong&gt;Read-Through&lt;/strong&gt; , your app only calls the cache; a loader behind the cache talks to the DB.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cleaner application code&lt;/strong&gt; : your code only knows “get from cache”.&lt;/li&gt;
&lt;li&gt;Cache libraries or infrastructure can handle loading, retries, and metrics.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If some writes go &lt;strong&gt;directly to the DB&lt;/strong&gt; (bypassing the cache API), the cache can easily become &lt;strong&gt;stale&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You need a cache provider or library that supports read-through loading.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When to use&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Larger teams where you want &lt;strong&gt;centralized cache logic&lt;/strong&gt; , not ad-hoc caching scattered everywhere.&lt;/li&gt;
&lt;li&gt;Situations where infra/platform team owns the cache layer.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Write-Through
&lt;/h2&gt;

&lt;p&gt;So far we talked about reads. Now let’s talk about &lt;strong&gt;writes&lt;/strong&gt; : how we keep cache and DB in sync.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Write-Through&lt;/strong&gt; means:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;On a write, update the cache &lt;strong&gt;and&lt;/strong&gt; the database synchronously. Only when both succeed is the write considered “done”.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Flow&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User updates something (e.g. changes quantity in a cart).&lt;/li&gt;
&lt;li&gt;App writes the new value into the &lt;strong&gt;cache&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;App also writes the same value into the &lt;strong&gt;database&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Only if both succeed do we return “OK” to the user.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Strong consistency&lt;/strong&gt; : cache and DB always match for that key.&lt;/li&gt;
&lt;li&gt;Reads from the cache always see the latest value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Slower writes&lt;/strong&gt; : every write has to hit both cache and DB before returning.&lt;/li&gt;
&lt;li&gt;If DB is slow, your API write latency is also slow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When to use&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When correctness matters more than raw speed:

&lt;ul&gt;
&lt;li&gt;balances in a &lt;strong&gt;wallet / bank&lt;/strong&gt; ,&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;inventory&lt;/strong&gt; in an e‑commerce site,&lt;/li&gt;
&lt;li&gt;data where a stale read would be really bad.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Write-Back (Write-Behind)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Write-Back&lt;/strong&gt; trades strict consistency for &lt;strong&gt;speed&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;On a write, update &lt;strong&gt;only the cache&lt;/strong&gt; and return success quickly. Later, an async process flushes those changes to the database.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Flow&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User sends a write.&lt;/li&gt;
&lt;li&gt;App writes to cache and returns &lt;code&gt;200 OK&lt;/code&gt; immediately.&lt;/li&gt;
&lt;li&gt;A background worker or the cache itself periodically writes batched updates into the DB.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Very fast writes&lt;/strong&gt; : app isn’t blocked waiting for DB.&lt;/li&gt;
&lt;li&gt;Great for high-throughput workloads:

&lt;ul&gt;
&lt;li&gt;counters (views, likes),&lt;/li&gt;
&lt;li&gt;logs / telemetry,&lt;/li&gt;
&lt;li&gt;social feed events.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Risk of data loss&lt;/strong&gt; : if the cache crashes before flushing to DB, those changes are gone.&lt;/li&gt;
&lt;li&gt;DB is &lt;strong&gt;eventually&lt;/strong&gt; updated, not immediately.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When to use&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write-heavy workloads where losing a tiny fraction of data is acceptable:

&lt;ul&gt;
&lt;li&gt;metrics, dashboards, click-streams,&lt;/li&gt;
&lt;li&gt;non-critical logs.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. Write-Around
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Write-Around&lt;/strong&gt; takes a different approach:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Writes &lt;strong&gt;skip the cache&lt;/strong&gt; and go straight to the DB. The cache is only filled later when data is read.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Flow&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A write goes &lt;strong&gt;directly&lt;/strong&gt; into the database.&lt;/li&gt;
&lt;li&gt;The cache is &lt;strong&gt;not&lt;/strong&gt; updated.&lt;/li&gt;
&lt;li&gt;On the next read, the app (or cache) sees a &lt;strong&gt;miss&lt;/strong&gt; :

&lt;ul&gt;
&lt;li&gt;loads from DB,&lt;/li&gt;
&lt;li&gt;populates the cache,&lt;/li&gt;
&lt;li&gt;and returns the value.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prevents “polluting” the cache with data that is &lt;strong&gt;written but rarely read&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Good when you have big write batches (imports, ETL jobs) that users won’t read immediately.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;first read&lt;/strong&gt; after a write is always a &lt;strong&gt;cache miss&lt;/strong&gt; (slower).&lt;/li&gt;
&lt;li&gt;More frequent DB reads if many keys are only read once.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When to use&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Large imports, archival data, logs that might be read only occasionally.&lt;/li&gt;
&lt;li&gt;Systems where memory is tight and you want the cache to focus on &lt;strong&gt;truly hot&lt;/strong&gt; data.&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;Here’s a quick comparison of these five strategies using the labels you provided.&lt;/p&gt;




&lt;h2&gt;
  
  
  How teams typically choose
&lt;/h2&gt;

&lt;p&gt;To connect this with the interactive content you built:&lt;/p&gt;

&lt;p&gt;These charts show two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cache-Aside&lt;/strong&gt; dominates in real systems because it’s &lt;strong&gt;simple and resilient&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write-Back&lt;/strong&gt; gives the fastest writes but carries the most risk; &lt;strong&gt;Write-Through&lt;/strong&gt; is safest but slower on each write.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Which caching strategy should you pick? (a practical rule-set)
&lt;/h2&gt;

&lt;p&gt;If you only remember one thing from this post, remember this: &lt;strong&gt;you pick a caching strategy based on the cost of a stale read and the cost of a slow write.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here’s a fast, real-world decision guide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Most read-heavy apps&lt;/strong&gt; (catalogs, blogs, dashboards):&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;You want a clean abstraction and centralized caching&lt;/strong&gt; (platform/infra owned):&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A stale read would be painful&lt;/strong&gt; (wallet balances, inventory, “did my payment go through?”):&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Writes are hot and you can tolerate some eventual consistency&lt;/strong&gt; (counters, analytics, clickstream):&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;You write lots of data that is rarely read&lt;/strong&gt; (imports, ETL, logs):&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Two failure modes teams hit in production (and what to do)
&lt;/h2&gt;

&lt;p&gt;Caching rarely fails in obvious ways. It fails with “the DB is melting” or “why is data stale?”. Two patterns show up everywhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  1) Cache stampede (thundering herd)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt; a hot key expires (or cache restarts), and suddenly thousands of requests miss at once and slam the DB.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mitigations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Request coalescing / single-flight&lt;/strong&gt; : only one request recomputes the value; others wait and reuse it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stale-while-revalidate&lt;/strong&gt; : keep serving a slightly stale value while one background refresh updates it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Jittered TTLs&lt;/strong&gt; : add randomization to expiration times so many keys don’t expire at the same second.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2) Hot key / hotspotting
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt; one key becomes so popular (home feed, trending item, auth config) that a single cache shard or a single DB row gets hammered.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mitigations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Shard the key&lt;/strong&gt; (e.g. &lt;code&gt;trending:v1:0..N&lt;/code&gt;) and merge results.&lt;/li&gt;
&lt;li&gt;Use a &lt;strong&gt;two-layer cache&lt;/strong&gt; : per-instance in-memory (tiny TTL) + shared Redis.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Precompute&lt;/strong&gt; or cache at a higher level (edge/CDN) if the data is public.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What to monitor so caching doesn’t become “magic”
&lt;/h2&gt;

&lt;p&gt;Whatever strategy you choose, watch these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cache hit rate&lt;/strong&gt; (overall and by endpoint)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DB QPS&lt;/strong&gt; (does caching actually reduce it?)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;p95/p99 latency&lt;/strong&gt; (cache helps only if tail latency improves)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Eviction rate / memory pressure&lt;/strong&gt; (are you constantly evicting hot data?)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stale reads / correctness signals&lt;/strong&gt; (app-specific: inventory mismatches, stale dashboards, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you can’t measure these, caching will eventually surprise you.&lt;/p&gt;




&lt;h2&gt;
  
  
  Putting it all together (for a newbie)
&lt;/h2&gt;

&lt;p&gt;If you’re just starting with caching:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Start with Cache-Aside&lt;/strong&gt; for reads. It’s simple, safe, and easy to reason about.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Add Read-Through&lt;/strong&gt; if you want a cleaner abstraction and your cache provider supports it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For writes:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Whatever you choose, always:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With just these five strategies, you can handle most caching problems you’ll run into as a backend engineer.&lt;/p&gt;

</description>
      <category>backend</category>
    </item>
    <item>
      <title>How Files Are Stored, Deleted, and Copied Inside Your Computer</title>
      <dc:creator>Ratnesh Maurya</dc:creator>
      <pubDate>Fri, 20 Feb 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/ratneshmaurya/how-files-are-stored-deleted-and-copied-inside-your-computer-2ojg</link>
      <guid>https://dev.to/ratneshmaurya/how-files-are-stored-deleted-and-copied-inside-your-computer-2ojg</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.amazonaws.com%2Fuploads%2Farticles%2Fn0htb1znah4enpcsnn7q.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn0htb1znah4enpcsnn7q.jpg" alt="How Files Are Stored, Deleted, and Copied Inside Your Computer" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  How Files Are Stored, Deleted, and Copied Inside Your Computer
&lt;/h1&gt;

&lt;p&gt;Have you ever noticed something interesting?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deleting a file happens instantly.&lt;/li&gt;
&lt;li&gt;Copying a file takes time.&lt;/li&gt;
&lt;li&gt;Moving a file is sometimes instant and sometimes slow.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;If you're new to operating systems and storage internals, this article explains everything in simple terms using real-world analogies, while also giving you a deeper technical understanding of what’s happening behind the scenes.&lt;/p&gt;

&lt;p&gt;By the end, you’ll understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How files are stored on disk&lt;/li&gt;
&lt;li&gt;Why delete is fast&lt;/li&gt;
&lt;li&gt;Why copy takes time&lt;/li&gt;
&lt;li&gt;Whether files are really deleted&lt;/li&gt;
&lt;li&gt;How HDD and SSD behave differently&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How Files Are Actually Stored on Disk
&lt;/h2&gt;

&lt;p&gt;Your computer does not store files the way you see them in folders.&lt;/p&gt;

&lt;p&gt;Internally, storage is divided into:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Data Blocks (or clusters)&lt;/strong&gt; – These contain the actual bytes of your file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metadata&lt;/strong&gt; – Information about the file:

&lt;ul&gt;
&lt;li&gt;File name&lt;/li&gt;
&lt;li&gt;File size&lt;/li&gt;
&lt;li&gt;Location of data blocks&lt;/li&gt;
&lt;li&gt;Permissions&lt;/li&gt;
&lt;li&gt;Created/modified timestamps&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A file system (like NTFS, ext4, FAT32) manages this structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example File Systems
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Windows → NTFS&lt;/li&gt;
&lt;li&gt;Linux → ext4&lt;/li&gt;
&lt;li&gt;USB drives → FAT32&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each filesystem maintains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A directory entry (file name)&lt;/li&gt;
&lt;li&gt;A metadata record (inode in Linux, MFT entry in NTFS)&lt;/li&gt;
&lt;li&gt;Pointers to the actual disk blocks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can think of it like a database that tracks where your file data lives on disk.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real-Life Analogy: A Library
&lt;/h2&gt;

&lt;p&gt;Imagine this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;library catalog&lt;/strong&gt; = filesystem metadata&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;books on shelves&lt;/strong&gt; = actual file data&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;shelf location number&lt;/strong&gt; = pointer to disk blocks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you open a file:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The system checks the catalog.&lt;/li&gt;
&lt;li&gt;It finds the shelf location.&lt;/li&gt;
&lt;li&gt;It retrieves the book (data blocks).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now let’s see what happens during delete and copy.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Deleting a File Is Instant
&lt;/h2&gt;

&lt;p&gt;When you delete a file, the system usually does &lt;strong&gt;not erase the data immediately&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead, it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Removes the file name from the directory.&lt;/li&gt;
&lt;li&gt;Marks its data blocks as “free”.&lt;/li&gt;
&lt;li&gt;Updates metadata records.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;The actual bytes are still physically on disk — but the system marks that space as available for reuse.&lt;/p&gt;

&lt;p&gt;Since this is mainly a metadata update, it happens very fast.&lt;/p&gt;

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

&lt;p&gt;Deleting is like removing the book’s entry from the library catalog.&lt;/p&gt;

&lt;p&gt;The book is still on the shelf — but nobody knows it exists anymore.&lt;/p&gt;

&lt;p&gt;This is why:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;File recovery tools can restore deleted files.&lt;/li&gt;
&lt;li&gt;Secure deletion requires special tools.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Do Files Actually Get Deleted?
&lt;/h2&gt;

&lt;p&gt;Short answer: &lt;strong&gt;Not immediately.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;They are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Marked as free space&lt;/li&gt;
&lt;li&gt;Eventually overwritten by new data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On SSDs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The operating system sends a &lt;strong&gt;TRIM command&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The SSD later clears unused blocks internally&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Deletion is logical first, physical later.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Copying a File Takes Time
&lt;/h2&gt;

&lt;p&gt;Copying is completely different.&lt;/p&gt;

&lt;p&gt;When copying:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The system reads every block from the source file.&lt;/li&gt;
&lt;li&gt;Loads it into memory (RAM).&lt;/li&gt;
&lt;li&gt;Writes those blocks to a new location.&lt;/li&gt;
&lt;li&gt;Creates new metadata for the copied file.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This process depends on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Disk speed&lt;/li&gt;
&lt;li&gt;File size&lt;/li&gt;
&lt;li&gt;HDD vs SSD&lt;/li&gt;
&lt;li&gt;CPU and memory performance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since the entire file’s data must be read and written, copying takes time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;Copying a 10GB file means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reading 10GB&lt;/li&gt;
&lt;li&gt;Writing 10GB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s 20GB of total I/O operations.&lt;/p&gt;

&lt;p&gt;That’s real physical work being done.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Moving Files Is Sometimes Instant
&lt;/h2&gt;

&lt;p&gt;This depends on where you move the file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Case 1: Same Drive (Same Filesystem)
&lt;/h3&gt;

&lt;p&gt;Move = metadata update only.&lt;/p&gt;

&lt;p&gt;The system just:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Updates the directory entry&lt;/li&gt;
&lt;li&gt;Keeps data blocks unchanged&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is very fast.&lt;/p&gt;

&lt;h3&gt;
  
  
  Case 2: Different Drive
&lt;/h3&gt;

&lt;p&gt;Move becomes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Copy the file&lt;/li&gt;
&lt;li&gt;Delete the original&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So it takes time.&lt;/p&gt;

&lt;p&gt;That’s why:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Moving inside C: is instant&lt;/li&gt;
&lt;li&gt;Moving from C: to D: takes time&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  HDD vs SSD Behavior
&lt;/h2&gt;

&lt;h3&gt;
  
  
  HDD (Hard Disk Drive)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Mechanical spinning disk&lt;/li&gt;
&lt;li&gt;Moving read/write head&lt;/li&gt;
&lt;li&gt;Slower seek time&lt;/li&gt;
&lt;li&gt;Sequential reads are faster&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Copying large files can be slower because of mechanical movement.&lt;/p&gt;

&lt;h3&gt;
  
  
  SSD (Solid State Drive)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;No moving parts&lt;/li&gt;
&lt;li&gt;Much faster random access&lt;/li&gt;
&lt;li&gt;Uses flash memory cells&lt;/li&gt;
&lt;li&gt;Uses TRIM and garbage collection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Deletion marks blocks unused first. The physical erase happens later internally.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Happens in the OS Layer
&lt;/h2&gt;

&lt;p&gt;At the system-call level (Linux example):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;delete&lt;/code&gt; → &lt;code&gt;unlink()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;copy&lt;/code&gt; → multiple &lt;code&gt;read()&lt;/code&gt; and &lt;code&gt;write()&lt;/code&gt; calls&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;move (same filesystem)&lt;/code&gt; → &lt;code&gt;rename()&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;strace &lt;span class="nb"&gt;rm &lt;/span&gt;file.txt

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

&lt;/div&gt;



&lt;p&gt;You'll see something like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;unlink("file.txt")&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That's simply removing the reference to the file.&lt;/p&gt;

&lt;p&gt;Copying involves many &lt;code&gt;read()&lt;/code&gt; and &lt;code&gt;write()&lt;/code&gt; operations, which take time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Deleting Many Files Can Be Slow
&lt;/h2&gt;

&lt;p&gt;Deleting one file is fast.&lt;/p&gt;

&lt;p&gt;Deleting thousands of small files can take time because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each file has metadata.&lt;/li&gt;
&lt;li&gt;Directory entries must be updated.&lt;/li&gt;
&lt;li&gt;Journaling systems must commit changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even metadata operations add up when repeated many times.&lt;/p&gt;




&lt;h2&gt;
  
  
  Secure Deletion
&lt;/h2&gt;

&lt;p&gt;Normal delete:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Marks space as free&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Secure delete:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Overwrites data blocks&lt;/li&gt;
&lt;li&gt;Ensures recovery is impossible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On SSDs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use drive-level secure erase&lt;/li&gt;
&lt;li&gt;Or enable full-disk encryption&lt;/li&gt;
&lt;/ul&gt;




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

&lt;ul&gt;
&lt;li&gt;Delete is fast because it removes metadata, not actual data.&lt;/li&gt;
&lt;li&gt;Copy is slow because it transfers real bytes.&lt;/li&gt;
&lt;li&gt;Move is fast only within the same filesystem.&lt;/li&gt;
&lt;li&gt;Deleted files remain until overwritten.&lt;/li&gt;
&lt;li&gt;SSDs and HDDs behave differently.&lt;/li&gt;
&lt;li&gt;Secure deletion requires special handling.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What to explore next
&lt;/h2&gt;

&lt;p&gt;File operations look simple from the UI, but under the surface the OS is managing metadata, block allocation, caching, journaling, and hardware coordination.&lt;/p&gt;

&lt;p&gt;If this interested you, here are some rabbit holes worth going down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;strace&lt;/code&gt; on Linux&lt;/strong&gt; — run &lt;code&gt;strace rm file.txt&lt;/code&gt; or &lt;code&gt;strace cp src dst&lt;/code&gt; to see the actual system calls involved&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filesystem internals&lt;/strong&gt; — look into how ext4 journaling works, or how ZFS and Btrfs use copy-on-write to make snapshots nearly free&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flash Translation Layer&lt;/strong&gt; — how SSDs remap logical blocks to physical NAND pages, and why TRIM exists&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data recovery tools&lt;/strong&gt; — tools like &lt;code&gt;testdisk&lt;/code&gt; and &lt;code&gt;photorec&lt;/code&gt; exploit the fact that "deleted" data is still on disk&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The next time a file deletes instantly, you'll know — it wasn't magic. It was just a metadata update.&lt;/p&gt;

</description>
      <category>systemdesign</category>
    </item>
    <item>
      <title>The Mechanics of Compression: How 100GB Becomes 25GB</title>
      <dc:creator>Ratnesh Maurya</dc:creator>
      <pubDate>Thu, 19 Feb 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/ratneshmaurya/the-mechanics-of-compression-how-100gb-becomes-25gb-2bh6</link>
      <guid>https://dev.to/ratneshmaurya/the-mechanics-of-compression-how-100gb-becomes-25gb-2bh6</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.amazonaws.com%2Fuploads%2Farticles%2Fx536l5x6g3dqtjdaxgkg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx536l5x6g3dqtjdaxgkg.png" alt="The Mechanics of Compression: How 100GB Becomes 25GB" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Mechanics of Compression: How 100GB Becomes 25GB
&lt;/h2&gt;

&lt;p&gt;In an era of 4K streaming and massive cloud databases, we often take for granted that a 100GB backup can be shrunk down to 25GB. It isn’t magic—and it isn’t just “squeezing” bits. It’s a careful process of spotting patterns, removing redundancy, and using mathematical shorthand so that the same information takes less space. This post explains how that works in plain terms, so you can understand what happens under the hood when you zip a folder or stream a video.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The Core Idea: Redundancy Is Waste
&lt;/h2&gt;

&lt;p&gt;At its heart, compression is about &lt;strong&gt;efficiency&lt;/strong&gt;. Most data is repetitive. The same words, phrases, or pixel patterns show up again and again. If the computer has already seen a pattern once, it doesn’t need to store it again in full—it can refer back to it or describe it in fewer bits.&lt;/p&gt;

&lt;p&gt;Think of a recipe that says “add salt” five times. You could write “add salt” five times, or you could write “add salt (×5).” The second version carries the same information in less space. Compression algorithms do something similar: they find repetition and describe it more compactly.&lt;/p&gt;

&lt;p&gt;So the main job of any compression scheme is to &lt;strong&gt;find redundancy&lt;/strong&gt; and &lt;strong&gt;encode it in fewer bits&lt;/strong&gt; without losing the ability to recover the original data when needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Real-Life Example: Compressing a Book with Repeated Words
&lt;/h3&gt;

&lt;p&gt;Imagine a &lt;strong&gt;book&lt;/strong&gt; where the same words appear again and again. Words like "the," "and," and "to" might show up thousands of times. Instead of writing the full word every time, we could agree on a &lt;strong&gt;legend&lt;/strong&gt; at the start and replace each repeated word with a short &lt;strong&gt;sub-symbol&lt;/strong&gt;. Anyone with the legend can reconstruct the original text exactly.&lt;/p&gt;

&lt;p&gt;Suppose we define a small dictionary at the top of the page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Legend: @ = the | # = and | % = to | § = of

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

&lt;/div&gt;



&lt;p&gt;Now take a normal sentence and "compress" it by substituting:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Original (longer):&lt;/strong&gt;"The king and the queen went to the castle and stayed there for the rest of the day."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compressed (shorter):&lt;/strong&gt;"@ king # @ queen went % @ castle # stayed there for @ rest § @ day."&lt;/p&gt;

&lt;p&gt;We still have the same meaning, but we used one character (@, #, %, §) wherever a repeated word appeared. The &lt;strong&gt;legend&lt;/strong&gt; is the "dictionary"—it has to be stored or sent once so the reader can decode. For a whole book, if "the" appears 2,000 times, we save (3 − 1) × 2,000 = 4,000 characters just on that one word. Add "and," "to," "of," and other frequent words, and the book shrinks noticeably without losing a single word.&lt;/p&gt;

&lt;p&gt;This is exactly the idea behind &lt;strong&gt;dictionary coding&lt;/strong&gt; and &lt;strong&gt;Huffman-style&lt;/strong&gt; compression: find what repeats, assign it a short code, and use that code everywhere. Real compressors do this automatically; they don't need a human to write the legend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A real experiment from the wild:&lt;/strong&gt; Researchers applied this idea to the full text of &lt;strong&gt;"Alice's Adventures in Wonderland"&lt;/strong&gt; by Lewis Carroll. They treated each &lt;em&gt;word&lt;/em&gt; as a symbol, counted how often it appeared, and assigned &lt;strong&gt;shorter codes to the most frequent words&lt;/strong&gt; (like "the," "and," "to," "a") and &lt;strong&gt;longer codes to rare words&lt;/strong&gt; (like "wretched," "yawned"). The result: the text went from &lt;strong&gt;164 KB down to 109 KB&lt;/strong&gt; —about &lt;strong&gt;one-third smaller&lt;/strong&gt; —with no information lost (&lt;a href="https://www.nayuki.io/page/huffman-coding-english-words" rel="noopener noreferrer"&gt;&lt;em&gt;Huffman-coding English words&lt;/em&gt;&lt;/a&gt;, Project Nayuki—includes original text from Project Gutenberg, input/output file sizes, and codebook samples). The same technique—replace repeated words with shorter symbols, and keep a mapping so we can decode—is what powers the compression we use every day in ZIP files and beyond.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Lossless vs. Lossy: Two Different Goals
&lt;/h2&gt;

&lt;p&gt;Before diving into algorithms, it helps to know that compression splits into two families: &lt;strong&gt;lossless&lt;/strong&gt; and &lt;strong&gt;lossy&lt;/strong&gt;. The choice depends on whether you can afford to lose any information.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lossless Compression: Every Bit Preserved
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Lossless&lt;/strong&gt; compression means that after you decompress, you get back &lt;strong&gt;exactly&lt;/strong&gt; the original data—every bit. Nothing is discarded.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How it works:&lt;/strong&gt; The algorithm finds statistical redundancy (repeated or predictable patterns) and encodes them more efficiently. Decompression reverses the process and reconstructs the original stream.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When to use it:&lt;/strong&gt; Whenever you cannot afford to lose information—source code, text files, databases, executables, legal documents, medical data, or images where every pixel must stay exact (e.g. PNG for graphics, FLAC for audio).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Common formats:&lt;/strong&gt; ZIP, GZIP, PNG, GIF (for lossless use), FLAC.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So when you compress 100GB of source code or logs to 25GB with a lossless tool, you can later decompress and get back the same 100GB bit-for-bit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lossy Compression: Smaller Files, Imperceptible Loss
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Lossy&lt;/strong&gt; compression &lt;strong&gt;discards&lt;/strong&gt; some information on purpose. What you get back is an &lt;strong&gt;approximation&lt;/strong&gt; of the original—close enough for human perception, but not identical.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How it works:&lt;/strong&gt; The algorithm keeps what matters for the intended use (e.g. what the eye or ear notices) and drops “invisible” or less important detail—e.g. colors we can’t easily tell apart, or sounds masked by louder ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When to use it:&lt;/strong&gt; Media where small quality loss is acceptable—photos (JPEG), music (MP3, AAC), video (H.264, VP9). Streaming and storage would be far heavier without lossy compression.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Common formats:&lt;/strong&gt; JPEG, MP3, AAC, H.264, VP9.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the rest of this post we focus on &lt;strong&gt;lossless&lt;/strong&gt; compression—the kind that powers ZIP, GZIP, and the 100GB→25GB backup scenario—and then briefly touch how &lt;strong&gt;video&lt;/strong&gt; combines similar ideas with lossy temporal compression.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. The Building Blocks: Huffman Coding and LZ77
&lt;/h2&gt;

&lt;p&gt;Most modern lossless compressors (including the ones inside ZIP and GZIP) combine two ideas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Dictionary / back-reference coding&lt;/strong&gt; (e.g. LZ77): “I’ve seen this phrase before; refer back to it.”&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entropy coding&lt;/strong&gt; (e.g. Huffman): “Frequent symbols get short codes; rare symbols get longer codes.”&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Together they form algorithms like &lt;strong&gt;DEFLATE&lt;/strong&gt; (used in ZIP and GZIP): first reduce repetition with something like LZ77, then shorten the remaining stream with Huffman (or similar) coding.&lt;/p&gt;




&lt;h3&gt;
  
  
  3.1 Huffman Coding: Short Codes for Common Symbols
&lt;/h3&gt;

&lt;p&gt;In normal text encoding (e.g. ASCII or UTF-8), every character uses the &lt;strong&gt;same&lt;/strong&gt; number of bits (e.g. 8 bits per character). So the letter “E” and the letter “Z” both cost 8 bits, even though “E” appears far more often in English text. That’s wasteful: we’re spending the same budget on rare and common symbols.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Huffman coding&lt;/strong&gt; fixes that by giving &lt;strong&gt;variable-length&lt;/strong&gt; codes: frequent symbols get &lt;strong&gt;shorter&lt;/strong&gt; codes, rare symbols get &lt;strong&gt;longer&lt;/strong&gt; codes. On average, the whole message uses fewer bits.&lt;/p&gt;

&lt;p&gt;One crucial constraint: no code is allowed to be a &lt;strong&gt;prefix&lt;/strong&gt; of another. So if “E” is encoded as &lt;code&gt;10&lt;/code&gt;, then no other character’s code can start with &lt;code&gt;10&lt;/code&gt; (e.g. no &lt;code&gt;100&lt;/code&gt; or &lt;code&gt;101&lt;/code&gt;). That way, when we read the compressed stream left-to-right, we always know where one symbol ends and the next begins—no need for extra separators (unlike Morse code, which needs pauses between letters).&lt;/p&gt;

&lt;p&gt;A simple way to build such codes is with a &lt;strong&gt;binary tree&lt;/strong&gt; : each character is a leaf, and the path from the root to that leaf (e.g. left=0, right=1) is its code. The algorithm builds the tree from the &lt;strong&gt;bottom up&lt;/strong&gt; , repeatedly grouping the two least frequent symbols (or groups) until everything is in one tree. Frequent characters end up near the root (short path); rare ones end up deeper (long path).&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Standard 8-bit encoding (e.g. ASCII): every character uses 8 bits
"E" = 01000101 (8 bits)
"Z" = 01011010 (8 bits)

// Huffman encoding (example): frequent letters get shorter codes
"E" = 10 (2 bits) ← common in English
"Z" = 111010 (6 bits) ← rare, so longer code

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

&lt;/div&gt;



&lt;p&gt;So Huffman doesn’t “invent” new information; it &lt;strong&gt;represents&lt;/strong&gt; the same information in fewer bits by exploiting how often each symbol appears.&lt;/p&gt;




&lt;h3&gt;
  
  
  3.2 LZ77: “I’ve Seen This Before—Point Back to It”
&lt;/h3&gt;

&lt;p&gt;Huffman only shortens symbols based on frequency. It doesn’t remove &lt;strong&gt;repeated phrases&lt;/strong&gt;. That’s where &lt;strong&gt;LZ77&lt;/strong&gt; (and family) comes in.&lt;/p&gt;

&lt;p&gt;LZ77 keeps a &lt;strong&gt;sliding window&lt;/strong&gt; of recently seen data. As it reads the input, it looks for the &lt;strong&gt;longest match&lt;/strong&gt; between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what’s coming next (the “look-ahead” buffer), and&lt;/li&gt;
&lt;li&gt;what it has already seen (the “search” buffer).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When it finds a match, it doesn’t output the phrase again. Instead it outputs a &lt;strong&gt;back-reference&lt;/strong&gt; : a pair &lt;strong&gt;(distance, length)&lt;/strong&gt; meaning “go back &lt;code&gt;distance&lt;/code&gt; bytes and copy &lt;code&gt;length&lt;/code&gt; bytes.” The decoder can then reconstruct the phrase from earlier in the stream.&lt;/p&gt;

&lt;p&gt;So the stream becomes a mix of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Literal&lt;/strong&gt; bytes (when there’s no useful match), and&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Back-references&lt;/strong&gt; (when a phrase repeats).&lt;/li&gt;
&lt;/ul&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;Input: "The quick brown fox jumps over the quick dog"
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        "the quick" appears twice

Compressed idea:
  Literals: "The quick brown fox jumps over "
  Back-reference: (distance=31, length=9) → copy 9 bytes from 31 bytes ago
  Literals: " dog"

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

&lt;/div&gt;



&lt;p&gt;After this step, the stream has fewer bytes but still contains the same information. Then Huffman (or similar) is applied to that stream to shorten the representation of literals and back-reference pairs—that’s DEFLATE in a nutshell.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. ZIP vs. TAR.GZ: Same Ideas, Different Packaging
&lt;/h2&gt;

&lt;p&gt;Both ZIP and TAR.GZ use lossless compression (often DEFLATE/GZIP-style), but they &lt;strong&gt;package&lt;/strong&gt; files differently. That difference affects compression ratio and how you can access files.&lt;/p&gt;

&lt;h3&gt;
  
  
  ZIP: One File at a Time
&lt;/h3&gt;

&lt;p&gt;ZIP compresses &lt;strong&gt;each file separately&lt;/strong&gt; and then puts them in one archive, with a central directory so you can list and extract individual files.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pros:&lt;/strong&gt;  &lt;strong&gt;Random access.&lt;/strong&gt; You can extract &lt;code&gt;image_402.jpg&lt;/code&gt; from a 50GB archive without reading or decompressing the rest. Good for browsing and pulling single files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cons:&lt;/strong&gt; The compressor never looks &lt;strong&gt;across&lt;/strong&gt; file boundaries. If 100 files are nearly identical, ZIP may store 100 separate compressed versions and miss shared patterns. So total size can be larger than a “solid” archive.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So ZIP is great when you need &lt;strong&gt;per-file access&lt;/strong&gt; and broad compatibility (e.g. Windows, macOS, Linux).&lt;/p&gt;

&lt;h3&gt;
  
  
  TAR.GZ: One Big Stream (Solid Archive)
&lt;/h3&gt;

&lt;p&gt;TAR.GZ is a &lt;strong&gt;two-step&lt;/strong&gt; process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;TAR (Tape Archiver):&lt;/strong&gt; Concatenate all files into one continuous &lt;strong&gt;stream&lt;/strong&gt; (no compression yet). This is a “solid” archive—one long byte stream.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GZIP:&lt;/strong&gt; Compress that &lt;strong&gt;entire&lt;/strong&gt; stream with DEFLATE (LZ77 + Huffman) as if it were a single file.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because GZIP sees the whole project as one stream, it can find patterns that span &lt;strong&gt;many files&lt;/strong&gt;. A repeated header in &lt;code&gt;file_A.txt&lt;/code&gt; can be used to compress the same header in &lt;code&gt;file_Z.txt&lt;/code&gt;. That’s why you can get a &lt;strong&gt;much&lt;/strong&gt; better ratio—e.g. 100GB down to 25GB—when you have lots of similar or repeated content across files.&lt;/p&gt;

&lt;p&gt;Trade-off: to get &lt;strong&gt;any&lt;/strong&gt; file out of a TAR.GZ, you typically have to decompress from the beginning up to that file. There’s no cheap “jump to file 402” as in ZIP.&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;# Step 1: Bundle everything into one stream (size unchanged)&lt;/span&gt;
&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-cvf&lt;/span&gt; backup.tar ./my_project

&lt;span class="c"&gt;# Step 2: Compress that whole stream&lt;/span&gt;
&lt;span class="nb"&gt;gzip &lt;/span&gt;backup.tar

&lt;span class="c"&gt;# Result: backup.tar.gz — one compressed stream&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When to use TAR.GZ:&lt;/strong&gt; Backups, source tarballs, logs, or any case where you want &lt;strong&gt;maximum compression&lt;/strong&gt; and usually extract the whole archive (or don’t mind decompressing from the start to reach a file). Common on Linux and in DevOps pipelines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to prefer ZIP:&lt;/strong&gt; When you need &lt;strong&gt;random access&lt;/strong&gt; to individual files or maximum compatibility with non-Unix systems.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. How Video Compression Goes Further: Temporal Redundancy
&lt;/h2&gt;

&lt;p&gt;Video has a special kind of redundancy: &lt;strong&gt;between frames&lt;/strong&gt; , most of the image doesn’t change. Only moving parts (and lighting changes) differ. So instead of storing every frame in full, modern codecs (e.g. H.264) use &lt;strong&gt;temporal compression&lt;/strong&gt; : store one full frame, then for the next frames store mainly &lt;strong&gt;what changed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Roughly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;I-frames (Intra-frames):&lt;/strong&gt; Full frames—like a JPEG image. They don’t depend on other frames. Used as anchors so you can seek or recover from errors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;P-frames (Predictive):&lt;/strong&gt; Encoded as “differences” from a previous frame (or I-frame). Much smaller than a full frame.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;B-frames (Bi-predictive):&lt;/strong&gt; Use both past and future frames to predict the current frame, so they can be even smaller.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frame 1 (I): Full image of a sunset
Frame 2 (P): “Same as Frame 1, but the bird moved 2 pixels left”
Frame 3 (P): “Same as Frame 2, but the bird moved 2 pixels left”
…
Total stored: one full frame + many small “deltas” and motion vectors

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd2ewk7a5qepgitv3e990.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd2ewk7a5qepgitv3e990.png" alt="Inter-frame prediction: I-frame and P-frames with motion vectors. Frame 1 is a full photo; Frames 2 and 3 store only the moving bird and motion vector (-2, 0)." width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s &lt;strong&gt;temporal&lt;/strong&gt; compression. Video also uses &lt;strong&gt;spatial&lt;/strong&gt; compression inside each frame (similar in spirit to JPEG). Together, temporal + spatial (and often lossy choices) let streaming and storage stay practical at 1080p and 4K.&lt;/p&gt;




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

&lt;p&gt;Compression is the invisible engine behind smaller backups, faster transfers, and watchable video. The main ideas are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Redundancy&lt;/strong&gt; is removed or shortened: repeated phrases become back-references (LZ77), and frequent symbols get short codes (Huffman).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lossless&lt;/strong&gt; (ZIP, GZIP, PNG) keeps every bit; &lt;strong&gt;lossy&lt;/strong&gt; (JPEG, MP3, H.264) trades a bit of quality for much smaller size.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ZIP&lt;/strong&gt; compresses file-by-file for random access; &lt;strong&gt;TAR.GZ&lt;/strong&gt; compresses one solid stream for better ratio when you don’t need per-file random access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Video&lt;/strong&gt; adds &lt;strong&gt;temporal&lt;/strong&gt; compression: store full frames rarely, and mostly store changes between frames.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Understanding these mechanics helps you choose the right format—whether you’re optimizing Next.js assets, shipping backups to S3, or tuning video encoding—and demystifies how 100GB can become 25GB without losing a single bit.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;written using AI tools&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>computerscience</category>
    </item>
    <item>
      <title>Building This Blog: A Modern Next.js Blog with Markdown</title>
      <dc:creator>Ratnesh Maurya</dc:creator>
      <pubDate>Mon, 08 Sep 2025 00:00:00 +0000</pubDate>
      <link>https://dev.to/ratneshmaurya/building-this-blog-a-modern-nextjs-blog-with-markdown-486p</link>
      <guid>https://dev.to/ratneshmaurya/building-this-blog-a-modern-nextjs-blog-with-markdown-486p</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.amazonaws.com%2Fuploads%2Farticles%2Flhlwidorfx8dagy05i0x.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flhlwidorfx8dagy05i0x.jpg" alt="Building This Blog: A Modern Next.js Blog with Markdown"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Building This Blog: an MDX‑powered Next.js blog
&lt;/h1&gt;

&lt;p&gt;This blog is a small, opinionated setup for writing long‑form content that feels good to read and fun to build on.&lt;/p&gt;

&lt;p&gt;Under the hood it uses static generation, MDX, and a theme‑aware UI that works in both light and dark modes.&lt;/p&gt;

&lt;p&gt;Everything after the frontmatter is pure &lt;strong&gt;MDX&lt;/strong&gt;. Components like &lt;code&gt;Callout&lt;/code&gt;, &lt;code&gt;Steps&lt;/code&gt;, architecture diagrams, flows, and charts are all React components rendered directly in the post body.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stack I ended up with
&lt;/h2&gt;

&lt;p&gt;I wanted something fast, simple, and easy to reason about over years—not weeks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The site is a static App Router app. Routes like `/blog/[slug]`, `/til/[slug]`, `/technical-terms/[slug]` are statically generated at build time.

TypeScript keeps the content layer and components honest. Tailwind + CSS variables handle layout and theming.

All long‑form content lives in the repo inside content/, written as `.md` or `.mdx` files with frontmatter.

Views, upvotes, and UTM events are stored in Supabase and surfaced through a custom analytics dashboard.

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  How content works
&lt;/h2&gt;

&lt;p&gt;All posts are simple files in the repo—no CMS required.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Your&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Post&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Title"&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Post&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;description"&lt;/span&gt;
&lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2024-01-20"&lt;/span&gt;
&lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Your&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Name"&lt;/span&gt;
&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tag1"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tag2"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Category"&lt;/span&gt;
&lt;span class="na"&gt;featured&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="s"&gt;Your content here...&lt;/span&gt;

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Markdown (&lt;code&gt;.md&lt;/code&gt;)&lt;/strong&gt; posts go through a Remark pipeline and are rendered as HTML.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MDX (&lt;code&gt;.mdx&lt;/code&gt;)&lt;/strong&gt; posts are compiled at runtime in the page using &lt;code&gt;next-mdx-remote/rsc&lt;/code&gt;, with a shared component map.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For posts that need diagrams, flows, or charts, I use &lt;code&gt;.mdx&lt;/code&gt; and drop in components like ArchitectureCard, FlowStep, and DemoBarChart.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authoring flow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Add a new `.md` or `.mdx` file to content/blog/ with frontmatter for SEO, tags, and images.

Run npm run dev and iterate on copy, diagrams, and layout until the post feels polished.

Push to the main branch. The build step generates static HTML for every route and updates search data + OG images.

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Architecture of the blog
&lt;/h2&gt;

&lt;p&gt;At a high level, the blog is just three pieces: browser, Next.js, and Supabase.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Readers get fully rendered HTML from the CDN, with minimal JavaScript on top for upvotes, analytics, and small interactions.

Next.js statically generates pages for blog posts, TIL entries, technical terms, and lists. It also exposes a few API routes for analytics.

Supabase stores per‑page views, upvotes, and UTM events that feed the analytics dashboard and charts.

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Request–response flow for a page view
&lt;/h2&gt;

&lt;p&gt;Here’s how a single blog page view flows through the system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The CDN serves a pre‑rendered HTML page that was generated at build time.

Next.js hydrates the page; components like the upvote button, custom cursor, and view counter start working.

A lightweight request records the view / upvote in Supabase without blocking the reader.

Aggregated stats are used to power Recharts visualizations on the analytics page.

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Visualizing traffic with charts
&lt;/h2&gt;

&lt;p&gt;The same Recharts setup used in the analytics dashboard is available inside MDX posts.&lt;/p&gt;

&lt;p&gt;Charts are plain React components exposed to MDX. They respect the global theme and use the same accent palette as the rest of the site.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance before and after
&lt;/h2&gt;

&lt;p&gt;Static export plus small tweaks around assets made a noticeable difference in user‑facing numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this setup works for me
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Files as the source of truth&lt;/strong&gt; – I can write posts in a text editor, version them in git, and refactor them like any other code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Static by default&lt;/strong&gt; – Most pages are static HTML, which is great for speed and reliability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MDX when I need power&lt;/strong&gt; – Architecture diagrams, flows, and charts are just components; I only reach for them when a post really needs them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Theme‑aware UI&lt;/strong&gt; – Components use the same CSS variables as the rest of the app, so they look good in both light and dark modes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you want to explore the implementation details, the full source code is on &lt;a href="https://github.com/ratnesh-maurya/blog.ratnesh-maurya.com" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. You could clone it, point it at your own content folder, and have a similar blog running in minutes.&lt;/p&gt;

</description>
      <category>webdev</category>
    </item>
    <item>
      <title>Optimizing Memory Layout in Go: A Deep Dive into Struct Design</title>
      <dc:creator>Ratnesh Maurya</dc:creator>
      <pubDate>Fri, 10 Jan 2025 00:00:00 +0000</pubDate>
      <link>https://dev.to/ratneshmaurya/optimizing-memory-layout-in-go-a-deep-dive-into-struct-design-29kf</link>
      <guid>https://dev.to/ratneshmaurya/optimizing-memory-layout-in-go-a-deep-dive-into-struct-design-29kf</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.amazonaws.com%2Fuploads%2Farticles%2Fpepv4cnecb9fmnp4sbpw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpepv4cnecb9fmnp4sbpw.jpg" alt="Optimizing Memory Layout in Go: A Deep Dive into Struct Design" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Reorder the fields in a Go struct and the size changes — without changing the data it holds. A &lt;code&gt;bool&lt;/code&gt; next to an &lt;code&gt;int64&lt;/code&gt; wastes 7 bytes of padding. Across 10 million allocations, that's 67MB of memory you're paying for but never using.&lt;/p&gt;

&lt;p&gt;This matters in high-throughput services where struct slices dominate heap usage: event pipelines, in-memory caches, analytics collectors.&lt;/p&gt;

&lt;h2&gt;
  
  
  How alignment and padding work
&lt;/h2&gt;

&lt;p&gt;Go stores struct fields in a contiguous block of memory. Each field must be aligned to a memory address that's a multiple of its own size — &lt;code&gt;int64&lt;/code&gt; aligns to 8 bytes, &lt;code&gt;int32&lt;/code&gt; to 4, &lt;code&gt;bool&lt;/code&gt; to 1. When a smaller field is followed by a larger one, the compiler inserts invisible padding bytes to satisfy the alignment requirement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Bad&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Active&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="c"&gt;// 1 byte&lt;/span&gt;
    &lt;span class="c"&gt;// 7 bytes padding&lt;/span&gt;
    &lt;span class="n"&gt;Balance&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt; &lt;span class="c"&gt;// 8 bytes&lt;/span&gt;
    &lt;span class="n"&gt;Age&lt;/span&gt; &lt;span class="kt"&gt;uint8&lt;/span&gt; &lt;span class="c"&gt;// 1 byte&lt;/span&gt;
    &lt;span class="c"&gt;// 7 bytes padding&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;// Total: 24 bytes (only 10 bytes of actual data)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Reorder from largest to smallest:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Good&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Balance&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt; &lt;span class="c"&gt;// 8 bytes&lt;/span&gt;
    &lt;span class="n"&gt;Active&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="c"&gt;// 1 byte&lt;/span&gt;
    &lt;span class="n"&gt;Age&lt;/span&gt; &lt;span class="kt"&gt;uint8&lt;/span&gt; &lt;span class="c"&gt;// 1 byte&lt;/span&gt;
    &lt;span class="c"&gt;// 6 bytes padding (struct itself aligns to 8)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;// Total: 16 bytes (same 10 bytes of data, 8 bytes less waste)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;That's a 33% reduction per struct, just by reordering fields.&lt;/p&gt;

&lt;h2&gt;
  
  
  Measuring the difference
&lt;/h2&gt;

&lt;p&gt;Use &lt;code&gt;reflect.TypeOf&lt;/code&gt; and &lt;code&gt;unsafe.Sizeof&lt;/code&gt; to check struct sizes at runtime:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"reflect"&lt;/span&gt;
    &lt;span class="s"&gt;"unsafe"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Bad&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Active&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;Balance&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt;
    &lt;span class="n"&gt;Age&lt;/span&gt; &lt;span class="kt"&gt;uint8&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Good&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Balance&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt;
    &lt;span class="n"&gt;Active&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;Age&lt;/span&gt; &lt;span class="kt"&gt;uint8&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bad:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unsafe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Bad&lt;/span&gt;&lt;span class="p"&gt;{}),&lt;/span&gt; &lt;span class="s"&gt;"bytes"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// 24&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Good:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unsafe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Good&lt;/span&gt;&lt;span class="p"&gt;{}),&lt;/span&gt; &lt;span class="s"&gt;"bytes"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// 16&lt;/span&gt;

    &lt;span class="c"&gt;// Field-by-field inspection&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;reflect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TypeOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Bad&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NumField&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" %s: size=%d, offset=%d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&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;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Size&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  How much memory this saves at scale
&lt;/h2&gt;

&lt;p&gt;Here's the math for a real scenario — an analytics service tracking page view events:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;PageView&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Unoptimized layout&lt;/span&gt;
    &lt;span class="n"&gt;IsBot&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="c"&gt;// 1 + 7 padding&lt;/span&gt;
    &lt;span class="n"&gt;Timestamp&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt; &lt;span class="c"&gt;// 8&lt;/span&gt;
    &lt;span class="n"&gt;StatusCode&lt;/span&gt; &lt;span class="kt"&gt;uint16&lt;/span&gt; &lt;span class="c"&gt;// 2 + 6 padding&lt;/span&gt;
    &lt;span class="n"&gt;Duration&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt; &lt;span class="c"&gt;// 8&lt;/span&gt;
    &lt;span class="n"&gt;UserID&lt;/span&gt; &lt;span class="kt"&gt;uint32&lt;/span&gt; &lt;span class="c"&gt;// 4 + 4 padding&lt;/span&gt;
    &lt;span class="n"&gt;PathHash&lt;/span&gt; &lt;span class="kt"&gt;uint64&lt;/span&gt; &lt;span class="c"&gt;// 8&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;// Size: 48 bytes&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;PageViewOptimized&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Sorted by alignment: 8 → 4 → 2 → 1&lt;/span&gt;
    &lt;span class="n"&gt;Timestamp&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt;
    &lt;span class="n"&gt;Duration&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt;
    &lt;span class="n"&gt;PathHash&lt;/span&gt; &lt;span class="kt"&gt;uint64&lt;/span&gt;
    &lt;span class="n"&gt;UserID&lt;/span&gt; &lt;span class="kt"&gt;uint32&lt;/span&gt;
    &lt;span class="n"&gt;StatusCode&lt;/span&gt; &lt;span class="kt"&gt;uint16&lt;/span&gt;
    &lt;span class="n"&gt;IsBot&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;// Size: 32 bytes&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;Struct count&lt;/th&gt;
&lt;th&gt;Unoptimized&lt;/th&gt;
&lt;th&gt;Optimized&lt;/th&gt;
&lt;th&gt;Saved&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;100K&lt;/td&gt;
&lt;td&gt;4.6 MB&lt;/td&gt;
&lt;td&gt;3.1 MB&lt;/td&gt;
&lt;td&gt;1.5 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1M&lt;/td&gt;
&lt;td&gt;45.8 MB&lt;/td&gt;
&lt;td&gt;30.5 MB&lt;/td&gt;
&lt;td&gt;15.3 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10M&lt;/td&gt;
&lt;td&gt;457 MB&lt;/td&gt;
&lt;td&gt;305 MB&lt;/td&gt;
&lt;td&gt;152 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;At 10 million structs, the difference is 152MB — enough to matter for your container memory limits and GC pressure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automated detection with fieldalignment
&lt;/h2&gt;

&lt;p&gt;You don't need to manually audit every struct. The &lt;code&gt;fieldalignment&lt;/code&gt; analyzer from &lt;code&gt;golang.org/x/tools&lt;/code&gt; catches suboptimal layouts automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;install &lt;/span&gt;golang.org/x/tools/go/analysis/passes/fieldalignment/cmd/fieldalignment@latest
fieldalignment ./...

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

&lt;/div&gt;



&lt;p&gt;It reports every struct that could be smaller and suggests the optimal field order. You can also run it as part of &lt;code&gt;golangci-lint&lt;/code&gt; by enabling the &lt;code&gt;govet&lt;/code&gt; linter with the &lt;code&gt;fieldalignment&lt;/code&gt; check.&lt;/p&gt;

&lt;h2&gt;
  
  
  The alignment rules
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;th&gt;Alignment&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;bool&lt;/code&gt;, &lt;code&gt;byte&lt;/code&gt;, &lt;code&gt;uint8&lt;/code&gt;, &lt;code&gt;int8&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;1 byte&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;uint16&lt;/code&gt;, &lt;code&gt;int16&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;2 bytes&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;uint32&lt;/code&gt;, &lt;code&gt;int32&lt;/code&gt;, &lt;code&gt;float32&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;4 bytes&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;uint64&lt;/code&gt;, &lt;code&gt;int64&lt;/code&gt;, &lt;code&gt;float64&lt;/code&gt;, pointer, &lt;code&gt;string&lt;/code&gt;, slice, map, interface&lt;/td&gt;
&lt;td&gt;8 bytes&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The general rule: &lt;strong&gt;sort fields from largest alignment to smallest.&lt;/strong&gt; This minimizes padding because smaller fields can pack together in the leftover space after larger fields.&lt;/p&gt;

&lt;p&gt;Structs themselves are padded to a multiple of their largest field's alignment. That's why the &lt;code&gt;Good&lt;/code&gt; struct above is 16 bytes (multiple of 8) even though the data only needs 10 bytes.&lt;/p&gt;

&lt;h2&gt;
  
  
  When not to bother
&lt;/h2&gt;

&lt;p&gt;Field ordering optimization is worth the effort when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You allocate millions of the same struct (event pipelines, time-series data, game state)&lt;/li&gt;
&lt;li&gt;The struct is stored in a large slice that stays in memory&lt;/li&gt;
&lt;li&gt;You're hitting container memory limits or seeing heavy GC pauses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's not worth the effort when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The struct is allocated once or a handful of times&lt;/li&gt;
&lt;li&gt;Readability would suffer from rearranging logically grouped fields&lt;/li&gt;
&lt;li&gt;The struct is mostly pointers and strings (already 8-byte aligned)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Run &lt;code&gt;fieldalignment&lt;/code&gt; on your codebase as a CI check. Fix the easy wins — the structs that save 8+ bytes per instance — and leave the rest alone. The tool does the thinking for you.&lt;/p&gt;

</description>
      <category>go</category>
    </item>
    <item>
      <title>Deploy a Nanoc Static Site to S3 with GitHub Actions</title>
      <dc:creator>Ratnesh Maurya</dc:creator>
      <pubDate>Sat, 23 Nov 2024 00:00:00 +0000</pubDate>
      <link>https://dev.to/ratneshmaurya/deploy-a-nanoc-static-site-to-s3-with-github-actions-239h</link>
      <guid>https://dev.to/ratneshmaurya/deploy-a-nanoc-static-site-to-s3-with-github-actions-239h</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.amazonaws.com%2Fuploads%2Farticles%2F0qr6px07ls90bwf9cay3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0qr6px07ls90bwf9cay3.jpg" alt="Deploy a Nanoc Static Site to S3 with GitHub Actions" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Deploying a static site to S3 manually means running &lt;code&gt;aws s3 sync&lt;/code&gt; from your laptop every time you make a change. That gets old fast. GitHub Actions can automate the entire flow: push to &lt;code&gt;main&lt;/code&gt;, and the site builds and deploys itself.&lt;/p&gt;

&lt;p&gt;This guide walks through the full setup for a &lt;a href="https://nanoc.app/" rel="noopener noreferrer"&gt;Nanoc&lt;/a&gt; site, but the S3 + GitHub Actions pattern works for any static site generator.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ratnesh-maurya/365-Days-of-DevOps/tree/main" rel="noopener noreferrer"&gt;Source code on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What you need before starting
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;strong&gt;AWS account&lt;/strong&gt; with an S3 bucket configured for static website hosting&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;IAM user&lt;/strong&gt; with scoped permissions (created in the steps below)&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;GitHub repository&lt;/strong&gt; containing your Nanoc source code&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Configure the S3 bucket policy
&lt;/h2&gt;

&lt;p&gt;Your bucket needs a policy that allows public read access to its contents. Apply this to the bucket in the S3 console under Permissions &amp;gt; Bucket Policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2008-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PolicyForPublicWebsiteContent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PublicReadGetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"AWS"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::docsite-github-action/*"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;docsite-github-action&lt;/code&gt; with your actual bucket name.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Create a scoped IAM user
&lt;/h2&gt;

&lt;p&gt;Create a dedicated IAM user for GitHub Actions — don't use your root credentials. Attach this policy, which gives the minimum permissions needed for &lt;code&gt;s3 sync&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AccessToGetBucketLocation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"s3:GetBucketLocation"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AccessToWebsiteBuckets"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"s3:PutObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"s3:PutObjectAcl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"s3:ListBucket"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"s3:DeleteObject"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::docsite-github-action"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::docsite-github-action/*"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Add AWS credentials to GitHub Secrets
&lt;/h2&gt;

&lt;p&gt;In your GitHub repository, go to &lt;strong&gt;Settings &amp;gt; Secrets and variables &amp;gt; Actions&lt;/strong&gt; and add two repository secrets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt; — your IAM user's access key&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt; — the corresponding secret key&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are injected into the workflow at runtime. They never appear in logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Create the GitHub Actions workflow
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;.github/workflows/deploy.yml&lt;/code&gt; in your repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Nanoc Compile and Upload to S3&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout Repository&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Ruby and Nanoc&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;sudo apt-get update&lt;/span&gt;
          &lt;span class="s"&gt;sudo apt-get install -y ruby-full build-essential zlib1g-dev&lt;/span&gt;
          &lt;span class="s"&gt;sudo gem install bundler&lt;/span&gt;
          &lt;span class="s"&gt;sudo gem install nanoc&lt;/span&gt;
          &lt;span class="s"&gt;sudo gem install adsf&lt;/span&gt;
          &lt;span class="s"&gt;sudo gem install kramdown&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Nanoc Website&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;ls&lt;/span&gt;
          &lt;span class="s"&gt;cd tutorial &amp;amp;&amp;amp; nanoc&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set AWS credentials&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/configure-aws-credentials@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;aws-access-key-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_ACCESS_KEY_ID }}&lt;/span&gt;
          &lt;span class="na"&gt;aws-secret-access-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_SECRET_ACCESS_KEY }}&lt;/span&gt;
          &lt;span class="na"&gt;aws-region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ap-south-1&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Push to S3&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws s3 sync tutorial/output/ s3://docsite-github-action&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The workflow triggers on every push to &lt;code&gt;main&lt;/code&gt;. It installs Ruby and Nanoc, compiles the site, and syncs the output directory to your S3 bucket.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternatives to consider
&lt;/h2&gt;

&lt;p&gt;This setup works well for simple static sites, but depending on your needs, other approaches might be a better fit:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;When to use it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;S3 + CloudFront&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You need HTTPS and a CDN for global performance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Vercel / Netlify&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You want zero-config deploys with preview URLs for every PR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GitHub Pages&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You don't need AWS and want the simplest possible hosting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS Amplify&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You want managed CI/CD with automatic branch deploys on AWS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;S3 alone doesn't give you HTTPS — you'd need CloudFront in front of it for that. If HTTPS and preview deployments matter to you, Vercel or Netlify will save you time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common pitfalls
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Forgetting to enable static website hosting&lt;/strong&gt; on the S3 bucket — without it, S3 serves files as downloads instead of web pages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overly broad IAM permissions&lt;/strong&gt; — scope the policy to your specific bucket, not &lt;code&gt;s3:*&lt;/code&gt; on &lt;code&gt;*&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache invalidation&lt;/strong&gt; — &lt;code&gt;s3 sync&lt;/code&gt; updates files but doesn't invalidate CloudFront caches. If you add CloudFront later, add &lt;code&gt;aws cloudfront create-invalidation&lt;/code&gt; to the workflow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Region mismatch&lt;/strong&gt; — set &lt;code&gt;aws-region&lt;/code&gt; in the workflow to match your bucket's region.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The complete workflow YAML and policies are in the &lt;a href="https://github.com/ratnesh-maurya/365-Days-of-DevOps/tree/main" rel="noopener noreferrer"&gt;repo&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>aws</category>
    </item>
    <item>
      <title>Architectural Design for a Ride App such as OLA, UBER, RAPIDO</title>
      <dc:creator>Ratnesh Maurya</dc:creator>
      <pubDate>Tue, 30 Jul 2024 00:00:00 +0000</pubDate>
      <link>https://dev.to/ratneshmaurya/architectural-design-for-a-ride-app-such-as-ola-uber-rapido-44o8</link>
      <guid>https://dev.to/ratneshmaurya/architectural-design-for-a-ride-app-such-as-ola-uber-rapido-44o8</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.amazonaws.com%2Fuploads%2Farticles%2Fh93z2dzga1012dqywmv8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh93z2dzga1012dqywmv8.jpg" alt="Architectural Design for a Ride App such as OLA, UBER, RAPIDO" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A ride-sharing app needs to match riders with drivers in real-time, track locations, process payments, and handle all of this at scale across a city. This is my take on how to architect such a system using microservices — and where a simpler approach might actually be better.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why microservices for a ride app
&lt;/h2&gt;

&lt;p&gt;The core challenge is that different parts of the system have very different scaling requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Geo-location tracking&lt;/strong&gt; needs to handle thousands of location updates per second with sub-100ms latency&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Payment processing&lt;/strong&gt; needs strong consistency and idempotency but handles far fewer requests&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notifications&lt;/strong&gt; are fire-and-forget at high volume&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User authentication&lt;/strong&gt; is read-heavy with infrequent writes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A monolith would force all of these to scale together. Microservices let you scale the geo-location service to 50 instances while keeping the payment service at 3.&lt;/p&gt;

&lt;p&gt;That said, if you're building an MVP or serving a single city, start with a monolith. Uber itself started as a monolith. Extract services only when specific components hit scaling bottlenecks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Service boundaries
&lt;/h2&gt;

&lt;p&gt;Each service owns its data and exposes a clear API:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;User Service&lt;/strong&gt; — Manages rider and driver accounts, authentication (OAuth2/OIDC), profile data, and session management. Backed by PostgreSQL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ride Service&lt;/strong&gt; — The core coordination service. Handles ride requests, matches riders with nearby available drivers, tracks ride state (requested → matched → in-progress → completed), and calculates fares. Backed by PostgreSQL with Redis for active ride state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Driver Service&lt;/strong&gt; — Manages driver availability, approval status, vehicle information, and earnings. Tracks which drivers are online, idle, or on a ride. Backed by PostgreSQL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Geo-Location Service&lt;/strong&gt; — The highest-throughput service. Receives GPS coordinates from driver and rider apps every 3–5 seconds, stores them in a spatial index (Redis with geospatial commands or a dedicated service like H3), and answers proximity queries ("find the 5 nearest available drivers within 3km"). This is the service that needs the most aggressive scaling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Payment Service&lt;/strong&gt; — Integrates with payment gateways (Razorpay, Stripe). Processes charges after ride completion, handles refunds, and manages driver payouts. Must be idempotent — a network retry should never charge a rider twice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notification Service&lt;/strong&gt; — Sends push notifications (ride matched, driver arriving, ride completed), SMS fallbacks, and email receipts. Consumes events from a message queue rather than being called directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the services communicate
&lt;/h2&gt;

&lt;p&gt;Not all communication should use the same pattern:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Use case&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;REST/HTTP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Client → API Gateway → Services&lt;/td&gt;
&lt;td&gt;Simple request/response for CRUD operations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;gRPC&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Service-to-service (e.g., Ride Service → Geo-Location Service)&lt;/td&gt;
&lt;td&gt;Low latency, typed contracts, streaming support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Message queue (Kafka/RabbitMQ)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Ride Service → Notification Service, Ride Service → Analytics&lt;/td&gt;
&lt;td&gt;Async, decoupled, no backpressure on the producer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;strong&gt;API Gateway&lt;/strong&gt; sits in front of all services and handles routing, rate limiting, and authentication token validation. Clients never talk directly to internal services.&lt;/p&gt;

&lt;p&gt;A critical design decision: the Ride Service publishes a &lt;code&gt;ride.completed&lt;/code&gt; event to Kafka. The Payment Service, Notification Service, and Analytics Service all consume this event independently. This means adding a new consumer (say, a driver-rating prompt) doesn't require changing the Ride Service at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scaling and fault tolerance
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Load balancing.&lt;/strong&gt; An L7 load balancer (like AWS ALB or Envoy) distributes requests across service instances. The Geo-Location Service gets its own load balancer with sticky sessions disabled (since requests are stateless).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Auto-scaling.&lt;/strong&gt; Kubernetes Horizontal Pod Autoscaler watches CPU and custom metrics (like queue depth for the Notification Service). The Geo-Location Service might scale from 10 pods at 2 AM to 80 pods at 6 PM during rush hour.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Circuit breakers.&lt;/strong&gt; If the Payment Service is down, the Ride Service shouldn't hang waiting for it. A circuit breaker (e.g., via Istio or a library like resilience4j) fails fast after N consecutive errors and falls back to queuing the payment for later processing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Health checks.&lt;/strong&gt; Every service exposes &lt;code&gt;/healthz&lt;/code&gt; (liveness) and &lt;code&gt;/readyz&lt;/code&gt; (readiness) endpoints. Kubernetes restarts crashed pods automatically and stops routing traffic to pods that aren't ready.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security considerations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Authentication:&lt;/strong&gt; OAuth2 with JWTs for user-facing APIs. Service-to-service calls use mTLS within the Kubernetes cluster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data encryption:&lt;/strong&gt; AES-256 at rest, TLS 1.3 in transit. Payment card data never touches your services — use the payment gateway's tokenization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate limiting:&lt;/strong&gt; Applied at the API Gateway level. Geo-location updates are rate-limited per device to prevent abuse.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secrets management:&lt;/strong&gt; HashiCorp Vault or AWS Secrets Manager. No secrets in environment variables or config files.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Deployment
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Containerization:&lt;/strong&gt; Each service is a Docker image with a multi-stage build (builder → runtime). Images are scanned for vulnerabilities in CI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orchestration:&lt;/strong&gt; Kubernetes with namespaces per environment (dev, staging, prod). Services declare resource requests and limits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD:&lt;/strong&gt; GitHub Actions or GitLab CI runs tests, builds images, pushes to a container registry, and deploys via Helm charts or ArgoCD.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observability:&lt;/strong&gt; Prometheus + Grafana for metrics, Jaeger for distributed tracing, Fluentd/Loki for centralized logs. Every service emits structured JSON logs with a correlation ID.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I'd do differently at different scales
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scale&lt;/th&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MVP (1 city, &amp;lt; 1K rides/day)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Monolith with a single PostgreSQL database. Extract the geo-location queries into a background worker if they slow down the main app.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Growth (5 cities, 10K rides/day)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Extract Geo-Location and Notification as separate services. Keep everything else in the monolith. Add Redis for caching.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scale (50+ cities, 100K+ rides/day)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Full microservices as described above. Invest in Kafka for event-driven architecture, dedicated SRE team, and per-service databases.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The biggest mistake is building for the third row when you're at the first row. Start simple, measure, and extract when the pain is real.&lt;/p&gt;

</description>
      <category>architecture</category>
    </item>
    <item>
      <title>Amazon SNS for Cost Reduction and Message Delivery Assurance in Startups</title>
      <dc:creator>Ratnesh Maurya</dc:creator>
      <pubDate>Sun, 10 Dec 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/ratneshmaurya/amazon-sns-for-cost-reduction-and-message-delivery-assurance-in-startups-ie3</link>
      <guid>https://dev.to/ratneshmaurya/amazon-sns-for-cost-reduction-and-message-delivery-assurance-in-startups-ie3</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.amazonaws.com%2Fuploads%2Farticles%2F1815byanlyt5nm8271cq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1815byanlyt5nm8271cq.jpg" alt="Amazon SNS for Cost Reduction and Message Delivery Assurance in Startups" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most startups need to send notifications — order confirmations, alerts, password resets — but don't want to run their own messaging infrastructure. &lt;a href="https://aws.amazon.com/sns/" rel="noopener noreferrer"&gt;Amazon Simple Notification Service (SNS)&lt;/a&gt; solves this: a fully managed pub/sub service where you pay per message, not per server.&lt;/p&gt;

&lt;p&gt;Here's what makes it worth evaluating, where it falls short, and how it compares to alternatives.&lt;/p&gt;

&lt;h2&gt;
  
  
  The startup messaging problem
&lt;/h2&gt;

&lt;p&gt;Early-stage teams face a specific tension: they need reliable message delivery across email, SMS, and push notifications, but can't justify the cost or operational overhead of self-hosted messaging systems. The requirements typically include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pay-as-you-go pricing&lt;/strong&gt; — no monthly minimums, no long-term contracts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-channel delivery&lt;/strong&gt; — email, SMS, mobile push, HTTP webhooks, Lambda triggers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic retries&lt;/strong&gt; — temporary failures shouldn't lose messages&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Global reach&lt;/strong&gt; — users in multiple regions need low-latency delivery&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SNS addresses all four. But so do other services, which is why the trade-offs matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  How SNS keeps costs low
&lt;/h2&gt;

&lt;p&gt;SNS uses a pay-per-message model. The first million SNS API requests per month are free. After that, it's $0.50 per million requests. SMS and email have separate per-message pricing that varies by destination country.&lt;/p&gt;

&lt;p&gt;For a startup sending 100K push notifications and 10K emails per month, the SNS cost is effectively zero (within the free tier). Compare that to a dedicated email service like SendGrid or Mailgun, which typically start at $15–20/month for similar volumes.&lt;/p&gt;

&lt;p&gt;The catch: SNS doesn't do rich email templates, drip campaigns, or analytics. It's a delivery pipe, not a marketing platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  How SNS ensures delivery
&lt;/h2&gt;

&lt;p&gt;Three mechanisms prevent message loss:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Retry logic.&lt;/strong&gt; When a delivery attempt fails (subscriber endpoint is down, network timeout), SNS automatically retries with exponential backoff. The retry policy is configurable per delivery protocol.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dead letter queues.&lt;/strong&gt; Messages that exhaust all retry attempts are routed to an SQS dead letter queue instead of being silently dropped. You can inspect these later, replay them, or trigger alerts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cross-AZ replication.&lt;/strong&gt; Messages are replicated across multiple availability zones within a region before SNS acknowledges the publish request. This protects against hardware failures in a single data center.&lt;/p&gt;

&lt;h2&gt;
  
  
  SNS vs SQS vs EventBridge: when to use what
&lt;/h2&gt;

&lt;p&gt;This is the decision most teams get wrong. All three are AWS messaging services, but they solve different problems:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Service&lt;/th&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SNS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pub/sub (fan-out)&lt;/td&gt;
&lt;td&gt;Broadcasting one event to many subscribers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SQS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Point-to-point queue&lt;/td&gt;
&lt;td&gt;Decoupling a producer from a single consumer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EventBridge&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Event bus with rules&lt;/td&gt;
&lt;td&gt;Routing events to different targets based on content&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The common pattern is SNS + SQS together: SNS fans out an event to multiple SQS queues, each consumed by a different microservice. This gives you both broadcast and buffering.&lt;/p&gt;

&lt;p&gt;If you only need one consumer, skip SNS and use SQS directly. If you need content-based routing (e.g., "send order events to the billing service, send inventory events to the warehouse service"), EventBridge is the better choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-world usage
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Netflix&lt;/strong&gt; uses SNS to send push notifications about new content releases. When a new season drops, SNS fans out the notification to millions of subscriber endpoints simultaneously.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Amazon&lt;/strong&gt; itself uses SNS for order lifecycle notifications — placed, shipped, delivered — routing events to email, SMS, and mobile push depending on customer preferences.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Walmart&lt;/strong&gt; uses SNS for order fulfillment and in-store pickup notifications, integrating with their logistics systems to trigger real-time updates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where SNS falls short
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No rich content.&lt;/strong&gt; SNS messages are plain text (or JSON for application-to-application). If you need HTML email templates, open/click tracking, or A/B testing, you need SES or a third-party email service.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No guaranteed ordering.&lt;/strong&gt; Standard SNS topics don't guarantee message order. FIFO topics do, but they're limited to 300 messages/second per topic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vendor lock-in.&lt;/strong&gt; SNS integrates deeply with AWS services (Lambda, SQS, CloudWatch). Migrating to a different cloud later means rewriting all your pub/sub logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SMS costs add up.&lt;/strong&gt; International SMS delivery can be expensive ($0.02–0.15 per message depending on country), and you need to manage opt-in compliance yourself.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to pick something else
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Transactional email with templates:&lt;/strong&gt; Use Amazon SES or SendGrid&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Marketing automation (drip campaigns, segmentation):&lt;/strong&gt; Use Brevo, Mailchimp, or Customer.io&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time chat or presence:&lt;/strong&gt; Use WebSockets or a service like Ably/Pusher&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-cloud pub/sub:&lt;/strong&gt; Use Google Cloud Pub/Sub, Confluent Kafka, or NATS&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;If you decide SNS fits, the setup is straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an SNS topic in the AWS Console or via CloudFormation/CDK&lt;/li&gt;
&lt;li&gt;Add subscribers (email, SQS queue, Lambda function, HTTP endpoint)&lt;/li&gt;
&lt;li&gt;Publish messages via the AWS SDK from your application code&lt;/li&gt;
&lt;li&gt;Configure a dead letter queue to catch failed deliveries&lt;/li&gt;
&lt;li&gt;Set up CloudWatch alarms on &lt;code&gt;NumberOfNotificationsFailed&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;a href="https://docs.aws.amazon.com/sns/latest/dg/welcome.html" rel="noopener noreferrer"&gt;AWS SNS documentation&lt;/a&gt; covers each step with working examples in Python, Node.js, and Java.&lt;/p&gt;

</description>
      <category>aws</category>
    </item>
    <item>
      <title>S3 Policies Explained: Bucket Policies vs IAM Policies vs ACLs</title>
      <dc:creator>Ratnesh Maurya</dc:creator>
      <pubDate>Thu, 23 Nov 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/ratneshmaurya/s3-policies-explained-bucket-policies-vs-iam-policies-vs-acls-3lc0</link>
      <guid>https://dev.to/ratneshmaurya/s3-policies-explained-bucket-policies-vs-iam-policies-vs-acls-3lc0</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.amazonaws.com%2Fuploads%2Farticles%2F4jigrt0sd72iolf8cww3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4jigrt0sd72iolf8cww3.jpg" alt="S3 Policies Explained: Bucket Policies vs IAM Policies vs ACLs" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;S3 has three overlapping access control systems — bucket policies, IAM policies, and ACLs — and the interaction between them confuses most people the first time. Here's how each one works, when to use which, and the JSON to copy for the most common scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three access control layers
&lt;/h2&gt;

&lt;p&gt;Every S3 request is evaluated against all applicable policies. If any of them explicitly deny the request, it's denied. Otherwise, at least one policy must explicitly allow it.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mechanism&lt;/th&gt;
&lt;th&gt;Attached to&lt;/th&gt;
&lt;th&gt;Written by&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bucket policies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The S3 bucket&lt;/td&gt;
&lt;td&gt;Bucket owner&lt;/td&gt;
&lt;td&gt;Cross-account access, public access, IP restrictions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;IAM policies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;IAM users/roles/groups&lt;/td&gt;
&lt;td&gt;Account admin&lt;/td&gt;
&lt;td&gt;Controlling what your own users and services can do&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ACLs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Buckets or objects&lt;/td&gt;
&lt;td&gt;Object owner&lt;/td&gt;
&lt;td&gt;Legacy use only — AWS recommends disabling these&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The rule of thumb:&lt;/strong&gt; Use IAM policies for your own users, bucket policies for external access or bucket-wide rules, and ignore ACLs unless you're dealing with legacy configurations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Anatomy of an S3 policy
&lt;/h2&gt;

&lt;p&gt;Every policy is a JSON document with these fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Version&lt;/strong&gt; — always &lt;code&gt;"2012-10-17"&lt;/code&gt; (the current policy language version)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Statement&lt;/strong&gt; — an array of permission rules, each containing:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Effect&lt;/strong&gt; — &lt;code&gt;"Allow"&lt;/code&gt; or &lt;code&gt;"Deny"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Principal&lt;/strong&gt; — who the rule applies to (&lt;code&gt;"*"&lt;/code&gt; for everyone, or a specific ARN)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action&lt;/strong&gt; — which S3 operations (&lt;code&gt;s3:GetObject&lt;/code&gt;, &lt;code&gt;s3:PutObject&lt;/code&gt;, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource&lt;/strong&gt; — which bucket/objects (specified as an ARN)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Condition&lt;/strong&gt; (optional) — extra constraints like IP range, encryption type, or request origin&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Common policies with working JSON
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Public read-only access
&lt;/h3&gt;

&lt;p&gt;Makes all objects in a bucket publicly readable. Use this for static website hosting or public assets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PublicReadGetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::my-bucket/*"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



&lt;p&gt;This allows anyone to read objects but not list the bucket contents, upload, or delete. The &lt;code&gt;/*&lt;/code&gt; in the Resource means all objects inside the bucket.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deny uploads without encryption
&lt;/h3&gt;

&lt;p&gt;Forces all uploaded objects to use server-side encryption. Note: this uses &lt;code&gt;Deny&lt;/code&gt; + a &lt;code&gt;StringNotEquals&lt;/code&gt; condition, not &lt;code&gt;Allow&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DenyUnencryptedUploads"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Deny"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:PutObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::my-bucket/*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"StringNotEquals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"s3:x-amz-server-side-encryption"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AES256"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



&lt;p&gt;This is the correct pattern. A common mistake is using &lt;code&gt;Allow&lt;/code&gt; with a &lt;code&gt;StringEquals&lt;/code&gt; condition — that permits encrypted uploads but doesn't block unencrypted ones if another policy allows &lt;code&gt;s3:PutObject&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scoped access for a specific IAM user
&lt;/h3&gt;

&lt;p&gt;Grants a single user read and write access to a bucket:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"UserReadWrite"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"AWS"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::123456789012:user/deploy-bot"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:PutObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:DeleteObject"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::my-bucket/*"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"UserListBucket"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"AWS"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::123456789012:user/deploy-bot"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:ListBucket"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::my-bucket"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



&lt;p&gt;Note the two statements: object-level actions use &lt;code&gt;my-bucket/*&lt;/code&gt; (objects inside), while &lt;code&gt;ListBucket&lt;/code&gt; uses &lt;code&gt;my-bucket&lt;/code&gt; (the bucket itself). Mixing these up is a common source of "Access Denied" errors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Restrict access by IP range
&lt;/h3&gt;

&lt;p&gt;Allows access only from your office or VPN IP range:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"RestrictToOfficeIP"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Deny"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::my-bucket"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::my-bucket/*"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"NotIpAddress"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"aws:SourceIp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"203.0.113.0/24"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Bucket policy vs IAM policy: when to use which
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Grant another AWS account access to your bucket&lt;/td&gt;
&lt;td&gt;Bucket policy (cross-account)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Make a bucket publicly readable&lt;/td&gt;
&lt;td&gt;Bucket policy (Principal: &lt;code&gt;*&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Control what your CI/CD pipeline can do&lt;/td&gt;
&lt;td&gt;IAM policy on the pipeline's IAM role&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Restrict access by IP or VPN&lt;/td&gt;
&lt;td&gt;Bucket policy with Condition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Give a Lambda function access to a bucket&lt;/td&gt;
&lt;td&gt;IAM policy on the Lambda execution role&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deny all public access organization-wide&lt;/td&gt;
&lt;td&gt;S3 Block Public Access (account-level setting)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In general: if the question is "who can access this bucket?", use a bucket policy. If the question is "what can this user/role do?", use an IAM policy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistakes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Forgetting S3 Block Public Access.&lt;/strong&gt; Even if your bucket policy allows public reads, the account-level Block Public Access setting overrides it. Check this first when public access isn't working.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource ARN mismatch.&lt;/strong&gt; &lt;code&gt;s3:ListBucket&lt;/code&gt; needs the bucket ARN (&lt;code&gt;arn:aws:s3:::my-bucket&lt;/code&gt;), while &lt;code&gt;s3:GetObject&lt;/code&gt; needs the object ARN (&lt;code&gt;arn:aws:s3:::my-bucket/*&lt;/code&gt;). This trips up almost everyone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Using ACLs.&lt;/strong&gt; AWS recommends disabling ACLs on new buckets (S3 Object Ownership: "Bucket owner enforced"). Bucket policies and IAM policies cover every use case that ACLs used to handle, with better auditability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overly broad wildcards.&lt;/strong&gt; &lt;code&gt;"Action": "s3:*"&lt;/code&gt; with &lt;code&gt;"Resource": "*"&lt;/code&gt; is an admin-level policy. Scope both to the specific actions and bucket you need.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;a href="https://awspolicygen.s3.amazonaws.com/policygen.html" rel="noopener noreferrer"&gt;AWS Policy Generator&lt;/a&gt; can help you build policies interactively if you're not sure about the syntax.&lt;/p&gt;

</description>
      <category>aws</category>
    </item>
  </channel>
</rss>
