<?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: MysticMc</title>
    <description>The latest articles on DEV Community by MysticMc (@nazmur96).</description>
    <link>https://dev.to/nazmur96</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%2F3770268%2F4a286af1-ae62-4533-9578-04a4bc8fb006.png</url>
      <title>DEV Community: MysticMc</title>
      <link>https://dev.to/nazmur96</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nazmur96"/>
    <language>en</language>
    <item>
      <title>5 Docker Scenarios Every Developer Should Practice (With Fixes &amp; Best Practices)</title>
      <dc:creator>MysticMc</dc:creator>
      <pubDate>Tue, 21 Apr 2026 20:56:35 +0000</pubDate>
      <link>https://dev.to/nazmur96/5-docker-scenarios-every-developer-should-practice-with-fixes-best-practices-3l70</link>
      <guid>https://dev.to/nazmur96/5-docker-scenarios-every-developer-should-practice-with-fixes-best-practices-3l70</guid>
      <description>&lt;p&gt;So you know the basics of Docker — &lt;code&gt;docker run&lt;/code&gt;, &lt;code&gt;docker build&lt;/code&gt;, maybe some &lt;code&gt;docker compose up&lt;/code&gt;. But do you know what happens when things break?&lt;/p&gt;

&lt;p&gt;This guide walks you through &lt;strong&gt;5 real-world Docker scenarios&lt;/strong&gt; that will sharpen your skills around debugging, security, storage, and production-readiness.&lt;/p&gt;




&lt;h2&gt;
  
  
  Scenario 1: The Broken Build 🔨
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Goal
&lt;/h3&gt;

&lt;p&gt;Fix a broken Dockerfile, then optimize it to be 10x smaller and production-ready.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;app.py&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello from Docker!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0.0.0.0&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;requirements.txt&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Flask==2.3.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ❌ The Broken Dockerfile
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; ubuntu:latest&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;python3

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . /opt/app&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; root&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; python /opt/app/app.py&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tasks
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Troubleshoot the Build
&lt;/h4&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; broken-app &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are &lt;strong&gt;at least 3 issues&lt;/strong&gt; hiding in that Dockerfile:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;pip&lt;/code&gt; is never installed&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;apt-get install&lt;/code&gt; is missing the &lt;code&gt;-y&lt;/code&gt; flag (hangs waiting for input)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;COPY&lt;/code&gt; happens before dependency install — busting the cache on every change&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  2. Fix Layer Caching
&lt;/h4&gt;

&lt;p&gt;Copy &lt;code&gt;requirements.txt&lt;/code&gt; first, install deps, &lt;em&gt;then&lt;/em&gt; copy the rest of the app. This way, changing &lt;code&gt;app.py&lt;/code&gt; won't trigger a full &lt;code&gt;pip install&lt;/code&gt; on every build.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; requirements.txt .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . /opt/app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Optimize the Image
&lt;/h4&gt;

&lt;p&gt;Switch from &lt;code&gt;ubuntu:latest&lt;/code&gt; to a slim base:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; python:3.12-slim&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /opt/app&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; requirements.txt .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-cache-dir&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 5000&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["python", "app.py"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Target:&lt;/strong&gt; &amp;lt; 150MB image size ✅&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Security Hardening
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Run as non-root&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; 1001&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run with a read-only filesystem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--read-only&lt;/span&gt; &lt;span class="nt"&gt;--tmpfs&lt;/span&gt; /tmp myapp:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Scenario 2: The Ghost Data 👻
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Goal
&lt;/h3&gt;

&lt;p&gt;Understand Docker's storage lifecycle and how to make data actually persist.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tasks
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Run an Ephemeral Container
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; web-test &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:80 nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Write Data Inside the Container
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; web-test bash
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"hello"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /usr/share/nginx/html/test.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visit &lt;code&gt;http://localhost:8080/test.txt&lt;/code&gt; — it's there!&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Destroy &amp;amp; Recreate
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker stop web-test
docker &lt;span class="nb"&gt;rm &lt;/span&gt;web-test
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; web-test2 &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:80 nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The file is gone. Why?&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Because the container filesystem is &lt;strong&gt;ephemeral&lt;/strong&gt; — it only lives as long as the container does.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  4. Named Volume Persistence
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker volume create web-data

docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; web-test &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:80 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; web-data:/usr/share/nginx/html &lt;span class="se"&gt;\&lt;/span&gt;
  nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  5. Verify Persistence
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; web-test bash
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"persistent data"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /usr/share/nginx/html/test.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stop and remove the container, then start a new one with the same volume — your file will still be there. 🎉&lt;/p&gt;

&lt;h4&gt;
  
  
  6. Cleanup
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker system prune &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: &lt;code&gt;system prune&lt;/code&gt; removes stopped containers, dangling images, and unused networks — but &lt;strong&gt;not named volumes&lt;/strong&gt; unless you add &lt;code&gt;--volumes&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Scenario 3: The Flaky Database Connection 🐘
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Goal
&lt;/h3&gt;

&lt;p&gt;Fix service startup dependency issues in Docker Compose.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Broken &lt;code&gt;docker-compose.yml&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;ports&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;5000:5000"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DB_HOST=postgres&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;

  &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:15&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD=secret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tasks
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Run the Stack
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; &lt;code&gt;depends_on&lt;/code&gt; only waits for the container to &lt;em&gt;start&lt;/em&gt;, not for Postgres to be &lt;em&gt;ready to accept connections&lt;/em&gt;. Your web app crashes on startup.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Add a Healthcheck to Postgres
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:15&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD=secret&lt;/span&gt;
  &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;test&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;CMD-SHELL"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pg_isready&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-U&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;postgres"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
    &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
    &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Fix &lt;code&gt;depends_on&lt;/code&gt; with a Condition
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_healthy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now your web service won't start until Postgres passes its healthcheck. ✅&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Move Secrets to &lt;code&gt;.env&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;.env&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;secret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;/strong&gt;&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;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD=${POSTGRES_PASSWORD}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  5. Keep Secrets Out of Git
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;.gitignore&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Never commit &lt;code&gt;.env&lt;/code&gt; files. Ever.&lt;/p&gt;




&lt;h2&gt;
  
  
  Scenario 4: The Evil Image Scanner 🔍
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Goal
&lt;/h3&gt;

&lt;p&gt;Find and fix vulnerabilities hiding in your Docker images.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tasks
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Build a Vulnerable Image
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; nginx:1.21.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Install Trivy
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;aquasecurity/trivy/trivy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or on Linux:&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;-sfL&lt;/span&gt; https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Scan the Image
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;trivy image nginx:1.21.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll see a wall of &lt;strong&gt;HIGH&lt;/strong&gt; and &lt;strong&gt;CRITICAL&lt;/strong&gt; CVEs. This is what ships to production when nobody checks.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Fix the Base Image
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; nginx:1.25-bookworm&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or go even lighter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; nginx:alpine&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  5. Rescan
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;trivy image nginx:1.25-bookworm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Expected:&lt;/strong&gt; 0 CRITICAL vulnerabilities ✅&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Make image scanning part of your CI/CD pipeline — not an afterthought.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Scenario 5: The Limited Resource Box 📦
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Goal
&lt;/h3&gt;

&lt;p&gt;Run containers safely under strict resource constraints and enable offline portability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tasks
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Build the Optimized Image
&lt;/h4&gt;

&lt;p&gt;Use the hardened image from Scenario 1.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Run with Resource Limits
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--memory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;256m &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cpus&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.5 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--read-only&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--tmpfs&lt;/span&gt; /tmp &lt;span class="se"&gt;\&lt;/span&gt;
  myapp:latest
&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;Flag&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--memory=256m&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hard cap on RAM usage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--cpus=0.5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Limits to half a CPU core&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--read-only&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Prevents filesystem writes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--tmpfs /tmp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mounts writable in-memory temp dir&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  3. Verify the Restrictions
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &amp;lt;container_id&amp;gt; bash
&lt;span class="nb"&gt;touch&lt;/span&gt; /etc/test
&lt;span class="c"&gt;# Permission denied ✅&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Monitor resource usage live:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker stats
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4. Export the Image
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker save &lt;span class="nt"&gt;-o&lt;/span&gt; myapp.tar myapp:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  5. Simulate an Offline Machine
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker rmi myapp:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  6. Restore the Image
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker load &lt;span class="nt"&gt;-i&lt;/span&gt; myapp.tar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  7. Run Without Internet
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run myapp:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Works fully offline. 🚀 Great for air-gapped environments, demos, or CI runners without registry access.&lt;/p&gt;




&lt;h2&gt;
  
  
  What You've Learned 🎓
&lt;/h2&gt;

&lt;p&gt;After completing all five scenarios, you now have hands-on experience with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Dockerfile debugging &amp;amp; optimization&lt;/strong&gt; — fixing real build errors and shrinking image sizes&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Layer caching strategies&lt;/strong&gt; — speeding up builds without reinstalling dependencies&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Volume persistence&lt;/strong&gt; — understanding ephemeral vs. persistent storage&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Compose healthchecks&lt;/strong&gt; — preventing race conditions between services&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Image vulnerability scanning&lt;/strong&gt; — catching CVEs before they reach production&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Runtime security hardening&lt;/strong&gt; — non-root users, read-only filesystems, resource limits&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Offline container portability&lt;/strong&gt; — shipping containers without a registry&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Want more? Drop a comment and I can turn this into a full GitHub repo with solutions, or expand each scenario into its own deep-dive post.&lt;/em&gt;&lt;/p&gt;



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

&lt;/div&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>containers</category>
      <category>beginners</category>
    </item>
    <item>
      <title>⚙️ My first CI/CD pipeline: From git push to production in 10 minutes</title>
      <dc:creator>MysticMc</dc:creator>
      <pubDate>Thu, 02 Apr 2026 19:45:56 +0000</pubDate>
      <link>https://dev.to/nazmur96/my-first-cicd-pipeline-from-git-push-to-production-in-10-minutes-1h4f</link>
      <guid>https://dev.to/nazmur96/my-first-cicd-pipeline-from-git-push-to-production-in-10-minutes-1h4f</guid>
      <description>&lt;p&gt;Remember the old days?&lt;/p&gt;

&lt;p&gt;You write code. You test it manually (maybe). You open FileZilla. You drag and drop files to a server. You pray.&lt;/p&gt;

&lt;p&gt;Then someone yells: "Who deployed on a Friday?!"&lt;/p&gt;

&lt;p&gt;Those days are dead.&lt;/p&gt;

&lt;p&gt;CI/CD pipelines are the reason modern developers ship code 10x faster with 90% fewer bugs. And the best part? You can set one up in 10 minutes. For free.&lt;/p&gt;

&lt;p&gt;Let me show you.&lt;/p&gt;




&lt;p&gt;What is CI/CD? (The 30-second explanation)&lt;/p&gt;

&lt;p&gt;CI = Continuous Integration – Every time you push code, automatically test it.&lt;/p&gt;

&lt;p&gt;CD = Continuous Delivery/Deployment – If tests pass, automatically deploy it.&lt;/p&gt;

&lt;p&gt;In practice:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push origin main
   ↓
&lt;span class="o"&gt;[&lt;/span&gt;Automatic] Run tests
   ↓
&lt;span class="o"&gt;[&lt;/span&gt;Automatic] Build the app
   ↓
&lt;span class="o"&gt;[&lt;/span&gt;Automatic] Deploy to server
   ↓
You get a notification: &lt;span class="s2"&gt;"✅ Deployment successful"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You never touch a server. You never run scp or FTP. You just push code.&lt;/p&gt;




&lt;p&gt;The 10-Minute Challenge&lt;/p&gt;

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

&lt;p&gt;· A simple Node.js/Express app (or your own project)&lt;br&gt;
· A GitHub repository&lt;br&gt;
· A GitHub Actions workflow that:&lt;br&gt;
  · Runs tests automatically&lt;br&gt;
  · Deploys to a free hosting service (Render.com – no credit card)&lt;/p&gt;

&lt;p&gt;Total time: ~10 minutes. I'll wait.&lt;/p&gt;



&lt;p&gt;What You'll Need (All Free)&lt;/p&gt;

&lt;p&gt;Tool Why&lt;br&gt;
GitHub account Hosts your code + runs CI/CD&lt;br&gt;
Render.com account Free hosting (similar to Heroku)&lt;br&gt;
A simple app We'll make one in 2 minutes&lt;/p&gt;

&lt;p&gt;No credit card required. No servers to manage.&lt;/p&gt;



&lt;p&gt;Step 1: The App (2 minutes)&lt;/p&gt;

&lt;p&gt;Create a new folder and a simple Express app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;my-cicd-app
&lt;span class="nb"&gt;cd &lt;/span&gt;my-cicd-app
npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;express
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create index.js:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&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;PORT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CI/CD works! 🚀&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/health&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;OK&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="c1"&gt;// A simple test endpoint&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/add/:a/:b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&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;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PORT&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="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="s2"&gt;`App running on port &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a test file test.js (we'll use Node's built-in assert):&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;assert&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Simple tests that will run in CI&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="s1"&gt;Running tests...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Test 1: Addition works&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strictEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;5&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="s1"&gt;✅ Test 1 passed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Test 2: String test&lt;/span&gt;
&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strictEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;✅ Test 2 passed&lt;/span&gt;&lt;span class="dl"&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;🎉 All tests passed!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update package.json with a test script:&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;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node test.js"&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;Test it locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;test&lt;/span&gt;          &lt;span class="c"&gt;# Should show "All tests passed!"&lt;/span&gt;
npm start         &lt;span class="c"&gt;# Visit http://localhost:3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Step 2: Push to GitHub (2 minutes)&lt;/p&gt;

&lt;p&gt;Create a repository on GitHub (don't initialize with README – we have our own).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git init
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Initial commit"&lt;/span&gt;
git remote add origin https://github.com/YOUR_USERNAME/my-cicd-app.git
git branch &lt;span class="nt"&gt;-M&lt;/span&gt; main
git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Step 3: Create the CI/CD Pipeline (3 minutes)&lt;/p&gt;

&lt;p&gt;This is where the magic happens. GitHub Actions reads a file in .github/workflows/ and runs it.&lt;/p&gt;

&lt;p&gt;Create this folder and file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; .github/workflows
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create .github/workflows/deploy.yml:&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;Deploy to Production&lt;/span&gt;

&lt;span class="c1"&gt;# When should this run?&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="nv"&gt;main&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# Every push to main branch&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;    &lt;span class="c1"&gt;# Also allow manual trigger&lt;/span&gt;

&lt;span class="c1"&gt;# What environment variables do we need?&lt;/span&gt;
&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;NODE_VERSION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;18'&lt;/span&gt;

&lt;span class="c1"&gt;# Jobs run in parallel by default&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# JOB 1: Test&lt;/span&gt;
  &lt;span class="na"&gt;test&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;Run Tests&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="c1"&gt;# Free Linux runner&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 code&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@v4&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;Setup Node.js&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/setup-node@v4&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;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.NODE_VERSION }}&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;Install dependencies&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;npm ci&lt;/span&gt;  &lt;span class="c1"&gt;# ci is faster and stricter than install&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;Run tests&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;npm test&lt;/span&gt;

  &lt;span class="c1"&gt;# JOB 2: Deploy (only if tests passed)&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to Render&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;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;  &lt;span class="c1"&gt;# Wait for test job to succeed&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 code&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@v4&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;Deploy to Render&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;johnbeynon/render-deploy-action@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;service-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.RENDER_SERVICE_ID }}&lt;/span&gt;
          &lt;span class="na"&gt;api-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.RENDER_API_KEY }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What this does:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;On every git push to main:&lt;/li&gt;
&lt;li&gt;Spin up a fresh Linux machine (free)&lt;/li&gt;
&lt;li&gt;Run npm test&lt;/li&gt;
&lt;li&gt;If tests pass → deploy to Render&lt;/li&gt;
&lt;li&gt;If tests fail → stop (no deploy)&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;Step 4: Hosting on Render (3 minutes)&lt;/p&gt;

&lt;p&gt;Render is like the old Heroku (but with a free tier that actually works).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to render.com and sign up with GitHub.&lt;/li&gt;
&lt;li&gt;Click "New +" → "Web Service"&lt;/li&gt;
&lt;li&gt;Connect your GitHub repository (my-cicd-app)&lt;/li&gt;
&lt;li&gt;Fill in the settings:
· Name: my-cicd-app
· Environment: Node
· Build Command: npm install
· Start Command: npm start
· Plan: Free&lt;/li&gt;
&lt;li&gt;Click "Create Web Service"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Render will deploy your app once manually. Wait for the green "Live" badge.&lt;/p&gt;

&lt;p&gt;You'll get a URL like: &lt;a href="https://my-cicd-app.onrender.com" rel="noopener noreferrer"&gt;https://my-cicd-app.onrender.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Visit it. You should see your JSON message.&lt;/p&gt;




&lt;p&gt;Step 5: Connect GitHub Actions to Render (2 minutes)&lt;/p&gt;

&lt;p&gt;Now we need to give GitHub Actions permission to deploy to Render.&lt;/p&gt;

&lt;p&gt;Get your Render API Key:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to Render Dashboard → Account Settings (top right)&lt;/li&gt;
&lt;li&gt;Scroll to "API Keys" → Click "Create API Key"&lt;/li&gt;
&lt;li&gt;Name it github-actions → Copy the key (starts with rnd_)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Get your Render Service ID:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to your Web Service page on Render&lt;/li&gt;
&lt;li&gt;Look at the URL: &lt;a href="https://dashboard.render.com/web/srv-abc123def" rel="noopener noreferrer"&gt;https://dashboard.render.com/web/srv-abc123def&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The srv-abc123def part is your Service ID&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Add them as GitHub Secrets:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to your GitHub repository → Settings → Secrets and variables → Actions&lt;/li&gt;
&lt;li&gt;Click "New repository secret"&lt;/li&gt;
&lt;li&gt;Add RENDER_API_KEY → paste your API key&lt;/li&gt;
&lt;li&gt;Add RENDER_SERVICE_ID → paste your Service ID&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;Step 6: Trigger Your First Pipeline (1 minute)&lt;/p&gt;

&lt;p&gt;Make a small change to trigger the pipeline:&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;# Change the message in index.js&lt;/span&gt;
res.json&lt;span class="o"&gt;({&lt;/span&gt; message: &lt;span class="s1"&gt;'My first CI/CD pipeline! 🎉'&lt;/span&gt; &lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c"&gt;# Commit and push&lt;/span&gt;
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Test CI/CD pipeline"&lt;/span&gt;
git push origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now go to your GitHub repository → Actions tab.&lt;/p&gt;

&lt;p&gt;You'll see a workflow running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deploy to Production
  ├── Run Tests (yellow → green)
  └── Deploy to Render (yellow → green)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When both turn green ✅, visit your Render URL. Your new message is live.&lt;/p&gt;

&lt;p&gt;You just did CI/CD. 🚀&lt;/p&gt;




&lt;p&gt;What Just Happened? (The Diagram)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your laptop
    │
    │ git push origin main
    ▼
GitHub (Actions)
    │
    │ Spins up runner
    ▼
┌─────────────────────────────────────┐
│  CI Pipeline (Test)                 │
│  ├── npm ci                         │
│  ├── npm test                       │
│  └── ✅ All tests passed            │
└─────────────────────────────────────┘
    │
    │ Tests pass → trigger CD
    ▼
┌─────────────────────────────────────┐
│  CD Pipeline (Deploy)               │
│  ├── Call Render API                │
│  ├── Render pulls code              │
│  ├── npm install                    │
│  ├── npm start                      │
│  └── ✅ Live at your URL            │
└─────────────────────────────────────┘
    │
    ▼
Production server (Render)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Common Variations (Adapt to Your Stack)&lt;/p&gt;

&lt;p&gt;For a Python (Django/Flask) app:&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="c1"&gt;# .github/workflows/deploy.yml&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;Setup Python&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/setup-python@v4&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;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.11'&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;Install dependencies&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;pip install -r requirements.txt&lt;/span&gt;
    &lt;span class="s"&gt;pip install pytest&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;Run tests&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;pytest&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;Deploy&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;# Render handles Python automatically&lt;/span&gt;
    &lt;span class="s"&gt;# Or use: flyctl deploy, railway up, etc.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a React/Vite static site:&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="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;Install dependencies&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;npm ci&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&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;npm run build&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;Deploy to Netlify&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;nwtgck/actions-netlify@v2&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;publish-dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./dist'&lt;/span&gt;
    &lt;span class="na"&gt;production-branch&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;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;NETLIFY_AUTH_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.NETLIFY_TOKEN }}&lt;/span&gt;
    &lt;span class="na"&gt;NETLIFY_SITE_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.NETLIFY_SITE_ID }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a Docker container:&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="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 Docker image&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;docker build -t myapp .&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 Docker Hub&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;echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin&lt;/span&gt;
    &lt;span class="s"&gt;docker push myusername/myapp:latest&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;Deploy to DigitalOcean&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;appleboy/ssh-action@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;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.HOST }}&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.USERNAME }}&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SSH_KEY }}&lt;/span&gt;
    &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker pull myusername/myapp &amp;amp;&amp;amp; docker-compose up -d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Pro Tips (From Someone Who Broke Production)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Always test before deploying (duh)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The needs: test line ensures you never deploy broken code. Add a failing test and watch the pipeline stop.&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="c1"&gt;// Add this to test.js – it will FAIL&lt;/span&gt;
&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strictEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&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="s1"&gt;This line never runs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Push it. Watch the pipeline fail at the test stage. Deploy never happens. You just saved production.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use npm ci instead of npm install&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;· npm install can update package-lock.json (unexpected changes)&lt;br&gt;
· npm ci installs exactly what's in package-lock.json (reproducible builds)&lt;/p&gt;

&lt;p&gt;Always use npm ci in CI.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add a "staging" environment&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For real projects, deploy to staging first:&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;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="nv"&gt;main&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;     &lt;span class="c1"&gt;# Deploys to staging&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="nv"&gt;production&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# Deploys to production&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Add notifications&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Get a Slack/Discord message when deploy finishes:&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="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;Send Slack notification&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;slackapi/slack-github-action@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;payload&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"text": "✅ Deployed to production!"&lt;/span&gt;
      &lt;span class="s"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;SLACK_WEBHOOK_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SLACK_WEBHOOK }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Manual approval for production (for serious teams)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;deploy-prod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;  &lt;span class="c1"&gt;# Requires approval in GitHub&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;Deploy to production&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;./deploy.sh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then go to GitHub → Settings → Environments → Add protection rule.&lt;/p&gt;




&lt;p&gt;Troubleshooting (When Things Go Wrong)&lt;/p&gt;

&lt;p&gt;Symptom Most likely fix&lt;br&gt;
Workflow doesn't trigger Check branch name: main vs master&lt;br&gt;
Tests fail but work locally Different Node version? Add .nvmrc file&lt;br&gt;
Deploy step fails Wrong Render Service ID or API key&lt;br&gt;
"Module not found" Forgot npm ci step?&lt;br&gt;
"Permission denied" GitHub Actions needs write permissions → Settings → Actions → General → Workflow permissions&lt;/p&gt;



&lt;p&gt;What You Just Learned&lt;/p&gt;

&lt;p&gt;✅ CI = Automatic testing on every push&lt;br&gt;
✅ CD = Automatic deployment if tests pass&lt;br&gt;
✅ GitHub Actions = Free CI/CD runners&lt;br&gt;
✅ Render = Free hosting with API deploys&lt;br&gt;
✅ Secrets = Store API keys safely&lt;/p&gt;

&lt;p&gt;You can now add CI/CD to any project in ~10 minutes.&lt;/p&gt;



&lt;p&gt;Next Steps (Level Up)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add more tests – Unit tests, integration tests&lt;/li&gt;
&lt;li&gt;Add a database – Render has free PostgreSQL&lt;/li&gt;
&lt;li&gt;Add a staging environment – Deploy to staging first, then production&lt;/li&gt;
&lt;li&gt;Add end-to-end tests – Cypress or Playwright&lt;/li&gt;
&lt;li&gt;Try other platforms – Vercel, Netlify, Railway, Fly.io&lt;/li&gt;
&lt;/ol&gt;



&lt;p&gt;The Ultimate Test&lt;/p&gt;

&lt;p&gt;Break something on purpose:&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="c1"&gt;// Add this to index.js – a hidden bug&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/broken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Oops&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// This will crash the server&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Push it. Watch the pipeline deploy it (tests passed, right?). Then visit /broken and watch it fail.&lt;/p&gt;

&lt;p&gt;Now fix it. Push again. Watch the pipeline fix production automatically.&lt;/p&gt;

&lt;p&gt;That's the power of CI/CD. You're not afraid to deploy anymore. Because if something breaks, you fix it and push again. No panic. No Friday deploys. Just code.&lt;/p&gt;




&lt;p&gt;Your 10-Minute Challenge Recap&lt;/p&gt;

&lt;p&gt;· Created an Express app&lt;br&gt;
· Pushed to GitHub&lt;br&gt;
· Created .github/workflows/deploy.yml&lt;br&gt;
· Signed up for Render&lt;br&gt;
· Added API keys as GitHub Secrets&lt;br&gt;
· Made a change and watched the pipeline run&lt;/p&gt;

&lt;p&gt;You did it. 🎉&lt;/p&gt;

&lt;p&gt;Now go add CI/CD to your real project. Your future self (and your team) will thank you.&lt;/p&gt;




&lt;p&gt;What stack do you want to see a CI/CD example for next? Drop a comment (Django, Spring Boot, Next.js, Go, Rust...).&lt;/p&gt;

&lt;p&gt;Follow for more DevOps-for-beginners content.&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>devops</category>
      <category>githubactions</category>
    </item>
    <item>
      <title>🚪 Authentication vs. Authorization – The Bouncer Analogy (Clear up the confusion forever)</title>
      <dc:creator>MysticMc</dc:creator>
      <pubDate>Thu, 02 Apr 2026 19:36:53 +0000</pubDate>
      <link>https://dev.to/nazmur96/authentication-vs-authorization-the-bouncer-analogy-clear-up-the-confusion-forever-5118</link>
      <guid>https://dev.to/nazmur96/authentication-vs-authorization-the-bouncer-analogy-clear-up-the-confusion-forever-5118</guid>
      <description>&lt;p&gt;I can't tell you how many times I've seen these two words used interchangeably.&lt;/p&gt;

&lt;p&gt;Even experienced developers sometimes slip up:&lt;/p&gt;

&lt;p&gt;"We need to add Google Auth so users can authorize with their email."&lt;/p&gt;

&lt;p&gt;No. That's authentication.&lt;/p&gt;

&lt;p&gt;"The JWT token authenticates whether the user is an admin."&lt;/p&gt;

&lt;p&gt;No. That's authorization.&lt;/p&gt;

&lt;p&gt;They sound similar. They work together. But they are not the same thing.&lt;/p&gt;

&lt;p&gt;And mixing them up leads to security holes, confused code, and embarrassing bugs.&lt;/p&gt;

&lt;p&gt;Here's the one analogy that makes it stick forever.&lt;/p&gt;




&lt;p&gt;The Bouncer Analogy 🚪&lt;/p&gt;

&lt;p&gt;Imagine you're at a nightclub.&lt;/p&gt;

&lt;p&gt;Step 1: Authentication (Getting past the front door)&lt;/p&gt;

&lt;p&gt;You walk up to the bouncer. He asks:&lt;/p&gt;

&lt;p&gt;"Do you have an ID?"&lt;/p&gt;

&lt;p&gt;You show your driver's license. He checks the photo. He scans it. He confirms:&lt;/p&gt;

&lt;p&gt;"Okay, you are who you say you are. You're on the guest list. Come in."&lt;/p&gt;

&lt;p&gt;That's authentication. You proved your identity. You're in the club.&lt;/p&gt;

&lt;p&gt;Authentication answers: "Are you who you claim to be?"&lt;/p&gt;




&lt;p&gt;Step 2: Authorization (Getting into VIP)&lt;/p&gt;

&lt;p&gt;Now you're inside the club. You see the VIP section – better drinks, better view, actual seats that aren't sticky.&lt;/p&gt;

&lt;p&gt;You try to walk in. Another bouncer stops you:&lt;/p&gt;

&lt;p&gt;"Whoa there. This is VIP. Do you have a wristband?"&lt;/p&gt;

&lt;p&gt;You show your black wristband (which you paid $500 for). He checks it and says:&lt;/p&gt;

&lt;p&gt;"Cool. You're authorized. Go ahead."&lt;/p&gt;

&lt;p&gt;That's authorization. Your identity is already confirmed. Now we're checking what you're allowed to do.&lt;/p&gt;

&lt;p&gt;Authorization answers: "Are you allowed to do this specific thing?"&lt;/p&gt;




&lt;p&gt;The Table That Finally Makes It Click&lt;/p&gt;

&lt;p&gt;Authentication Authorization&lt;br&gt;
Question it answers "Who are you?" "What can you do?"&lt;br&gt;
When it happens First (at login) After (on each request)&lt;br&gt;
What it proves Identity Permissions&lt;br&gt;
How it works Passwords, biometrics, security keys Roles, permissions, policies&lt;br&gt;
Tells you "You are Bob" "Bob can delete posts"&lt;br&gt;
Bouncer analogy Checking your ID at the door Checking your VIP wristband&lt;br&gt;
HTTP Status Code 401 Unauthorized (ironically named) 403 Forbidden&lt;/p&gt;

&lt;p&gt;Side note: Yes, HTTP 401 says "Unauthorized" but actually means "unauthenticated." It's a historical mistake that confuses everyone. Just remember: 401 = Login first. 403 = You're logged in but not allowed.&lt;/p&gt;



&lt;p&gt;Real Web Examples&lt;/p&gt;

&lt;p&gt;Example 1: Logging into Gmail&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Authentication: You type your email + password. Google checks it's really you. (Success → you get a session cookie or JWT token)&lt;/li&gt;
&lt;li&gt;Authorization: You try to delete an email. Google checks: "Does this user have 'delete' permission for this email?" (Yes, it's your own email)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Same user, same login, but authorization happens on every single action.&lt;/p&gt;



&lt;p&gt;Example 2: Google Drive sharing&lt;/p&gt;

&lt;p&gt;· Authentication: You log into your Google account.&lt;br&gt;
· Authorization: You try to open a shared document. Google checks: "Is this user on the 'can view' list?" If yes → authorized. If no → 403 error.&lt;/p&gt;

&lt;p&gt;You are authenticated (Google knows it's you), but not authorized (you don't own that doc).&lt;/p&gt;



&lt;p&gt;Example 3: Admin dashboard&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="c1"&gt;// Authentication: Did the user log in?&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;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;Please log in first&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="c1"&gt;// Authorization: Is the logged-in user an admin?&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;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;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;Admins only&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="c1"&gt;// If we reach here, user is BOTH authenticated AND authorized&lt;/span&gt;
&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Welcome to the admin panel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See the difference? Two checks, two different purposes.&lt;/p&gt;




&lt;p&gt;The Technologies (What actually powers authN and authZ)&lt;/p&gt;

&lt;p&gt;Now let's connect the theory to the actual code you'll write.&lt;/p&gt;

&lt;p&gt;Authentication Technologies (Proving who you are)&lt;/p&gt;

&lt;p&gt;Technology What it does When to use&lt;br&gt;
Passwords + Hash (bcrypt) User provides secret; you compare hashed version Most apps (standard)&lt;br&gt;
JWT (JSON Web Token) Encoded token containing user ID + signature Stateless APIs, mobile apps&lt;br&gt;
Sessions (with cookies) Server stores user data; cookie acts as key Traditional web apps (Rails, PHP, Node with express-session)&lt;br&gt;
OAuth 2.0 "Login with Google/GitHub/Facebook" Letting third parties prove identity&lt;br&gt;
Biometrics Fingerprint, FaceID, passkeys Mobile apps, high-security&lt;br&gt;
2FA / MFA Password + one-time code from phone Any app with sensitive data&lt;/p&gt;

&lt;p&gt;Authentication result: You get a credential (session cookie, JWT token, API key) that you send with every subsequent request.&lt;/p&gt;



&lt;p&gt;Authorization Technologies (What you're allowed to do)&lt;/p&gt;

&lt;p&gt;Technology What it does When to use&lt;br&gt;
RBAC (Role-Based Access Control) Users have roles (admin, editor, viewer); roles have permissions Most business apps (simplest)&lt;br&gt;
ABAC (Attribute-Based Access Control) Permissions based on attributes (time of day, user location, resource owner) Complex systems (healthcare, finance)&lt;br&gt;
ACL (Access Control Lists) Each resource has a list of who can access it File systems, legacy apps&lt;br&gt;
Policies (Casbin, OPA) Declarative rules: "user can edit post if user.id == post.authorId" Fine-grained permissions&lt;/p&gt;

&lt;p&gt;Authorization result: A yes/no answer for each action. No tokens. Just logic.&lt;/p&gt;



&lt;p&gt;The Confusion: JWT, Sessions, Cookies, localStorage&lt;/p&gt;

&lt;p&gt;This is where beginners get lost. Let me untangle it.&lt;/p&gt;

&lt;p&gt;What stores your authentication state?&lt;/p&gt;

&lt;p&gt;After you log in, you need to remember that you're authenticated for future requests.&lt;/p&gt;

&lt;p&gt;Option 1: Sessions (Server-side)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. You log in.
2. Server creates a session record in its database (or Redis).
3. Server sends you a cookie containing a session ID.
4. You send that cookie with every request.
5. Server looks up the session ID to know who you are.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Option 2: JWT (Client-side)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. You log in.
2. Server creates a JWT token (contains your user ID, expiration, signature).
3. Server sends you the token.
4. You store it in localStorage or an HTTP-only cookie.
5. You send the token in the Authorization header with every request.
6. Server verifies the signature (no database lookup needed).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which one should you use?&lt;/p&gt;

&lt;p&gt;Sessions JWT&lt;br&gt;
Where is data stored? Server (database/Redis) Client (token itself)&lt;br&gt;
Can you revoke instantly? ✅ Yes (delete session from DB) ❌ No (token valid until expiration)&lt;br&gt;
Scales how? Need shared session store (Redis) Stateless (any server can verify)&lt;br&gt;
Best for... Traditional web apps Mobile apps, microservices, SPAs&lt;/p&gt;

&lt;p&gt;My advice for beginners: Start with sessions + HTTP-only cookies. It's simpler and more secure by default. Move to JWT only when you have a reason (e.g., mobile app, separate API server).&lt;/p&gt;



&lt;p&gt;localStorage vs. cookies (Security warning!)&lt;/p&gt;

&lt;p&gt;This is critical.&lt;/p&gt;

&lt;p&gt;Storage method Accessible by JavaScript? Vulnerable to XSS? HttpOnly option?&lt;br&gt;
localStorage ✅ Yes (any script can read it) ❌ Yes (high risk) ❌ No&lt;br&gt;
Regular cookie ✅ Yes ❌ Yes ❌ No&lt;br&gt;
HttpOnly cookie ❌ No (JS cannot read it) ✅ No (much safer) ✅ Yes&lt;/p&gt;

&lt;p&gt;Rule of thumb:&lt;/p&gt;

&lt;p&gt;· Never store authentication tokens in localStorage if you care about security. Any XSS vulnerability = attacker steals every user's token.&lt;br&gt;
· Use HttpOnly cookies for sessions or JWTs. They can't be read by 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="c1"&gt;// BAD (vulnerable to XSS)&lt;/span&gt;
&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userJWT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// GOOD (more secure)&lt;/span&gt;
&lt;span class="c1"&gt;// Set cookie on server with:&lt;/span&gt;
&lt;span class="nb"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;Cookie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;xyz&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;HttpOnly&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;Secure&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;SameSite&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;Strict&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;OAuth 2.0 – The special case&lt;/p&gt;

&lt;p&gt;OAuth is often called "authentication," but that's not quite right.&lt;/p&gt;

&lt;p&gt;OAuth is actually authorization that implies authentication.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;You click "Login with Google."&lt;/li&gt;
&lt;li&gt;Google asks: "This app wants to see your email and name. Allow?"&lt;/li&gt;
&lt;li&gt;You say yes.&lt;/li&gt;
&lt;li&gt;Google tells your app: "This user is &lt;a href="mailto:bob@gmail.com"&gt;bob@gmail.com&lt;/a&gt;" (authentication info) AND "Here's a token to access their Google Drive" (authorization).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;OAuth solves: "Let me prove who I am without giving you my password, and also let me give you limited access to my data."&lt;/p&gt;

&lt;p&gt;Common confusion: People call OAuth "social login" (authentication), but OAuth was designed for delegated authorization (like "let this app post to my Twitter"). The login part is a bonus.&lt;/p&gt;




&lt;p&gt;Common Real-World Scenarios&lt;/p&gt;

&lt;p&gt;Scenario 1: You're logged into Netflix but can't watch a specific movie&lt;/p&gt;

&lt;p&gt;· Authentication: ✅ You logged in. Netflix knows it's you.&lt;br&gt;
· Authorization: ❌ Your plan doesn't include that movie (or it's region-locked).&lt;/p&gt;

&lt;p&gt;Error message: "This title is not available in your region." (403 Forbidden)&lt;/p&gt;



&lt;p&gt;Scenario 2: You try to delete a comment on Reddit that isn't yours&lt;/p&gt;

&lt;p&gt;· Authentication: ✅ You're logged in.&lt;br&gt;
· Authorization: ❌ You didn't write that comment.&lt;/p&gt;

&lt;p&gt;Error message: "You cannot delete this comment." (403)&lt;/p&gt;



&lt;p&gt;Scenario 3: You open a private GitHub repo without logging in&lt;/p&gt;

&lt;p&gt;· Authentication: ❌ GitHub has no idea who you are.&lt;br&gt;
· Authorization: ⏸️ Not even checked because you're not authenticated.&lt;/p&gt;

&lt;p&gt;Error message: "Not Found" (404 – GitHub does this on purpose to hide private repos exist). But technically it's a 401.&lt;/p&gt;



&lt;p&gt;The 5-Minute Implementation (Node.js + Express)&lt;/p&gt;

&lt;p&gt;Here's a minimal example showing both concepts:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Fake database&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;alice@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;alice123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bob@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bob123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;viewer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Post 1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;authorId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Post 2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;authorId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// ---------- AUTHENTICATION ----------&lt;/span&gt;
&lt;span class="c1"&gt;// Login endpoint – proves who you are&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;password&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid credentials&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// 401 = unauthenticated&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Create a session (in real life, use express-session)&lt;/span&gt;
  &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Logged in!&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="c1"&gt;// Check authentication middleware&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isAuthenticated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Please log in first&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;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ---------- AUTHORIZATION ----------&lt;/span&gt;
&lt;span class="c1"&gt;// Check authorization middleware (role-based)&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isAdmin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&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;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Admins only&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// 403 = forbidden&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Check authorization (ownership)&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isOwner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&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;postId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;postId&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&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;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorId&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;You can only edit your own posts&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;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ---------- ROUTES ----------&lt;/span&gt;
&lt;span class="c1"&gt;// Anyone can view (no authentication needed)&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Authenticated only (any logged-in user)&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isAuthenticated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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="c1"&gt;// Create a new post&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Post created&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="c1"&gt;// Authorization: must be admin OR owner&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/posts/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isAuthenticated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isOwner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Post updated&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="c1"&gt;// Authorization: admin only&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/posts/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isAuthenticated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isAdmin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Post deleted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See the pattern?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Authentication happens first (isAuthenticated).&lt;/li&gt;
&lt;li&gt;Authorization happens second (isAdmin, isOwner).&lt;/li&gt;
&lt;li&gt;You can be authenticated but not authorized (403).&lt;/li&gt;
&lt;li&gt;You can be neither (401).&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;The Security Checklist&lt;/p&gt;

&lt;p&gt;When building auth, use this mental checklist:&lt;/p&gt;

&lt;p&gt;Question Check&lt;br&gt;
Are passwords hashed with bcrypt (not plain text)? ☐&lt;br&gt;
Is HTTPS enabled everywhere? ☐&lt;br&gt;
Are session cookies marked HttpOnly + Secure? ☐&lt;br&gt;
Do you have rate limiting on login attempts? ☐&lt;br&gt;
Does every protected endpoint check authentication FIRST? ☐&lt;br&gt;
Does every sensitive endpoint check authorization SECOND? ☐&lt;br&gt;
Are you using the correct HTTP status codes (401 vs 403)? ☐&lt;br&gt;
Are JWT tokens (if used) stored in HttpOnly cookies, not localStorage? ☐&lt;/p&gt;



&lt;p&gt;Quick Reference Card (Save This)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────┐
│  AUTHENTICATION                     AUTHORIZATION           │
│  "Who are you?"                     "What can you do?"      │
│                                                             │
│  First (login)                      After (every action)    │
│  Passwords, JWT, OAuth              Roles, permissions      │
│  HTTP 401 (Unauthorized)            HTTP 403 (Forbidden)    │
│                                                             │
│  Bouncer at the door 🚪             Bouncer at VIP 🎟️        │
│  "Show ID"                           "Show wristband"       │
└─────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Your Turn&lt;/p&gt;

&lt;p&gt;Go check your own code (or a project you're working on):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Do you have endpoints that check authentication?&lt;/li&gt;
&lt;li&gt;Do you have separate checks for authorization?&lt;/li&gt;
&lt;li&gt;Are you using 401 vs 403 correctly?&lt;/li&gt;
&lt;li&gt;Are your tokens in localStorage? (Move them if yes!)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Leave a comment with your biggest "aha moment" or your worst auth-related bug story.&lt;/p&gt;

&lt;p&gt;Follow for more security deep dives (next up: JWT vs. Sessions – which one actually wins?)&lt;/p&gt;




&lt;p&gt;TL;DR: Authentication = proving you're you (login). Authorization = proving you're allowed to do the thing (permissions). One happens first, one happens on every request. Mix them up and hackers win.&lt;/p&gt;

</description>
      <category>authentication</category>
      <category>authorization</category>
      <category>security</category>
      <category>backend</category>
    </item>
    <item>
      <title>The 80/20 Rule for Learning Any New Technology (Stop Reading Manuals)</title>
      <dc:creator>MysticMc</dc:creator>
      <pubDate>Thu, 02 Apr 2026 19:22:45 +0000</pubDate>
      <link>https://dev.to/nazmur96/the-8020-rule-for-learning-any-new-technology-stop-reading-manuals-1fc8</link>
      <guid>https://dev.to/nazmur96/the-8020-rule-for-learning-any-new-technology-stop-reading-manuals-1fc8</guid>
      <description>&lt;p&gt;I've seen the same pattern repeat itself for over a decade.&lt;/p&gt;

&lt;p&gt;A junior engineer gets assigned a new tech stack – let's say React, or Docker, or Rust. Their first instinct?&lt;/p&gt;

&lt;p&gt;They buy a 700-page book. Or start a 40-hour video course.&lt;/p&gt;

&lt;p&gt;Two weeks later, they're burned out, confused, and still can't build anything.&lt;/p&gt;

&lt;p&gt;Meanwhile, a senior engineer picks up the same technology and ships a working feature by Friday.&lt;/p&gt;

&lt;p&gt;The difference isn't intelligence. It's not experience.&lt;/p&gt;

&lt;p&gt;It's the 80/20 Rule.&lt;/p&gt;




&lt;p&gt;What is the 80/20 Rule (Pareto Principle)?&lt;/p&gt;

&lt;p&gt;The Pareto Principle says:&lt;/p&gt;

&lt;p&gt;80% of the results come from 20% of the effort.&lt;/p&gt;

&lt;p&gt;In learning any new technology:&lt;/p&gt;

&lt;p&gt;· 20% of the features will be used 80% of the time.&lt;br&gt;
· 80% of the documentation is edge cases, deprecated methods, or advanced optimizations you will never need as a beginner.&lt;/p&gt;

&lt;p&gt;The trick is: Identify that 20% first. Learn it deeply. Ignore the rest until you actually need it.&lt;/p&gt;



&lt;p&gt;The Wrong Way (What most beginners do)&lt;/p&gt;

&lt;p&gt;Let's say you want to learn Docker.&lt;/p&gt;

&lt;p&gt;❌ The 100% approach:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read the entire Docker documentation (600+ pages).&lt;/li&gt;
&lt;li&gt;Watch a 12-hour "Docker Masterclass" on YouTube.&lt;/li&gt;
&lt;li&gt;Learn about every command: docker network, docker volume, docker swarm, docker stack.&lt;/li&gt;
&lt;li&gt;Try to memorize all flags for docker run.&lt;/li&gt;
&lt;li&gt;Give up when you hit "OverlayFS internals."&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;✅ The 80/20 approach:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Learn 5 commands: docker build, docker run, docker ps, docker stop, docker rm.&lt;/li&gt;
&lt;li&gt;Understand 2 concepts: Dockerfile + image vs. container.&lt;/li&gt;
&lt;li&gt;Build one thing: "Containerize my Node.js app."&lt;/li&gt;
&lt;li&gt;Ship it. Learn docker-compose only when you need two containers.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Same technology. 90% less time. Actually shipping code.&lt;/p&gt;



&lt;p&gt;The 80/20 Framework (4 Steps)&lt;/p&gt;

&lt;p&gt;Step 1: Find the "Core 20%" before you write a single line&lt;/p&gt;

&lt;p&gt;Ask three questions:&lt;/p&gt;

&lt;p&gt;Question Example (Learning React)&lt;br&gt;
What do I actually need to build? "A todo app with form inputs and a list"&lt;br&gt;
What 3-5 concepts power 90% of that? Components, props, state, useEffect, JSX&lt;br&gt;
What can I safely ignore for now? Context API, useReducer, memo, custom hooks, SSR&lt;/p&gt;

&lt;p&gt;Research for 20 minutes, not 20 hours. Skim the table of contents. Look at 3 "Getting Started" tutorials. Spot the overlap. That overlap is your 20%.&lt;/p&gt;



&lt;p&gt;Step 2: Build a "Vertical Slice" immediately&lt;/p&gt;

&lt;p&gt;Don't learn horizontally (all about X). Learn vertically (a tiny working thing).&lt;/p&gt;

&lt;p&gt;Horizontal learning (bad):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Chapter 1: Variables
Chapter 2: Loops
Chapter 3: Functions
Chapter 4: Objects
... (2 weeks later) ... Chapter 12: Build a project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vertical learning (good):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Write "Hello World" (5 min)
2. Add a button that changes text (10 min)
3. Add an input field (10 min)
4. Add a second page (20 min)
→ You now know 80% of what you need for basic apps.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal is not mastery. The goal is a working feedback loop.&lt;/p&gt;




&lt;p&gt;Step 3: Learn just-in-time, not just-in-case&lt;/p&gt;

&lt;p&gt;This is the biggest mindset shift.&lt;/p&gt;

&lt;p&gt;Just-in-case (slow) Just-in-time (fast)&lt;br&gt;
"I should learn all of Git before I start." "I'll learn git commit when I need to save."&lt;br&gt;
"Let me read the entire SQL chapter on JOINs." "I have two tables. Let me Google 'SQL JOIN example'."&lt;br&gt;
"I better understand Kubernetes architecture first." "My Docker container needs to scale. Time to learn pods."&lt;/p&gt;

&lt;p&gt;Your brain remembers what it uses. If you learn it before you need it, you'll forget it. If you learn it because you need it, it sticks.&lt;/p&gt;



&lt;p&gt;Step 4: Stop at "Good Enough" (for now)&lt;/p&gt;

&lt;p&gt;Here's a secret senior devs know:&lt;/p&gt;

&lt;p&gt;You don't need to be an expert. You need to be productive.&lt;/p&gt;

&lt;p&gt;Define your "exit criteria" before you start:&lt;/p&gt;

&lt;p&gt;· ✅ "I can build a CRUD app with authentication."&lt;br&gt;
· ❌ "I understand every internal optimization."&lt;/p&gt;

&lt;p&gt;When you hit your criteria, stop the tutorial. Start building your real project. You will learn the remaining 20% (the hard parts) when you break something in production at 2 AM. That's fine. That's real learning.&lt;/p&gt;



&lt;p&gt;Real Examples: The 20% for Popular Technologies&lt;/p&gt;

&lt;p&gt;Here's the cheat sheet you actually need.&lt;/p&gt;

&lt;p&gt;Git (80% of what you'll ever do)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"message"&lt;/span&gt;
git push origin main
git pull origin main
git clone &amp;lt;url&amp;gt;
git status
git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ignore: git rebase, git reflog, git bisect, git filter-branch&lt;/p&gt;




&lt;p&gt;Docker (80% of daily work)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Dockerfile basics&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:18&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["npm", "start"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Commands: docker build, docker run, docker ps, docker stop, docker rm&lt;/p&gt;

&lt;p&gt;Ignore: Docker Swarm, custom networks, volumes (until you need persistence)&lt;/p&gt;




&lt;p&gt;React (80% of components)&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="c1"&gt;// 1. Functional component&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MyComponent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 2. useState for local state&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// 3. useEffect for side effects&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&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;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Clicked &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; times`&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="c1"&gt;// 4. JSX (HTML in JavaScript)&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;clicked&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;times&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ignore: useReducer, useContext, custom hooks, memo, forwardRef, Portals&lt;/p&gt;




&lt;p&gt;Python (for scripting/data)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# 1. Lists and dicts
&lt;/span&gt;&lt;span class="n"&gt;my_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;my_dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# 2. Loops and conditionals
&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 3. Functions
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;

&lt;span class="c1"&gt;# 4. List comprehensions
&lt;/span&gt;&lt;span class="n"&gt;squares&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="c1"&gt;# 5. Importing libraries
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ignore: Classes (for data work), decorators, async/await, metaclasses&lt;/p&gt;




&lt;p&gt;SQL (for querying)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- 1. SELECT with WHERE&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- 2. JOIN (INNER is 90% of joins)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&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;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- 3. GROUP BY with aggregation&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;department&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;AVG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;salary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;employees&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;department&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- 4. INSERT/UPDATE/DELETE&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Bob'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Bob'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Bob'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ignore: Window functions, triggers, stored procedures, indexing internals&lt;/p&gt;




&lt;p&gt;Regular Expressions (just enough)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\d      # any digit (0-9)
\w      # any letter/number/underscore
.       # any character
+       # one or more
*       # zero or more
?       # zero or one
{3}     # exactly 3 times
[abc]   # a, b, or c
^       # start of string
$       # end of string
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This covers 90% of regex needs. Ignore lookaheads, lookbehinds, backreferences.&lt;/p&gt;




&lt;p&gt;The Anti-Patterns (What to avoid)&lt;/p&gt;

&lt;p&gt;❌ Tutorial Hell&lt;/p&gt;

&lt;p&gt;You finish 5 courses but can't build a project without hand-holding.&lt;/p&gt;

&lt;p&gt;Fix: Delete the tutorial after 30 minutes. Try to build. Get stuck. Google the error. Repeat.&lt;/p&gt;

&lt;p&gt;❌ The "Perfect Setup" Trap&lt;/p&gt;

&lt;p&gt;You spend 3 days configuring your editor, themes, and dotfiles before writing code.&lt;/p&gt;

&lt;p&gt;Fix: Use the default settings. Write code. Suffer a little. Then customize that one thing that hurts.&lt;/p&gt;

&lt;p&gt;❌ Memorizing Syntax&lt;/p&gt;

&lt;p&gt;You create flashcards for every function.&lt;/p&gt;

&lt;p&gt;Fix: Use Google, ChatGPT, or man pages. Your brain is for patterns, not syntax. I've written Python for 10 years and still Google python list comprehension every single time.&lt;/p&gt;

&lt;p&gt;❌ Reading Release Notes&lt;/p&gt;

&lt;p&gt;You read "What's new in TypeScript 5.3" before you know TypeScript 1.0.&lt;/p&gt;

&lt;p&gt;Fix: Ignore versions until you hit a specific limitation. Use the LTS (Long Term Support) and forget about it.&lt;/p&gt;




&lt;p&gt;The 80/20 Learning Timeline (Example: Learning AWS in 1 week)&lt;/p&gt;

&lt;p&gt;Day 80/20 Focus What you ignore&lt;br&gt;
Day 1 Create an AWS account, launch an EC2 instance (virtual server) IAM roles, VPC networking, pricing calculators&lt;br&gt;
Day 2 SSH into EC2, install Nginx, serve a "Hello World" page Load balancers, auto-scaling, security groups (beyond basics)&lt;br&gt;
Day 3 Store a file in S3 (bucket + upload + public URL) S3 lifecycle policies, cross-region replication, Glacier&lt;br&gt;
Day 4 Set up a database with RDS (Postgres), connect from EC2 Read replicas, performance insights, backup windows&lt;br&gt;
Day 5 Deploy a simple Node.js app that uses S3 + RDS CloudFormation, Terraform, Lambda, API Gateway&lt;/p&gt;

&lt;p&gt;Result: In 5 days, you can build a real app on AWS. You are not an expert. You don't need to be. You are productive.&lt;/p&gt;




&lt;p&gt;The Mindset Shift (Read this twice)&lt;/p&gt;

&lt;p&gt;Here's the truth most tutorials won't tell you:&lt;/p&gt;

&lt;p&gt;You will never "finish" learning a technology.&lt;/p&gt;

&lt;p&gt;There is no graduation day. There is no certificate that makes you an expert.&lt;/p&gt;

&lt;p&gt;The goal is not to know everything.&lt;/p&gt;

&lt;p&gt;The goal is to know enough to build what you want, and learn the rest when you need it.&lt;/p&gt;

&lt;p&gt;The 80/20 rule isn't about being lazy. It's about being strategic. It's about recognizing that:&lt;/p&gt;

&lt;p&gt;· 80% of the documentation is for edge cases you'll never hit.&lt;br&gt;
· 80% of your time will be spent on 20% of the features.&lt;br&gt;
· 80% of your learning should happen while building, not before.&lt;/p&gt;




&lt;p&gt;Your 30-Minute Challenge&lt;/p&gt;

&lt;p&gt;Right now, pick a technology you've been "meaning to learn" but avoiding.&lt;/p&gt;

&lt;p&gt;Set a timer for 30 minutes.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Minutes 0-5: Find the official "Quickstart" or "Getting Started" guide. Skim it.&lt;/li&gt;
&lt;li&gt;Minutes 5-10: Identify the 3-5 core commands/concepts. Write them down.&lt;/li&gt;
&lt;li&gt;Minutes 10-25: Build the most minimal thing possible. "Hello World" is fine.&lt;/li&gt;
&lt;li&gt;Minutes 25-30: Break it on purpose. Then fix it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You will know more in 30 minutes than most people learn in 2 weeks of reading.&lt;/p&gt;

&lt;p&gt;Now go break something. 🚀&lt;/p&gt;




&lt;p&gt;TL;DR (The 80/20 of this article)&lt;/p&gt;

&lt;p&gt;· Learn 20% of features that give you 80% of results.&lt;br&gt;
· Build a tiny working thing before you understand it fully.&lt;br&gt;
· Learn just-in-time, not just-in-case.&lt;br&gt;
· Stop at "good enough for now" – mastery comes from real projects.&lt;br&gt;
· Google is your memory. Don't memorize syntax.&lt;/p&gt;




&lt;p&gt;What technology have you been avoiding? Do the 30-minute challenge right now and report back in the comments.&lt;/p&gt;

&lt;p&gt;Follow for more pragmatic, no-fluff learning guides.&lt;/p&gt;

</description>
      <category>learning</category>
      <category>productivity</category>
      <category>mentorship</category>
    </item>
    <item>
      <title>Git vs. GitHub: The 5-minute guide for absolute beginners</title>
      <dc:creator>MysticMc</dc:creator>
      <pubDate>Thu, 02 Apr 2026 19:08:40 +0000</pubDate>
      <link>https://dev.to/nazmur96/git-vs-github-the-5-minute-guide-for-absolute-beginners-32hd</link>
      <guid>https://dev.to/nazmur96/git-vs-github-the-5-minute-guide-for-absolute-beginners-32hd</guid>
      <description>&lt;p&gt;If you're new to coding, you've probably heard people say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Just push it to GitHub."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Make sure you commit your changes."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And if you're like most beginners, you quietly nodded… while secretly thinking: &lt;em&gt;"Wait… are Git and GitHub the same thing?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You are not alone.&lt;/strong&gt; This is &lt;em&gt;the&lt;/em&gt; most common confusion for new developers.&lt;/p&gt;

&lt;p&gt;Here's the truth in one sentence:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Git&lt;/strong&gt; is the tool. &lt;strong&gt;GitHub&lt;/strong&gt; is the website where you put the tool's work.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let me explain in 5 minutes (or less).&lt;/p&gt;




&lt;h2&gt;
  
  
  The 2-Second 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;strong&gt;Git&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;GitHub&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;What is it?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A program on your computer&lt;/td&gt;
&lt;td&gt;A website in the cloud&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;What does it do?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Tracks changes to your code&lt;/td&gt;
&lt;td&gt;Hosts your Git repositories online&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Do you need internet?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ No (works offline)&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Is it free?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Yes (always)&lt;/td&gt;
&lt;td&gt;✅ Yes for public repos (paid for private team features)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Who makes it?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Linus Torvalds (same guy who made Linux)&lt;/td&gt;
&lt;td&gt;Microsoft (acquired in 2018)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  The Analogy: Writing a Book 📚
&lt;/h2&gt;

&lt;p&gt;Imagine you're writing a novel.&lt;/p&gt;

&lt;h3&gt;
  
  
  Git is your "Save &amp;amp; Track Changes" button (locally)
&lt;/h3&gt;

&lt;p&gt;You write on your laptop. Every time you hit &lt;strong&gt;Save&lt;/strong&gt;, Git takes a snapshot. You can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go back to page 37 from yesterday.&lt;/li&gt;
&lt;li&gt;See exactly what words you deleted.&lt;/li&gt;
&lt;li&gt;Try a crazy experiment (kill off the main character!) without losing the original.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;All of this happens on your own computer. No internet required.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub is the library (cloud hosting)
&lt;/h3&gt;

&lt;p&gt;Now you want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Share your book with a co-author.&lt;/li&gt;
&lt;li&gt;Show your progress to the world.&lt;/li&gt;
&lt;li&gt;Make sure your laptop exploding doesn't erase 6 months of work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So you &lt;strong&gt;upload&lt;/strong&gt; your Git project to GitHub. It's like putting your book in a public library (or a private locker). Others can read it, suggest changes, or download their own copy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This requires the internet.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What Git actually does (the 3 commands you need)
&lt;/h2&gt;

&lt;p&gt;Git tracks your code using &lt;strong&gt;repositories&lt;/strong&gt; (folders with a special &lt;code&gt;.git&lt;/code&gt; hidden folder). Here's the basic workflow:&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;# 1. You change a file (index.html)&lt;/span&gt;
&lt;span class="c"&gt;# 2. You stage it (tell Git "hey, pay attention to this")&lt;/span&gt;
git add index.html

&lt;span class="c"&gt;# 3. You commit it (take a permanent snapshot)&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Fixed the broken button"&lt;/span&gt;

&lt;span class="c"&gt;# 4. Repeat 100 times. You now have 100 snapshots.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Git never touches the internet. It's just a smart "undo" button on steroids.&lt;/p&gt;




&lt;h2&gt;
  
  
  What GitHub actually does (the 3 things you need)
&lt;/h2&gt;

&lt;p&gt;GitHub takes your local Git repository and:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Hosts it online&lt;/strong&gt; – So you don't lose it if your computer dies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lets others collaborate&lt;/strong&gt; – Multiple people can push changes to the same repo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adds project management tools&lt;/strong&gt; – Issue tracking, pull requests, code reviews, CI/CD.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# After you've committed locally, you send it to GitHub:&lt;/span&gt;
git push origin main

&lt;span class="c"&gt;# Now your code is on GitHub.com. Anyone can see it (if public).&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Common beginner mistakes (and how to fix them)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ❌ "I deleted my project folder. But I pushed to GitHub yesterday, so I'm safe!"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Not exactly.&lt;/strong&gt; GitHub has your code, but you still need to &lt;code&gt;git clone&lt;/code&gt; it back down. It's not magic. You have to explicitly download it.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Fix:&lt;/strong&gt; &lt;code&gt;git clone https://github.com/yourname/yourrepo.git&lt;/code&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  ❌ "I made changes on GitHub.com (edited a file in the browser) and now my local version is different."
&lt;/h3&gt;

&lt;p&gt;This creates a &lt;strong&gt;merge conflict&lt;/strong&gt;. GitHub has version A, your laptop has version B. Git doesn't know which is correct.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Fix:&lt;/strong&gt; &lt;code&gt;git pull origin main&lt;/code&gt; before you start working. Always.&lt;/p&gt;




&lt;h3&gt;
  
  
  ❌ "Git and GitHub are the same company, right?"
&lt;/h3&gt;

&lt;p&gt;Nope. Git was created in 2005 by Linus Torvalds (Linux guy). GitHub launched in 2008 as a startup that built a website &lt;em&gt;around&lt;/em&gt; Git. Microsoft bought GitHub for $7.5 billion in 2018.&lt;/p&gt;

&lt;p&gt;Alternatives to GitHub:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitLab&lt;/strong&gt; (self-hosted option)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bitbucket&lt;/strong&gt; (Atlassian)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SourceForge&lt;/strong&gt; (the old guard)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But they all use &lt;strong&gt;Git&lt;/strong&gt; underneath. Git is the engine. GitHub is just one car brand.&lt;/p&gt;




&lt;h2&gt;
  
  
  Visual timeline of a real workflow
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Your laptop]                    [GitHub cloud]
     |                                |
     | 1. Write code                  |
     | 2. git add .                   |
     | 3. git commit -m "..."         |
     |                                |
     | 4. git push -----------------&amp;gt; | 5. Code appears online
     |                                |
     | 6. Friend clones or forks      |
     |    the repo from GitHub         |
     |                                |
     | 7. git pull &amp;lt;------------------| 8. Get their changes
     |                                |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Internet is only needed for steps 4, 6, and 8.&lt;/strong&gt; Everything else works offline.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why you need BOTH (not one or the other)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;If you ONLY use Git (no GitHub)&lt;/th&gt;
&lt;th&gt;If you ONLY use GitHub (no Git locally)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;✅ You have version history&lt;/td&gt;
&lt;td&gt;✅ Your code is backed up online&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✅ You can undo mistakes&lt;/td&gt;
&lt;td&gt;✅ Others can see your work&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;❌ No cloud backup&lt;/td&gt;
&lt;td&gt;❌ You need internet for &lt;em&gt;everything&lt;/em&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;❌ Hard to collaborate&lt;/td&gt;
&lt;td&gt;❌ You can't work offline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;❌ Computer dies = code dies&lt;/td&gt;
&lt;td&gt;❌ You're just editing files in a browser (not real dev work)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The pro move:&lt;/strong&gt; Use Git locally for daily work. Push to GitHub periodically for backup and collaboration.&lt;/p&gt;




&lt;h2&gt;
  
  
  Your first 10 minutes with Git + GitHub
&lt;/h2&gt;

&lt;p&gt;Here's a concrete starter plan:&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Install Git
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mac:&lt;/strong&gt; &lt;code&gt;brew install git&lt;/code&gt; or download from git-scm.com&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Windows:&lt;/strong&gt; Download from git-scm.com (Git Bash included)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linux:&lt;/strong&gt; &lt;code&gt;sudo apt install git&lt;/code&gt; (Ubuntu/Debian)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 2: Configure your identity (one time)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; user.name &lt;span class="s2"&gt;"Your Name"&lt;/span&gt;
git config &lt;span class="nt"&gt;--global&lt;/span&gt; user.email &lt;span class="s2"&gt;"your@email.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Create a GitHub account
&lt;/h3&gt;

&lt;p&gt;Go to &lt;a href="https://github.com" rel="noopener noreferrer"&gt;github.com&lt;/a&gt; and sign up (free).&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Create a repo on GitHub
&lt;/h3&gt;

&lt;p&gt;Click the &lt;strong&gt;"+"&lt;/strong&gt; icon → "New repository" → name it "my-first-repo" → check "Add a README" → Create.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Clone it to your computer
&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/yourusername/my-first-repo.git
&lt;span class="nb"&gt;cd &lt;/span&gt;my-first-repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 6: Make a change
&lt;/h3&gt;

&lt;p&gt;Open the README.md file. Add a line: &lt;code&gt;"I understand Git vs. GitHub now!"&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 7: Commit and push
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add README.md
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Added my realization"&lt;/span&gt;
git push origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 8: Refresh GitHub.com
&lt;/h3&gt;

&lt;p&gt;See your change live. 🎉&lt;/p&gt;




&lt;h2&gt;
  
  
  The "Aha!" moment explained
&lt;/h2&gt;

&lt;p&gt;Here's how you'll know you truly understand:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Git&lt;/strong&gt; is to &lt;strong&gt;GitHub&lt;/strong&gt; as &lt;strong&gt;your camera roll&lt;/strong&gt; is to &lt;strong&gt;Instagram&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Your camera roll (Git) stores all your photos locally. You can edit, delete, and organize them offline.&lt;/li&gt;
&lt;li&gt;Instagram (GitHub) is where you upload some of those photos to share with the world.&lt;/li&gt;
&lt;li&gt;You can delete Instagram and still have your photos. You can delete your camera roll and lose everything (unless Instagram had a copy).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Never trust the cloud as your only copy.&lt;/strong&gt; Always have Git locally.&lt;/p&gt;




&lt;h2&gt;
  
  
  FAQ (from actual beginners)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "Do I need to learn Git before using GitHub?"
&lt;/h3&gt;

&lt;p&gt;Yes, but only the basics (&lt;code&gt;add&lt;/code&gt;, &lt;code&gt;commit&lt;/code&gt;, &lt;code&gt;push&lt;/code&gt;, &lt;code&gt;pull&lt;/code&gt;, &lt;code&gt;clone&lt;/code&gt;). You can learn those in 30 minutes.&lt;/p&gt;

&lt;h3&gt;
  
  
  "Can I use GitHub without using Git?"
&lt;/h3&gt;

&lt;p&gt;Technically yes (you can edit files directly on GitHub.com). But that's like editing a website using only Notepad. Professionals don't do this.&lt;/p&gt;

&lt;h3&gt;
  
  
  "What's a 'fork'?"
&lt;/h3&gt;

&lt;p&gt;A copy of someone else's GitHub repository that lives under &lt;em&gt;your&lt;/em&gt; GitHub account. You can modify it without affecting the original.&lt;/p&gt;

&lt;h3&gt;
  
  
  "What's a 'pull request'?"
&lt;/h3&gt;

&lt;p&gt;You saying: "Hey, I changed your code. Here are my changes. Want to pull them into your project?"&lt;/p&gt;

&lt;h3&gt;
  
  
  "Is GitHub safe for proprietary code?"
&lt;/h3&gt;

&lt;p&gt;Yes, but you need a &lt;strong&gt;private repository&lt;/strong&gt; (paid on some plans, free on GitHub for small teams). For top-secret stuff, companies use self-hosted GitLab.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final cheat sheet (bookmark this)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Git commands (work offline)&lt;/span&gt;
git init                 &lt;span class="c"&gt;# Start tracking a folder&lt;/span&gt;
git add file.txt         &lt;span class="c"&gt;# Stage a file&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"message"&lt;/span&gt;  &lt;span class="c"&gt;# Take a snapshot&lt;/span&gt;
git log                  &lt;span class="c"&gt;# See your history&lt;/span&gt;
git diff                 &lt;span class="c"&gt;# See what changed&lt;/span&gt;
git checkout &lt;span class="o"&gt;[&lt;/span&gt;commitID]  &lt;span class="c"&gt;# Go back in time&lt;/span&gt;

&lt;span class="c"&gt;# GitHub commands (need internet)&lt;/span&gt;
git clone &lt;span class="o"&gt;[&lt;/span&gt;url]          &lt;span class="c"&gt;# Download a repo from GitHub&lt;/span&gt;
git push origin main     &lt;span class="c"&gt;# Upload your commits to GitHub&lt;/span&gt;
git pull origin main     &lt;span class="c"&gt;# Download latest changes from GitHub&lt;/span&gt;
git remote &lt;span class="nt"&gt;-v&lt;/span&gt;            &lt;span class="c"&gt;# See which GitHub URL you're connected to&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;Now go do this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open your terminal.&lt;/li&gt;
&lt;li&gt;Create a folder called &lt;code&gt;git-practice&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;git init&lt;/code&gt; inside it.&lt;/li&gt;
&lt;li&gt;Create a file called &lt;code&gt;hello.txt&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;git add .&lt;/code&gt; then &lt;code&gt;git commit -m "first commit"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Go to GitHub, create a new repo (don't add a README this time).&lt;/li&gt;
&lt;li&gt;Follow the "...or push an existing repository from the command line" instructions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You just became a real developer. 🚀&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Found this helpful?&lt;/strong&gt; Leave a comment with your biggest Git or GitHub facepalm moment. We've all been there.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Want more beginner guides? Drop a follow and I'll cover branching, merging, and fixing merge conflicts next.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>versioncontrol</category>
      <category>github</category>
    </item>
    <item>
      <title>🚀 Beginner’s Guide: TCP vs. UDP – Which One Should You Use?</title>
      <dc:creator>MysticMc</dc:creator>
      <pubDate>Thu, 02 Apr 2026 18:46:23 +0000</pubDate>
      <link>https://dev.to/nazmur96/beginners-guide-tcp-vs-udp-which-one-should-you-use-4nin</link>
      <guid>https://dev.to/nazmur96/beginners-guide-tcp-vs-udp-which-one-should-you-use-4nin</guid>
      <description>&lt;p&gt;If you’ve ever looked at a networking diagram or tried to debug a slow API, you’ve probably seen the acronyms &lt;strong&gt;TCP&lt;/strong&gt; and &lt;strong&gt;UDP&lt;/strong&gt;. They sound similar, but they are fundamentally different.&lt;/p&gt;

&lt;p&gt;Think of them as two different ways to send a letter (or a package) across the internet.&lt;/p&gt;

&lt;p&gt;In this beginner-friendly guide, we’ll break down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What TCP and UDP actually are.&lt;/li&gt;
&lt;li&gt;The "Mail Analogy" (visual thinking).&lt;/li&gt;
&lt;li&gt;Key differences in speed vs. reliability.&lt;/li&gt;
&lt;li&gt;When to use which in your projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s dive in! 🏊‍♂️&lt;/p&gt;




&lt;h2&gt;
  
  
  The OSI Model (The 2-second intro)
&lt;/h2&gt;

&lt;p&gt;Without getting too theoretical, the internet works in layers. TCP and UDP live at the &lt;strong&gt;Transport Layer&lt;/strong&gt; (Layer 4). Their job is simple: &lt;strong&gt;Take data from your app, package it up, and send it to another computer.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But &lt;em&gt;how&lt;/em&gt; they package it is where the magic happens.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Analogy: Mailing a Book 📖
&lt;/h2&gt;

&lt;p&gt;Imagine you want to send a 1,000-page book to a friend.&lt;/p&gt;

&lt;h3&gt;
  
  
  TCP = Registered Mail (With tracking &amp;amp; receipts)
&lt;/h3&gt;

&lt;p&gt;You go to the post office. You tear the book into 1,000 individual pages. You number each page.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Send:&lt;/strong&gt; You mail page 1. Your friend texts you: "Got page 1."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Send:&lt;/strong&gt; You mail page 2. Your friend texts: "Got page 2."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Oh no!&lt;/strong&gt; Page 5 gets lost. Your friend texts: "I’m missing page 5." You re-send page 5.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Result:&lt;/strong&gt; Your friend receives every single page, in perfect order, before reading the book.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  UDP = Standard Mail (Fire &amp;amp; forget)
&lt;/h3&gt;

&lt;p&gt;You rip out the 1,000 pages, shove them into envelopes without numbering them, and dump them in the mailbox.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Send:&lt;/strong&gt; You don't care if they arrive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Send:&lt;/strong&gt; You don't care what order they arrive in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Result:&lt;/strong&gt; Your friend gets 980 pages, out of order, 10 seconds faster. If a page is missing, he just reads around it.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Technical Definitions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  TCP (Transmission Control Protocol)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Nickname:&lt;/strong&gt; "The Reliable One"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handshake:&lt;/strong&gt; Requires a 3-way handshake (SYN, SYN-ACK, ACK) before sending data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error checking:&lt;/strong&gt; Yes. If data is corrupted or lost, TCP asks for it again.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ordering:&lt;/strong&gt; Yes. Packets are reassembled in the exact order sent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed:&lt;/strong&gt; Slower (due to overhead).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  UDP (User Datagram Protocol)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Nickname:&lt;/strong&gt; "The Fast One"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handshake:&lt;/strong&gt; No handshake. Just sends data immediately.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error checking:&lt;/strong&gt; Minimal (checksum only). No retransmission.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ordering:&lt;/strong&gt; No. Packets are processed as they arrive (or not at all).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed:&lt;/strong&gt; Very fast.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Code Snippet (Python example)
&lt;/h2&gt;

&lt;p&gt;Here is a simple way to visualize the difference in code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# TCP: You wait for confirmation
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;
&lt;span class="n"&gt;tcp_socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SOCK_STREAM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tcp_socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;google.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# &amp;lt;-- Blocks until connection is made
&lt;/span&gt;&lt;span class="n"&gt;tcp_socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET / HTTP/1.1&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tcp_socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# &amp;lt;-- Waits for guaranteed data
&lt;/span&gt;
&lt;span class="c1"&gt;# UDP: Just throw it into the void
&lt;/span&gt;&lt;span class="n"&gt;udp_socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SOCK_DGRAM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;udp_socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello world&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;192.168.1.1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9999&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# No connection. No confirmation. Just vibes.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Head-to-Head Comparison
&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;TCP&lt;/th&gt;
&lt;th&gt;UDP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Connection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Connection-oriented&lt;/td&gt;
&lt;td&gt;Connectionless&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reliability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ High (Retransmits lost data)&lt;/td&gt;
&lt;td&gt;❌ Low (No retransmission)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ordering&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Preserves order&lt;/td&gt;
&lt;td&gt;❌ No order guarantee&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Speed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;🐢 Slower&lt;/td&gt;
&lt;td&gt;🚀 Faster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Header Size&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;20-60 bytes&lt;/td&gt;
&lt;td&gt;8 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Congestion Control&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes (slows down if network is busy)&lt;/td&gt;
&lt;td&gt;No (keeps blasting)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Broadcast/Multicast&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Real-World Examples (When to use which)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Use TCP when:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Browsing the web (HTTP/HTTPS).&lt;/strong&gt; You cannot have missing chunks of a webpage.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Sending an email (SMTP, IMAP).&lt;/strong&gt; Missing a sentence changes the meaning.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Transferring a file (FTP, SFTP).&lt;/strong&gt; One wrong byte corrupts a ZIP file.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Connecting to a database (PostgreSQL, MySQL).&lt;/strong&gt; You need accurate queries.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Use UDP when:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Live Video Streaming (YouTube Live, Zoom, Twitch).&lt;/strong&gt; You’d rather have a slightly blurry frame than wait for a missing packet to retransmit (which would cause buffering).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Online Gaming (Call of Duty, Fortnite).&lt;/strong&gt; If you lose one packet about player position, don't ask for it again—just update the next position. Speed &amp;gt; Perfect accuracy.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;DNS Lookups.&lt;/strong&gt; Translating &lt;code&gt;google.com&lt;/code&gt; to an IP address requires one tiny request and reply. UDP is perfect because it's fast and connectionless.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;VoIP (Phone calls).&lt;/strong&gt; "Can you hear me now?" is better than "Waiting for packet #42..."&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pro Tip:&lt;/strong&gt; Even Zoom and YouTube actually use &lt;strong&gt;TCP&lt;/strong&gt; for the &lt;em&gt;control signals&lt;/em&gt; (login, chat) but &lt;strong&gt;UDP&lt;/strong&gt; for the actual video/audio stream. You can use both!&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The "Gotcha" for Beginners
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;"If UDP is faster, why don't we always use it?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because &lt;strong&gt;reliability matters more than speed for most things&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Imagine buying something on Amazon using UDP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You click "Buy." The packet gets lost.&lt;/li&gt;
&lt;li&gt;Your credit card gets charged (packet arrived).&lt;/li&gt;
&lt;li&gt;The confirmation email never arrives (packet lost).&lt;/li&gt;
&lt;li&gt;You have no idea if the order worked.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With TCP, the browser keeps asking, "Did you get my request?" until it gets a "Yes."&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary Cheat Sheet
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;If you need...&lt;/th&gt;
&lt;th&gt;Choose...&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;100% accuracy&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;TCP&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resending lost data&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;TCP&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ordered packets&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;TCP&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speed above all else&lt;/td&gt;
&lt;td&gt;🚀 &lt;strong&gt;UDP&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Live streaming / Gaming&lt;/td&gt;
&lt;td&gt;🚀 &lt;strong&gt;UDP&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Broadcasting to many devices&lt;/td&gt;
&lt;td&gt;🚀 &lt;strong&gt;UDP&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Final Takeaway
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;TCP is polite:&lt;/strong&gt; "Hello, are you there? Okay, I will send page 1. Did you get it? Okay, here is page 2..."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UDP is reckless:&lt;/strong&gt; "HERE IS PAGE 1, PAGE 2, PAGE 5, PAGE 3... GOOD LUCK!"&lt;/p&gt;

&lt;p&gt;Now that you know the difference, go look at your favorite app. Is it using TCP or UDP? (Hint: &lt;code&gt;netstat -an&lt;/code&gt; on your terminal can tell you!).&lt;/p&gt;

&lt;p&gt;Happy coding! 🖥️&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Found this helpful? Leave a like or comment below. What protocol confused you the most when you started?&lt;/em&gt;&lt;/p&gt;

</description>
      <category>networking</category>
      <category>tcp</category>
      <category>udp</category>
    </item>
    <item>
      <title>Struggling to break into Devops!</title>
      <dc:creator>MysticMc</dc:creator>
      <pubDate>Wed, 01 Apr 2026 13:58:38 +0000</pubDate>
      <link>https://dev.to/nazmur96/struggling-to-break-into-devops-3dog</link>
      <guid>https://dev.to/nazmur96/struggling-to-break-into-devops-3dog</guid>
      <description>&lt;p&gt;Most engineers don’t struggle because they’re undisciplined.&lt;br&gt;
They struggle because the way DevOps is taught mirrors the way a library is organized: everything is available, but nothing is connected. You finish a Docker course and move to Kubernetes. You finish Kubernetes and start Terraform. Each thing makes sense on its own. None of it prepares you for the moment someone puts an incident in front of you and asks what you see.&lt;/p&gt;

&lt;p&gt;That gap, between knowing tools and thinking in systems , is where most careers stall. And almost no one tells you it exists until you’re already stuck in it.&lt;/p&gt;

&lt;p&gt;Everything on this page exists to close that gap deliberately.&lt;/p&gt;

&lt;p&gt;Start Here&lt;br&gt;
The DevOps Operating System&lt;br&gt;
The structured path from confusion to a hireable engineer&lt;/p&gt;

&lt;p&gt;It’s a 6-week curriculum built around one progression: reading → building → understanding → explaining → getting hired. The first four phases give you a working local environment, Linux, Git, Docker, and Kubernetes running on MicroK8s. After that, the curriculum moves you into realistic production scenarios: real world tickets, infrastructure tasks, and a capstone enterprise system you build end-to-end.&lt;/p&gt;

&lt;p&gt;By the end, you won’t need someone to walk you through a debugging session. You’ll already know what to look for, and how to explain what you found.&lt;/p&gt;

&lt;p&gt;If You’re Not Ready for That Yet&lt;br&gt;
Start with these. They’re free. They’re the same resources engineers have used to get clear, get confident, and get interviews.&lt;/p&gt;

&lt;p&gt;Free DevOps Resume Template. DevOps resumes fail because they list tools instead of demonstrating judgment. This template is structured around what hiring managers actually look for: evidence that you understand real infrastructure and can demonstrate operational judgment under real constraints, not just coursework.&lt;/p&gt;

&lt;p&gt;Real-World DevOps Project Portfolio The question that ends most interviews isn’t technical. It’s “Can you show me something you built and debugged?” This portfolio gives you production-style projects across CI/CD, Kubernetes, and cloud infrastructure, the kind that answer that question before it’s asked.&lt;/p&gt;

&lt;p&gt;GitHub Troubleshooting Toolkit: When something breaks in production, the engineers who stay calm aren’t calmer by nature. They have a method. This toolkit gives you a repeatable diagnostic process so that “the system is down” becomes a starting point, not a crisis.&lt;/p&gt;

&lt;p&gt;For Engineers Ready to Go Deeper&lt;br&gt;
The Kubernetes Detective: A pod is crashing. kubectl logs shows nothing useful. Three engineers are watching you, and you have no idea where to start. This guide is the systematic debugging method that turns that moment from panic into a process. It's what separates engineers who guess from engineers who diagnose.&lt;/p&gt;

&lt;p&gt;The DevOps Interview Decoder. Candidates fail interviews not because of a lack of knowledge, but because they can’t articulate how systems actually work under pressure. This framework closes that gap. Engineers who have used it have landed roles exceeding $170K globally, not because it’s a script, but because it teaches you to think out loud like someone who has already seen production.&lt;/p&gt;

&lt;p&gt;AI for DevOps: AI won’t replace engineers. It will replace engineers who treat it as a search engine. This guide covers 47 tested prompts for troubleshooting, automating learning, and recovering hours every week, built for engineers who want to operate faster, not just differently.&lt;/p&gt;

&lt;p&gt;Stay Close&lt;br&gt;
Weekly Newsletter Every week: a breakdown of a real production incident, an architecture lesson, a cost-saving tactic used inside actual companies, and occasionally an honest account of something that went badly and what it taught. No hype. No listicles. Signal only.&lt;br&gt;
Sign Up Here&lt;/p&gt;

&lt;p&gt;You don’t need more courses.&lt;/p&gt;

&lt;p&gt;You need fewer distractions, better systems, and one structured path that connects what you’re learning to what production actually looks like.&lt;/p&gt;

&lt;p&gt;🔖 Tip: Bookmark this page. I update it regularly with new tools, labs, and frameworks.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>From Linux Admin to DevOps &amp; AI: My Journey Begins</title>
      <dc:creator>MysticMc</dc:creator>
      <pubDate>Wed, 01 Apr 2026 13:45:55 +0000</pubDate>
      <link>https://dev.to/nazmur96/from-linux-admin-to-devops-ai-my-journey-begins-2m3f</link>
      <guid>https://dev.to/nazmur96/from-linux-admin-to-devops-ai-my-journey-begins-2m3f</guid>
      <description>&lt;h2&gt;
  
  
  Why I'm Sharing This Journey
&lt;/h2&gt;

&lt;p&gt;Hi! I'm Nazmur, a Junior Linux Administrator who's decided to level up. Like many in operations, I've realized that the future belongs to those who can bridge &lt;strong&gt;traditional sysadmin work&lt;/strong&gt; with modern &lt;strong&gt;DevOps practices&lt;/strong&gt; and emerging &lt;strong&gt;AI technologies&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is the first post in my journey from Linux admin → DevOps Engineer → AI/ML Engineer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I Started
&lt;/h2&gt;

&lt;p&gt;As a Linux admin, my daily work involves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Managing and monitoring Linux servers&lt;/li&gt;
&lt;li&gt;Writing bash scripts to automate repetitive tasks&lt;/li&gt;
&lt;li&gt;Troubleshooting system issues&lt;/li&gt;
&lt;li&gt;Ensuring uptime and reliability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's solid work, but I kept asking myself: &lt;em&gt;"How can I do this faster? More efficiently? What's next?"&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three Pillars I'm Focusing On
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. DevOps &amp;amp; Cloud
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Kubernetes&lt;/strong&gt; - Container orchestration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker&lt;/strong&gt; - Containerization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD&lt;/strong&gt; - GitHub Actions, Jenkins&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure as Code&lt;/strong&gt; - Terraform&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Platforms&lt;/strong&gt; - AWS, Azure&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Generative AI &amp;amp; Agentic AI
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;RAG (Retrieval-Augmented Generation)&lt;/strong&gt; - Building context-aware AI systems&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LangChain &amp;amp; LlamaIndex&lt;/strong&gt; - AI agent frameworks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LLM Integration&lt;/strong&gt; - Working with GPT, open-source models&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt Engineering&lt;/strong&gt; - Getting the best from AI&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Python Deep Dive
&lt;/h3&gt;

&lt;p&gt;I already know Python basics, but now I'm focusing on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automation scripts for infrastructure&lt;/li&gt;
&lt;li&gt;API integrations for AI agents&lt;/li&gt;
&lt;li&gt;Building tools that bridge ops and AI&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I've Built So Far
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Week 1-2: Kubernetes Homelab
&lt;/h3&gt;

&lt;p&gt;I set up &lt;strong&gt;k3s&lt;/strong&gt; on an old laptop to get hands-on:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
bash
# Install k3s
curl -sfL https://get.k3s.io | sh -

# Check my cluster
kubectl get nodes
Result: A working Kubernetes cluster in my living room!

Week 3: First RAG Agent
I built a simple RAG (Retrieval-Augmented Generation) agent that:

Ingests documents

Creates embeddings

Answers questions based on the documents

Here's a snippet:

python
from langchain.document_loaders import TextLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import FAISS

# Load documents
loader = TextLoader("my_docs.txt")
documents = loader.load()

# Split into chunks
text_splitter = CharacterTextSplitter(chunk_size=1000)
docs = text_splitter.split_documents(documents)

# Create vector store
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(docs, embeddings)
It's basic, but it works! Next step: adding memory and tool use.

My Learning Resources
Topic   Resources
Kubernetes  KodeKloud, K8s Official Docs
AI/LLM  LangChain Docs, DeepLearning.AI
DevOps  TechWorld with Nana, Adrian Cantrill
What's Next
Next week:

Deploy a real app on my K8s cluster

Add memory to my RAG agent

Write a detailed Terraform setup guide

By end of month:

Full CI/CD pipeline with GitHub Actions

Deploy AI agent as a web service

Document everything (this helps others and solidifies my learning)

Why This Matters to You
If you're also transitioning from sysadmin to DevOps or AI, here's what I'm learning:

Your Linux skills are invaluable — cloud is just Linux at scale

Start with a homelab — break things without fear

Build publicly — share what you learn (like this post!)

Focus on fundamentals — containers, networking, automation

Let's Connect
I'll be posting weekly about:

Kubernetes deep dives

AI agent experiments

DevOps project builds

Career transition lessons

Follow along if you're on a similar journey!

📦 GitHub: github.com/nazmur96
💼 LinkedIn: linkedin.com/in/nazmur96

From servers to agents — building the future, one line of code at a time.

If this post helped you, leave a comment or reaction! I'd love to hear about your journey too.



Result: A working Kubernetes cluster in my living room!

Week 3: First RAG Agent
I built a simple RAG (Retrieval-Augmented Generation) agent that:

Ingests documents

Creates embeddings

Answers questions based on the documents

Here's a snippet:

python
from langchain.document_loaders import TextLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import FAISS

# Load documents
loader = TextLoader("my_docs.txt")
documents = loader.load()

# Split into chunks
text_splitter = CharacterTextSplitter(chunk_size=1000)
docs = text_splitter.split_documents(documents)

# Create vector store
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(docs, embeddings)
It's basic, but it works! Next step: adding memory and tool use.

My Learning Resources
Topic   Resources
Kubernetes  KodeKloud, K8s Official Docs
AI/LLM  LangChain Docs, DeepLearning.AI
DevOps  TechWorld with Nana, Adrian Cantrill
What's Next
Next week:

Deploy a real app on my K8s cluster

Add memory to my RAG agent

Write a detailed Terraform setup guide

By end of month:

Full CI/CD pipeline with GitHub Actions

Deploy AI agent as a web service

Document everything (this helps others and solidifies my learning)

Why This Matters to You
If you're also transitioning from sysadmin to DevOps or AI, here's what I'm learning:

Your Linux skills are invaluable — cloud is just Linux at scale

Start with a homelab — break things without fear

Build publicly — share what you learn (like this post!)

Focus on fundamentals — containers, networking, automation

Let's Connect
I'll be posting weekly about:

Kubernetes deep dives

AI agent experiments

DevOps project builds

Career transition lessons

Follow along if you're on a similar journey!

📦 GitHub: github.com/nazmur96
💼 LinkedIn: linkedin.com/in/nazmur96

From servers to agents — building the future, one line of code at a time.

If this post helped you, leave a comment or reaction! I'd love to hear about your journey too.

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

&lt;/div&gt;

</description>
    </item>
  </channel>
</rss>
