<?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: PyShine</title>
    <description>The latest articles on DEV Community by PyShine (@pyshine).</description>
    <link>https://dev.to/pyshine</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4038957%2Fb442fb1c-7b10-4183-9114-1d61ee37691c.png</url>
      <title>DEV Community: PyShine</title>
      <link>https://dev.to/pyshine</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pyshine"/>
    <language>en</language>
    <item>
      <title>Learn Cryptography in a Single Post: A Complete Tutorial From Symmetric and Asymmetric Encryption to Hashing, TLS, and Applied Security</title>
      <dc:creator>PyShine</dc:creator>
      <pubDate>Thu, 23 Jul 2026 12:42:46 +0000</pubDate>
      <link>https://dev.to/pyshine/learn-cryptography-in-a-single-post-a-complete-tutorial-from-symmetric-and-asymmetric-encryption-4o3e</link>
      <guid>https://dev.to/pyshine/learn-cryptography-in-a-single-post-a-complete-tutorial-from-symmetric-and-asymmetric-encryption-4o3e</guid>
      <description>&lt;h1&gt;
  
  
  Learn Cryptography in a Single Post: Complete Tutorial From Symmetric and Asymmetric Encryption to TLS and Applied Security
&lt;/h1&gt;

&lt;p&gt;Cryptography is the math and engineering that lets two parties communicate securely over an insecure channel — where anyone can listen. It's the foundation of every HTTPS page, every SSH login, every secure message, and every password you've ever stored. This single post teaches the whole field in five stages, with hand-drawn diagrams and runnable examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning Roadmap
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbo50evk1w8sbjrt7j93d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbo50evk1w8sbjrt7j93d.png" alt="Cryptography Learning Roadmap" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The roadmap moves from the fastest kind of encryption (Stage 1), through the key-exchange solution to its key-sharing problem (Stage 2), to the integrity/authentication layer (Stage 3), the protocols that combine them (Stage 4), and the applied layer you build with (Stage 5).&lt;/p&gt;




&lt;h2&gt;
  
  
  Stage 1 — Symmetric Encryption
&lt;/h2&gt;

&lt;h3&gt;
  
  
  One shared key
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symmetric encryption&lt;/strong&gt; uses &lt;strong&gt;one key&lt;/strong&gt; for both encryption and decryption. It's fast (AES hardware-accelerated on every modern CPU) and the workhorse of all bulk data encryption.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8myqqxmoql2runh4kdly.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8myqqxmoql2runh4kdly.png" alt="Symmetric Encryption: One Shared Key" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;encrypt(key, plaintext)  -&amp;gt;  ciphertext
decrypt(key, ciphertext) -&amp;gt;  plaintext
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;cryptography.hazmat.primitives.ciphers.aead&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AESGCM&lt;/span&gt;
&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AESGCM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bit_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;# 32-byte key
&lt;/span&gt;&lt;span class="n"&gt;aesgcm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AESGCM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;nonce&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urandom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                        &lt;span class="c1"&gt;# 12-byte nonce, unique per encryption
&lt;/span&gt;&lt;span class="n"&gt;ciphertext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;aesgcm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nonce&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;secret message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;plaintext&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;aesgcm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ciphertext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# b"secret message"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  AES and modes
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;AES&lt;/strong&gt; (Advanced Encryption Standard) is the standard symmetric cipher, with 128/192/256-bit keys. But AES alone is a &lt;strong&gt;block cipher&lt;/strong&gt; — it encrypts one 16-byte block. A &lt;strong&gt;mode of operation&lt;/strong&gt; turns it into a general-purpose cipher:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;GCM&lt;/strong&gt; (Galois/Counter Mode)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;AEAD&lt;/strong&gt; — encrypts + authenticates in one pass. &lt;strong&gt;The default choice.&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ChaCha20-Poly1305&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;an AEAD alternative to AES-GCM, fast in software (no AES-NI needed)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CBC&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;encrypts blocks chained together; needs a separate MAC for integrity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CTR&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;turns AES into a stream cipher; needs a MAC for integrity&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;AEAD&lt;/strong&gt; (Authenticated Encryption with Associated Data) is the key concept: it &lt;strong&gt;encrypts and authenticates&lt;/strong&gt; in one operation. If someone tampers with the ciphertext, decryption fails — you don't need a separate MAC. &lt;strong&gt;Always use an AEAD mode&lt;/strong&gt; (GCM or ChaCha20-Poly1305); CBC/CTR alone don't detect tampering.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; The &lt;strong&gt;nonce&lt;/strong&gt; (number used once) must be &lt;strong&gt;unique per key&lt;/strong&gt; — never reuse a nonce with the same key in GCM/CTR. Reusing a nonce leaks the key's keystream, breaking the encryption entirely. Generate a random nonce per message, or use a counter.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  The key-sharing problem
&lt;/h3&gt;

&lt;p&gt;Symmetric encryption has one weakness: &lt;strong&gt;both sides need the same key, but how do they share it over an insecure channel?&lt;/strong&gt; That's what asymmetric cryptography (Stage 2) solves.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stage 2 — Asymmetric Encryption
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Two keys: public and private
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Asymmetric encryption&lt;/strong&gt; uses a &lt;strong&gt;key pair&lt;/strong&gt;: a &lt;strong&gt;public key&lt;/strong&gt; (shared freely) and a &lt;strong&gt;private key&lt;/strong&gt; (kept secret). What one encrypts, the other decrypts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk3ml1dqg555bj4xbnti5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk3ml1dqg555bj4xbnti5.png" alt="Asymmetric: Public + Private Keys" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two operations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Encrypt with public key&lt;/strong&gt; → only the private key can decrypt. Anyone can send you a secret; only you can read it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sign with private key&lt;/strong&gt; → anyone can verify with the public key. Only you could have signed it; it proves authenticity.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Algorithms
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Algorithm&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;RSA&lt;/strong&gt; (2048+ bits)&lt;/td&gt;
&lt;td&gt;encryption + signatures&lt;/td&gt;
&lt;td&gt;the classic; large keys, slower&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;ECC&lt;/strong&gt; (Elliptic Curve)&lt;/td&gt;
&lt;td&gt;key exchange + signatures&lt;/td&gt;
&lt;td&gt;X25519 for exchange, Ed25519 for signatures; smaller keys, faster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Diffie-Hellman (DH / ECDH)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;key exchange&lt;/td&gt;
&lt;td&gt;two parties derive a shared secret without ever sending it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Key exchange — the solution to the key-sharing problem
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Diffie-Hellman&lt;/strong&gt; (and its elliptic-curve variant &lt;strong&gt;ECDH&lt;/strong&gt;) lets two parties derive a &lt;strong&gt;shared secret&lt;/strong&gt; over an insecure channel, without ever transmitting the secret itself. Each side generates a key pair, exchanges public keys, and computes the same shared secret from their own private key + the other's public key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Alice:  shared = ECDH(Alice_private, Bob_public)
Bob:    shared = ECDH(Bob_private, Alice_public)
# both compute the SAME shared secret, but no one listening can
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That shared secret becomes the &lt;strong&gt;symmetric key&lt;/strong&gt; for AES — so you get the speed of symmetric encryption with the key-sharing solution of asymmetric. This is how TLS, SSH, and Signal all establish their session keys.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; DH/ECDH alone is vulnerable to a &lt;strong&gt;man-in-the-middle&lt;/strong&gt; (Mallory intercepts both public keys and substitutes her own). You need &lt;strong&gt;authentication&lt;/strong&gt; — a way to prove the public key is really theirs (certificates in TLS, host keys in SSH). Without authentication, key exchange is secure against eavesdroppers but not against active attackers.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 3 — Hashing, HMAC, Signatures, Passwords
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Cryptographic hashes
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;hash function&lt;/strong&gt; takes any input and produces a fixed-size &lt;strong&gt;digest&lt;/strong&gt; (e.g. SHA-256 → 256 bits). Properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One-way&lt;/strong&gt; — you can't reverse a hash to get the input.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deterministic&lt;/strong&gt; — same input always produces the same hash.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avalanche&lt;/strong&gt; — changing one bit changes ~half the output bits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collision-resistant&lt;/strong&gt; — hard to find two inputs with the same hash.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;
&lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sha256&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&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;# 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
&lt;/span&gt;&lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sha256&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 &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# completely different (space added)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  HMAC — keyed hashing
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;HMAC&lt;/strong&gt; (Hash-based Message Authentication Code) is a hash with a &lt;strong&gt;key&lt;/strong&gt;: &lt;code&gt;HMAC-SHA256(key, message) → tag&lt;/code&gt;. The recipient verifies the tag with the same key. If it matches, the message is authentic and untampered. This is symmetric message authentication.&lt;/p&gt;

&lt;h3&gt;
  
  
  Digital signatures
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;digital signature&lt;/strong&gt; combines hashing + asymmetric: sign &lt;code&gt;hash(message)&lt;/code&gt; with your private key; anyone verifies with your public key. It proves &lt;strong&gt;who sent it&lt;/strong&gt; (authentication) and &lt;strong&gt;that it wasn't modified&lt;/strong&gt; (integrity), with &lt;strong&gt;non-repudiation&lt;/strong&gt; (you can't deny signing).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sign:  signature = RSA-PSS(private_key, SHA-256(message))
verify: RSA-PSS-verify(public_key, message, signature) -&amp;gt; true/false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Modern signature algorithms: &lt;strong&gt;Ed25519&lt;/strong&gt; (fast, small, recommended for new systems), &lt;strong&gt;ECDSA&lt;/strong&gt; (used in TLS), &lt;strong&gt;RSA-PSS&lt;/strong&gt; (classic).&lt;/p&gt;

&lt;h3&gt;
  
  
  Password storage
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqyvouppn2ckzfak4l9z0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqyvouppn2ckzfak4l9z0.png" alt="Hashing, HMAC, Signatures, Passwords" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Passwords must never be stored in plaintext or even as a plain SHA-256 hash (rainbow tables + GPU brute-force crack SHA-256 fast). Use a &lt;strong&gt;slow, salted hash&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;import&lt;/span&gt; &lt;span class="n"&gt;bcrypt&lt;/span&gt;
&lt;span class="n"&gt;hashed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hashpw&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;password123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gensalt&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;   &lt;span class="c1"&gt;# $2b$12$...
&lt;/span&gt;&lt;span class="n"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checkpw&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;password123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hashed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                      &lt;span class="c1"&gt;# True
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Salt&lt;/strong&gt; — a random per-user value mixed in, so two users with the same password get different hashes. Prevents rainbow tables.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Slow&lt;/strong&gt; — bcrypt/scrypt/argon2 are &lt;em&gt;deliberately slow&lt;/em&gt; (cost factor adjustable), so brute-force takes years, not seconds. SHA-256 is fast — wrong for passwords.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;argon2&lt;/strong&gt; — the current recommendation (memory-hard, resists GPU/ASIC attacks).&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; Never roll your own crypto, and never store passwords with &lt;code&gt;SHA-256(password)&lt;/code&gt;. Use &lt;code&gt;bcrypt&lt;/code&gt;, &lt;code&gt;scrypt&lt;/code&gt;, or &lt;code&gt;argon2&lt;/code&gt; with a per-user salt. The library handles the salt (it's embedded in the hash output). And &lt;strong&gt;rate-limit login attempts&lt;/strong&gt; — even a slow hash falls to unlimited online guessing.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 4 — Protocols: TLS, HTTPS, SSH, PKI
&lt;/h2&gt;

&lt;h3&gt;
  
  
  TLS 1.3 — the protocol behind HTTPS
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftpiohaga7q5369sc4gpf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftpiohaga7q5369sc4gpf.png" alt="Protocols: TLS, HTTPS, SSH, PKI" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TLS&lt;/strong&gt; (Transport Layer Security) is how HTTPS works. The handshake (simplified):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Client Hello&lt;/strong&gt; → client offers cipher suites + a random.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server Hello + Certificate&lt;/strong&gt; → server picks a cipher, sends its &lt;strong&gt;certificate&lt;/strong&gt; (public key + identity, signed by a CA).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key exchange&lt;/strong&gt; → ECDHE: both derive a shared secret (the session key) — never sent over the wire.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Finished&lt;/strong&gt; → both switch to encrypted communication with AES-GCM, using the session key.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;TLS 1.3 (the current standard) collapses this to one round-trip and supports zero-round-trip resumption. It combines everything from Stages 1-3: asymmetric for key exchange, symmetric for the bulk data, hashing/HMAC for integrity, certificates for authentication.&lt;/p&gt;

&lt;h3&gt;
  
  
  SSH
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;SSH&lt;/strong&gt; uses a similar handshake: key exchange (curve25519), server authentication via &lt;strong&gt;host keys&lt;/strong&gt; (a server's public key, stored in &lt;code&gt;~/.ssh/known_hosts&lt;/code&gt; — trust on first use), and user authentication via &lt;strong&gt;public key&lt;/strong&gt; (your &lt;code&gt;~/.ssh/id_ed25519.pub&lt;/code&gt; on the server, private key signs a challenge). Never use password auth over SSH; disable it in &lt;code&gt;sshd_config&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  PKI — Public Key Infrastructure
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;PKI&lt;/strong&gt; is the system of &lt;strong&gt;certificate authorities&lt;/strong&gt; (CAs) that vouch for public keys. A certificate binds a public key to an identity (a domain name) and is signed by a CA whose root your browser trusts. The chain: &lt;strong&gt;root CA → intermediate CA → leaf certificate&lt;/strong&gt; (your site). If any link is broken, the cert is invalid.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;X.509&lt;/strong&gt; — the certificate format.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Let's Encrypt&lt;/strong&gt; — free, automated CA for HTTPS (ACME protocol).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Revocation&lt;/strong&gt; — CRL (certificate revocation list) or OCSP (online status) to invalidate a compromised cert before expiry.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; A self-signed certificate encrypts the channel but &lt;strong&gt;doesn't prove identity&lt;/strong&gt; — anyone can generate one. Without a CA-validated chain, you're vulnerable to MITM. Use Let's Encrypt (free) or a real CA; never self-sign in production.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 5 — Applied Cryptography
&lt;/h2&gt;

&lt;h3&gt;
  
  
  JWT (JSON Web Tokens)
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;JWT&lt;/strong&gt; is a signed token: a header + payload + signature, base64-encoded. The server signs it (HMAC or RSA); the client sends it back on each request; the server verifies the signature. It's stateless auth — the server doesn't need to look up a session, just verify the signature. &lt;strong&gt;Never put secrets in a JWT&lt;/strong&gt; — the payload is base64 (not encrypted); only the signature prevents tampering.&lt;/p&gt;

&lt;h3&gt;
  
  
  OAuth 2.1 / OIDC
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;OAuth 2.1&lt;/strong&gt; is the delegated-authorization standard: "let app X access my data on service Y, without giving app X my password." It uses access tokens + refresh tokens + authorization codes. &lt;strong&gt;OIDC&lt;/strong&gt; (OpenID Connect) adds identity (who the user is) on top. Use a library; the spec has many sharp edges (PKCE for public clients, exact redirect-URI matching, token lifetimes).&lt;/p&gt;

&lt;h3&gt;
  
  
  End-to-end encryption
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;E2EE&lt;/strong&gt; (e.g. the Signal Protocol) means only the endpoints can decrypt — not the server, not the network provider. It combines key exchange (X3DH), ratcheting (double ratchet for forward secrecy), and AEAD. The result: even if the server is compromised, old messages stay unreadable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Zero-knowledge proofs
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;zero-knowledge proof&lt;/strong&gt; lets you prove a statement is true without revealing &lt;em&gt;why&lt;/em&gt;. "I know the password" without sending it; "I'm over 18" without revealing my age; "this transaction is valid" without revealing the amount. Used in Zcash (private blockchain), Tornado Cash, and increasingly in auth (WebAuthn / passkeys prove possession of a key without the server ever seeing the private key).&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick-Start Checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Use a library, never roll your own crypto&lt;/strong&gt; — &lt;code&gt;cryptography&lt;/code&gt; (Python), &lt;code&gt;ring&lt;/code&gt;/&lt;code&gt;rustls&lt;/code&gt; (Rust), Go's &lt;code&gt;crypto/*&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use AES-GCM or ChaCha20-Poly1305&lt;/strong&gt; for symmetric encryption (AEAD — encrypts + authenticates).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never reuse a nonce&lt;/strong&gt; with the same key in GCM/CTR.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use ECDH (X25519)&lt;/strong&gt; for key exchange; authenticate with certificates (TLS) or host keys (SSH).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Ed25519&lt;/strong&gt; for signatures (fast, small, modern).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Store passwords with bcrypt/argon2 + salt&lt;/strong&gt;, never SHA-256 or plaintext.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use TLS (Let's Encrypt) for all web traffic&lt;/strong&gt;; never HTTP, never self-signed in prod.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use SSH key auth&lt;/strong&gt;, not passwords; disable password auth.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JWT: sign, don't encrypt&lt;/strong&gt; — the payload isn't secret; never put secrets in it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate-limit&lt;/strong&gt; auth endpoints — crypto doesn't stop online brute-force; limits do.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Common Pitfalls
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rolling your own crypto&lt;/strong&gt; — the #1 rule: don't. Use vetted libraries and standard protocols.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reusing a nonce&lt;/strong&gt; in GCM/CTR — leaks the keystream, breaks everything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SHA-256 for passwords&lt;/strong&gt; — too fast; use bcrypt/argon2 (slow, salted).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No salt&lt;/strong&gt; in password hashing — rainbow tables crack unsalted hashes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-signed certs in production&lt;/strong&gt; — encrypts but doesn't authenticate; MITM-vulnerable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CBC/CTR without a MAC&lt;/strong&gt; — no integrity; attacker can tamper undetected. Use AEAD.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secrets in JWT payload&lt;/strong&gt; — base64 isn't encryption; anyone can read the payload.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storing the private key in Git&lt;/strong&gt; — &lt;code&gt;id_ed25519&lt;/code&gt; is a secret; gitignore it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Password SSH auth&lt;/strong&gt; — brute-forceable; use keys, disable &lt;code&gt;PasswordAuthentication&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No rate limiting on login&lt;/strong&gt; — even a slow hash falls to unlimited online guessing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://cryptopals.com/" rel="noopener noreferrer"&gt;Cryptography Engineering&lt;/a&gt; — the Cryptopals challenges (learn by breaking)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.oreilly.com/library/view/serious-cryptography/9781492040574/" rel="noopener noreferrer"&gt;Serious Cryptography&lt;/a&gt; by Jean-Philippe Aumasson — the modern practical book&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cryptopals.com/" rel="noopener noreferrer"&gt;The Cryptopals Crypto Challenges&lt;/a&gt; — hands-on, "break real crypto"&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://letsencrypt.org/" rel="noopener noreferrer"&gt;Let's Encrypt&lt;/a&gt; — free TLS certificates&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html" rel="noopener noreferrer"&gt;OWASP Crypto Storage Cheat Sheet&lt;/a&gt; — what to use&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Related guides
&lt;/h2&gt;

&lt;p&gt;Cryptography underpins every secure system — these PyShine tutorials connect to it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Computer-Networking-in-One-Post-Complete-Tutorial-OSI-TCP-UDP-HTTP-Quick-Start/"&gt;Learn Computer Networking in One Post&lt;/a&gt;&lt;/strong&gt; — TLS sits at layer 4-6 of the OSI model; networking is the substrate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-REST-API-in-One-Post-Complete-Tutorial-Methods-Status-Codes-Production-Quick-Start/"&gt;Learn REST API in One Post&lt;/a&gt;&lt;/strong&gt; — HTTPS/TLS is the transport; JWT/OAuth the auth.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Python-in-One-Post-Complete-Tutorial-Async-Type-Hints-Quick-Start/"&gt;Learn Python in One Post&lt;/a&gt;&lt;/strong&gt; — the &lt;code&gt;cryptography&lt;/code&gt; + &lt;code&gt;bcrypt&lt;/code&gt; libraries are Python.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Rust-in-One-Post-Complete-Tutorial-Ownership-Borrow-Async-Quick-Start/"&gt;Learn Rust in One Post&lt;/a&gt;&lt;/strong&gt; — &lt;code&gt;ring&lt;/code&gt; / &lt;code&gt;rustls&lt;/code&gt; are the Rust crypto stack; Rust's safety makes it a popular crypto language.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-System-Design-in-One-Post-Complete-Tutorial-Scaling-CAP-Tradeoffs-Interview-Quick-Start/"&gt;Learn System Design in One Post&lt;/a&gt;&lt;/strong&gt; — encryption-at-rest, mTLS, and secret management are system-design concerns.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Cryptography is the one field where "it works" is not enough — it must work &lt;em&gt;against an adversary&lt;/em&gt;, and the failure mode is silent (you don't know you're broken until it's too late). The five stages here — symmetric, asymmetric, hashing, protocols, applied — cover the whole map from a single AES key to a zero-knowledge proof. The two rules that pay off forever: &lt;strong&gt;never roll your own crypto&lt;/strong&gt; (use vetted libraries and standard protocols), and &lt;strong&gt;use AEAD + slow password hashes + TLS + key-based auth&lt;/strong&gt; — the defaults that are almost always right. Install the &lt;code&gt;cryptography&lt;/code&gt; library, encrypt a message with AES-GCM, hash a password with bcrypt, and set up a Let's Encrypt cert — once you've done those three, you understand the foundation of every secure system.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://pyshine.com/Learn-Cryptography-in-One-Post-Complete-Tutorial-Symmetric-Asymmetric-Hashing-TLS-Quick-Start/" rel="noopener noreferrer"&gt;pyshine.com&lt;/a&gt;. The full tutorial with all 5 hand-drawn diagrams lives there — this cross-post is kept in sync via canonical URL.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>cryptography</category>
      <category>security</category>
      <category>encryption</category>
      <category>tls</category>
    </item>
    <item>
      <title>Learn Data Structures and Algorithms in a Single Post: A Complete DSA Tutorial From Big-O to Trees, Graphs, and Dynamic Programming</title>
      <dc:creator>PyShine</dc:creator>
      <pubDate>Thu, 23 Jul 2026 12:42:33 +0000</pubDate>
      <link>https://dev.to/pyshine/learn-data-structures-and-algorithms-in-a-single-post-a-complete-dsa-tutorial-from-big-o-to-trees-5eh7</link>
      <guid>https://dev.to/pyshine/learn-data-structures-and-algorithms-in-a-single-post-a-complete-dsa-tutorial-from-big-o-to-trees-5eh7</guid>
      <description>&lt;h1&gt;
  
  
  Learn Data Structures and Algorithms in a Single Post: Complete Tutorial From Big-O to Dynamic Programming
&lt;/h1&gt;

&lt;p&gt;Data structures and algorithms (DSA) is the grammar of computing. Every program stores data &lt;em&gt;some&lt;/em&gt; way and processes it &lt;em&gt;some&lt;/em&gt; way; DSA is the study of which ways are fast, which are slow, and why. It's also the bedrock of technical interviews and the lens through which you read any codebase. This single post teaches the whole subject in five stages, with hand-drawn diagrams and runnable snippets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning Roadmap
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl0msqg0r8fqytzc0qtra.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl0msqg0r8fqytzc0qtra.png" alt="Data Structures &amp;amp; Algorithms Roadmap" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The roadmap moves from complexity analysis (Stage 1), through the linear data structures (Stage 2), to trees and graphs (Stage 3), the classic algorithms (Stage 4), and the advanced patterns that tie them together (Stage 5).&lt;/p&gt;




&lt;h2&gt;
  
  
  Stage 1 — Big-O + Basics
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Big-O notation
&lt;/h3&gt;

&lt;p&gt;Big-O describes how an algorithm's &lt;strong&gt;time or space&lt;/strong&gt; grows as the input &lt;code&gt;n&lt;/code&gt; grows — dropping constants and lower-order terms. It's about &lt;em&gt;scale&lt;/em&gt;, not exact speed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ficguy05efxghi3dcp969.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ficguy05efxghi3dcp969.png" alt="Big-O Complexity Growth" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Complexity&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;constant&lt;/td&gt;
&lt;td&gt;array index access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;O(log n)&lt;/td&gt;
&lt;td&gt;logarithmic&lt;/td&gt;
&lt;td&gt;binary search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;td&gt;linear&lt;/td&gt;
&lt;td&gt;scan an array&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;O(n log n)&lt;/td&gt;
&lt;td&gt;linearithmic&lt;/td&gt;
&lt;td&gt;efficient sorts (quicksort, mergesort)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;O(n²)&lt;/td&gt;
&lt;td&gt;quadratic&lt;/td&gt;
&lt;td&gt;nested loops, bubble sort&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;O(2ⁿ)&lt;/td&gt;
&lt;td&gt;exponential&lt;/td&gt;
&lt;td&gt;naive recursion (naive Fibonacci, N-queens)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;O(n!)&lt;/td&gt;
&lt;td&gt;factorial&lt;/td&gt;
&lt;td&gt;all permutations&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; Big-O drops &lt;em&gt;constants&lt;/em&gt;, so O(100n) is O(n). That's why a "slower" O(n) algorithm can beat an O(n²) one on small inputs — the constant matters below a threshold. Big-O tells you what wins &lt;em&gt;as n → ∞&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Arrays and strings
&lt;/h3&gt;

&lt;p&gt;An array is a contiguous block of memory; indexing is O(1) because the address is computed directly. Inserting in the middle is O(n) because every later element shifts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;nums&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="mi"&gt;4&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="n"&gt;nums&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="c1"&gt;# O(1) access
&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="c1"&gt;# amortized O(1)
&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&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;# O(n) — shifts everything
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A string is (conceptually) an array of characters — immutable in Python/Java, so &lt;code&gt;s += "x"&lt;/code&gt; is O(n) (builds a new string). Use a list + &lt;code&gt;"".join&lt;/code&gt; for repeated concatenation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Complexity analysis rules
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A loop over &lt;code&gt;n&lt;/code&gt; items: O(n).&lt;/li&gt;
&lt;li&gt;A nested loop over &lt;code&gt;n&lt;/code&gt; × &lt;code&gt;n&lt;/code&gt;: O(n²).&lt;/li&gt;
&lt;li&gt;A loop that halves the range each step (binary search): O(log n).&lt;/li&gt;
&lt;li&gt;A sort followed by a linear scan: O(n log n) + O(n) = O(n log n) (dominant term).&lt;/li&gt;
&lt;li&gt;Recursion: O(branching_factor ^ depth) if pure recursion; reduced by memoization.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Stage 2 — Linear Structures
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Linked lists
&lt;/h3&gt;

&lt;p&gt;A linked list stores nodes with a value + a pointer to the next node. O(1) insert/delete &lt;em&gt;given a node pointer&lt;/em&gt;, but O(n) access (you walk from the head).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Node&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;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;

&lt;span class="c1"&gt;# singly linked list: 1 -&amp;gt; 2 -&amp;gt; 3
&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Node&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="nc"&gt;Node&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="nc"&gt;Node&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="c1"&gt;# reverse it
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;nxt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;
        &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prev&lt;/span&gt;
        &lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nxt&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;prev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; A classic interview trap — losing the rest of the list by reassigning &lt;code&gt;head.next&lt;/code&gt; before saving &lt;code&gt;head.next&lt;/code&gt;. Always save the next pointer first (as &lt;code&gt;nxt&lt;/code&gt; above).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Stacks (LIFO)
&lt;/h3&gt;

&lt;p&gt;A stack is last-in-first-out: push/pop are O(1). Use for undo, expression evaluation, balanced-parentheses, and DFS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;stack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;# 2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Queues (FIFO)
&lt;/h3&gt;

&lt;p&gt;A queue is first-in-first-out: enqueue/dequeue are O(1). Use for BFS, scheduling, buffering. In Python use &lt;code&gt;collections.deque&lt;/code&gt; (O(1) on both ends); a plain list's &lt;code&gt;pop(0)&lt;/code&gt; is O(n).&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;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;deque&lt;/span&gt;
&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;deque&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;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;popleft&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;# 1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Hash maps (dictionaries)
&lt;/h3&gt;

&lt;p&gt;A hash map gives O(1) average lookup/insert/delete by hashing the key to a bucket. Worst case O(n) if all keys collide (rare with a good hash). This is the workhorse of "seen it before" problems (two-sum, frequency counts, caching).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;seen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&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;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&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;target&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; Hash maps don't preserve order (pre-3.7 Python, and in most languages). If you need order + O(1), use an ordered dict or a separate list.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Data structures + access costs
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8n6mtmxnczr5lfmmnqk8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8n6mtmxnczr5lfmmnqk8.png" alt="Data Structures + Access Costs" width="799" height="445"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Stage 3 — Trees + Graphs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Binary search tree (BST)
&lt;/h3&gt;

&lt;p&gt;A BST keeps ordered data: left subtree &amp;lt; node &amp;lt; right subtree. Search/insert/delete are O(log n) &lt;em&gt;if balanced&lt;/em&gt; — O(n) if degenerate (like a linked list). Self-balancing variants (AVL, red-black) guarantee O(log n).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TreeNode&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;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;

&lt;span class="c1"&gt;# in-order traversal of a BST yields sorted order
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;inorder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;inorder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&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="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;inorder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Heaps
&lt;/h3&gt;

&lt;p&gt;A heap is a complete binary tree with the heap property (min-heap: parent ≤ children). The root is the min (or max). &lt;code&gt;push&lt;/code&gt;/&lt;code&gt;pop&lt;/code&gt; are O(log n); &lt;code&gt;peek&lt;/code&gt; is O(1). Use for priority queues, top-K, and as the backbone of heapsort.&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;import&lt;/span&gt; &lt;span class="n"&gt;heapq&lt;/span&gt;
&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="n"&gt;heapq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;heappush&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&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;heapq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;heappush&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&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="n"&gt;heapq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;heappop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# 1 (smallest)
# top-K largest: push into a min-heap of size K
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tries
&lt;/h3&gt;

&lt;p&gt;A trie (prefix tree) stores strings by shared prefixes. Lookup/insert is O(L) where L is the word length — independent of how many words are stored. Used for autocomplete, dictionaries, IP routing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Graphs
&lt;/h3&gt;

&lt;p&gt;A graph is nodes (vertices) + edges. Represent as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Adjacency list&lt;/strong&gt; — &lt;code&gt;graph[u] = [v1, v2, ...]&lt;/code&gt; (sparse graphs; the default).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adjacency matrix&lt;/strong&gt; — &lt;code&gt;n × n&lt;/code&gt; matrix (dense graphs; O(1) edge lookup but O(n²) space).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# adjacency list
&lt;/span&gt;&lt;span class="n"&gt;graph&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;A&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;B&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;C&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;B&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;D&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;C&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;D&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;D&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  BFS — breadth-first search
&lt;/h4&gt;

&lt;p&gt;Level by level, using a queue. Finds shortest path in an &lt;strong&gt;unweighted&lt;/strong&gt; graph.&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;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;deque&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nf"&gt;deque&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;popleft&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;node&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="n"&gt;visited&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="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;node&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;n&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&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;order&lt;/span&gt;   &lt;span class="c1"&gt;# ['A','B','C','D']
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  DFS — depth-first search
&lt;/h4&gt;

&lt;p&gt;Go deep first, using recursion (or an explicit stack). Used for connected components, topological sort, cycle detection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;visited&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&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;visited&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;visited&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;visited&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="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;node&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;n&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;visited&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;visited&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;BFS vs DFS:&lt;/strong&gt; BFS = shortest path (unweighted), level order; O(V+E). DFS = connectivity, topo sort, cycle detection; O(V+E). Both are O(V+E) with an adjacency list.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 4 — Sorting + Searching
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Sorting
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Algorithm&lt;/th&gt;
&lt;th&gt;Avg&lt;/th&gt;
&lt;th&gt;Worst&lt;/th&gt;
&lt;th&gt;Stable?&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Quicksort&lt;/td&gt;
&lt;td&gt;O(n log n)&lt;/td&gt;
&lt;td&gt;O(n²)&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;in-place, fast in practice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mergesort&lt;/td&gt;
&lt;td&gt;O(n log n)&lt;/td&gt;
&lt;td&gt;O(n log n)&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;needs O(n) extra space&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Heapsort&lt;/td&gt;
&lt;td&gt;O(n log n)&lt;/td&gt;
&lt;td&gt;O(n log n)&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;in-place&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Counting sort&lt;/td&gt;
&lt;td&gt;O(n + k)&lt;/td&gt;
&lt;td&gt;O(n + k)&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;when keys are small ints&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; &lt;code&gt;sorted()&lt;/code&gt; in Python and &lt;code&gt;Arrays.sort()&lt;/code&gt; in Java are O(n log n) and stable — just use them. Writing your own sort in an interview is rarely the point; knowing &lt;em&gt;when&lt;/em&gt; each algorithm wins is.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Quicksort (the one to know)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;quicksort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&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;a&lt;/span&gt;
    &lt;span class="n"&gt;pivot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;left&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="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="n"&gt;a&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;mid&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="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="n"&gt;a&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;right&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="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="n"&gt;a&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;quicksort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;quicksort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Binary search
&lt;/h3&gt;

&lt;p&gt;On a &lt;strong&gt;sorted&lt;/strong&gt; array, binary search is O(log n). The bug-prone part is the boundary conditions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;binary_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lo&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;)&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;if&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;target&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;mid&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; &lt;code&gt;mid = (lo + hi) // 2&lt;/code&gt; can overflow in languages with fixed ints (C/Java). Use &lt;code&gt;mid = lo + (hi - lo) // 2&lt;/code&gt;. Python ints don't overflow, but it's the right habit.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Two pointers
&lt;/h3&gt;

&lt;p&gt;A sorted-array pattern that turns O(n²) into O(n): one pointer at the start, one at the end, move them toward each other.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;two_sum_sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;hi&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;s&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Sliding window
&lt;/h3&gt;

&lt;p&gt;For subarray/substring problems, a window [left, right] that expands and contracts — O(n) instead of O(n²).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;max_subarray_sum_k&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;window&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="n"&gt;best&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&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="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
        &lt;span class="n"&gt;window&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;best&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;best&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;window&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;best&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Stage 5 — Advanced Patterns
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Dynamic programming
&lt;/h3&gt;

&lt;p&gt;DP solves problems with &lt;strong&gt;overlapping subproblems&lt;/strong&gt; and &lt;strong&gt;optimal substructure&lt;/strong&gt; by caching subproblem results (memoization top-down, or tabulation bottom-up).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2vwumfpzaswxk5mcpa31.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2vwumfpzaswxk5mcpa31.png" alt="Algorithm Families" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Fibonacci (the canonical example)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# naive recursion: O(2^n) — recomputes the same values
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fib_naive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&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;n&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;fib_naive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&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;+&lt;/span&gt; &lt;span class="nf"&gt;fib_naive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# memoization (top-down): O(n)
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;
&lt;span class="nd"&gt;@cache&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&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;n&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&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;+&lt;/span&gt; &lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# tabulation (bottom-up): O(n), O(1) space
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&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="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  0/1 Knapsack (the classic DP)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;knapsack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weights&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;dp&lt;/span&gt; &lt;span class="o"&gt;=&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="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;capacity&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weights&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&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="n"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w&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;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;   &lt;span class="c1"&gt;# iterate backward for 0/1
&lt;/span&gt;            &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;v&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;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; The 0/1 knapsack iterates &lt;code&gt;c&lt;/code&gt; &lt;strong&gt;backward&lt;/strong&gt; (so each item is used once); the unbounded knapsack iterates &lt;strong&gt;forward&lt;/strong&gt; (items can repeat). Getting the direction wrong silently changes the answer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Greedy
&lt;/h3&gt;

&lt;p&gt;Greedy picks the locally optimal choice at each step. It works when the problem has the &lt;strong&gt;greedy-choice property&lt;/strong&gt; (a local optimum is part of the global optimum) — e.g. activity selection, Huffman coding, Dijkstra. It fails when a locally bad choice would unlock a globally better one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Divide and conquer
&lt;/h3&gt;

&lt;p&gt;Split the problem, solve the halves, combine. Quicksort, mergesort, and binary search are all divide-and-conquer. The Master Theorem gives the complexity: &lt;code&gt;T(n) = aT(n/b) + f(n)&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Backtracking
&lt;/h3&gt;

&lt;p&gt;Explore all possibilities by trying a choice, recursing, then &lt;strong&gt;undoing&lt;/strong&gt; it. Used for permutations, combinations, N-queens, Sudoku. Pruning (skipping branches that can't improve) is what makes it tractable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;permutations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&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;backtrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;remaining&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;remaining&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;remaining&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="nf"&gt;backtrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&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="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;remaining&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;remaining&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;
    &lt;span class="nf"&gt;backtrack&lt;/span&gt;&lt;span class="p"&gt;([],&lt;/span&gt; &lt;span class="n"&gt;a&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;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Interview prep
&lt;/h3&gt;

&lt;p&gt;The patterns above cover the overwhelming majority of interview questions. The standard path:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;NeetCode 150&lt;/strong&gt; / &lt;strong&gt;Blind 75&lt;/strong&gt; — curated problem set that maps to these patterns.&lt;/li&gt;
&lt;li&gt;Practice one pattern at a time (not random problems) until you recognize the pattern from the problem statement.&lt;/li&gt;
&lt;li&gt;Always say the time/space complexity out loud before coding — that's what interviewers grade.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Toolchain
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd5rz60jne4r95o49fr69.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd5rz60jne4r95o49fr69.png" alt="DSA Practice + Toolchain" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Practice&lt;/strong&gt;: LeetCode, HackerRank, Codeforces, Codewars.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visualizers&lt;/strong&gt;: VisuAlgo, USFCA Data Structure Visualizer, Big-O Cheat Sheet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Languages&lt;/strong&gt;: Python (concise, interview-friendly), C++ (fast, STL), Java, Rust.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interview prep&lt;/strong&gt;: NeetCode 150, Blind 75, &lt;em&gt;Cracking the Coding Interview&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Quick-Start Checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Learn Big-O cold&lt;/strong&gt; — know O(1)/O(log n)/O(n)/O(n log n)/O(n²)/O(2ⁿ) and recognize them in code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Master arrays + hash maps first&lt;/strong&gt; — they solve most easy problems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learn the two-pointer and sliding-window patterns&lt;/strong&gt; — they turn O(n²) into O(n) on sorted/contiguous data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Know one sort (quicksort) and binary search&lt;/strong&gt; — and their boundary bugs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learn BFS and DFS&lt;/strong&gt; on graphs — they're the same algorithm with a queue vs a stack.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learn one tree (BST) and one heap&lt;/strong&gt; — and when to use each.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start DP with Fibonacci, then knapsack&lt;/strong&gt; — memoization first, tabulation second.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Practice by pattern, not randomly&lt;/strong&gt; — NeetCode 150 groups problems by pattern.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Always state time + space complexity&lt;/strong&gt; before coding — it's the interview grade.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visualize&lt;/strong&gt; on VisuAlgo when a data structure doesn't click — seeing a heap push is worth a paragraph.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Common Pitfalls
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Off-by-one in binary search&lt;/strong&gt; — &lt;code&gt;lo &amp;lt;= hi&lt;/code&gt; vs &lt;code&gt;lo &amp;lt; hi&lt;/code&gt;, and the &lt;code&gt;+1&lt;/code&gt;/&lt;code&gt;-1&lt;/code&gt; on the bounds. Decide inclusive vs exclusive and stay consistent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integer overflow in &lt;code&gt;mid&lt;/code&gt;&lt;/strong&gt; — use &lt;code&gt;lo + (hi - lo) // 2&lt;/code&gt; in C/Java.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modifying a list while iterating it&lt;/strong&gt; — skip/delete bugs. Iterate over a copy, or use a separate result list.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;O(n) &lt;code&gt;pop(0)&lt;/code&gt; on a Python list&lt;/strong&gt; — use &lt;code&gt;collections.deque&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;String concatenation in a loop&lt;/strong&gt; — O(n²) for immutable strings; build a list and &lt;code&gt;join&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forgetting to mark nodes visited&lt;/strong&gt; in BFS/DFS — infinite loops on cyclic graphs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;0/1 vs unbounded knapsack direction&lt;/strong&gt; — backward vs forward iteration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Greedy on a problem that needs DP&lt;/strong&gt; — check for the greedy-choice property before reaching for greedy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Naive recursion without memoization&lt;/strong&gt; — O(2ⁿ) when O(n) is a &lt;code&gt;@cache&lt;/code&gt; away.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.bigocheatsheet.com/" rel="noopener noreferrer"&gt;Big-O Cheat Sheet&lt;/a&gt; — complexity reference&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://visualgo.net/" rel="noopener noreferrer"&gt;VisuAlgo&lt;/a&gt; — algorithm visualizations&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://neetcode.io/" rel="noopener noreferrer"&gt;NeetCode&lt;/a&gt; — curated roadmap + video solutions&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cp-algorithms.com/" rel="noopener noreferrer"&gt;CP Algorithms&lt;/a&gt; — competitive-programming reference&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://mitpress.mit.edu/9780262046305/introduction-to-algorithms/" rel="noopener noreferrer"&gt;Introduction to Algorithms (CLRS)&lt;/a&gt; — the canonical textbook&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Related guides
&lt;/h2&gt;

&lt;p&gt;DSA underpins efficient code in every language — these PyShine tutorials apply it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Python-in-One-Post-Complete-Tutorial-Async-Type-Hints-Quick-Start/"&gt;Learn Python in One Post: Complete Tutorial&lt;/a&gt;&lt;/strong&gt; — the snippets above are Python; pair DSA with Python's &lt;code&gt;collections&lt;/code&gt; (&lt;code&gt;deque&lt;/code&gt;, &lt;code&gt;Counter&lt;/code&gt;, &lt;code&gt;heapq&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-CPP-in-One-Post-Complete-Tutorial-Modern-Cpp-Quick-Start/"&gt;Learn C++ in One Post: Complete Tutorial&lt;/a&gt;&lt;/strong&gt; — STL containers (&lt;code&gt;vector&lt;/code&gt;, &lt;code&gt;unordered_map&lt;/code&gt;, &lt;code&gt;priority_queue&lt;/code&gt;) are the interview-standard DSA toolkit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Rust-in-One-Post-Complete-Tutorial-Ownership-Borrow-Async-Quick-Start/"&gt;Learn Rust in One Post: Complete Tutorial&lt;/a&gt;&lt;/strong&gt; — ownership makes linked structures harder; learn Rust's &lt;code&gt;Vec&lt;/code&gt;/&lt;code&gt;HashMap&lt;/code&gt;/&lt;code&gt;BinaryHeap&lt;/code&gt; approach.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-SQL-in-One-Post-Complete-Tutorial-Joins-Window-Functions-Transactions-Quick-Start/"&gt;Learn SQL in One Post: Complete Tutorial&lt;/a&gt;&lt;/strong&gt; — query planning is applied DSA (B-trees, hash joins, sort-merge).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Go-in-One-Post-Complete-Tutorial-Goroutines-Channels-Generics-Quick-Start/"&gt;Learn Go in One Post: Complete Tutorial&lt;/a&gt;&lt;/strong&gt; — Go's built-in &lt;code&gt;sort&lt;/code&gt;, &lt;code&gt;container/heap&lt;/code&gt;, and maps are DSA in the standard library.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;DSA is the subject where reading is no substitute for doing. The five stages here — Big-O, linear structures, trees and graphs, sorting and searching, advanced patterns — cover the whole map, but each only clicks once you've solved ten problems that use it. Spend a week per stage on NeetCode 150, state the complexity out loud every time, and within two months you'll read a problem and know the pattern before you've finished the prompt. Run every snippet above; then go to LeetCode and solve the easy version of each pattern today.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://pyshine.com/Learn-Data-Structures-and-Algorithms-in-One-Post-Complete-Tutorial-Big-O-Trees-Graphs-DP-Quick-Start/" rel="noopener noreferrer"&gt;pyshine.com&lt;/a&gt;. The full tutorial with all 5 hand-drawn diagrams lives there — this cross-post is kept in sync via canonical URL.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>datastructures</category>
      <category>algorithms</category>
      <category>dsa</category>
      <category>bigo</category>
    </item>
    <item>
      <title>Learn Deep Learning in a Single Post: A Complete Tutorial From Neural Networks and CNNs to Transformers and PyTorch Training</title>
      <dc:creator>PyShine</dc:creator>
      <pubDate>Thu, 23 Jul 2026 12:42:19 +0000</pubDate>
      <link>https://dev.to/pyshine/learn-deep-learning-in-a-single-post-a-complete-tutorial-from-neural-networks-and-cnns-to-15ik</link>
      <guid>https://dev.to/pyshine/learn-deep-learning-in-a-single-post-a-complete-tutorial-from-neural-networks-and-cnns-to-15ik</guid>
      <description>&lt;h1&gt;
  
  
  Learn Deep Learning in a Single Post: Complete Tutorial From Neural Networks to Transformers and PyTorch Training
&lt;/h1&gt;

&lt;p&gt;Deep learning is the branch of machine learning that uses &lt;strong&gt;neural networks&lt;/strong&gt; — stacks of layers that learn hierarchical representations from data. It's the technology behind image recognition, speech transcription, machine translation, and every large language model (GPT, Claude, Gemini). This single post teaches the whole field in five stages, with hand-drawn diagrams and runnable PyTorch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning Roadmap
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7c5g7347xnotvx8oc60l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7c5g7347xnotvx8oc60l.png" alt="Deep Learning Roadmap" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The roadmap moves from the neuron (Stage 1), through how it learns (Stage 2), the architectures for images and sequences (Stages 3-4), and the practical framework + deployment (Stage 5). The &lt;a href="https://dev.to/Learn-Machine-Learning-in-One-Post-Complete-Tutorial-Supervised-Unsupervised-Deep-Learning-Quick-Start/"&gt;ML basics tutorial&lt;/a&gt; is the prerequisite — this post goes deep.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stage 1 — Neural Networks
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The neuron
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;neuron&lt;/strong&gt; is the unit of a neural network: it takes weighted inputs, sums them, adds a bias, and applies a non-linear &lt;strong&gt;activation function&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwqisrwf541tj55i61rfs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwqisrwf541tj55i61rfs.png" alt="Neural Network: Neurons, Layers, Forward/Backward" width="800" height="409"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;y = activation(w1*x1 + w2*x2 + ... + b)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Weights&lt;/strong&gt; (&lt;code&gt;w1&lt;/code&gt;, &lt;code&gt;w2&lt;/code&gt;, ...) — learned parameters; they're what the network &lt;em&gt;learns&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bias&lt;/strong&gt; (&lt;code&gt;b&lt;/code&gt;) — a learned offset.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Activation function&lt;/strong&gt; — the non-linearity that lets the network learn complex patterns. Without it, a stack of linear layers is still linear (a composition of linear functions is linear).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Common activations
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Function&lt;/th&gt;
&lt;th&gt;Formula&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ReLU&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;max(0, x)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the default for hidden layers; simple, fast, no vanishing gradient for positive values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sigmoid&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1 / (1 + e^-x)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;squashes to (0,1); binary classification output; vanishing gradient problem in deep nets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tanh&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(e^x - e^-x) / (e^x + e^-x)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;squashes to (-1,1); similar vanishing issue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GELU&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;x * Phi(x)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;used in transformers (smoother than ReLU)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Softmax&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;e^xi / sum(e^xj)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;multi-class output (probabilities summing to 1)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Layers = stacked neurons
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;layer&lt;/strong&gt; is a set of neurons that all receive the same input and produce outputs that feed the next layer. A network is a stack of layers: &lt;strong&gt;input → hidden → hidden → ... → output&lt;/strong&gt;. The "deep" in deep learning = many layers, each learning progressively more abstract features.&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;import&lt;/span&gt; &lt;span class="n"&gt;torch.nn&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;

&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Sequential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Linear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;784&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;   &lt;span class="c1"&gt;# input (28x28 pixels) -&amp;gt; 128 neurons
&lt;/span&gt;    &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ReLU&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;             &lt;span class="c1"&gt;# activation
&lt;/span&gt;    &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Linear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;    &lt;span class="c1"&gt;# 128 -&amp;gt; 64
&lt;/span&gt;    &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ReLU&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Linear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&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;# 64 -&amp;gt; 10 classes
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The forward pass
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;forward pass&lt;/strong&gt; pushes input through the layers to get a prediction: &lt;code&gt;y = model(x)&lt;/code&gt;. Each layer transforms its input; the output of one layer is the input of the next.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stage 2 — Training
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The training loop
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg65zcnkw45v8pmbnh13m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg65zcnkw45v8pmbnh13m.png" alt="Training: Loss, Gradient Descent, Optimizers" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Training is a loop, repeated many times (&lt;strong&gt;epochs&lt;/strong&gt;) over the dataset:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Forward pass&lt;/strong&gt; — &lt;code&gt;predictions = model(inputs)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loss&lt;/strong&gt; — compare predictions to true labels: &lt;code&gt;loss = loss_fn(predictions, labels)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backpropagation&lt;/strong&gt; — compute the gradient of the loss w.r.t. every weight: &lt;code&gt;loss.backward()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Update&lt;/strong&gt; — nudge weights to reduce loss: &lt;code&gt;optimizer.step()&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch.nn&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch.optim&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;optim&lt;/span&gt;

&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Sequential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Linear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;784&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ReLU&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Linear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&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="n"&gt;loss_fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CrossEntropyLoss&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;optimizer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Adam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;1e-3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;epoch&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;X_batch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_batch&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dataloader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;pred&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_batch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;              &lt;span class="c1"&gt;# forward
&lt;/span&gt;        &lt;span class="n"&gt;loss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;loss_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pred&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_batch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="c1"&gt;# loss
&lt;/span&gt;        &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zero_grad&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;backward&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                    &lt;span class="c1"&gt;# backprop (gradients)
&lt;/span&gt;        &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                   &lt;span class="c1"&gt;# update weights
&lt;/span&gt;    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;epoch &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;epoch&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, loss &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Loss functions
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Loss&lt;/th&gt;
&lt;th&gt;When&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;MSE&lt;/strong&gt; (mean squared error)&lt;/td&gt;
&lt;td&gt;regression (predict a number)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cross-entropy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;classification (predict a class)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Binary cross-entropy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;binary classification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CTC&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;sequence-to-sequence with alignment (speech)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Gradient descent + optimizers
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Gradient descent&lt;/strong&gt;: &lt;code&gt;w -= lr * gradient&lt;/code&gt; — step in the direction that reduces loss. The &lt;strong&gt;learning rate&lt;/strong&gt; (&lt;code&gt;lr&lt;/code&gt;) is the step size — too big and you overshoot/diverge; too small and you crawl. The &lt;strong&gt;optimizer&lt;/strong&gt; decides how to step:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Optimizer&lt;/th&gt;
&lt;th&gt;How&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SGD&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;vanilla &lt;code&gt;w -= lr * grad&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SGD + momentum&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;add a running average of past gradients (smoother, faster)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Adam&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;adaptive per-parameter learning rate + momentum — &lt;strong&gt;the default&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AdamW&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Adam + decoupled weight decay (L2 regularization) — the modern default&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Backpropagation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Backpropagation&lt;/strong&gt; is the algorithm that computes all gradients efficiently using the &lt;strong&gt;chain rule&lt;/strong&gt;: starting from the loss, it walks backward through the network, computing the derivative of the loss with respect to each weight layer by layer. PyTorch's &lt;code&gt;autograd&lt;/code&gt; does this automatically — you call &lt;code&gt;loss.backward()&lt;/code&gt; and every weight's &lt;code&gt;.grad&lt;/code&gt; is populated.&lt;/p&gt;

&lt;h3&gt;
  
  
  Regularization — preventing overfitting
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Technique&lt;/th&gt;
&lt;th&gt;How&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dropout&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;randomly zero out neurons during training (forces redundancy)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;L2 regularization&lt;/strong&gt; (weight decay)&lt;/td&gt;
&lt;td&gt;add &lt;code&gt;lambda * sum(w^2)&lt;/code&gt; to the loss (penalize large weights)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Early stopping&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;stop when validation loss starts rising&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data augmentation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;transform training data (flip, crop, rotate) to effectively get more&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Batch normalization&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;normalize layer inputs per-batch (stabilizes training)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; The &lt;strong&gt;learning rate&lt;/strong&gt; is the single most important hyperparameter. Too high → the loss diverges (NaN). Too low → training takes forever. Start with &lt;code&gt;1e-3&lt;/code&gt; for Adam, and use a &lt;strong&gt;learning rate schedule&lt;/strong&gt; (warmup + decay) for large models. Always watch the training + validation loss curves.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 3 — CNNs (Convolutional Neural Networks)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why CNNs for images
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffxakweestfxjlxr8x3rv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffxakweestfxjlxr8x3rv.png" alt="Architectures: CNN, RNN, Transformer" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A fully-connected layer on an image would need millions of weights (every pixel to every neuron). A &lt;strong&gt;CNN&lt;/strong&gt; uses &lt;strong&gt;convolutional filters&lt;/strong&gt; — small learned kernels (e.g. 3x3) that slide across the image, detecting local patterns with far fewer parameters. Early layers detect edges; later layers detect shapes, then objects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Convolution, pooling, and a typical architecture
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch.nn&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;

&lt;span class="n"&gt;cnn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Sequential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Conv2d&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;32&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;padding&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="c1"&gt;# 3 channels -&amp;gt; 32 filters, 3x3
&lt;/span&gt;    &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ReLU&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MaxPool2d&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="c1"&gt;# downsample by 2
&lt;/span&gt;    &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Conv2d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64&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;padding&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="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ReLU&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MaxPool2d&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="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Flatten&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Linear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;8&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;# fully-connected -&amp;gt; 10 classes
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Conv2d&lt;/strong&gt; — convolution: &lt;code&gt;in_channels → out_channels&lt;/code&gt; filters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MaxPool2d&lt;/strong&gt; — downsampling (take the max in each window); reduces spatial size, adds invariance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flatten + Linear&lt;/strong&gt; — convert the feature maps to a vector, then classify.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Famous CNN architectures
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Architecture&lt;/th&gt;
&lt;th&gt;Innovation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;LeNet&lt;/strong&gt; (1998)&lt;/td&gt;
&lt;td&gt;the first CNN (handwritten digit recognition)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;AlexNet&lt;/strong&gt; (2012)&lt;/td&gt;
&lt;td&gt;deep CNN + ReLU + GPU; started the deep learning era&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;ResNet&lt;/strong&gt; (2015)&lt;/td&gt;
&lt;td&gt;residual connections (skip connections) that enable very deep networks (50-152 layers)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EfficientNet&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;scaled width/depth/resolution together&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Vision Transformer&lt;/strong&gt; (ViT)&lt;/td&gt;
&lt;td&gt;transformers applied to image patches (the modern alternative)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Stage 4 — Transformers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The problem with RNNs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;RNNs&lt;/strong&gt; (recurrent neural networks) process sequences one step at a time, carrying hidden state — but they're &lt;strong&gt;sequential&lt;/strong&gt; (can't parallelize) and suffer from &lt;strong&gt;vanishing gradients&lt;/strong&gt; on long sequences. &lt;strong&gt;LSTMs&lt;/strong&gt; added gates to fix the gradient issue, but not the sequentiality.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Transformer: self-attention
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;Transformer&lt;/strong&gt; (2017, "Attention Is All You Need") replaced recurrence with &lt;strong&gt;self-attention&lt;/strong&gt;: each position in the sequence attends to (weighs) all other positions simultaneously. This is &lt;strong&gt;parallelizable&lt;/strong&gt; (process all positions at once on a GPU) and captures long-range dependencies far better.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Self-attention&lt;/strong&gt; in one line: for each token, compute a weighted average of all tokens, where the weights are learned from the query-key dot product:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Attention(Q, K, V) = softmax(Q @ K^T / sqrt(d)) @ V
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Q&lt;/strong&gt; (query) — "what am I looking for?"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;K&lt;/strong&gt; (key) — "what do I contain?"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;V&lt;/strong&gt; (value) — "what information do I carry?"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;softmax(Q @ K^T)&lt;/strong&gt; — how much each position should attend to each other&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-head attention&lt;/strong&gt; — run multiple attention heads in parallel, each learning a different pattern&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Transformers → LLMs
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;large language model&lt;/strong&gt; (GPT, Claude, Gemini) is a &lt;strong&gt;transformer&lt;/strong&gt; trained on massive text:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GPT-style&lt;/strong&gt; (decoder-only): predicts the next token; autoregressive generation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BERT-style&lt;/strong&gt; (encoder-only): bidirectional; used for understanding (classification, search).&lt;/li&gt;
&lt;li&gt;The model learns language, facts, and reasoning from the training data; fine-tuning + RLHF adapt its behavior.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Diffusion models
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Diffusion&lt;/strong&gt; (Stable Diffusion, DALL-E) generates images: add Gaussian noise to an image step by step, then train a neural network (often a U-Net) to reverse the process. At generation, start from pure noise and denoise into an image, conditioned on a text prompt (via a CLIP encoder).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; Transformers are &lt;strong&gt;data-hungry&lt;/strong&gt; — they need millions/billions of examples to train well. On small datasets, a CNN or a tree-based model (XGBoost) often wins. The "scale is all you need" approach only works with the data and compute to match.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 5 — Frameworks, Training Loop, GPU, Deploy
&lt;/h2&gt;

&lt;h3&gt;
  
  
  PyTorch — the dominant framework
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbqjclyk28afq3dky28pm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbqjclyk28afq3dky28pm.png" alt="Frameworks, Training Loop, GPU, Deploy" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PyTorch&lt;/strong&gt; is the default for research and increasingly production: eager execution (debuggable), dynamic graphs, a rich ecosystem (HuggingFace Transformers, torchvision, torchaudio). &lt;strong&gt;TensorFlow/Keras&lt;/strong&gt; (Google) and &lt;strong&gt;JAX&lt;/strong&gt; (functional, XLA-compiled) are alternatives.&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;# GPU
&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;device&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cuda&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;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cuda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_available&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cpu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;X_batch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_batch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;X_batch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;y_batch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# mixed precision (2x faster, half the memory)
&lt;/span&gt;&lt;span class="n"&gt;scaler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GradScaler&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;autocast&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;pred&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_batch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;loss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;loss_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pred&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_batch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;scaler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;backward&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;scaler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;scaler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The training loop (full)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;epoch&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="n"&gt;num_epochs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;train&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                          &lt;span class="c1"&gt;# training mode (dropout active)
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;train_loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;pred&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;loss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;loss_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pred&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zero_grad&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;backward&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                           &lt;span class="c1"&gt;# eval mode (dropout off, batchnorm fixed)
&lt;/span&gt;    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;no_grad&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;                  &lt;span class="c1"&gt;# no gradients (saves memory)
&lt;/span&gt;        &lt;span class="n"&gt;val_loss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;loss_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Xv&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;yv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Xv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;yv&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;val_loader&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;epoch &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;epoch&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: train &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; val &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;val_loss&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deploy
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# export to ONNX (interchange format, runs on CPU/mobile/server)
&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onnx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dummy_input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model.onnx&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# or TorchScript for production serving
&lt;/span&gt;&lt;span class="n"&gt;scripted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;script&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;scripted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model.pt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# serve: TorchServe, NVIDIA Triton, or a FastAPI endpoint wrapping the model
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Quick-Start Checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install PyTorch&lt;/strong&gt; (&lt;code&gt;pip install torch torchvision&lt;/code&gt;); verify GPU with &lt;code&gt;torch.cuda.is_available()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write a 3-layer MLP&lt;/strong&gt; on MNIST; train it for 5 epochs; watch the loss drop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learn the training loop&lt;/strong&gt;: forward → loss → &lt;code&gt;backward()&lt;/code&gt; → &lt;code&gt;step()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Adam&lt;/strong&gt; (lr=1e-3); if the loss diverges, lower the lr by 10x.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch train vs val loss&lt;/strong&gt; — if val rises while train drops, you overfit (add dropout/early stop).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build a CNN&lt;/strong&gt; on CIFAR-10; see convolutions outperform the MLP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Try a pretrained model&lt;/strong&gt; — &lt;code&gt;torchvision.models.resnet18(pretrained=True)&lt;/code&gt;; fine-tune on your data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use HuggingFace Transformers&lt;/strong&gt; — load a pretrained BERT/GPT in 3 lines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Train on GPU&lt;/strong&gt; with mixed precision; it's 2-5x faster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Export to ONNX&lt;/strong&gt; and serve; or use a pre-trained model from HuggingFace Hub.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Common Pitfalls
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Learning rate too high&lt;/strong&gt; — loss goes to NaN; reduce by 10x.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learning rate too low&lt;/strong&gt; — loss barely moves; increase or use a schedule.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overfitting&lt;/strong&gt; — train loss down, val loss up; add dropout, data augmentation, early stopping.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not setting &lt;code&gt;model.train()&lt;/code&gt; / &lt;code&gt;model.eval()&lt;/code&gt;&lt;/strong&gt; — dropout and batchnorm behave differently; forgetting &lt;code&gt;eval()&lt;/code&gt; gives wrong validation results.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forgetting &lt;code&gt;optimizer.zero_grad()&lt;/code&gt;&lt;/strong&gt; — gradients accumulate across batches; stale gradients corrupt training.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not using &lt;code&gt;torch.no_grad()&lt;/code&gt; in evaluation&lt;/strong&gt; — wastes memory computing gradients you don't need.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data on CPU, model on GPU&lt;/strong&gt; — every batch transfer is a bottleneck; move data to GPU once.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Small data + big model&lt;/strong&gt; — a transformer on 1,000 examples overfits instantly; use a pretrained model + fine-tune, or a simpler architecture.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not normalizing inputs&lt;/strong&gt; — unnormalized data (pixels 0-255 instead of 0-1) makes training unstable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pytorch.org/tutorials/" rel="noopener noreferrer"&gt;PyTorch Tutorials&lt;/a&gt; — the official starting point&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.deeplearningbook.org/" rel="noopener noreferrer"&gt;Deep Learning Book&lt;/a&gt; by Goodfellow et al — the theory reference (free)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://d2l.ai/" rel="noopener noreferrer"&gt;Dive into Deep Learning&lt;/a&gt; — interactive, PyTorch + theory&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://huggingface.co/learn" rel="noopener noreferrer"&gt;HuggingFace Course&lt;/a&gt; — transformers + NLP&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://paperswithcode.com/" rel="noopener noreferrer"&gt;Papers With Code&lt;/a&gt; — state of the art + implementations&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/@karpathy" rel="noopener noreferrer"&gt;Andrej Karpathy's YouTube&lt;/a&gt; — "Let's build GPT" from scratch&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Related guides
&lt;/h2&gt;

&lt;p&gt;Deep learning builds on programming + math fundamentals — these PyShine tutorials connect to it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Machine-Learning-in-One-Post-Complete-Tutorial-Supervised-Unsupervised-Deep-Learning-Quick-Start/"&gt;Learn Machine Learning in One Post&lt;/a&gt;&lt;/strong&gt; — the prerequisite; ML basics before going deep.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Python-in-One-Post-Complete-Tutorial-Async-Type-Hints-Quick-Start/"&gt;Learn Python in One Post&lt;/a&gt;&lt;/strong&gt; — the language every DL framework uses; NumPy tensors are Python.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Data-Structures-and-Algorithms-in-One-Post-Complete-Tutorial-Big-O-Trees-Graphs-DP-Quick-Start/"&gt;Learn Data Structures and Algorithms in One Post&lt;/a&gt;&lt;/strong&gt; — Big-O for model complexity; matrix math fundamentals.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-PostgreSQL-in-One-Post-Complete-Tutorial-Indexes-MVCC-Performance-Quick-Start/"&gt;Learn PostgreSQL in One Post&lt;/a&gt;&lt;/strong&gt; — pgvector stores and searches DL embeddings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Docker-in-One-Post-Complete-Tutorial-Dockerfile-Volumes-Compose-Quick-Start/"&gt;Learn Docker in One Post&lt;/a&gt;&lt;/strong&gt; — containerize model training and serving.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Deep learning's power is the same idea repeated at scale: &lt;strong&gt;a layer learns a representation, the next layer builds on it, and a deep stack learns hierarchical features no human designed&lt;/strong&gt;. The five stages here — neural networks, training, CNNs, transformers, frameworks — cover everything from a single neuron to a billion-parameter LLM. The two habits that pay off: &lt;strong&gt;start with a pretrained model and fine-tune&lt;/strong&gt; (don't train from scratch unless you have the data), and &lt;strong&gt;watch the training + validation loss curves&lt;/strong&gt; — they tell you everything about what's happening. Install PyTorch, train a 3-layer net on MNIST for 5 epochs, and watch the loss drop — that's the moment it clicks.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://pyshine.com/Learn-Deep-Learning-in-One-Post-Complete-Tutorial-Neural-Networks-CNN-Transformers-PyTorch-Quick-Start/" rel="noopener noreferrer"&gt;pyshine.com&lt;/a&gt;. The full tutorial with all 5 hand-drawn diagrams lives there — this cross-post is kept in sync via canonical URL.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>deeplearning</category>
      <category>neuralnetworks</category>
      <category>pytorch</category>
      <category>cnn</category>
    </item>
    <item>
      <title>Learn FastAPI in a Single Post: A Complete Tutorial From Path Operations and Pydantic to Async Databases and Production</title>
      <dc:creator>PyShine</dc:creator>
      <pubDate>Thu, 23 Jul 2026 12:42:05 +0000</pubDate>
      <link>https://dev.to/pyshine/learn-fastapi-in-a-single-post-a-complete-tutorial-from-path-operations-and-pydantic-to-async-lb8</link>
      <guid>https://dev.to/pyshine/learn-fastapi-in-a-single-post-a-complete-tutorial-from-path-operations-and-pydantic-to-async-lb8</guid>
      <description>&lt;h1&gt;
  
  
  Learn FastAPI in a Single Post: Complete Tutorial From Path Operations and Pydantic to Async Databases and Production
&lt;/h1&gt;

&lt;p&gt;FastAPI is the modern Python web framework: it takes Python type hints, turns them into automatic request validation, serialization, and interactive API docs, and runs on an async (ASGI) runtime for high concurrency. It's become the default for new Python APIs — replacing Flask for anything that wants async, validation, or OpenAPI for free. This single post teaches the whole framework in five stages, with hand-drawn diagrams and runnable Python.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning Roadmap
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft9ufzdtb5kwuvyeofm4v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft9ufzdtb5kwuvyeofm4v.png" alt="FastAPI Learning Roadmap" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The roadmap moves from basics (Stage 1), through the Pydantic models that make FastAPI work (Stage 2), routing + dependencies (Stage 3), async + databases (Stage 4), and production (Stage 5). You'll want solid &lt;a href="https://dev.to/Learn-Python-in-One-Post-Complete-Tutorial-Async-Type-Hints-Quick-Start/"&gt;Python&lt;/a&gt; and &lt;a href="https://dev.to/Learn-REST-API-in-One-Post-Complete-Tutorial-Methods-Status-Codes-Production-Quick-Start/"&gt;REST API&lt;/a&gt; fundamentals first.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stage 1 — Basics
&lt;/h2&gt;

&lt;h3&gt;
  
  
  A first app
&lt;/h3&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;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&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;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nd"&gt;@app.get&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;read_root&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hello&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;world&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/users/{user_id}&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;read_user&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="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_id&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;q&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="s2"&gt;"fastapi[standard]"&lt;/span&gt;
fastapi dev main.py        &lt;span class="c"&gt;# hot-reload dev server at http://localhost:8000&lt;/span&gt;
&lt;span class="c"&gt;# then open http://localhost:8000/docs  &amp;lt;- automatic interactive docs!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Path operations
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;path operation&lt;/strong&gt; is a route: a decorator (&lt;code&gt;@app.get&lt;/code&gt;, &lt;code&gt;@app.post&lt;/code&gt;, ...) on a function.&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="nd"&gt;@app.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/items&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;create_item&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="n"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;           &lt;span class="c1"&gt;# body validated via Pydantic (Stage 2)
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;

&lt;span class="nd"&gt;@app.put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/items/{item_id}&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;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&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="n"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;    &lt;span class="c1"&gt;# path param + body
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;item_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_dump&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;

&lt;span class="nd"&gt;@app.delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/items/{item_id}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;204&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;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Parameters — types do the work
&lt;/h3&gt;

&lt;p&gt;FastAPI reads your &lt;strong&gt;type hints&lt;/strong&gt; and converts them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Path params&lt;/strong&gt; (&lt;code&gt;user_id: int&lt;/code&gt;) — parsed from the URL, validated as &lt;code&gt;int&lt;/code&gt; (a string here returns 422).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query params&lt;/strong&gt; (&lt;code&gt;q: str | None = None&lt;/code&gt;) — optional query string.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request body&lt;/strong&gt; (&lt;code&gt;item: Item&lt;/code&gt;, a Pydantic model) — parsed + validated JSON.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Headers/cookies&lt;/strong&gt; — via &lt;code&gt;Header&lt;/code&gt; / &lt;code&gt;Cookie&lt;/code&gt; defaults.
&lt;/li&gt;
&lt;/ul&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;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Query&lt;/span&gt;
&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/search&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;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min_length&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="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;q&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;limit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The request/response flow + auto docs
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmvphqp0b0csyjly9pcpx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmvphqp0b0csyjly9pcpx.png" alt="Request -&gt; Validate -&gt; Handler -&gt; Response + Auto Docs" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every request is validated by Pydantic before your handler runs (invalid → 422 with a precise error), the handler runs, and the &lt;code&gt;response_model&lt;/code&gt; serializes and filters the output. &lt;strong&gt;Swagger UI at &lt;code&gt;/docs&lt;/code&gt; and ReDoc at &lt;code&gt;/redoc&lt;/code&gt; are generated automatically&lt;/strong&gt; from your types — no separate spec to maintain.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; Because validation is from type hints, a missing annotation (&lt;code&gt;def f(x):&lt;/code&gt; with no type) means FastAPI treats &lt;code&gt;x&lt;/code&gt; as a query param with no validation — silently. Always annotate. Run &lt;code&gt;mypy&lt;/code&gt;/&lt;code&gt;pyright&lt;/code&gt; in CI to catch missing hints.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 2 — Pydantic
&lt;/h2&gt;

&lt;p&gt;Pydantic is the engine under FastAPI: typed data models that &lt;strong&gt;validate, coerce, and serialize&lt;/strong&gt;. Your request bodies and responses are Pydantic models.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxsh9j13i7fxeo8jm08iy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxsh9j13i7fxeo8jm08iy.png" alt="Pydantic: Validation + Serialization + Settings" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  A model
&lt;/h3&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;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;EmailStr&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&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="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min_length&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="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;EmailStr&lt;/span&gt;
    &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ge&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&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="c1"&gt;# default empty list (safe - not mutable-shared)
&lt;/span&gt;
&lt;span class="c1"&gt;# validation happens on construction:
&lt;/span&gt;&lt;span class="nc"&gt;UserCreate&lt;/span&gt;&lt;span class="p"&gt;(&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;Ada&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a@b.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&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="p"&gt;)&lt;/span&gt;       &lt;span class="c1"&gt;# ok
&lt;/span&gt;&lt;span class="nc"&gt;UserCreate&lt;/span&gt;&lt;span class="p"&gt;(&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="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bad&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&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;999&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;             &lt;span class="c1"&gt;# ValidationError (precise)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Validation, coercion, serialization
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Coercion&lt;/strong&gt; — &lt;code&gt;UserCreate(age="30")&lt;/code&gt; coerces the string &lt;code&gt;"30"&lt;/code&gt; to &lt;code&gt;int&lt;/code&gt; 30 (controlled; use &lt;code&gt;Strict&lt;/code&gt; to disable).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validation&lt;/strong&gt; — &lt;code&gt;Field(min_length=1, ge=0)&lt;/code&gt; constraints; type mismatches raise &lt;code&gt;ValidationError&lt;/code&gt; with the exact failing field/loc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serialization&lt;/strong&gt; — &lt;code&gt;.model_dump()&lt;/code&gt; (dict) and &lt;code&gt;.model_dump_json()&lt;/code&gt; (JSON); &lt;code&gt;response_model&lt;/code&gt; filters to only the declared fields.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;UserCreate&lt;/span&gt;&lt;span class="p"&gt;(&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;Ada&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a@b.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&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="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_dump&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;          &lt;span class="c1"&gt;# {'name': 'Ada', 'email': 'a@b.com', 'age': 30, 'tags': []}
&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserOut&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;EmailStr&lt;/span&gt;       &lt;span class="c1"&gt;# no 'age' or 'tags' -&amp;gt; response_model filters them out
&lt;/span&gt;
&lt;span class="nd"&gt;@app.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/users&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;UserOut&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;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UserCreate&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;UserOut&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&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="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;u&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;email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# age/tags never leak
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Custom validators
&lt;/h3&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;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;field_validator&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;
    &lt;span class="nd"&gt;@field_validator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@classmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;positive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&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;v&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price must be positive&lt;/span&gt;&lt;span class="sh"&gt;"&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;v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Settings (config from env vars)
&lt;/h3&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;pydantic_settings&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseSettings&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Settings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseSettings&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;db_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;postgresql://localhost/app&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="n"&gt;model_config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SettingsConfigDict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env_prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;APP_&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# APP_DB_URL, APP_DEBUG
&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Settings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;    &lt;span class="c1"&gt;# reads env vars, typed
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; A mutable default (&lt;code&gt;tags: list[str] = []&lt;/code&gt;) is safe in Pydantic (it copies per instance), unlike plain Python class attributes where it'd be shared. Still, prefer &lt;code&gt;Field(default_factory=list)&lt;/code&gt; for clarity in older code.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 3 — Routing + Dependencies
&lt;/h2&gt;

&lt;h3&gt;
  
  
  APIRouter — split routes into modules
&lt;/h3&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;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;APIRouter&lt;/span&gt;
&lt;span class="n"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;APIRouter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/users&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tags&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;users&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="nd"&gt;@router.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/{user_id}&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;get_user&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="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;

&lt;span class="c1"&gt;# main.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;router&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;users_router&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;include_router&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;users_router&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Dependency injection via &lt;code&gt;Depends&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Depends&lt;/code&gt; is how FastAPI shares logic — a function whose return value is injected into your handler. It's composable and cached per-request by default.&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;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Depends&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_db&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;           &lt;span class="c1"&gt;# yields a DB session, closes it after the request
&lt;/span&gt;    &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SessionLocal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;
    &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/users/{id}&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;read_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_db&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;User&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="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;Depends&lt;/code&gt; for: DB sessions, auth (get current user), settings, pagination params, rate limiting. It's cleaner than globals and testable (override in tests).&lt;/p&gt;

&lt;h3&gt;
  
  
  Middleware
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@app.middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_timing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;call_next&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;call_next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;X-Process-Time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&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;response&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Auth
&lt;/h3&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;fastapi.security&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OAuth2PasswordBearer&lt;/span&gt;
&lt;span class="n"&gt;oauth2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OAuth2PasswordBearer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokenUrl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;token&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oauth2&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;decode_jwt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;HTTPException&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;invalid token&lt;/span&gt;&lt;span class="sh"&gt;"&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;user&lt;/span&gt;

&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/me&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;me&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_user&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;user&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;fastapi.security&lt;/code&gt; provides OAuth2, JWT, API keys, HTTP basic — wired into the auto-docs so the "Authorize" button works.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stage 4 — Async + Databases
&lt;/h2&gt;

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

&lt;p&gt;The DB call is the bottleneck in most APIs. With &lt;code&gt;async&lt;/code&gt; + &lt;code&gt;await&lt;/code&gt;, the worker thread is &lt;strong&gt;released&lt;/strong&gt; while waiting on I/O, so one event loop serves many in-flight requests. This is FastAPI's main advantage over Flask.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdv8he68eyrsg19a633v8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdv8he68eyrsg19a633v8.png" alt="Async + Database + Dependency Injection" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  An async handler with an async DB session
&lt;/h3&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;sqlalchemy.ext.asyncio&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AsyncSession&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_db&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;AsyncSessionLocal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;

&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/users/{id}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AsyncSession&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_db&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;HTTPException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&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;user&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Async DB options
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;When&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SQLAlchemy 2.0 async&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;the default ORM; async sessions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;asyncpg&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;raw, fast async Postgres driver&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SQLModel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;SQLAlchemy + Pydantic fused (by the FastAPI author)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;aioredis / redis-py async&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;async &lt;a href="https://dev.to/Learn-Redis-in-One-Post-Complete-Tutorial-Data-Structures-Caching-Persistence-Quick-Start/"&gt;Redis&lt;/a&gt; for cache/sessions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  HTTP clients + background work
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; 
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AsyncClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
        &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;c&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="n"&gt;url&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="c1"&gt;# fire-and-forget background job (for simple cases; use a queue for real)
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BackgroundTasks&lt;/span&gt;
&lt;span class="nd"&gt;@app.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/send&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BackgroundTasks&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;send_email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# runs after the response
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;queued&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; A &lt;strong&gt;blocking&lt;/strong&gt; call in an &lt;code&gt;async&lt;/code&gt; handler (&lt;code&gt;requests.get&lt;/code&gt;, &lt;code&gt;time.sleep&lt;/code&gt;, sync DB) freezes the whole event loop, not just one request — exactly like &lt;a href="https://dev.to/Learn-Node-js-Express-in-One-Post-Complete-Tutorial-Event-Loop-Middleware-Quick-Start/"&gt;Node&lt;/a&gt;. Use async libraries (&lt;code&gt;httpx&lt;/code&gt;, &lt;code&gt;asyncpg&lt;/code&gt;), or offload with &lt;code&gt;run_in_threadpool&lt;/code&gt; / a real queue (Celery, RQ, Dramatiq) for heavy work.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 5 — Production
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Run: uvicorn + gunicorn
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# dev&lt;/span&gt;
fastapi dev main.py
&lt;span class="c"&gt;# production (Linux): gunicorn managing uvicorn workers, one per core&lt;/span&gt;
gunicorn main:app &lt;span class="nt"&gt;-w&lt;/span&gt; 4 &lt;span class="nt"&gt;-k&lt;/span&gt; uvicorn.workers.UvicornWorker &lt;span class="nt"&gt;-b&lt;/span&gt; 0.0.0.0:8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each uvicorn worker is an async event loop; gunicorn manages worker processes (restart on crash, graceful reload). Use 2-4× CPU cores for I/O-bound; tune for your load.&lt;/p&gt;

&lt;h3&gt;
  
  
  Migrations: Alembic
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;alembic
alembic init alembic
alembic revision &lt;span class="nt"&gt;--autogenerate&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"create users"&lt;/span&gt;
alembic upgrade &lt;span class="nb"&gt;head&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Never &lt;code&gt;create_all&lt;/code&gt; in production; use Alembic to version and migrate the schema. See the &lt;a href="https://dev.to/Learn-PostgreSQL-in-One-Post-Complete-Tutorial-Indexes-MVCC-Performance-Quick-Start/"&gt;PostgreSQL tutorial&lt;/a&gt; for the migration mindset.&lt;/p&gt;

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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AsyncClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ASGITransport&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;

&lt;span class="nd"&gt;@pytest.fixture&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;AsyncClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transport&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;ASGITransport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://test&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;

&lt;span class="nd"&gt;@pytest.mark.anyio&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_root&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&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="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;assert&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;r&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="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;hello&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;world&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;httpx.AsyncClient&lt;/code&gt; with &lt;code&gt;ASGITransport&lt;/code&gt; (no network needed). Override &lt;code&gt;Depends&lt;/code&gt; in tests to swap the DB for a test DB or mocks.&lt;/p&gt;

&lt;h3&gt;
  
  
  The toolchain
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4xztmze3dwydw02e3vge.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4xztmze3dwydw02e3vge.png" alt="FastAPI Toolchain + Ecosystem" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concern&lt;/th&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Run&lt;/td&gt;
&lt;td&gt;uvicorn, gunicorn, hypercorn, Docker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DB + migrate&lt;/td&gt;
&lt;td&gt;SQLAlchemy (async), asyncpg, Alembic, Tortoise&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test + docs&lt;/td&gt;
&lt;td&gt;pytest + httpx, TestClient, /docs + /redoc, mypy/pyright&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth + extras&lt;/td&gt;
&lt;td&gt;OAuth2/JWT, CORS + middleware, background tasks, serverless (Lambda, Cloud Run)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Deploy
&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; python:3.12-slim&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; 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;CMD&lt;/span&gt;&lt;span class="s"&gt; ["gunicorn", "main:app", "-w", "4", "-k", "uvicorn.workers.UvicornWorker", "-b", "0.0.0.0:8000"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or go &lt;strong&gt;serverless&lt;/strong&gt;: FastAPI on AWS Lambda (via Mangum), Google Cloud Run, or Vercel — the ASGI design makes it portable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick-Start Checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install&lt;/strong&gt; &lt;code&gt;pip install "fastapi[standard]"&lt;/code&gt; and run &lt;code&gt;fastapi dev main.py&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open &lt;code&gt;/docs&lt;/code&gt;&lt;/strong&gt; — your types already generated Swagger UI. That's the FastAPI wow moment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Define Pydantic models&lt;/strong&gt; for request bodies and &lt;code&gt;response_model&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Annotate every param&lt;/strong&gt; — path, query, body; types do the validation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Split routes&lt;/strong&gt; into &lt;code&gt;APIRouter&lt;/code&gt;s; &lt;code&gt;app.include_router(...)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;Depends&lt;/code&gt;&lt;/strong&gt; for the DB session, auth, settings — not globals.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Go async&lt;/strong&gt; for DB/HTTP; use asyncpg/SQLAlchemy async/httpx.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never block the loop&lt;/strong&gt; — no sync I/O in async handlers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set up Alembic&lt;/strong&gt; for schema migrations; never &lt;code&gt;create_all&lt;/code&gt; in prod.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test with httpx AsyncClient&lt;/strong&gt;; run uvicorn via gunicorn in production.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Common Pitfalls
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Missing type hints&lt;/strong&gt; — no annotation = no validation, treated as a plain query param. Annotate everything; run mypy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blocking calls in async handlers&lt;/strong&gt; — &lt;code&gt;requests&lt;/code&gt;, &lt;code&gt;time.sleep&lt;/code&gt;, sync DB freeze the event loop. Use async libs or offload.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;response_model&lt;/code&gt; omitted&lt;/strong&gt; — without it, extra fields leak and the OpenAPI schema is wrong. Always set it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mutable default shared&lt;/strong&gt; — rare in Pydantic, but watch &lt;code&gt;Field(default_factory=...)&lt;/code&gt; in older code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;create_all&lt;/code&gt; in production&lt;/strong&gt; — no migrations; use Alembic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One uvicorn worker&lt;/strong&gt; — underuses multi-core; let gunicorn manage N workers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not overriding &lt;code&gt;Depends&lt;/code&gt; in tests&lt;/strong&gt; — test against a real/seeded DB or a mock, via &lt;code&gt;app.dependency_overrides&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trusting client input&lt;/strong&gt; — Pydantic validates shape, not business rules; add &lt;code&gt;@field_validator&lt;/code&gt; and auth.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://fastapi.tiangolo.com/" rel="noopener noreferrer"&gt;FastAPI Docs&lt;/a&gt; — official, thorough, with a full tutorial&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.pydantic.dev/" rel="noopener noreferrer"&gt;Pydantic Docs&lt;/a&gt; — models, validation, v2&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.sqlalchemy.org/en/20/orm/extensions/asyncio.html" rel="noopener noreferrer"&gt;SQLAlchemy 2.0 async docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testdriven.io/blog/topics/fastapi/" rel="noopener noreferrer"&gt;TestDriven.io FastAPI&lt;/a&gt; — practical deep dives&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/zhanymkanov/fastapi-best-practices" rel="noopener noreferrer"&gt;Real World FastAPI&lt;/a&gt; — community best-practices list&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Related guides
&lt;/h2&gt;

&lt;p&gt;FastAPI is the Python backend layer — these PyShine tutorials are its stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Python-in-One-Post-Complete-Tutorial-Async-Type-Hints-Quick-Start/"&gt;Learn Python in One Post&lt;/a&gt;&lt;/strong&gt; — the language; type hints and async are FastAPI's foundation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-REST-API-in-One-Post-Complete-Tutorial-Methods-Status-Codes-Production-Quick-Start/"&gt;Learn REST API in One Post&lt;/a&gt;&lt;/strong&gt; — methods, status codes, idempotency; FastAPI implements REST.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-PostgreSQL-in-One-Post-Complete-Tutorial-Indexes-MVCC-Performance-Quick-Start/"&gt;Learn PostgreSQL in One Post&lt;/a&gt;&lt;/strong&gt; — what SQLAlchemy/asyncpg talks to; Alembic migrates it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Redis-in-One-Post-Complete-Tutorial-Data-Structures-Caching-Persistence-Quick-Start/"&gt;Learn Redis in One Post&lt;/a&gt;&lt;/strong&gt; — cache, sessions, rate limiting behind FastAPI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Docker-in-One-Post-Complete-Tutorial-Dockerfile-Volumes-Compose-Quick-Start/"&gt;Learn Docker in One Post&lt;/a&gt;&lt;/strong&gt; — containerize and ship the app (the Dockerfile above).&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;FastAPI's pitch is simple: &lt;strong&gt;type hints in, production API with docs and validation out&lt;/strong&gt;. The five stages here — basics, Pydantic, routing + deps, async + DB, production — cover everything from a "hello world" to a containerized, migrated, tested, async API backed by Postgres + Redis. The two habits that pay off: &lt;strong&gt;annotate everything&lt;/strong&gt; (it's where the magic comes from), and &lt;strong&gt;never block the event loop&lt;/strong&gt; (use async libs or offload). Run &lt;code&gt;fastapi dev main.py&lt;/code&gt;, open &lt;code&gt;/docs&lt;/code&gt;, and watch your types become an interactive API — that's the moment the framework clicks.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://pyshine.com/Learn-FastAPI-in-One-Post-Complete-Tutorial-Pydantic-Async-Dependency-Injection-Quick-Start/" rel="noopener noreferrer"&gt;pyshine.com&lt;/a&gt;. The full tutorial with all 5 hand-drawn diagrams lives there — this cross-post is kept in sync via canonical URL.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>fastapi</category>
      <category>python</category>
      <category>backend</category>
      <category>pydantic</category>
    </item>
    <item>
      <title>Learn GitHub Actions in a Single Post: A Complete Tutorial From Workflows and Jobs to Runners, Secrets, and Reusable Pipelines</title>
      <dc:creator>PyShine</dc:creator>
      <pubDate>Thu, 23 Jul 2026 12:41:51 +0000</pubDate>
      <link>https://dev.to/pyshine/learn-github-actions-in-a-single-post-a-complete-tutorial-from-workflows-and-jobs-to-runners-37k4</link>
      <guid>https://dev.to/pyshine/learn-github-actions-in-a-single-post-a-complete-tutorial-from-workflows-and-jobs-to-runners-37k4</guid>
      <description>&lt;h1&gt;
  
  
  Learn GitHub Actions in a Single Post: Complete Tutorial From Workflows and Jobs to Runners, Secrets, and Reusable Pipelines
&lt;/h1&gt;

&lt;p&gt;GitHub Actions is GitHub's built-in CI/CD: you write a YAML file, push it to your repo, and GitHub runs your build, test, deploy — on every push, every pull request, on a schedule, or on demand. It's the CI/CD most open-source and many private projects use, because it's free for public repos, integrated into the platform you already use, and has a marketplace of thousands of pre-built actions. This single post teaches the whole system in five stages, with hand-drawn diagrams and runnable YAML.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning Roadmap
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3obqsgmtu3g40lz11c9q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3obqsgmtu3g40lz11c9q.png" alt="GitHub Actions Roadmap" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The roadmap moves from the workflow file (Stage 1), through jobs and steps (Stage 2), the reusable action ecosystem (Stage 3), where it runs (Stage 4), and the security + reuse layer (Stage 5). You'll want the &lt;a href="https://dev.to/Learn-Git-in-One-Post-Complete-Tutorial-Branches-Rebase-Workflows-Quick-Start/"&gt;Git tutorial&lt;/a&gt; and basic &lt;a href="https://dev.to/Learn-Docker-in-One-Post-Complete-Tutorial-Dockerfile-Volumes-Compose-Quick-Start/"&gt;YAML&lt;/a&gt; as prerequisites.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stage 1 — Workflows
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What a workflow is
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;workflow&lt;/strong&gt; is a YAML file in &lt;code&gt;.github/workflows/&lt;/code&gt; that describes an automated process. GitHub reads it and runs it when its &lt;strong&gt;trigger&lt;/strong&gt; (&lt;code&gt;on:&lt;/code&gt;) fires.&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/ci.yml&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;CI&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;        &lt;span class="c1"&gt;# trigger: run on push and PR&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;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;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;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a complete CI pipeline: on every push or PR, GitHub checks out your code, installs deps, and runs tests — on a fresh Ubuntu VM, for free (public repos). Push the file and it runs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Triggers — the &lt;code&gt;on:&lt;/code&gt; field
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1hxld3famda3tvt80ljy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1hxld3famda3tvt80ljy.png" alt="Triggers (the 'on:' field)" width="800" height="418"&gt;&lt;/a&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;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="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;release/*'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;     &lt;span class="c1"&gt;# only these branches&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;opened&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;synchronize&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;        &lt;span class="c1"&gt;# on PR open + update&lt;/span&gt;
  &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*'&lt;/span&gt;                 &lt;span class="c1"&gt;# nightly at 2am UTC&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;# manual "Run workflow" button&lt;/span&gt;
    &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;choice&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;staging&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;prod&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;published&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;                  &lt;span class="c1"&gt;# on release publish&lt;/span&gt;
  &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;src/**'&lt;/span&gt;                          &lt;span class="c1"&gt;# only if src/ changed (skip docs)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The trigger is the entry point. &lt;code&gt;workflow_dispatch&lt;/code&gt; adds a manual button in the Actions tab (great for deploys). &lt;code&gt;schedule&lt;/code&gt; uses standard cron. &lt;code&gt;paths&lt;/code&gt; filters to only run when relevant files change.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; &lt;code&gt;on: [push]&lt;/code&gt; runs on &lt;em&gt;every&lt;/em&gt; push to &lt;em&gt;every&lt;/em&gt; branch. Usually you want &lt;code&gt;on: push: branches: [main]&lt;/code&gt; to avoid running CI on every feature branch push (or you might want it — be deliberate).&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 2 — Jobs + Steps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The hierarchy: workflow → job → step
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5c4uk19fbj4vrf6iaqbl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5c4uk19fbj4vrf6iaqbl.png" alt="Workflow -&gt; Job -&gt; Step -&gt; Action/Run" width="799" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Workflow&lt;/strong&gt; — the YAML file; defines triggers and contains jobs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Job&lt;/strong&gt; — a set of steps that run on the &lt;strong&gt;same runner&lt;/strong&gt; (VM). Jobs run in &lt;strong&gt;parallel&lt;/strong&gt; by default; use &lt;code&gt;needs:&lt;/code&gt; to serialize them into a DAG.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step&lt;/strong&gt; — one task: either an &lt;strong&gt;action&lt;/strong&gt; (&lt;code&gt;uses:&lt;/code&gt;) or a &lt;strong&gt;shell command&lt;/strong&gt; (&lt;code&gt;run:&lt;/code&gt;). Steps run &lt;strong&gt;sequentially&lt;/strong&gt; within a job.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Jobs: parallel and sequential
&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;jobs&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="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;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;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="na"&gt;build&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="c1"&gt;# wait for test to pass&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;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;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="na"&gt;deploy&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;build&lt;/span&gt;
    &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.ref == 'refs/heads/main'&lt;/span&gt;   &lt;span class="c1"&gt;# only on main&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;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo "deploying"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without &lt;code&gt;needs:&lt;/code&gt;, jobs run in parallel. With &lt;code&gt;needs:&lt;/code&gt;, they form a &lt;strong&gt;DAG&lt;/strong&gt; — &lt;code&gt;test → build → deploy&lt;/code&gt;. If &lt;code&gt;test&lt;/code&gt; fails, &lt;code&gt;build&lt;/code&gt; and &lt;code&gt;deploy&lt;/code&gt; don't run.&lt;/p&gt;

&lt;h3&gt;
  
  
  Steps: &lt;code&gt;uses&lt;/code&gt; (actions) and &lt;code&gt;run&lt;/code&gt; (shell)
&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;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;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="c1"&gt;# an action (from the marketplace)&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 deps&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;# a shell command&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;Test&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="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;CI&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;                        &lt;span class="c1"&gt;# env var for this step&lt;/span&gt;
  &lt;span class="pi"&gt;-&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/upload-artifact@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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;coverage&lt;/span&gt;
      &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;coverage/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;uses:&lt;/code&gt; runs a pre-built action (from the marketplace or a repo). &lt;code&gt;run:&lt;/code&gt; executes a shell command (bash on Linux/macOS, PowerShell on Windows). Each step gets &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;with:&lt;/code&gt; (inputs), &lt;code&gt;env:&lt;/code&gt; (env vars).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; &lt;code&gt;actions/checkout@v4&lt;/code&gt; is the first step of almost every job — without it, your runner has an empty workspace. Forget it and every &lt;code&gt;run: npm ...&lt;/code&gt; fails with "package.json not found."&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 3 — Actions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What an action is
&lt;/h3&gt;

&lt;p&gt;An &lt;strong&gt;action&lt;/strong&gt; is a reusable unit: a step you &lt;code&gt;uses:&lt;/code&gt; instead of writing &lt;code&gt;run:&lt;/code&gt;. The &lt;a href="https://github.com/marketplace?type=actions" rel="noopener noreferrer"&gt;GitHub Marketplace&lt;/a&gt; has thousands — checkout, cache, upload-artifact, setup-node, docker build, slack notify, deploy to AWS/Vercel/Cloudflare...&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;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;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;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="m"&gt;20&lt;/span&gt;
  &lt;span class="pi"&gt;-&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/cache@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;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/.npm&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;${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}&lt;/span&gt;
  &lt;span class="pi"&gt;-&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pin to a version
&lt;/h3&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;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="c1"&gt;# major version (recommended for public)&lt;/span&gt;
&lt;span class="pi"&gt;-&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.1.0&lt;/span&gt;       &lt;span class="c1"&gt;# exact version (most reproducible)&lt;/span&gt;
&lt;span class="pi"&gt;-&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@&amp;lt;commit-sha&amp;gt;&lt;/span&gt;  &lt;span class="c1"&gt;# SHA pin (most secure, supply-chain safe)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; &lt;code&gt;@main&lt;/code&gt; or &lt;code&gt;@master&lt;/code&gt; on a third-party action means it can change silently — a supply-chain risk. Pin to a major version (&lt;code&gt;@v4&lt;/code&gt;) at minimum; for sensitive workflows, pin to a SHA. GitHub's Dependabot can keep your action versions up to date.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Composite actions — bundle steps
&lt;/h3&gt;

&lt;p&gt;A composite action packages multiple steps into one reusable action:&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/actions/setup-and-test/action.yml&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 and Test&lt;/span&gt;
&lt;span class="na"&gt;inputs&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="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="na"&gt;runs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;using&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;composite&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;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;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="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="pi"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;inputs.node-version&lt;/span&gt; &lt;span class="pi"&gt;}}&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="pi"&gt;-&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 &amp;amp;&amp;amp; npm test&lt;/span&gt;
      &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bash&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# in a workflow&lt;/span&gt;
&lt;span class="pi"&gt;-&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;./.github/actions/setup-and-test&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;20&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Custom actions (Docker / JS)
&lt;/h3&gt;

&lt;p&gt;You can write actions in JavaScript (fast, cross-platform) or as a Docker container (any language, any tool). For most teams, the marketplace + composite covers it; custom is for when you need a tool the marketplace doesn't have.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stage 4 — Runners
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Where it runs
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4eh7f0mrobu2h30c8a2h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4eh7f0mrobu2h30c8a2h.png" alt="Runners, Matrix, Cache, Artifacts" width="800" height="418"&gt;&lt;/a&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;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;# GitHub-hosted: ephemeral Ubuntu VM&lt;/span&gt;
&lt;span class="c1"&gt;# or:&lt;/span&gt;
&lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;self-hosted&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;linux&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;x64&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;   &lt;span class="c1"&gt;# your own machine&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;GitHub-hosted runners&lt;/strong&gt; are ephemeral VMs GitHub manages — &lt;code&gt;ubuntu-latest&lt;/code&gt;, &lt;code&gt;windows-latest&lt;/code&gt;, &lt;code&gt;macos-latest&lt;/code&gt;. Free for public repos (2,000 min/month free for private). No setup; limited customization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Self-hosted runners&lt;/strong&gt; are your own machines (a VM, a k8s pod, a physical box). Full control, can run on your network, no per-minute cost — but &lt;strong&gt;you maintain and secure them&lt;/strong&gt; (apply OS updates, rotate tokens, isolate workloads). Never use self-hosted on public repos with untrusted PRs without sandboxing — a PR can run arbitrary code on your runner.&lt;/p&gt;

&lt;h3&gt;
  
  
  Matrix — test across combinations
&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;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;os&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ubuntu-latest&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;windows-latest&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;macos-latest&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;node&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;18&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;20&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;22&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ matrix.os }}&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;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="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="pi"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;matrix.node&lt;/span&gt; &lt;span class="pi"&gt;}}&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates &lt;strong&gt;9 jobs&lt;/strong&gt; (3 OS × 3 Node versions) — each runs your tests in one combination. Use &lt;code&gt;fail-fast: false&lt;/code&gt; to see all failures, not just the first.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caching and artifacts
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# cache npm deps across runs&lt;/span&gt;
&lt;span class="pi"&gt;-&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/cache@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;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/.npm&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;${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}&lt;/span&gt;
    &lt;span class="na"&gt;restore-keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ runner.os }}-npm-&lt;/span&gt;

&lt;span class="c1"&gt;# pass build output to another job&lt;/span&gt;
&lt;span class="pi"&gt;-&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/upload-artifact@v4&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;dist/&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;# in the deploy job:&lt;/span&gt;
&lt;span class="pi"&gt;-&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/download-artifact@v4&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;dist/&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Caching cuts install time dramatically (skip re-downloading node_modules on every run). Artifacts pass build outputs between jobs (build → upload → download → deploy) and are stored for 90 days.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; The cache key must include something that changes when deps change (&lt;code&gt;hashFiles('**/package-lock.json')&lt;/code&gt;). A static key serves a stale cache forever; a too-dynamic key never hits.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 5 — Secrets + Environments
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Secrets
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# set in repo Settings -&amp;gt; Secrets and variables -&amp;gt; Actions&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;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker push ${{ secrets.REGISTRY }}/app:latest&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;DOCKER_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.DOCKER_PASSWORD }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Secrets are encrypted in the repo/org settings, masked in logs, and available to workflows via &lt;code&gt;${{ secrets.NAME }}&lt;/code&gt;. &lt;strong&gt;Never&lt;/strong&gt; commit secrets to code; never &lt;code&gt;echo&lt;/code&gt; them (they'll be masked, but don't risk it). For org-wide secrets, use &lt;strong&gt;Organization secrets&lt;/strong&gt; with selected-repo access.&lt;/p&gt;

&lt;h3&gt;
  
  
  Environment variables
&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;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;CI&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;NODE_ENV&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;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&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="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;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo ${{ env.ENVIRONMENT }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;env:&lt;/code&gt; at the top level applies to all jobs; at the job level to all steps in that job; at the step level to that step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Environments (gates + protection)
&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;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy-prod&lt;/span&gt;&lt;span class="pi"&gt;:&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;# protected environment&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;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;An &lt;strong&gt;environment&lt;/strong&gt; (Settings → Environments) can require &lt;strong&gt;manual approval&lt;/strong&gt;, restrict to specific branches, and hold its own secrets. Use &lt;code&gt;environment: production&lt;/code&gt; on a deploy job so a human must approve before it runs — a deployment gate.&lt;/p&gt;

&lt;h3&gt;
  
  
  OIDC — cloud auth without stored keys
&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;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;id-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;        &lt;span class="c1"&gt;# request an OIDC token&lt;/span&gt;
  &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;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;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/configure-aws-credentials@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;role-to-assume&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;arn:aws:iam::123:role/github-actions&lt;/span&gt;
          &lt;span class="na"&gt;aws-region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-east-1&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws s3 cp build/ s3://my-bucket/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;OIDC&lt;/strong&gt; lets GitHub Actions authenticate to your cloud (AWS, GCP, Azure) &lt;strong&gt;without storing long-lived keys&lt;/strong&gt;. GitHub mints a short-lived token; your cloud trusts GitHub's OIDC provider. No key to leak, no rotation — this is the modern, secure way to deploy from CI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reusable workflows
&lt;/h3&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/ci-lib.yml&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;CI Library&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;workflow_call&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;          &lt;span class="c1"&gt;# callable from other workflows&lt;/span&gt;
    &lt;span class="na"&gt;inputs&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="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;string&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;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;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="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="pi"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;inputs.node-version&lt;/span&gt; &lt;span class="pi"&gt;}}&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
      &lt;span class="pi"&gt;-&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 &amp;amp;&amp;amp; npm test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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/ci.yml — calls the reusable workflow&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;call-ci&lt;/span&gt;&lt;span class="pi"&gt;:&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;./.github/workflows/ci-lib.yml&lt;/span&gt;
    &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;20&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reusable workflows (&lt;code&gt;workflow_call&lt;/code&gt;) let you DRY your CI across many repos or many jobs — define once, call everywhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  The ecosystem
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnwx9wdcp8y4ytkzwxali.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnwx9wdcp8y4ytkzwxali.png" alt="Marketplace, Reusable, Environments, OIDC" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concern&lt;/th&gt;
&lt;th&gt;Tool/Pattern&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Marketplace&lt;/td&gt;
&lt;td&gt;checkout, cache, upload-artifact, docker/build-push, slack notify&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reuse&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;workflow_call&lt;/code&gt; (reusable workflows), composite actions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;td&gt;secrets, environments (approval gates), OIDC (no stored keys), &lt;code&gt;permissions:&lt;/code&gt; (least privilege)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Patterns&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;needs:&lt;/code&gt; (DAG), &lt;code&gt;if:&lt;/code&gt; (conditional), &lt;code&gt;concurrency:&lt;/code&gt; (cancel old runs), &lt;code&gt;matrix&lt;/code&gt; (combinatorial)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; Set &lt;code&gt;permissions:&lt;/code&gt; to least-privilege in every workflow. The default token has write access to your repo; a compromised action or a typosquatted dependency could push to your branches. &lt;code&gt;permissions: { contents: read }&lt;/code&gt; is the safe default.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Quick-Start Checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create &lt;code&gt;.github/workflows/ci.yml&lt;/code&gt;&lt;/strong&gt; — &lt;code&gt;on: [push]&lt;/code&gt;, one job, &lt;code&gt;checkout&lt;/code&gt; + &lt;code&gt;npm test&lt;/code&gt;. Push it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch it run&lt;/strong&gt; in the Actions tab. Green? You have CI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add &lt;code&gt;pull_request&lt;/code&gt; trigger&lt;/strong&gt; so PRs are gated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;needs:&lt;/code&gt;&lt;/strong&gt; to build a DAG: test → build → deploy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pin action versions&lt;/strong&gt; (&lt;code&gt;@v4&lt;/code&gt; or SHA), never &lt;code&gt;@main&lt;/code&gt; on third-party.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache deps&lt;/strong&gt; with &lt;code&gt;actions/cache&lt;/code&gt; keyed on the lockfile hash.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Upload artifacts&lt;/strong&gt; to pass build outputs to the deploy job.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Store secrets&lt;/strong&gt; in repo settings, reference via &lt;code&gt;${{ secrets.X }}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add an environment&lt;/strong&gt; with required approval for production deploys.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use OIDC&lt;/strong&gt; for cloud deploys — no stored keys.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Common Pitfalls
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Forgetting &lt;code&gt;actions/checkout&lt;/code&gt;&lt;/strong&gt; — the runner starts with an empty workspace; every step that needs your code fails without it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;on: [push]&lt;/code&gt; on every branch&lt;/strong&gt; — usually want &lt;code&gt;branches: [main]&lt;/code&gt; to limit runs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unpinned third-party actions (&lt;code&gt;@main&lt;/code&gt;)&lt;/strong&gt; — supply-chain risk; pin to a version or SHA.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No cache key&lt;/strong&gt; or a static key — stale cache or never hits; key on the lockfile hash.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secrets in logs&lt;/strong&gt; — they're masked, but don't &lt;code&gt;echo&lt;/code&gt; them; don't put them in env var names.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Over-broad &lt;code&gt;permissions:&lt;/code&gt;&lt;/strong&gt; — default token can write to the repo; set &lt;code&gt;contents: read&lt;/code&gt; unless you need write.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-hosted runners on public repos&lt;/strong&gt; — a PR can run arbitrary code on your machine; isolate or sandbox.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No &lt;code&gt;concurrency:&lt;/code&gt;&lt;/strong&gt; — pushing rapidly runs redundant workflows; &lt;code&gt;concurrency: { group: ${{ github.ref }}, cancel-in-progress: true }&lt;/code&gt; cancels old runs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Long-lived cloud keys&lt;/strong&gt; — use OIDC instead; no key to leak or rotate.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.github.com/actions" rel="noopener noreferrer"&gt;GitHub Actions Docs&lt;/a&gt; — the official reference&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/sdras/awesome-actions" rel="noopener noreferrer"&gt;Awesome Actions&lt;/a&gt; — curated action list&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/marketplace?type=actions" rel="noopener noreferrer"&gt;Actions Marketplace&lt;/a&gt; — search thousands of actions&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.github.com/actions/using-workflows/workflow-syntax-for-github-actions" rel="noopener noreferrer"&gt;GitHub Actions Workflow Syntax&lt;/a&gt; — every YAML field&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.github.com/actions/security-guides" rel="noopener noreferrer"&gt;Security Hardening for GitHub Actions&lt;/a&gt; — the official security guide&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Related guides
&lt;/h2&gt;

&lt;p&gt;GitHub Actions is the CI/CD layer that ties the DevOps stack together — these PyShine tutorials connect to it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Git-in-One-Post-Complete-Tutorial-Branches-Rebase-Workflows-Quick-Start/"&gt;Learn Git in One Post&lt;/a&gt;&lt;/strong&gt; — Actions runs on Git events (push, PR, tag); know Git first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Docker-in-One-Post-Complete-Tutorial-Dockerfile-Volumes-Compose-Quick-Start/"&gt;Learn Docker in One Post&lt;/a&gt;&lt;/strong&gt; — CI builds and pushes Docker images; the &lt;code&gt;docker/build-push-action&lt;/code&gt; is standard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Kubernetes-in-One-Post-Complete-Tutorial-Pods-Deployments-Services-Production-Quick-Start/"&gt;Learn Kubernetes in One Post&lt;/a&gt;&lt;/strong&gt; — CI deploys to K8s; &lt;code&gt;kubectl apply&lt;/code&gt; from a workflow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Bash-in-One-Post-Complete-Tutorial-Pipelines-Functions-Scripts-Quick-Start/"&gt;Learn Bash in One Post&lt;/a&gt;&lt;/strong&gt; — every &lt;code&gt;run:&lt;/code&gt; step is a shell script; know Bash.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Node-js-Express-in-One-Post-Complete-Tutorial-Event-Loop-Middleware-Quick-Start/"&gt;Learn Node.js + Express in One Post&lt;/a&gt;&lt;/strong&gt; — &lt;code&gt;npm ci&lt;/code&gt;, &lt;code&gt;npm test&lt;/code&gt; are the steps in most JS CI.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;GitHub Actions is the CI/CD that's already where your code is — no separate server, no extra account, just a YAML file in your repo. The five stages here — workflows, jobs + steps, actions, runners, secrets + environments — cover everything from a 5-line test job to a matrix-tested, OIDC-authenticated, environment-gated deploy pipeline with reusable workflows. The two habits that pay off: &lt;strong&gt;pin your actions&lt;/strong&gt; (supply-chain safety) and &lt;strong&gt;set &lt;code&gt;permissions:&lt;/code&gt; to least privilege&lt;/strong&gt; (the default token is too powerful). Write a &lt;code&gt;ci.yml&lt;/code&gt;, push it, watch the green checkmark, and you've got CI — then layer in caching, artifacts, and a gated deploy as you grow.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://pyshine.com/Learn-GitHub-Actions-in-One-Post-Complete-Tutorial-Workflows-Jobs-Runners-Secrets-Quick-Start/" rel="noopener noreferrer"&gt;pyshine.com&lt;/a&gt;. The full tutorial with all 5 hand-drawn diagrams lives there — this cross-post is kept in sync via canonical URL.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>githubactions</category>
      <category>cicd</category>
      <category>devops</category>
      <category>automation</category>
    </item>
    <item>
      <title>Learn HTML and CSS in a Single Post: A Complete Tutorial From Semantic Markup and the Box Model to Flexbox, Grid, and Responsive Design</title>
      <dc:creator>PyShine</dc:creator>
      <pubDate>Thu, 23 Jul 2026 12:32:59 +0000</pubDate>
      <link>https://dev.to/pyshine/learn-html-and-css-in-a-single-post-a-complete-tutorial-from-semantic-markup-and-the-box-model-to-1g9a</link>
      <guid>https://dev.to/pyshine/learn-html-and-css-in-a-single-post-a-complete-tutorial-from-semantic-markup-and-the-box-model-to-1g9a</guid>
      <description>&lt;h1&gt;
  
  
  Learn HTML and CSS in a Single Post: Complete Tutorial From Semantic Markup to Flexbox, Grid, and Responsive Design
&lt;/h1&gt;

&lt;p&gt;HTML is the structure of every web page; CSS is how it looks. Together they're the foundation of all frontend development — and unlike frameworks that come and go, the core has been stable for two decades. This single post teaches both in five stages, with hand-drawn diagrams and runnable snippets you can paste into a &lt;code&gt;.html&lt;/code&gt; file and open in a browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning Roadmap
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F60yi5n1lwyw3e0walaag.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F60yi5n1lwyw3e0walaag.png" alt="HTML + CSS Learning Roadmap" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The roadmap moves from HTML structure (Stage 1), through CSS fundamentals (Stage 2), to layout (Stage 3), responsive design (Stage 4), and modern CSS + tooling (Stage 5).&lt;/p&gt;




&lt;h2&gt;
  
  
  Stage 1 — HTML: Structure
&lt;/h2&gt;

&lt;h3&gt;
  
  
  A minimal page
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;My Page&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"style.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Hello, HTML!&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;This is a paragraph.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"app.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/code&gt; triggers standards mode. &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; holds metadata (title, charset, viewport, stylesheet links — not shown on the page); &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; holds the visible content. The &lt;code&gt;viewport&lt;/code&gt; meta tag is mandatory for responsive design on mobile.&lt;/p&gt;

&lt;h3&gt;
  
  
  Elements, tags, attributes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Element&lt;/strong&gt; — a piece of content wrapped in tags: &lt;code&gt;&amp;lt;p&amp;gt;text&amp;lt;/p&amp;gt;&lt;/code&gt;. Most elements have opening and closing tags; a few are &lt;strong&gt;void&lt;/strong&gt; (self-closing): &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attributes&lt;/strong&gt; — key/value pairs on the opening tag: &lt;code&gt;&amp;lt;a href="..."&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;img src="..." alt="..."&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;input type="text" required&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nesting&lt;/strong&gt; — elements contain elements; the result is a tree.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Semantic HTML
&lt;/h3&gt;

&lt;p&gt;Use elements that describe &lt;strong&gt;meaning&lt;/strong&gt;, not appearance. Semantic HTML helps accessibility (screen readers), SEO (search engines understand structure), and maintainability:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Semantic&lt;/th&gt;
&lt;th&gt;Use for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt; / &lt;code&gt;&amp;lt;footer&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;page or section header/footer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;navigation links&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the main content (one per page)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;article&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;a self-contained composition (a blog post, a card)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;a thematic grouping&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;aside&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;tangentially related (sidebar, ad)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;–&lt;code&gt;&amp;lt;h6&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;headings (one &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; per page)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;figure&amp;gt;&lt;/code&gt; / &lt;code&gt;&amp;lt;figcaption&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;an image with a caption&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;time&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;a date/time&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Avoid &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; when a semantic element fits — they carry no meaning. Use them only as generic containers for styling.&lt;/p&gt;

&lt;h3&gt;
  
  
  From HTML to the DOM
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc5f6eewum379qw2twced.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc5f6eewum379qw2twced.png" alt="HTML -&gt; DOM -&gt; Render" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The browser &lt;strong&gt;parses&lt;/strong&gt; your HTML into a tree called the &lt;strong&gt;DOM&lt;/strong&gt; (Document Object Model), then applies CSS, lays out boxes, and paints pixels. JavaScript manipulates the DOM; DevTools (the Elements panel) shows it live. Every "frontend bug" is ultimately about the DOM, the CSS applied to it, or the layout it produces.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stage 2 — CSS Basics
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Selectors and the cascade
&lt;/h3&gt;

&lt;p&gt;CSS targets elements with &lt;strong&gt;selectors&lt;/strong&gt; and applies &lt;strong&gt;declarations&lt;/strong&gt; (&lt;code&gt;property: value&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* element selector */&lt;/span&gt;
&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#333&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* class (.name) — reusable */&lt;/span&gt;
&lt;span class="nc"&gt;.button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* id (#name) — unique, high specificity, avoid for styling */&lt;/span&gt;
&lt;span class="nf"&gt;#hero&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#f0f0f0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* descendant */&lt;/span&gt;
&lt;span class="nt"&gt;nav&lt;/span&gt; &lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;text-decoration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* pseudo-class (state) */&lt;/span&gt;
&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="nd"&gt;:focus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;border-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* combinators */&lt;/span&gt;
&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;   &lt;span class="c"&gt;/* adjacent sibling */&lt;/span&gt;
&lt;span class="nc"&gt;.list&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;           &lt;span class="c"&gt;/* direct child */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Specificity
&lt;/h3&gt;

&lt;p&gt;When two rules target the same element, &lt;strong&gt;specificity&lt;/strong&gt; decides which wins — not "which comes later." The score is &lt;code&gt;(inline, IDs, classes/attrs/pseudo-classes, elements)&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;*&lt;/code&gt; → 0,0,0,0&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;p&lt;/code&gt; → 0,0,0,1&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.button&lt;/code&gt; → 0,0,1,0&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;#hero&lt;/code&gt; → 0,1,0,0&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;style="..."&lt;/code&gt; (inline) → 1,0,0,0&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;!important&lt;/code&gt; → overrides everything (avoid)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; "My CSS isn't applying!" is almost always a specificity loss or a typo in the selector. Use the DevTools Elements panel — it shows every rule applied to an element and which won, with the losers struck through. Don't reach for &lt;code&gt;!important&lt;/code&gt;; fix the specificity.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  The box model
&lt;/h3&gt;

&lt;p&gt;Every element is a &lt;strong&gt;box&lt;/strong&gt; with four layers:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk1vaauu5z1u180lyvufw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk1vaauu5z1u180lyvufw.png" alt="The CSS Box Model" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;content&lt;/strong&gt; — the text/image itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;padding&lt;/strong&gt; — space &lt;em&gt;inside&lt;/em&gt; the border (background fills this).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;border&lt;/strong&gt; — the line around padding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;margin&lt;/strong&gt; — space &lt;em&gt;outside&lt;/em&gt; the border (transparent; collapses with neighbors).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.box&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#333&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-sizing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;border-box&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c"&gt;/* width INCLUDES padding + border */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; By default, &lt;code&gt;width&lt;/code&gt; sets the &lt;em&gt;content&lt;/em&gt; box, so &lt;code&gt;width: 200px&lt;/code&gt; + &lt;code&gt;padding: 20px&lt;/code&gt; + &lt;code&gt;border: 2px&lt;/code&gt; = 244px wide — surprises everyone. Set &lt;code&gt;box-sizing: border-box&lt;/code&gt; globally (&lt;code&gt;*, *::before, *::after { box-sizing: border-box; }&lt;/code&gt;) so &lt;code&gt;width&lt;/code&gt; includes padding and border. It's the first line of every modern stylesheet.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 3 — Layout
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Normal flow
&lt;/h3&gt;

&lt;p&gt;Without CSS, elements stack in &lt;strong&gt;normal flow&lt;/strong&gt;: block elements (&lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;) stack vertically and take full width; inline elements (&lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;strong&amp;gt;&lt;/code&gt;) flow like text. &lt;code&gt;display&lt;/code&gt; changes this: &lt;code&gt;display: block&lt;/code&gt;, &lt;code&gt;inline&lt;/code&gt;, &lt;code&gt;inline-block&lt;/code&gt; (inline but accepts width/height).&lt;/p&gt;

&lt;h3&gt;
  
  
  Flexbox (1D layout)
&lt;/h3&gt;

&lt;p&gt;Flexbox lays items in &lt;strong&gt;one direction&lt;/strong&gt; (a row or column) and aligns them. It's the default for navbars, card rows, and centering.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpd1l6wuczhcmhoxmdfma.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpd1l6wuczhcmhoxmdfma.png" alt="Layout: Flexbox vs Grid + Positioning" width="800" height="418"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.nav&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;space-between&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c"&gt;/* main axis: spread items */&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;             &lt;span class="c"&gt;/* cross axis: vertically center */&lt;/span&gt;
  &lt;span class="py"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.nav&lt;/span&gt; &lt;span class="nc"&gt;.logo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;margin-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="c"&gt;/* push the rest to the right */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key properties: &lt;code&gt;flex-direction&lt;/code&gt; (row/column), &lt;code&gt;justify-content&lt;/code&gt; (main-axis alignment), &lt;code&gt;align-items&lt;/code&gt; (cross-axis alignment), &lt;code&gt;gap&lt;/code&gt; (spacing between items), &lt;code&gt;flex&lt;/code&gt; (grow/shrink on children). The modern centering one-liner: &lt;code&gt;.parent { display: grid; place-items: center; }&lt;/code&gt; or &lt;code&gt;.parent { display: flex; align-items: center; justify-content: center; }&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  CSS Grid (2D layout)
&lt;/h3&gt;

&lt;p&gt;Grid lays items in &lt;strong&gt;two dimensions&lt;/strong&gt; (rows and columns). Use it for page layouts and dashboards:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.page&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200px&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c"&gt;/* sidebar + flexible main */&lt;/span&gt;
  &lt;span class="py"&gt;grid-template-rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;min-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vh&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;&lt;code&gt;1fr&lt;/code&gt; is "one fraction of the remaining space"; &lt;code&gt;auto&lt;/code&gt; sizes to content. &lt;code&gt;grid-template-areas&lt;/code&gt; lets you name regions for a visual layout. &lt;strong&gt;Rule of thumb: Grid for page-level 2D structure, Flexbox for 1D component layout.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Positioning
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;position&lt;/code&gt; takes an element out of normal flow:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;static&lt;/code&gt; (default)&lt;/td&gt;
&lt;td&gt;normal flow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;relative&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;offset from its normal position; keeps its space&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;absolute&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;positioned relative to nearest positioned ancestor; removed from flow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fixed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;positioned relative to the viewport (stays on scroll)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sticky&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;normal flow until it hits a threshold, then sticks (sticky headers)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; &lt;code&gt;position: absolute&lt;/code&gt; without a positioned ancestor positions relative to the viewport-ish root, surprising everyone. Set &lt;code&gt;position: relative&lt;/code&gt; on the parent you want it anchored to.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 4 — Responsive Design
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The viewport meta tag
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without this, mobile browsers render the desktop layout at ~980px and zoom out — tiny and unusable. This tag makes the layout match the device width.&lt;/p&gt;

&lt;h3&gt;
  
  
  Media queries
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* base: mobile-first (smallest screens) */&lt;/span&gt;
&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* tablets and up */&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;600px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* desktops */&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;900px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Mobile-first&lt;/strong&gt; means the base styles target small screens and &lt;code&gt;min-width&lt;/code&gt; queries add complexity for larger ones. It's simpler and faster on mobile (less CSS to override) than desktop-first with &lt;code&gt;max-width&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fluid units
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;%&lt;/code&gt;&lt;/strong&gt; — relative to the parent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;vw&lt;/code&gt; / &lt;code&gt;vh&lt;/code&gt;&lt;/strong&gt; — 1% of viewport width/height.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;rem&lt;/code&gt;&lt;/strong&gt; — relative to the root font size (scales with user zoom; prefer for text and spacing).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;em&lt;/code&gt;&lt;/strong&gt; — relative to the element's own font size (cascades; tricky for spacing).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;clamp(min, ideal, max)&lt;/code&gt;&lt;/strong&gt; — fluid value with bounds: &lt;code&gt;font-size: clamp(1rem, 2.5vw, 2rem)&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1.5rem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5vw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3rem&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;   &lt;span class="c"&gt;/* grows with viewport, bounded */&lt;/span&gt;
&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;         &lt;span class="c"&gt;/* never overflow container */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; Hardcoded &lt;code&gt;width: 800px&lt;/code&gt; overflows on phones. Use &lt;code&gt;max-width&lt;/code&gt; + relative units so content shrinks to fit. Test by resizing the browser window to ~360px wide — your layout should survive.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 5 — Modern CSS + Tooling
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Custom properties (CSS variables)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--brand&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#2563eb&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--space&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--brand&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--space&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--radius&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.button&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;color-mix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;srgb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--brand&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt; &lt;span class="m"&gt;10%&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;Variables cascade (override in a scope), theme dynamically (&lt;code&gt;[data-theme="dark"] { --brand: #58a6ff; }&lt;/code&gt;), and reduce duplication. This site's own dark theme uses them — see the &lt;a href="https://dev.to/categories/"&gt;categories page fix&lt;/a&gt; for a real example.&lt;/p&gt;

&lt;h3&gt;
  
  
  Transitions and animations
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;background&lt;/span&gt; &lt;span class="m"&gt;0.2s&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transform&lt;/span&gt; &lt;span class="m"&gt;0.2s&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.button&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#1e40af&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-1px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@keyframes&lt;/span&gt; &lt;span class="n"&gt;spin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;to&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;360deg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.spinner&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;spin&lt;/span&gt; &lt;span class="m"&gt;1s&lt;/span&gt; &lt;span class="n"&gt;linear&lt;/span&gt; &lt;span class="n"&gt;infinite&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;&lt;code&gt;transition&lt;/code&gt; smoothly interpolates between states; &lt;code&gt;@keyframes&lt;/code&gt; define multi-step animations. Respect users who prefer reduced motion: &lt;code&gt;@media (prefers-reduced-motion: reduce) { * { animation: none !important; transition: none !important; } }&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The toolchain
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftiucsym1mhk3asgvnnnx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftiucsym1mhk3asgvnnnx.png" alt="Browser, DevTools, Frameworks, Build" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Browsers&lt;/strong&gt;: Chrome (Blink/V8), Firefox (Gecko), Safari (WebKit) — test in all three; they render differently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DevTools&lt;/strong&gt;: Elements (inspect DOM/CSS live), Console (JS), Network (requests), Performance (flame graph). &lt;code&gt;F12&lt;/code&gt; / &lt;code&gt;Cmd+Opt+I&lt;/code&gt;. The Elements panel is your primary debugging tool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frameworks&lt;/strong&gt;: React/Vue/Svelte (component-based JS frameworks that generate HTML), Tailwind (utility-class CSS), Bootstrap (component CSS).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build + check&lt;/strong&gt;: Vite/Webpack (bundle + dev server), PostCSS (transform CSS — autoprefixer, nesting), ESLint/Stylelint (lint), Lighthouse (audit performance + accessibility).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Accessibility (a11y)
&lt;/h3&gt;

&lt;p&gt;Good HTML is mostly accessible by default: use semantic elements, real &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;/&lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; (not &lt;code&gt;&amp;lt;div onclick&amp;gt;&lt;/code&gt;), &lt;code&gt;alt&lt;/code&gt; on images, &lt;code&gt;label&lt;/code&gt; on inputs, sufficient color contrast (4.5:1 for text). Test with the keyboard (Tab through) and a screen reader. Lighthouse scores accessibility automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick-Start Checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Write a minimal page&lt;/strong&gt; — &lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/code&gt;, head with viewport, body, link a CSS file. Open it in a browser.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use semantic HTML&lt;/strong&gt; — &lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;article&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;–&lt;code&gt;&amp;lt;h6&amp;gt;&lt;/code&gt; over &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set &lt;code&gt;box-sizing: border-box&lt;/code&gt; globally&lt;/strong&gt; — it's the first line of your CSS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learn selectors + specificity&lt;/strong&gt; — and debug with the DevTools Elements panel, not &lt;code&gt;!important&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Center things with Flexbox/Grid&lt;/strong&gt; — &lt;code&gt;display: grid; place-items: center;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use Grid for 2D page layout, Flexbox for 1D components.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make it responsive&lt;/strong&gt; — viewport meta, &lt;code&gt;max-width&lt;/code&gt; + relative units, mobile-first media queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use CSS variables&lt;/strong&gt; for colors, spacing, radii — theme by overriding in a scope.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test in Chrome, Firefox, Safari&lt;/strong&gt; and at 360px width.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run Lighthouse&lt;/strong&gt; — it audits performance, accessibility, and SEO in one click.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Common Pitfalls
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No viewport meta tag&lt;/strong&gt; — the page is unusably tiny on mobile. Always include it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;width&lt;/code&gt; without &lt;code&gt;box-sizing: border-box&lt;/code&gt;&lt;/strong&gt; — padding + border make the box bigger than expected. Set border-box globally.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;!important&lt;/code&gt; to force a style&lt;/strong&gt; — a specificity loss you're patching; fix the selector instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;&amp;lt;div onclick&amp;gt;&lt;/code&gt; instead of &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;&lt;/strong&gt; — breaks keyboard navigation and screen readers. Use real interactive elements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hardcoded px widths&lt;/strong&gt; — overflow on small screens. Use &lt;code&gt;max-width&lt;/code&gt; + relative units.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;position: absolute&lt;/code&gt; without a positioned parent&lt;/strong&gt; — anchors to the wrong reference. Set &lt;code&gt;position: relative&lt;/code&gt; on the intended parent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forgetting &lt;code&gt;alt&lt;/code&gt; on images&lt;/strong&gt; — fails accessibility and SEO. Decorative images get &lt;code&gt;alt=""&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Desktop-first media queries&lt;/strong&gt; — more CSS to override on mobile; go mobile-first with &lt;code&gt;min-width&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Low color contrast&lt;/strong&gt; — text on a low-contrast background is unreadable; aim for 4.5:1.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/" rel="noopener noreferrer"&gt;MDN Web Docs&lt;/a&gt; — the authoritative HTML/CSS reference&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://web.dev/" rel="noopener noreferrer"&gt;web.dev&lt;/a&gt; — Google's modern web guidance (CSS, performance, a11y)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://css-tricks.com/" rel="noopener noreferrer"&gt;CSS Tricks&lt;/a&gt; — practical CSS recipes and almanac&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://flexboxfroggy.com/" rel="noopener noreferrer"&gt;Flexbox Froggy&lt;/a&gt; — learn Flexbox with a game&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cssgridgarden.com/" rel="noopener noreferrer"&gt;Grid Garden&lt;/a&gt; — learn Grid with a game&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.w3.org/Style/CSS/" rel="noopener noreferrer"&gt;The CSS spec (W3C)&lt;/a&gt; — when you need the source of truth&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Related guides
&lt;/h2&gt;

&lt;p&gt;HTML/CSS is the foundation of all web work — these PyShine tutorials build on it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-JavaScript-TypeScript-in-One-Post-Complete-Tutorial-Async-Types-Quick-Start/"&gt;Learn JavaScript + TypeScript in One Post&lt;/a&gt;&lt;/strong&gt; — JS manipulates the DOM this post describes; the two are inseparable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-REST-API-in-One-Post-Complete-Tutorial-Methods-Status-Codes-Production-Quick-Start/"&gt;Learn REST API in One Post&lt;/a&gt;&lt;/strong&gt; — the frontend fetches data from these APIs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Computer-Networking-in-One-Post-Complete-Tutorial-OSI-TCP-UDP-HTTP-Quick-Start/"&gt;Learn Computer Networking in One Post&lt;/a&gt;&lt;/strong&gt; — HTTP, the browser, and the request lifecycle under every page load.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-SQL-in-One-Post-Complete-Tutorial-Joins-Window-Functions-Transactions-Quick-Start/"&gt;Learn SQL in One Post&lt;/a&gt;&lt;/strong&gt; — the data behind most pages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Bash-in-One-Post-Complete-Tutorial-Pipelines-Functions-Scripts-Quick-Start/"&gt;Learn Bash in One Post&lt;/a&gt;&lt;/strong&gt; — &lt;code&gt;curl&lt;/code&gt;, build scripts, and the CLI around your frontend tooling.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;HTML and CSS are unusual in tech: the fundamentals you learn today will still be valid in twenty years. The five stages here — structure, styling, layout, responsive, modern — cover everything you need to build any web page, and the frameworks (React, Vue, Tailwind) are all conveniences on top of these primitives. Spend a day per stage, build a real page (a portfolio, a blog), resize the browser to 360px, run Lighthouse, and fix what it flags. The skills only stick once you've fought a layout into working at every width — so open a text file and start.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://pyshine.com/Learn-HTML-CSS-in-One-Post-Complete-Tutorial-Semantic-Markup-Box-Model-Flexbox-Grid-Quick-Start/" rel="noopener noreferrer"&gt;pyshine.com&lt;/a&gt;. The full tutorial with all 5 hand-drawn diagrams lives there — this cross-post is kept in sync via canonical URL.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>html</category>
      <category>css</category>
      <category>webdev</category>
      <category>flexbox</category>
    </item>
    <item>
      <title>Learn Kubernetes in a Single Post: A Complete K8s Tutorial From Pods and Deployments to Services and Production Operations</title>
      <dc:creator>PyShine</dc:creator>
      <pubDate>Thu, 23 Jul 2026 12:32:47 +0000</pubDate>
      <link>https://dev.to/pyshine/learn-kubernetes-in-a-single-post-a-complete-k8s-tutorial-from-pods-and-deployments-to-services-33e1</link>
      <guid>https://dev.to/pyshine/learn-kubernetes-in-a-single-post-a-complete-k8s-tutorial-from-pods-and-deployments-to-services-33e1</guid>
      <description>&lt;h1&gt;
  
  
  Learn Kubernetes in a Single Post: Complete Tutorial From Pods and Deployments to Services and Production
&lt;/h1&gt;

&lt;p&gt;Kubernetes is the operating system of the cloud. It takes the container idea from Docker and adds orchestration at scale: it schedules containers across a cluster of machines, restarts them when they fail, scales them on demand, load-balances traffic, and rolls out new versions without downtime. This single post teaches the whole platform in five stages, with hand-drawn diagrams and runnable manifests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning Roadmap
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftfhmkrodlpa4rsxf6s4s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftfhmkrodlpa4rsxf6s4s.png" alt="Kubernetes Learning Roadmap" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The roadmap moves from understanding &lt;em&gt;why&lt;/em&gt; Kubernetes exists (Stage 1), through the core workload objects (Stage 2), networking and storage (Stage 3), scheduling and scaling (Stage 4), to production operations (Stage 5).&lt;/p&gt;




&lt;h2&gt;
  
  
  Stage 1 — Fundamentals: Why Kubernetes, Pods, kubectl
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why Kubernetes?
&lt;/h3&gt;

&lt;p&gt;Docker runs containers on &lt;strong&gt;one machine&lt;/strong&gt;. The moment you have more than one machine — or you need your containers to survive crashes, scale with load, or update without downtime — you need an orchestrator. Kubernetes (K8s) is the standard: it runs your containers across a cluster, keeps the desired state reconciled against reality, and exposes a single API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pods: the atom of Kubernetes
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;Pod&lt;/strong&gt; is the smallest deployable unit — one or more containers that share a network namespace (same IP, same port space) and storage volumes. You almost never create a Pod directly; you create a Deployment, which creates a ReplicaSet, which creates Pods.&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;# a single Pod (rarely written by hand)&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pod&lt;/span&gt;
&lt;span class="na"&gt;metadata&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;nginx&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;containers&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;nginx&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;nginx:1.27-alpine&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="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cluster architecture
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl2d2fkqi14ckafg4tp5p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl2d2fkqi14ckafg4tp5p.png" alt="Kubernetes Cluster Architecture" width="799" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A cluster has two planes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Control plane&lt;/strong&gt; (master) — the brain: &lt;code&gt;kube-apiserver&lt;/code&gt; (the API you talk to), &lt;code&gt;etcd&lt;/code&gt; (the cluster's key-value store of record), &lt;code&gt;kube-scheduler&lt;/code&gt; (decides which node runs which Pod), &lt;code&gt;kube-controller-manager&lt;/code&gt; (reconciles state), and the &lt;code&gt;cloud-controller-manager&lt;/code&gt; (talks to your cloud).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Worker nodes&lt;/strong&gt; (data plane) — where your Pods run: each has &lt;code&gt;kubelet&lt;/code&gt; (talks to the control plane), &lt;code&gt;kube-proxy&lt;/code&gt; (networking), and a &lt;strong&gt;container runtime&lt;/strong&gt; (&lt;code&gt;containerd&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  kubectl basics
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods                    &lt;span class="c"&gt;# list pods in the default namespace&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-A&lt;/span&gt;                &lt;span class="c"&gt;# all namespaces&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-o&lt;/span&gt; wide           &lt;span class="c"&gt;# more detail (node, IP)&lt;/span&gt;
kubectl describe pod nginx         &lt;span class="c"&gt;# deep inspect (events, state)&lt;/span&gt;
kubectl logs nginx                 &lt;span class="c"&gt;# stdout of the pod's container&lt;/span&gt;
kubectl logs &lt;span class="nt"&gt;-f&lt;/span&gt; nginx              &lt;span class="c"&gt;# follow (tail)&lt;/span&gt;
kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; nginx &lt;span class="nt"&gt;--&lt;/span&gt; sh       &lt;span class="c"&gt;# shell into the container&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; manifest.yaml      &lt;span class="c"&gt;# create/update from a file&lt;/span&gt;
kubectl delete &lt;span class="nt"&gt;-f&lt;/span&gt; manifest.yaml     &lt;span class="c"&gt;# delete&lt;/span&gt;
kubectl delete pod nginx           &lt;span class="c"&gt;# delete one pod (a Deployment will recreate it)&lt;/span&gt;
kubectl get all                    &lt;span class="c"&gt;# everything in the namespace&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; &lt;code&gt;kubectl delete pod &amp;lt;name&amp;gt;&lt;/code&gt; when the Pod is owned by a Deployment just kills &lt;em&gt;that&lt;/em&gt; Pod — the ReplicaSet immediately creates a replacement. To actually scale down, change the Deployment's &lt;code&gt;replicas&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 2 — Workload Objects: Deployment, ReplicaSet, Job
&lt;/h2&gt;

&lt;p&gt;The Pod-ReplicaSet-Deployment-Service hierarchy is the core mental model.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsqrvv4544thjvukjdcdj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsqrvv4544thjvukjdcdj.png" alt="Pod, ReplicaSet, Deployment, Service" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Deployment
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;Deployment&lt;/strong&gt; declares the desired state (image, replicas, ports) and the controller reconciles reality to it. Updating the image triggers a &lt;strong&gt;rolling update&lt;/strong&gt;; the old ReplicaSet is scaled down as the new one scales up, with automatic rollback if the rollout fails.&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;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&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;api&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;           &lt;span class="c1"&gt;# the Pod template every replica uses&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&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;api&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;myapi:1.0&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="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8000&lt;/span&gt;
          &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;100m"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;128Mi"&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;   &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;500m"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;512Mi"&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; deployment.yaml
kubectl rollout status deployment/api
kubectl &lt;span class="nb"&gt;set &lt;/span&gt;image deployment/api &lt;span class="nv"&gt;api&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;myapi:1.1    &lt;span class="c"&gt;# rolling update&lt;/span&gt;
kubectl rollout undo deployment/api               &lt;span class="c"&gt;# rollback&lt;/span&gt;
kubectl scale deployment/api &lt;span class="nt"&gt;--replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5          &lt;span class="c"&gt;# manual scale&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ReplicaSet
&lt;/h3&gt;

&lt;p&gt;The Deployment creates a &lt;strong&gt;ReplicaSet&lt;/strong&gt; to guarantee &lt;code&gt;replicas&lt;/code&gt; copies are running. You rarely touch ReplicaSets directly — the Deployment owns them. Each rollout creates a new ReplicaSet; old ones are kept (scaled to 0) for rollback history.&lt;/p&gt;

&lt;h3&gt;
  
  
  Job and CronJob
&lt;/h3&gt;

&lt;p&gt;For work that runs to completion (batch, migrations, backups), use a &lt;strong&gt;Job&lt;/strong&gt;; for scheduled work, a &lt;strong&gt;CronJob&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;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;batch/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Job&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;db-migrate&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;backoffLimit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;            &lt;span class="c1"&gt;# retries on failure&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;restartPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OnFailure&lt;/span&gt;
      &lt;span class="na"&gt;containers&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;migrate&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;myapi:1.0&lt;/span&gt;
          &lt;span class="na"&gt;command&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;./migrate.sh"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Stage 3 — Networking + Storage
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Service
&lt;/h3&gt;

&lt;p&gt;Pods are ephemeral (they die and get recreated with new IPs). A &lt;strong&gt;Service&lt;/strong&gt; gives them a &lt;strong&gt;stable IP + DNS name&lt;/strong&gt; and load-balances across the matching Pods:&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;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;api&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api&lt;/span&gt;          &lt;span class="c1"&gt;# routes to pods with this label&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="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three Service types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ClusterIP&lt;/strong&gt; (default) — reachable only inside the cluster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NodePort&lt;/strong&gt; — exposes on each node's IP at a port (30000–32767).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LoadBalancer&lt;/strong&gt; — provisions a cloud load balancer (AWS ELB, GCLB).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Ingress
&lt;/h3&gt;

&lt;p&gt;For HTTP(S) routing by host/path, use an &lt;strong&gt;Ingress&lt;/strong&gt; (needs an Ingress controller like nginx-ingress or Traefik):&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;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Ingress&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;api&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&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;api.example.com&lt;/span&gt;
      &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
            &lt;span class="na"&gt;pathType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prefix&lt;/span&gt;
            &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;api&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;number&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;80&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ConfigMap and Secret
&lt;/h3&gt;

&lt;p&gt;Decouple config from images. A &lt;strong&gt;ConfigMap&lt;/strong&gt; holds non-sensitive config; a &lt;strong&gt;Secret&lt;/strong&gt; holds sensitive data (base64 — not encryption by default).&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;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ConfigMap&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;api-config&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;LOG_LEVEL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;info"&lt;/span&gt;
  &lt;span class="na"&gt;DB_HOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;db.default.svc"&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Secret&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;api-secret&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Opaque&lt;/span&gt;
&lt;span class="na"&gt;stringData&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;API_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;super-secret"&lt;/span&gt;      &lt;span class="c1"&gt;# stringData avoids manual base64&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mount them as env vars or as files in a volume:&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;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;containers&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;api&lt;/span&gt;
      &lt;span class="na"&gt;envFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;configMapRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;api-config&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;secretRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;    &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;api-secret&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Volumes, PersistentVolume, PersistentVolumeClaim
&lt;/h3&gt;

&lt;p&gt;Pod filesystems are ephemeral. For persistent data, a &lt;strong&gt;PersistentVolumeClaim (PVC)&lt;/strong&gt; requests storage; Kubernetes binds it to a &lt;strong&gt;PersistentVolume (PV)&lt;/strong&gt; provisioned by a CSI driver:&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;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PersistentVolumeClaim&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;data&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;accessModes&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;ReadWriteOnce"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;10Gi&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;containers&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;db&lt;/span&gt;
      &lt;span class="na"&gt;volumeMounts&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;data&lt;/span&gt;
          &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/lib/postgresql/data&lt;/span&gt;
  &lt;span class="na"&gt;volumes&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;data&lt;/span&gt;
      &lt;span class="na"&gt;persistentVolumeClaim&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;claimName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;data&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Stage 4 — Scheduling + Scaling
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Labels and selectors
&lt;/h3&gt;

&lt;p&gt;Labels are key/value pairs on objects; selectors query them. This is how Services find their Pods and how Deployments manage their ReplicaSets.&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;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api&lt;/span&gt;
    &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prod&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;api,env&lt;span class="o"&gt;=&lt;/span&gt;prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Probes: liveness and readiness
&lt;/h3&gt;

&lt;p&gt;Probes tell Kubernetes whether a container is healthy and whether it's ready to receive traffic:&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;livenessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;/health&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;8000&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;initialDelaySeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
  &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
&lt;span class="na"&gt;readinessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;/ready&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;8000&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;initialDelaySeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
  &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Liveness&lt;/strong&gt; — fails → restart the container (recovers from deadlock).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Readiness&lt;/strong&gt; — fails → remove the Pod from the Service's endpoints (stops routing to it, but doesn't restart).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Horizontal Pod Autoscaler (HPA)
&lt;/h3&gt;

&lt;p&gt;The HPA scales a Deployment based on CPU/memory (or custom metrics):&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;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;autoscaling/v2&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HorizontalPodAutoscaler&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;api&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scaleTargetRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;apps/v1&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;Deployment&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;api&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;minReplicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;maxReplicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
  &lt;span class="na"&gt;metrics&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Resource&lt;/span&gt;
      &lt;span class="na"&gt;resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;Utilization&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;averageUtilization&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;70&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Resources, affinity, and node affinity
&lt;/h3&gt;

&lt;p&gt;Always set &lt;code&gt;resources.requests&lt;/code&gt; and &lt;code&gt;resources.limits&lt;/code&gt; — without them the scheduler can't place your Pod sanely and a runaway container can starve a node. Node affinity/anti-affinity controls which nodes a Pod can land on; pod anti-affinity spreads replicas across nodes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stage 5 — Production + Operations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Core objects overview
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr4cpctu5jpbyhah0exv6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr4cpctu5jpbyhah0exv6.png" alt="Kubernetes Core Objects" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Beyond Deployments, learn these as needed: &lt;strong&gt;StatefulSet&lt;/strong&gt; (databases — ordered, stable identity), &lt;strong&gt;DaemonSet&lt;/strong&gt; (one Pod per node — logging agents), &lt;strong&gt;Namespace&lt;/strong&gt; (logical partition + RBAC scope), &lt;strong&gt;ServiceAccount&lt;/strong&gt; (Pod identity for API access), &lt;strong&gt;HPA/VPA&lt;/strong&gt; (horizontal/vertical autoscaling).&lt;/p&gt;

&lt;h3&gt;
  
  
  Helm: the package manager
&lt;/h3&gt;

&lt;p&gt;Helm packages manifests into reusable &lt;strong&gt;charts&lt;/strong&gt; with templated values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm repo add bitnami https://charts.bitnami.com/bitnami
helm &lt;span class="nb"&gt;install &lt;/span&gt;my-db bitnami/postgresql &lt;span class="nt"&gt;--set&lt;/span&gt; auth.postgresPassword&lt;span class="o"&gt;=&lt;/span&gt;secret
helm upgrade my-db bitnami/postgresql &lt;span class="nt"&gt;--set&lt;/span&gt; &lt;span class="nv"&gt;replicaCount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3
helm uninstall my-db
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Kustomize: overlay patches
&lt;/h3&gt;

&lt;p&gt;Kustomize composes overlays (dev/staging/prod) over a base without templating:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-k&lt;/span&gt; overlays/prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  RBAC
&lt;/h3&gt;

&lt;p&gt;Role-Based Access Control scopes what a user or ServiceAccount can do:&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;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rbac.authorization.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Role&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;pod-reader&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;dev&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiGroups&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;"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;resources&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;pods"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;verbs&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;get"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;list"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bind it to a ServiceAccount with a RoleBinding.&lt;/p&gt;

&lt;h3&gt;
  
  
  Observability + GitOps
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Metrics&lt;/strong&gt;: Prometheus (scrapes kubelet/cAdvisor) + Grafana.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logs&lt;/strong&gt;: Loki or ELK aggregating container stdout.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tracing&lt;/strong&gt;: OpenTelemetry / Jaeger.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitOps&lt;/strong&gt;: ArgoCD or Flux watches a Git repo and applies changes to the cluster — the repo is the source of truth, not &lt;code&gt;kubectl apply&lt;/code&gt; from a laptop.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The toolchain
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkf2eidt0zdj5pbyz1112.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkf2eidt0zdj5pbyz1112.png" alt="Kubernetes Toolchain" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Interface&lt;/th&gt;
&lt;th&gt;What it standardizes&lt;/th&gt;
&lt;th&gt;Examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;CRI&lt;/strong&gt; (Container Runtime Interface)&lt;/td&gt;
&lt;td&gt;how K8s runs containers&lt;/td&gt;
&lt;td&gt;containerd, CRI-O&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;CNI&lt;/strong&gt; (Container Network Interface)&lt;/td&gt;
&lt;td&gt;pod networking&lt;/td&gt;
&lt;td&gt;Calico, Cilium, Flannel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;CSI&lt;/strong&gt; (Container Storage Interface)&lt;/td&gt;
&lt;td&gt;persistent volumes&lt;/td&gt;
&lt;td&gt;Longhorn, Rook, cloud CSI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CLI / packaging&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;how you drive K8s&lt;/td&gt;
&lt;td&gt;kubectl, helm, kustomize, k9s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Quick-Start Checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Get a cluster&lt;/strong&gt; — &lt;code&gt;kind&lt;/code&gt; (Kubernetes-in-Docker) or &lt;code&gt;minikube&lt;/code&gt; for local; a managed cluster (GKE/EKS/AKS) for real.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run kubectl&lt;/strong&gt; — &lt;code&gt;kubectl get nodes&lt;/code&gt;, &lt;code&gt;kubectl get pods -A&lt;/code&gt;. Understand the cluster is up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apply a Deployment&lt;/strong&gt; — the nginx example above, then &lt;code&gt;kubectl get pods&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expose a Service&lt;/strong&gt; — &lt;code&gt;kubectl expose deployment api --port=80 --type=LoadBalancer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add a liveness/readiness probe&lt;/strong&gt; so unhealthy Pods self-heal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set resource requests/limits&lt;/strong&gt; on every container.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add a ConfigMap + Secret&lt;/strong&gt; and mount them as env/volume.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attach a PVC&lt;/strong&gt; for persistent data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Install something with Helm&lt;/strong&gt; (e.g. bitnami/postgresql) to see packaging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Roll out an update&lt;/strong&gt; and &lt;code&gt;kubectl rollout undo&lt;/code&gt; it — see rolling updates work.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Common Pitfalls
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No resource requests/limits&lt;/strong&gt; — the scheduler can't place Pods sanely; one container can starve a node. Always set them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Missing readiness probe&lt;/strong&gt; — traffic routes to a Pod before it's ready, or stays pointed at a dead Pod. Both probes matter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deleting a Pod owned by a Deployment&lt;/strong&gt; — the ReplicaSet just recreates it. Change the Deployment, not the Pod.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secrets aren't encrypted by default&lt;/strong&gt; — base64 only. Enable etcd encryption at rest and use a secrets manager (External Secrets, Vault) for production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forgetting namespaces&lt;/strong&gt; — objects in different namespaces can't reach each other by short DNS name; use &lt;code&gt;svc.namespace.svc.cluster.local&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NodePort in production&lt;/strong&gt; — use Ingress or LoadBalancer; NodePort exposes random high ports on every node.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;:latest&lt;/code&gt; image tag&lt;/strong&gt; — K8s won't pull a new image on &lt;code&gt;apply&lt;/code&gt; if the tag is unchanged and &lt;code&gt;imagePullPolicy&lt;/code&gt; defaults. Pin versions or set &lt;code&gt;imagePullPolicy: Always&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No PodDisruptionBudget&lt;/strong&gt; — voluntary disruptions (drains) can take down all replicas at once. Add a PDB for HA workloads.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kubernetes.io/docs/" rel="noopener noreferrer"&gt;Kubernetes Docs&lt;/a&gt; — the official reference&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.redhat.com/en/resources/oreilly-kubernetes-patterns-cloud-native-apps" rel="noopener noreferrer"&gt;Kubernetes Patterns (book)&lt;/a&gt; — reusable design patterns&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kelseyhightower/kubernetes-the-hard-way" rel="noopener noreferrer"&gt;Kubernetes the Hard Way&lt;/a&gt; — build a cluster by hand to understand every piece&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/reference/kubectl/cheatsheet/" rel="noopener noreferrer"&gt;kubectl cheatsheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://helm.sh/docs/" rel="noopener noreferrer"&gt;Helm Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Related guides
&lt;/h2&gt;

&lt;p&gt;Kubernetes is the capstone of the container + DevOps stack — these PyShine tutorials lead into it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Docker-in-One-Post-Complete-Tutorial-Dockerfile-Volumes-Compose-Quick-Start/"&gt;Learn Docker in One Post: Complete Tutorial&lt;/a&gt;&lt;/strong&gt; — K8s runs containers; Docker is the prerequisite. A Pod is one or more containers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Git-in-One-Post-Complete-Tutorial-Branches-Rebase-Workflows-Quick-Start/"&gt;Learn Git in One Post: Complete Tutorial&lt;/a&gt;&lt;/strong&gt; — GitOps (ArgoCD/Flux) drives clusters from a Git repo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Bash-in-One-Post-Complete-Tutorial-Pipelines-Functions-Scripts-Quick-Start/"&gt;Learn Bash in One Post: Complete Tutorial&lt;/a&gt;&lt;/strong&gt; — &lt;code&gt;kubectl&lt;/code&gt; pipelines, deploy scripts, and &lt;code&gt;k9s&lt;/code&gt; are all shell-driven.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-REST-API-in-One-Post-Complete-Tutorial-Methods-Status-Codes-Production-Quick-Start/"&gt;Learn YAML / REST API in One Post&lt;/a&gt;&lt;/strong&gt; — every K8s manifest is YAML; the control plane is a REST API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Go-in-One-Post-Complete-Tutorial-Goroutines-Channels-Generics-Quick-Start/"&gt;Learn Go in One Post: Complete Tutorial&lt;/a&gt;&lt;/strong&gt; — Kubernetes itself is written in Go; operators are too.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Kubernetes has a reputation for complexity, but its core is a small set of ideas: &lt;strong&gt;desired state in manifests, controllers that reconcile reality to it, and labels that wire objects together&lt;/strong&gt;. Spend a day per stage and you'll move from "I can run &lt;code&gt;kubectl get pods&lt;/code&gt;" to "I can write a Deployment with probes, expose it via a Service and Ingress, persist its data with a PVC, and roll out a new version with a rollback ready." From there, Helm, Kustomize, and GitOps are the production layer. Run every manifest above against a &lt;code&gt;kind&lt;/code&gt; or &lt;code&gt;minikube&lt;/code&gt; cluster; K8s is learned by applying, not by reading.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://pyshine.com/Learn-Kubernetes-in-One-Post-Complete-Tutorial-Pods-Deployments-Services-Production-Quick-Start/" rel="noopener noreferrer"&gt;pyshine.com&lt;/a&gt;. The full tutorial with all 5 hand-drawn diagrams lives there — this cross-post is kept in sync via canonical URL.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>k8s</category>
      <category>devops</category>
      <category>containers</category>
    </item>
    <item>
      <title>Learn Linear Algebra for Machine Learning in a Single Post: A Complete Tutorial From Vectors and Matrices to SVD and Neural Network Weights</title>
      <dc:creator>PyShine</dc:creator>
      <pubDate>Thu, 23 Jul 2026 12:32:31 +0000</pubDate>
      <link>https://dev.to/pyshine/learn-linear-algebra-for-machine-learning-in-a-single-post-a-complete-tutorial-from-vectors-and-2je8</link>
      <guid>https://dev.to/pyshine/learn-linear-algebra-for-machine-learning-in-a-single-post-a-complete-tutorial-from-vectors-and-2je8</guid>
      <description>&lt;h1&gt;
  
  
  Learn Linear Algebra for Machine Learning in a Single Post: Complete Tutorial From Vectors and Matrices to SVD and Neural Network Weights
&lt;/h1&gt;

&lt;p&gt;Linear algebra is the &lt;strong&gt;language of machine learning&lt;/strong&gt;: every neural network is a series of matrix multiplications, every embedding is a vector, every gradient is a vector, and every dimensionality reduction is a matrix decomposition. If you understand vectors, matrices, and their operations, you can read the internals of any ML framework. This single post teaches the whole subject in five stages, with hand-drawn diagrams and runnable NumPy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning Roadmap
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4lhp62xlgsxazc56b007.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4lhp62xlgsxazc56b007.png" alt="Linear Algebra for ML Roadmap" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The roadmap moves from vectors (Stage 1), through matrices (Stage 2), transformations (Stage 3), decomposition (Stage 4), and the ML applications that tie it all together (Stage 5).&lt;/p&gt;




&lt;h2&gt;
  
  
  Stage 1 — Vectors
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What a vector is
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;vector&lt;/strong&gt; is an ordered list of numbers — a point in space, a direction, or a data point. In ML, a vector is how you represent a data sample (its features) or a learned parameter (a weight vector).&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;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;

&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&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;4&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;          &lt;span class="c1"&gt;# a 2D vector
&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&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="c1"&gt;# a 3D vector
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Magnitude (length)
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;magnitude&lt;/strong&gt; (or &lt;strong&gt;norm&lt;/strong&gt;) of a vector is its length: &lt;code&gt;||v|| = sqrt(sum(vi^2))&lt;/code&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="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linalg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;             &lt;span class="c1"&gt;# 5.0 (3-4-5 triangle)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Dot product — the most important operation
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;dot product&lt;/strong&gt; of two vectors measures their &lt;strong&gt;alignment&lt;/strong&gt;: &lt;code&gt;a · b = sum(ai * bi)&lt;/code&gt;. It's the foundation of similarity, attention, and projection.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsyj0qeia7y7sn993h7ps.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsyj0qeia7y7sn993h7ps.png" alt="Vectors: Magnitude, Dot Product, Angle, Projection" width="800" height="409"&gt;&lt;/a&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="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&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;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;4&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="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                   &lt;span class="c1"&gt;# 1*4 + 2*5 + 3*6 = 32
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Geometric meaning&lt;/strong&gt;: &lt;code&gt;a · b = ||a|| ||b|| cos(θ)&lt;/code&gt;. If the dot product is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Positive&lt;/strong&gt; → vectors point roughly the same direction (acute angle).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero&lt;/strong&gt; → vectors are &lt;strong&gt;orthogonal&lt;/strong&gt; (perpendicular; 90°).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Negative&lt;/strong&gt; → vectors point roughly opposite (obtuse angle).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why &lt;strong&gt;cosine similarity&lt;/strong&gt; (dot product of normalized vectors) measures how similar two embeddings are — it's the cosine of the angle between them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Angle and cosine similarity
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;cos_sim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&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="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linalg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linalg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# = cos(angle between a and b)
# 1 = identical, 0 = orthogonal, -1 = opposite
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Projection
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;projection&lt;/strong&gt; of &lt;code&gt;a&lt;/code&gt; onto &lt;code&gt;b&lt;/code&gt; is the shadow of &lt;code&gt;a&lt;/code&gt; cast onto the line of &lt;code&gt;b&lt;/code&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="n"&gt;proj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Projection is how &lt;strong&gt;PCA&lt;/strong&gt; finds the directions of maximum variance — it projects data onto principal axes. It's also how attention works: the query projects onto the keys.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stage 2 — Matrices
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What a matrix is
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;matrix&lt;/strong&gt; is a 2D grid of numbers — a collection of vectors (rows or columns), or a &lt;strong&gt;linear transformation&lt;/strong&gt; (a function that maps vectors to vectors). In ML, a matrix is a weight layer, a batch of data, or a covariance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;A&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&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="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;4&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;    &lt;span class="c1"&gt;# 2x2 matrix
&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&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="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;    &lt;span class="c1"&gt;# 2x2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Matrix multiplication
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8pbf4p4vfqyt7p0lu0qp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8pbf4p4vfqyt7p0lu0qp.png" alt="Matrix Multiplication + Dimensions" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;C = A @ B&lt;/code&gt;&lt;/strong&gt; — the inner dimensions must match: &lt;code&gt;(m × n) @ (n × p) → (m × p)&lt;/code&gt;. Each element &lt;code&gt;C[i,j]&lt;/code&gt; is the dot product of row &lt;code&gt;i&lt;/code&gt; of &lt;code&gt;A&lt;/code&gt; with column &lt;code&gt;j&lt;/code&gt; of &lt;code&gt;B&lt;/code&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="n"&gt;C&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;                       &lt;span class="c1"&gt;# (2x2) @ (2x2) -&amp;gt; (2x2)
# [[19, 22],
#  [43, 50]]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Matrix multiplication is composition&lt;/strong&gt;: applying &lt;code&gt;B&lt;/code&gt; then &lt;code&gt;A&lt;/code&gt; is &lt;code&gt;A @ B&lt;/code&gt;. &lt;strong&gt;Order matters&lt;/strong&gt; — &lt;code&gt;AB ≠ BA&lt;/code&gt; in general (non-commutative). This is why the order of layers in a neural network matters.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key matrix properties
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Formula&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Identity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;I: A @ I = A&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;does nothing (like multiplying by 1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Transpose&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;A^T: swap rows/cols&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;flips the matrix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Inverse&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;A^-1: A @ A^-1 = I&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;undoes the transform (if it exists)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Determinant&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;det(A)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;volume scaling factor; 0 = singular (no inverse)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;                              &lt;span class="c1"&gt;# transpose
&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linalg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                &lt;span class="c1"&gt;# inverse (if det != 0)
&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linalg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;det&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                 &lt;span class="c1"&gt;# determinant
&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eye&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="c1"&gt;# 3x3 identity
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; Not every matrix has an inverse. A matrix with &lt;code&gt;det = 0&lt;/code&gt; is &lt;strong&gt;singular&lt;/strong&gt; — its columns are linearly dependent (one is a combination of others). This is why collinear features in ML cause numerical instability.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 3 — Linear Transformations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  A matrix is a transformation
&lt;/h3&gt;

&lt;p&gt;Multiplying a vector by a matrix &lt;strong&gt;transforms&lt;/strong&gt; it: rotates, scales, shears, or projects it. The matrix is the function; the vector is the input.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvnen8wf6e7nffrrq795t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvnen8wf6e7nffrrq795t.png" alt="Linear Transformations + Eigenvalues" width="800" height="409"&gt;&lt;/a&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="c1"&gt;# rotation by 45 degrees
&lt;/span&gt;&lt;span class="n"&gt;theta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pi&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
&lt;span class="n"&gt;R&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;([[&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;theta&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;theta&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
              &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;theta&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;theta&lt;/span&gt;&lt;span class="p"&gt;)]])&lt;/span&gt;
&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&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;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;R&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;                            &lt;span class="c1"&gt;# rotated vector
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Transform&lt;/th&gt;
&lt;th&gt;Matrix (2D)&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rotation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[[cos, -sin], [sin, cos]]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;rotates by angle θ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scaling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[[s, 0], [0, s]]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;stretches/shrinks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reflection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[[-1, 0], [0, 1]]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;flips&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Shear&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[[1, k], [0, 1]]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;slides one axis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Projection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;onto a subspace&lt;/td&gt;
&lt;td&gt;reduces dimensionality&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Eigenvectors and eigenvalues
&lt;/h3&gt;

&lt;p&gt;An &lt;strong&gt;eigenvector&lt;/strong&gt; of a matrix &lt;code&gt;A&lt;/code&gt; is a vector that &lt;strong&gt;only scales&lt;/strong&gt; (doesn't rotate) when transformed: &lt;code&gt;A v = λ v&lt;/code&gt;. The &lt;strong&gt;eigenvalue&lt;/strong&gt; &lt;code&gt;λ&lt;/code&gt; is how much it scales.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;eigenvalues&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eigenvectors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linalg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# eigenvalues: the scaling factors
# eigenvectors: the directions that don't rotate
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eigenvectors are the &lt;strong&gt;natural axes&lt;/strong&gt; of a transformation. This is the foundation of &lt;strong&gt;PCA&lt;/strong&gt; (Stage 4) — the principal components are the eigenvectors of the covariance matrix, and the eigenvalues tell you how much variance each captures.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; Not every matrix has real eigenvalues. A rotation by 90° has no real eigenvector (every vector rotates). Symmetric matrices (like covariance matrices) always have real eigenvalues — which is why PCA always works.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 4 — Decomposition: SVD, PCA, Rank
&lt;/h2&gt;

&lt;h3&gt;
  
  
  SVD (Singular Value Decomposition)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;SVD&lt;/strong&gt; decomposes any matrix &lt;code&gt;A&lt;/code&gt; into three matrices: &lt;code&gt;A = U Σ V^T&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;U&lt;/strong&gt; — left singular vectors (output directions)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Σ&lt;/strong&gt; — singular values (diagonal; how much each direction matters)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;V^T&lt;/strong&gt; — right singular vectors (input directions)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Vt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linalg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;svd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# A = U @ np.diag(S) @ Vt
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SVD is the &lt;strong&gt;most general decomposition&lt;/strong&gt; — it works on any matrix (even non-square, even singular). It reveals the "structure" of the matrix: the singular values tell you the &lt;strong&gt;rank&lt;/strong&gt; (how many independent directions) and the &lt;strong&gt;importance&lt;/strong&gt; of each.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rank-k approximation
&lt;/h3&gt;

&lt;p&gt;Keep only the top &lt;code&gt;k&lt;/code&gt; singular values → a &lt;strong&gt;rank-k approximation&lt;/strong&gt; that captures the most information with the fewest dimensions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;A_approx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;diag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;Vt&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;:]&lt;/span&gt;
&lt;span class="c1"&gt;# compresses A to its k most important directions
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is how &lt;strong&gt;image compression&lt;/strong&gt;, &lt;strong&gt;denoising&lt;/strong&gt;, and &lt;strong&gt;recommendation systems&lt;/strong&gt; (Netflix prize) work — truncate to the top-k singular values.&lt;/p&gt;

&lt;h3&gt;
  
  
  PCA (Principal Component Analysis)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;PCA&lt;/strong&gt; is SVD applied to centered data — it finds the directions (principal components) of maximum variance:&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;sklearn.decomposition&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PCA&lt;/span&gt;
&lt;span class="n"&gt;pca&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PCA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n_components&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;X_2d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pca&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit_transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="c1"&gt;# 1000D -&amp;gt; 2D, preserving max variance
&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;pca&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;explained_variance_ratio_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# how much each PC captures
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PCA centers the data (subtract the mean), computes the covariance matrix, eigendecomposes it, and projects onto the top-k eigenvectors. It's &lt;strong&gt;SVD on centered data&lt;/strong&gt; — the same math, applied to find the most informative axes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rank
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;rank&lt;/strong&gt; of a matrix is the number of linearly independent rows/columns — the number of genuinely different directions. A rank-1 matrix is an outer product of two vectors; a full-rank square matrix has an inverse. Rank deficiency (rank &amp;lt; dimensions) means redundant information.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; PCA assumes linear relationships and that high-variance directions are the most informative. If your data's structure is non-linear (clusters, manifolds), PCA won't find it — use t-SNE, UMAP, or an autoencoder instead.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 5 — ML Applications
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Neural network weights are matrices
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg8xn8sbcl3oarqjikvpm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg8xn8sbcl3oarqjikvpm.png" alt="ML Applications of Linear Algebra" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;neural network layer&lt;/strong&gt; is literally a matrix multiplication + a bias + an activation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;activation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# W: weight matrix (out_dim x in_dim)
# x: input vector (in_dim)
# b: bias vector (out_dim)
# y: output vector (out_dim)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;forward pass&lt;/strong&gt; of a deep network is a sequence of matrix multiplications. A batch of &lt;code&gt;B&lt;/code&gt; inputs is a &lt;code&gt;B × in_dim&lt;/code&gt; matrix, and the layer is &lt;code&gt;W @ X^T&lt;/code&gt; (or &lt;code&gt;X @ W^T&lt;/code&gt; depending on convention). &lt;strong&gt;GPUs are fast at matrix multiplication&lt;/strong&gt; — this is why deep learning runs on GPUs (and why NVIDIA is worth what it is).&lt;/p&gt;

&lt;h3&gt;
  
  
  Embeddings are vectors
&lt;/h3&gt;

&lt;p&gt;An &lt;strong&gt;embedding&lt;/strong&gt; (word2vec, GPT, CLIP) turns a discrete object (a word, an image, a user) into a &lt;strong&gt;vector&lt;/strong&gt; in a continuous space where similar things are close. Similarity is the &lt;strong&gt;dot product&lt;/strong&gt; (or cosine), and nearest-neighbor search is finding the closest vectors. The &lt;a href="https://dev.to/Learn-PostgreSQL-in-One-Post-Complete-Tutorial-Indexes-MVCC-Performance-Quick-Start/"&gt;pgvector extension&lt;/a&gt; stores and searches these.&lt;/p&gt;

&lt;h3&gt;
  
  
  Attention is dot products
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Self-attention&lt;/strong&gt; in a transformer is literally batched matrix multiplications of dot products:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Attention(Q, K, V) = softmax(Q @ K^T / sqrt(d)) @ V
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Q @ K^T&lt;/code&gt; is a matrix of dot products — every query attends to every key. The softmax normalizes to attention weights, then &lt;code&gt;@ V&lt;/code&gt; takes the weighted combination. The entire transformer is &lt;strong&gt;linear algebra&lt;/strong&gt;: matrix multiplications, element-wise operations, and nonlinearities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gradient descent is vector math
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;gradient&lt;/strong&gt; of the loss is a vector pointing in the direction of steepest ascent. Gradient descent steps in the &lt;strong&gt;opposite&lt;/strong&gt; direction: &lt;code&gt;w -= lr * gradient&lt;/code&gt;. The &lt;strong&gt;Hessian&lt;/strong&gt; (second derivative) is a matrix giving curvature information. Stochastic gradient descent, Adam, and all optimizers are linear-algebra operations on the loss landscape.&lt;/p&gt;

&lt;h3&gt;
  
  
  Covariance and correlation
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;covariance matrix&lt;/strong&gt; of a dataset is &lt;code&gt;X^T X / (n-1)&lt;/code&gt; (after centering) — it captures how features vary together. Its eigenvectors are the principal components (PCA). Correlation is normalized covariance. These are the statistics that PCA, factor analysis, and portfolio optimization build on.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick-Start Checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install NumPy&lt;/strong&gt; — &lt;code&gt;pip install numpy&lt;/code&gt;; it's the linear algebra library for Python.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Play with vectors&lt;/strong&gt; — &lt;code&gt;np.array&lt;/code&gt;, &lt;code&gt;np.dot&lt;/code&gt;, &lt;code&gt;np.linalg.norm&lt;/code&gt;, cosine similarity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multiply matrices&lt;/strong&gt; — &lt;code&gt;A @ B&lt;/code&gt;; understand the dimension rule and non-commutativity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compute eigendecomposition&lt;/strong&gt; — &lt;code&gt;np.linalg.eig&lt;/code&gt; on a symmetric matrix; verify &lt;code&gt;A @ v = λ v&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run SVD&lt;/strong&gt; — &lt;code&gt;np.linalg.svd&lt;/code&gt; on a real matrix; reconstruct it from &lt;code&gt;U Σ V^T&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do PCA&lt;/strong&gt; — &lt;code&gt;sklearn.decomposition.PCA&lt;/code&gt;; reduce a high-D dataset to 2D; plot it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trace a neural network layer&lt;/strong&gt; — see that &lt;code&gt;nn.Linear&lt;/code&gt; is &lt;code&gt;W @ x + b&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Understand attention&lt;/strong&gt; — trace &lt;code&gt;Q @ K^T&lt;/code&gt; as a matrix of dot products.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read gradient descent&lt;/strong&gt; — &lt;code&gt;w -= lr * grad&lt;/code&gt; as a vector operation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use cosine similarity&lt;/strong&gt; on real embeddings — measure how close two word vectors are.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Common Pitfalls
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dimension mismatch in matmul&lt;/strong&gt; — &lt;code&gt;(m × n) @ (n × p)&lt;/code&gt;; the inner dims must match. The #1 NumPy bug is a shape error from forgetting to transpose.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Non-commutativity&lt;/strong&gt; — &lt;code&gt;AB ≠ BA&lt;/code&gt;; the order of matrix multiplication matters (and so does the order of neural network layers).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Singular matrix&lt;/strong&gt; — &lt;code&gt;det = 0&lt;/code&gt; means no inverse; collinear features cause this and numerical instability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confusing row vs column vectors&lt;/strong&gt; — NumPy is row-major; &lt;code&gt;v&lt;/code&gt; is 1D (no row/column distinction), but &lt;code&gt;v.reshape(-1, 1)&lt;/code&gt; makes it a column. Mind the shapes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PCA on non-centered data&lt;/strong&gt; — PCA centers internally, but if you do SVD by hand, center first or the first component is the mean, not a direction of variance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assuming PCA finds non-linear structure&lt;/strong&gt; — PCA is linear; clusters and manifolds need t-SNE/UMAP/autoencoders.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Floating point in linear algebra&lt;/strong&gt; — &lt;code&gt;A @ inv(A)&lt;/code&gt; isn't exactly &lt;code&gt;I&lt;/code&gt; due to floating point; use &lt;code&gt;np.allclose&lt;/code&gt; not &lt;code&gt;==&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/playlist?list=PLZHQObOWTQDPD3MizzM2xVFitgF8hE_ab" rel="noopener noreferrer"&gt;3Blue1Brown: Essence of Linear Algebra&lt;/a&gt; — the best visual introduction&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://linear.axler.net/" rel="noopener noreferrer"&gt;Linear Algebra Done Right&lt;/a&gt; by Sheldon Axler — the rigorous textbook&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://numpy.org/doc/stable/reference/routines.linalg.html" rel="noopener noreferrer"&gt;NumPy Linear Algebra Docs&lt;/a&gt; — every function&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.deeplearningbook.org/contents/linear_algebra.html" rel="noopener noreferrer"&gt;Deep Learning Book: Linear Algebra Chapter&lt;/a&gt; by Goodfellow et al — LA for DL specifically&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://immersivemath.com/" rel="noopener noreferrer"&gt;Immersive Math&lt;/a&gt; — interactive 3D linear algebra&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Related guides
&lt;/h2&gt;

&lt;p&gt;Linear algebra is the math layer under ML and DL — these PyShine tutorials apply it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Machine-Learning-in-One-Post-Complete-Tutorial-Supervised-Unsupervised-Deep-Learning-Quick-Start/"&gt;Learn Machine Learning in One Post&lt;/a&gt;&lt;/strong&gt; — PCA, embeddings, and model weights are all linear algebra.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Deep-Learning-in-One-Post-Complete-Tutorial-Neural-Networks-CNN-Transformers-PyTorch-Quick-Start/"&gt;Learn Deep Learning in One Post&lt;/a&gt;&lt;/strong&gt; — every layer is a matmul; attention is Q·K; gradients are vectors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Python-in-One-Post-Complete-Tutorial-Async-Type-Hints-Quick-Start/"&gt;Learn Python in One Post&lt;/a&gt;&lt;/strong&gt; — NumPy is the Python linear algebra library.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-PostgreSQL-in-One-Post-Complete-Tutorial-Indexes-MVCC-Performance-Quick-Start/"&gt;Learn PostgreSQL in One Post&lt;/a&gt;&lt;/strong&gt; — pgvector stores and searches embedding vectors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Data-Structures-and-Algorithms-in-One-Post-Complete-Tutorial-Big-O-Trees-Graphs-DP-Quick-Start/"&gt;Learn Data Structures and Algorithms in One Post&lt;/a&gt;&lt;/strong&gt; — matrix chain multiplication is a classic DP; graph algorithms use adjacency matrices.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Linear algebra is the math that makes ML computable: vectors represent data and parameters, matrices represent transformations, and decompositions reveal structure. The five stages here — vectors, matrices, transformations, decomposition, ML applications — cover everything from a dot product to the attention mechanism in a transformer. The two habits that pay off: &lt;strong&gt;always mind the shapes&lt;/strong&gt; (dimension mismatch is the #1 bug), and &lt;strong&gt;think geometrically&lt;/strong&gt; — a dot product is an angle, a matrix is a transformation, an eigenvector is a natural axis. Open a Python REPL, create two vectors, take their dot product, compute the cosine similarity, and watch &lt;code&gt;a · b / (||a|| ||b||)&lt;/code&gt; give you the angle between them — once you see the geometry, the algebra makes sense.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://pyshine.com/Learn-Linear-Algebra-for-ML-in-One-Post-Complete-Tutorial-Vectors-Matrices-SVD-Eigen-Quick-Start/" rel="noopener noreferrer"&gt;pyshine.com&lt;/a&gt;. The full tutorial with all 5 hand-drawn diagrams lives there — this cross-post is kept in sync via canonical URL.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>linearalgebra</category>
      <category>mathematics</category>
      <category>machinelearning</category>
      <category>numpy</category>
    </item>
    <item>
      <title>Learn Machine Learning in a Single Post: A Complete Tutorial From Supervised Learning and Clustering to Neural Networks and the ML Workflow</title>
      <dc:creator>PyShine</dc:creator>
      <pubDate>Thu, 23 Jul 2026 12:31:28 +0000</pubDate>
      <link>https://dev.to/pyshine/learn-machine-learning-in-a-single-post-a-complete-tutorial-from-supervised-learning-and-42l7</link>
      <guid>https://dev.to/pyshine/learn-machine-learning-in-a-single-post-a-complete-tutorial-from-supervised-learning-and-42l7</guid>
      <description>&lt;h1&gt;
  
  
  Learn Machine Learning in a Single Post: Complete Tutorial From Supervised Learning to Neural Networks and the ML Workflow
&lt;/h1&gt;

&lt;p&gt;Machine learning is the practice of building systems that learn patterns from data instead of being explicitly programmed. It powers search ranking, recommendation, fraud detection, speech recognition, self-driving perception, and every modern AI product. This single post teaches the whole field in five stages, with hand-drawn diagrams and runnable Python snippets — from the simplest linear model to what a neural network actually does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning Roadmap
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faav9op47ioeimgrj1tn1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faav9op47ioeimgrj1tn1.png" alt="Machine Learning Roadmap" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The roadmap moves from the core concepts (Stage 1), through the three paradigms (Stages 2-4), to the end-to-end workflow that ties them together (Stage 5). You'll want &lt;a href="https://dev.to/Learn-Python-in-One-Post-Complete-Tutorial-Async-Type-Hints-Quick-Start/"&gt;Python&lt;/a&gt; and basic &lt;a href="https://dev.to/Learn-Data-Structures-and-Algorithms-in-One-Post-Complete-Tutorial-Big-O-Trees-Graphs-DP-Quick-Start/"&gt;linear algebra&lt;/a&gt; as prerequisites.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stage 1 — Core Concepts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is machine learning?
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;model&lt;/strong&gt; is a function &lt;code&gt;f(x) -&amp;gt; y&lt;/code&gt; that maps inputs (features) to outputs. &lt;strong&gt;Learning&lt;/strong&gt; is the process of finding the &lt;code&gt;f&lt;/code&gt; that best fits your data, by minimizing some measure of how wrong it is. You don't write &lt;code&gt;f&lt;/code&gt; by hand — you define a family of possible functions (linear, tree, neural net) and an optimization process searches for the best member of that family.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features, labels, examples
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Example / sample&lt;/strong&gt; — one data point (a row).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Features (X)&lt;/strong&gt; — the inputs: the things you measure. For a house: square footage, bedrooms, zip code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Label (y)&lt;/strong&gt; — the output you're predicting, if you have one: the house's sale price.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dataset&lt;/strong&gt; — a collection of &lt;code&gt;(X, y)&lt;/code&gt; pairs (supervised) or just &lt;code&gt;X&lt;/code&gt; (unsupervised).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Train / validation / test
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff32drdmsiccqdwovzy10.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff32drdmsiccqdwovzy10.png" alt="Supervised Learning: Regression + Classification" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You &lt;strong&gt;train&lt;/strong&gt; on one set of data, &lt;strong&gt;validate&lt;/strong&gt; (tune) on another, and &lt;strong&gt;test&lt;/strong&gt; (final honest evaluation) on a third you've never touched. The cardinal sin: evaluating on data you trained on — the model has memorized it, so the score is meaningless.&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;sklearn.model_selection&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;train_test_split&lt;/span&gt;
&lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;X_test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;train_test_split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;random_state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Bias-variance and overfitting
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Overfitting&lt;/strong&gt; — the model fits the training data perfectly (memorizes noise) but fails on new data. Symptom: train loss goes down while validation loss goes up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Underfitting&lt;/strong&gt; — the model is too simple; it can't capture the pattern. Symptom: both losses are high.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bias-variance tradeoff&lt;/strong&gt; — a model with high bias underfits (too rigid); high variance overfits (too flexible). The goal is the sweet spot: enough capacity to capture the pattern, not enough to memorize the noise.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; Overfitting is the #1 beginner mistake. If your model gets 99% on training and 60% on validation, you overfit. Fixes: more data, simpler model, regularization (L1/L2), dropout (for NNs), early stopping.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 2 — Supervised Learning
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The paradigms
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fenu8sa0zzwm014e9fbq8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fenu8sa0zzwm014e9fbq8.png" alt="ML Paradigms + Task Families" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Supervised learning has &lt;strong&gt;labels&lt;/strong&gt;. Two task types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Regression&lt;/strong&gt; — predict a continuous number (house price, temperature). Loss: &lt;strong&gt;MSE&lt;/strong&gt; (mean squared error), &lt;strong&gt;MAE&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Classification&lt;/strong&gt; — predict a discrete class (spam/not, dog/cat/bird). Loss: &lt;strong&gt;cross-entropy&lt;/strong&gt;. Metrics: &lt;strong&gt;accuracy&lt;/strong&gt;, &lt;strong&gt;precision/recall/F1&lt;/strong&gt;, &lt;strong&gt;AUC&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  A first model: linear regression
&lt;/h3&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;sklearn.linear_model&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LinearRegression&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LinearRegression&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_train&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;         &lt;span class="c1"&gt;# "learn" the weights
&lt;/span&gt;&lt;span class="n"&gt;predictions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_test&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# apply to new data
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;fit&lt;/code&gt; runs the optimization (ordinary least squares for linear regression) to find the weights that minimize MSE on the training set.&lt;/p&gt;

&lt;h3&gt;
  
  
  A first classifier: logistic regression
&lt;/h3&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;sklearn.linear_model&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LogisticRegression&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LogisticRegression&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_train&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_test&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;           &lt;span class="c1"&gt;# predicted class
&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict_proba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_test&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="c1"&gt;# probability per class
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Logistic regression is a &lt;strong&gt;classifier&lt;/strong&gt; (despite the name): it outputs a probability via the sigmoid function, then thresholds.&lt;/p&gt;

&lt;h3&gt;
  
  
  The model zoo
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Good for&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Linear / logistic regression&lt;/td&gt;
&lt;td&gt;baselines, interpretable&lt;/td&gt;
&lt;td&gt;the starting point; rarely the ending point&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decision trees&lt;/td&gt;
&lt;td&gt;interpretable, non-linear&lt;/td&gt;
&lt;td&gt;prone to overfit alone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Random forest / gradient boosting&lt;/td&gt;
&lt;td&gt;tabular data, strong&lt;/td&gt;
&lt;td&gt;the default for structured data; XGBoost/LightGBM win Kaggle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;k-NN&lt;/td&gt;
&lt;td&gt;small, simple&lt;/td&gt;
&lt;td&gt;lazy; scales poorly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Naive Bayes&lt;/td&gt;
&lt;td&gt;text, baselines&lt;/td&gt;
&lt;td&gt;fast, independence assumption&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Neural networks&lt;/td&gt;
&lt;td&gt;images, text, audio&lt;/td&gt;
&lt;td&gt;when data is unstructured and large&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; On &lt;strong&gt;tabular data&lt;/strong&gt; (rows and columns), gradient-boosted trees (XGBoost, LightGBM) usually beat neural networks. Reach for deep learning when the data is unstructured (images, text, audio) or enormous. Don't default to a neural net for a 50-column spreadsheet.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Metrics (classification)
&lt;/h3&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;sklearn.metrics&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;accuracy_score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;classification_report&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;confusion_matrix&lt;/span&gt;
&lt;span class="nf"&gt;accuracy_score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_pred&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;               &lt;span class="c1"&gt;# fraction correct
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;classification_report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_pred&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# precision, recall, F1 per class
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Accuracy&lt;/strong&gt; — fraction correct. Misleading on imbalanced data (99% accuracy if 99% are one class).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Precision&lt;/strong&gt; — of predicted positives, how many are real? (avoid false alarms)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recall&lt;/strong&gt; — of real positives, how many did we catch? (don't miss cases)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;F1&lt;/strong&gt; — the harmonic mean of precision and recall (balance).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AUC&lt;/strong&gt; — area under the ROC curve; threshold-independent ranking quality.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; Accuracy on an imbalanced dataset lies. If 1% of transactions are fraud, a model that always says "not fraud" is 99% accurate and useless. Use precision, recall, F1, or AUC.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 3 — Unsupervised Learning
&lt;/h2&gt;

&lt;p&gt;Unsupervised learning has &lt;strong&gt;no labels&lt;/strong&gt; — you find structure in the data itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clustering
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;k-means&lt;/strong&gt; groups points into &lt;code&gt;k&lt;/code&gt; clusters by minimizing within-cluster distance:&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;sklearn.cluster&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;KMeans&lt;/span&gt;
&lt;span class="n"&gt;kmeans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;KMeans&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n_clusters&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;random_state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;labels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kmeans&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit_predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# assign each point to a cluster
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other algorithms: &lt;strong&gt;DBSCAN&lt;/strong&gt; (density-based, finds arbitrary shapes, no need to set &lt;code&gt;k&lt;/code&gt;), &lt;strong&gt;hierarchical clustering&lt;/strong&gt; (dendrogram).&lt;/p&gt;

&lt;h3&gt;
  
  
  Dimensionality reduction
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;PCA&lt;/strong&gt; (principal component analysis) projects high-dimensional data onto fewer axes that capture the most variance — for visualization, compression, or as a preprocessing step:&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;sklearn.decomposition&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PCA&lt;/span&gt;
&lt;span class="n"&gt;pca&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PCA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n_components&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;X_2d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pca&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit_transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# 100-dim -&amp;gt; 2-dim for plotting
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Embeddings
&lt;/h3&gt;

&lt;p&gt;An &lt;strong&gt;embedding&lt;/strong&gt; is a learned dense vector representation of something (a word, a user, an image) where &lt;strong&gt;similar things are close in vector space&lt;/strong&gt;. Word2vec, GloVe, and the embeddings inside transformers (Stage 4) turn discrete objects into continuous vectors so similarity (cosine distance) and analogies ("king - man + woman ≈ queen") work. Embeddings are the foundation of modern search, recommendation, and LLMs — the &lt;a href="https://dev.to/Learn-PostgreSQL-in-One-Post-Complete-Tutorial-Indexes-MVCC-Performance-Quick-Start/"&gt;pgvector extension&lt;/a&gt; in Postgres stores and searches them.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stage 4 — Deep Learning
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What a neural network is
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;neural network&lt;/strong&gt; is a stack of layers; each layer is a linear transformation followed by a non-linear &lt;strong&gt;activation&lt;/strong&gt; function. The "deep" in deep learning = many layers. Each layer learns progressively more abstract features: pixels → edges → shapes → parts → objects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhx0y88speao2x3p0edm9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhx0y88speao2x3p0edm9.png" alt="Deep Learning: Layers, Backprop, Gradient Descent" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Forward pass, loss, backprop, update
&lt;/h3&gt;

&lt;p&gt;Training is a loop:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Forward pass&lt;/strong&gt; — push inputs through the layers, get predictions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loss&lt;/strong&gt; — compare predictions to labels (MSE, cross-entropy).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backpropagation&lt;/strong&gt; — compute the gradient of the loss with respect to every weight, using the chain rule, layer by layer from output back to input.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Update&lt;/strong&gt; — nudge each weight in the direction that reduces the loss: &lt;code&gt;weight -= learning_rate * gradient&lt;/code&gt; (&lt;strong&gt;gradient descent&lt;/strong&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Repeat over the whole dataset for many &lt;strong&gt;epochs&lt;/strong&gt;. The main knobs: &lt;strong&gt;learning rate&lt;/strong&gt; (step size — too big diverges, too small crawls), &lt;strong&gt;batch size&lt;/strong&gt; (examples per update), and the &lt;strong&gt;architecture&lt;/strong&gt; (how many layers, how wide).&lt;/p&gt;

&lt;h3&gt;
  
  
  A first neural net in PyTorch
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch.nn&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;

&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Sequential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Linear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;784&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;   &lt;span class="c1"&gt;# input (28x28 pixels) -&amp;gt; 128
&lt;/span&gt;    &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ReLU&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;             &lt;span class="c1"&gt;# non-linear activation
&lt;/span&gt;    &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Linear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&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;# 128 -&amp;gt; 10 classes
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;loss_fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CrossEntropyLoss&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;optimizer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;optim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Adam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;1e-3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;epoch&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;X_batch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_batch&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dataloader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;pred&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_batch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                    &lt;span class="c1"&gt;# forward
&lt;/span&gt;        &lt;span class="n"&gt;loss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;loss_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pred&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_batch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;            &lt;span class="c1"&gt;# loss
&lt;/span&gt;        &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zero_grad&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;backward&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                          &lt;span class="c1"&gt;# backprop (compute gradients)
&lt;/span&gt;        &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                         &lt;span class="c1"&gt;# update weights
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Architectures by data type
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Data&lt;/th&gt;
&lt;th&gt;Architecture&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Images&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;CNN&lt;/strong&gt; (convolutional)&lt;/td&gt;
&lt;td&gt;convolutions capture spatial patterns (edges, shapes) with few parameters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sequences (text, time)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;RNN/LSTM&lt;/strong&gt; (legacy) → &lt;strong&gt;Transformer&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;transformers attend to all positions at once, parallelizable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Text (modern)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Transformer&lt;/strong&gt; (GPT, BERT, Claude...)&lt;/td&gt;
&lt;td&gt;self-attention; the architecture behind every LLM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tabular&lt;/td&gt;
&lt;td&gt;usually &lt;strong&gt;gradient boosting&lt;/strong&gt; &amp;gt; NNs&lt;/td&gt;
&lt;td&gt;trees handle structured data better&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; For most real problems, &lt;strong&gt;start simple&lt;/strong&gt; (linear/logistic regression, then a tree model) and only reach for deep learning when you have unstructured data and enough of it. A neural net on a small tabular dataset usually loses to XGBoost and takes 10x longer to train.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 5 — The ML Workflow
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The end-to-end pipeline
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft9q0zxfx09hm9gvgeos1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft9q0zxfx09hm9gvgeos1.png" alt="The ML Workflow" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Building a model is ~20% of the work; the rest is the pipeline around it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Data&lt;/strong&gt; — collect, clean, label, split. "Garbage in, garbage out" is the #1 ML truth. Most ML time is spent here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Features&lt;/strong&gt; — transform raw data into what the model consumes: scale numerical features, encode categories (one-hot, embedding), handle missing values, create derived features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Train&lt;/strong&gt; — fit the model; tune hyperparameters (learning rate, tree depth) using the validation set.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evaluate&lt;/strong&gt; — report metrics on the &lt;strong&gt;test&lt;/strong&gt; set (the one you never touched). Do &lt;strong&gt;error analysis&lt;/strong&gt;: look at where it's wrong, not just the aggregate score.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy&lt;/strong&gt; — serve the model (REST, batch, on-device). &lt;strong&gt;Monitor for drift&lt;/strong&gt; — when the real-world data distribution shifts from training, accuracy silently degrades. Retrain on a schedule.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; A model that scores great in a notebook but isn't monitored in production will silently degrade as the world changes. Drift detection (track input distributions + prediction distributions over time) is how you catch it before users do.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Feature engineering and scaling
&lt;/h3&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;sklearn.preprocessing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;StandardScaler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OneHotEncoder&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.pipeline&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Pipeline&lt;/span&gt;

&lt;span class="n"&gt;pipeline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Pipeline&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;scaler&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;StandardScaler&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;       &lt;span class="c1"&gt;# normalize numerical features to mean 0, std 1
&lt;/span&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;LogisticRegression&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_train&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;Scale your features.&lt;/strong&gt; Many models (linear, NNs, k-NN) behave badly when features are on different scales (a feature in millions dominates one in decimals). Tree models don't care; everything else does.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cross-validation
&lt;/h3&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;sklearn.model_selection&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;cross_val_score&lt;/span&gt;
&lt;span class="n"&gt;scores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;cross_val_score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cv&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# 5-fold CV
&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;scores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;std&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cross-validation splits the data into &lt;code&gt;k&lt;/code&gt; folds, trains on &lt;code&gt;k-1&lt;/code&gt; and validates on the held-out one, rotating — a more robust estimate of generalization than a single train/test split.&lt;/p&gt;

&lt;h3&gt;
  
  
  MLOps
&lt;/h3&gt;

&lt;p&gt;The deployment + monitoring layer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Versioning&lt;/strong&gt; — track which model version is serving (MLflow, Weights &amp;amp; Biases).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serving&lt;/strong&gt; — REST endpoint (FastAPI + the model), batch scoring, or on-device.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring&lt;/strong&gt; — drift detection, prediction latency, input schema validation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retraining&lt;/strong&gt; — schedule retraining as data drifts; A/B test new models against the current one.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Quick-Start Checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install scikit-learn + pandas&lt;/strong&gt; — &lt;code&gt;pip install scikit-learn pandas matplotlib&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Load a dataset&lt;/strong&gt; — &lt;code&gt;sklearn.datasets.load_iris()&lt;/code&gt; (classification) or &lt;code&gt;load_diabetes()&lt;/code&gt; (regression).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Split train/test&lt;/strong&gt; — always hold out a test set you never touch until the end.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start with a baseline&lt;/strong&gt; — logistic regression or a decision tree. Beat it before going complex.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick the metric for the problem&lt;/strong&gt; — F1 for imbalanced classification, MSE for regression.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-validate&lt;/strong&gt; — don't trust a single split.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Try gradient boosting&lt;/strong&gt; (XGBoost/LightGBM) for tabular data — usually the winner.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reach for PyTorch&lt;/strong&gt; only when data is unstructured (images, text) or large.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scale features&lt;/strong&gt; for anything that isn't a tree.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set up drift monitoring&lt;/strong&gt; before you ship — a model degrades silently.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Common Pitfalls
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Evaluating on training data&lt;/strong&gt; — the model has seen it; the score is meaningless. Always hold out a test set.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overfitting&lt;/strong&gt; — train loss down, val loss up. Regularize, get more data, or simplify.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accuracy on imbalanced data&lt;/strong&gt; — misleading; use precision/recall/F1/AUC.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not scaling features&lt;/strong&gt; — breaks linear models, NNs, k-NN; trees are immune.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data leakage&lt;/strong&gt; — scaling/encoding on the whole dataset before splitting leaks test info into training. Fit preprocessors on train only; transform test with the fitted transformer (use a &lt;code&gt;Pipeline&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Defaulting to deep learning&lt;/strong&gt; — for tabular data, trees usually win and train 10x faster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ignoring drift&lt;/strong&gt; — a great model in the notebook silently degrades in production as the world changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No baseline&lt;/strong&gt; — start with the simplest model; if a linear regression gets 90%, a neural net that gets 91% isn't worth the complexity.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.oreilly.com/library/view/hands-on-machine-learning/9781098125967/" rel="noopener noreferrer"&gt;Hands-On Machine Learning&lt;/a&gt; by Aurélien Géron — the standard practical book (scikit-learn + TensorFlow/Keras/PyTorch)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://scikit-learn.org/stable/user_guide.html" rel="noopener noreferrer"&gt;scikit-learn User Guide&lt;/a&gt; — the docs are a tutorial&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pytorch.org/tutorials/" rel="noopener noreferrer"&gt;PyTorch Tutorials&lt;/a&gt; — the deep-learning starting point&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.deeplearningbook.org/" rel="noopener noreferrer"&gt;Deep Learning Book&lt;/a&gt; by Goodfellow et al — the theory reference (free)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/@karpathy" rel="noopener noreferrer"&gt;Andrej Karpathy's YouTube&lt;/a&gt; — "Let's build GPT" etc., from first principles&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://paperswithcode.com/" rel="noopener noreferrer"&gt;Papers With Code&lt;/a&gt; — state-of-the-art + implementations&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Related guides
&lt;/h2&gt;

&lt;p&gt;ML is the applied-math layer on top of programming fundamentals — these PyShine tutorials connect to it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Python-in-One-Post-Complete-Tutorial-Async-Type-Hints-Quick-Start/"&gt;Learn Python in One Post&lt;/a&gt;&lt;/strong&gt; — the language every ML library uses; NumPy, pandas, scikit-learn, PyTorch are all Python.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Data-Structures-and-Algorithms-in-One-Post-Complete-Tutorial-Big-O-Trees-Graphs-DP-Quick-Start/"&gt;Learn Data Structures and Algorithms in One Post&lt;/a&gt;&lt;/strong&gt; — Big-O and the fundamentals you need to reason about model complexity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-SQL-in-One-Post-Complete-Tutorial-Joins-Window-Functions-Transactions-Quick-Start/"&gt;Learn SQL in One Post&lt;/a&gt;&lt;/strong&gt; — ML models train on data; most of it lives in a database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-PostgreSQL-in-One-Post-Complete-Tutorial-Indexes-MVCC-Performance-Quick-Start/"&gt;Learn PostgreSQL in One Post&lt;/a&gt;&lt;/strong&gt; — the &lt;code&gt;pgvector&lt;/code&gt; extension stores and searches ML embeddings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Docker-in-One-Post-Complete-Tutorial-Dockerfile-Volumes-Compose-Quick-Start/"&gt;Learn Docker in One Post&lt;/a&gt;&lt;/strong&gt; — containerize model training and serving.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Machine learning is less a single skill than a stack of decisions: what paradigm (supervised? unsupervised?), what model family (trees? neural nets?), what metric, what preprocessing, what monitoring. The five stages here — concepts, supervised, unsupervised, deep learning, the workflow — cover the whole map from "what is a feature" to "how do I detect drift in production." The habit that separates a beginner from a practitioner is &lt;strong&gt;start with a baseline and beat it&lt;/strong&gt;: a logistic regression or a tree, cross-validated, with the right metric, before you ever reach for a neural network. Load &lt;code&gt;load_iris()&lt;/code&gt;, run the snippets above, and watch a model go from random to useful in ten lines — that's the moment the field clicks.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://pyshine.com/Learn-Machine-Learning-in-One-Post-Complete-Tutorial-Supervised-Unsupervised-Deep-Learning-Quick-Start/" rel="noopener noreferrer"&gt;pyshine.com&lt;/a&gt;. The full tutorial with all 5 hand-drawn diagrams lives there — this cross-post is kept in sync via canonical URL.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>deeplearning</category>
      <category>ai</category>
      <category>neuralnetworks</category>
    </item>
    <item>
      <title>Learn Node.js and Express in a Single Post: A Complete Tutorial From the Event Loop and Modules to Middleware and Production</title>
      <dc:creator>PyShine</dc:creator>
      <pubDate>Thu, 23 Jul 2026 12:31:15 +0000</pubDate>
      <link>https://dev.to/pyshine/learn-nodejs-and-express-in-a-single-post-a-complete-tutorial-from-the-event-loop-and-modules-to-11kp</link>
      <guid>https://dev.to/pyshine/learn-nodejs-and-express-in-a-single-post-a-complete-tutorial-from-the-event-loop-and-modules-to-11kp</guid>
      <description>&lt;h1&gt;
  
  
  Learn Node.js and Express in a Single Post: Complete Tutorial From the Event Loop to Middleware and Production
&lt;/h1&gt;

&lt;p&gt;Node.js is JavaScript on the server: it takes the V8 engine from Chrome, adds non-blocking I/O via an event loop, and lets you write networked backends in the same language as the frontend. Express is the minimal web framework most Node servers are built on. Together they're the default entry point to backend JavaScript. This single post teaches both in five stages, with hand-drawn diagrams and runnable snippets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning Roadmap
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnvbtrxuvh5qkmqb82zat.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnvbtrxuvh5qkmqb82zat.png" alt="Node.js + Express Roadmap" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The roadmap moves from the runtime model (Stage 1), through modules (Stage 2), async (Stage 3), Express (Stage 4), and production (Stage 5). You'll want solid &lt;a href="https://dev.to/Learn-JavaScript-TypeScript-in-One-Post-Complete-Tutorial-Async-Types-Quick-Start/"&gt;JavaScript&lt;/a&gt; first — Node &lt;em&gt;is&lt;/em&gt; JS.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stage 1 — The Runtime
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What Node is
&lt;/h3&gt;

&lt;p&gt;Node is a &lt;strong&gt;runtime&lt;/strong&gt;, not a language: it runs JavaScript using the &lt;strong&gt;V8&lt;/strong&gt; engine (the same one in Chrome), plus a set of C++ bindings for I/O (files, network, crypto) and &lt;strong&gt;libuv&lt;/strong&gt;, the library that provides the event loop and a thread pool.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fage1x636nif8ea6o5n4x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fage1x636nif8ea6o5n4x.png" alt="Node.js Architecture" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The event loop and the single thread
&lt;/h3&gt;

&lt;p&gt;Your JavaScript runs on &lt;strong&gt;one thread&lt;/strong&gt;. The event loop keeps that thread busy with I/O callbacks: when a network request arrives, or a file read completes, libuv notifies the loop, which runs your callback. Because the loop never blocks on I/O, a single thread can handle thousands of concurrent connections.&lt;/p&gt;

&lt;p&gt;The hard rule: &lt;strong&gt;never block the event loop&lt;/strong&gt;. A CPU-bound loop (&lt;code&gt;while(true){}&lt;/code&gt;), a synchronous file read (&lt;code&gt;fs.readFileSync&lt;/code&gt; of a big file), or a heavy computation freezes &lt;em&gt;every&lt;/em&gt; connection, not just the one doing the work.&lt;/p&gt;

&lt;h3&gt;
  
  
  The libuv thread pool
&lt;/h3&gt;

&lt;p&gt;Some operations can't be made non-blocking at the OS level (file I/O on some platforms, &lt;code&gt;crypto.pbkdf2&lt;/code&gt;, DNS lookups). Node offloads these to a &lt;strong&gt;thread pool&lt;/strong&gt; (default 4 threads, configurable via &lt;code&gt;UV_THREADPOOL_SIZE&lt;/code&gt;) so the event loop keeps running. Your callback still runs on the single main thread when the work completes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; The thread pool is &lt;em&gt;not&lt;/em&gt; parallelism for your JS — it's for the C++ I/O work. If you need real parallel CPU work in JS, use &lt;strong&gt;worker threads&lt;/strong&gt; (&lt;code&gt;worker_threads&lt;/code&gt;) or a child process; the thread pool won't help you.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 2 — Modules
&lt;/h2&gt;

&lt;h3&gt;
  
  
  CommonJS vs ES Modules
&lt;/h3&gt;

&lt;p&gt;Node historically used &lt;strong&gt;CommonJS&lt;/strong&gt; (&lt;code&gt;require&lt;/code&gt;/&lt;code&gt;module.exports&lt;/code&gt;); modern Node also supports &lt;strong&gt;ES Modules&lt;/strong&gt; (&lt;code&gt;import&lt;/code&gt;/&lt;code&gt;export&lt;/code&gt;). Use ESM for new code; CommonJS still works for legacy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm3gqxxehsf7ks4yuk8lr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm3gqxxehsf7ks4yuk8lr.png" alt="Modules: CommonJS vs ESM + npm" width="800" height="382"&gt;&lt;/a&gt;&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;// CommonJS (legacy)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fs&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;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&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;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="c1"&gt;// const { add } = require('./math');&lt;/span&gt;

&lt;span class="c1"&gt;// ES Modules (modern) — package.json: "type": "module"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&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="c1"&gt;// import { add } from './math';&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;CommonJS&lt;/th&gt;
&lt;th&gt;ESM&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Syntax&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;require&lt;/code&gt; / &lt;code&gt;module.exports&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;import&lt;/code&gt; / &lt;code&gt;export&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resolution&lt;/td&gt;
&lt;td&gt;runtime, synchronous&lt;/td&gt;
&lt;td&gt;static, hoisted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extension&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.cjs&lt;/code&gt; or default&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.mjs&lt;/code&gt; or &lt;code&gt;"type":"module"&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Top-level await&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tree-shaking&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;h3&gt;
  
  
  npm and &lt;code&gt;package.json&lt;/code&gt;
&lt;/h3&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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"module"&lt;/span&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;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nodemon 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;"vitest"&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;"dependencies"&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;"express"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.19.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"pg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^8.11.0"&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;"devDependencies"&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;"nodemon"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^3.1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"vitest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^2.0.0"&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;"engines"&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;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;=20"&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;express            &lt;span class="c"&gt;# add a runtime dep&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; nodemon &lt;span class="c"&gt;# add a dev dep&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt;                    &lt;span class="c"&gt;# install everything from package.json + lockfile&lt;/span&gt;
npm run dev                    &lt;span class="c"&gt;# run the "dev" script&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;node_modules/&lt;/code&gt; holds installed packages; &lt;code&gt;package-lock.json&lt;/code&gt; pins exact versions for reproducibility (&lt;strong&gt;commit the lockfile&lt;/strong&gt;). For speed, use &lt;strong&gt;pnpm&lt;/strong&gt; (dedupes via symlinks) or &lt;strong&gt;Bun&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; &lt;code&gt;npm install &amp;lt;pkg&amp;gt;&lt;/code&gt; without &lt;code&gt;-D&lt;/code&gt; puts a build tool into &lt;code&gt;dependencies&lt;/code&gt;, shipping it to production. Use &lt;code&gt;--save-dev&lt;/code&gt; / &lt;code&gt;-D&lt;/code&gt; for anything only needed at build/test time.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 3 — Async
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Callbacks -&amp;gt; promises -&amp;gt; async/await
&lt;/h3&gt;

&lt;p&gt;Node's async story evolved: &lt;strong&gt;callbacks&lt;/strong&gt; (error-first) -&amp;gt; &lt;strong&gt;promises&lt;/strong&gt; -&amp;gt; &lt;strong&gt;async/await&lt;/strong&gt;. Use async/await; it reads top-to-bottom like sync code but never blocks.&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;// callback (legacy, error-first)&lt;/span&gt;
&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;f.txt&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;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// promise + async/await (modern)&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;readFile&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node:fs/promises&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&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;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;f.txt&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;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// suspends, doesn't block&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Always handle errors&lt;/strong&gt; — an unhandled promise rejection crashes the process (since Node 15). Wrap &lt;code&gt;await&lt;/code&gt; in &lt;code&gt;try/catch&lt;/code&gt; or attach &lt;code&gt;.catch()&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Streams
&lt;/h3&gt;

&lt;p&gt;Streams process data in chunks as it arrives, instead of buffering it all in memory — essential for large files, uploads, or piping:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createReadStream&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node:fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;pipeline&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node:stream/promises&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// pipe a file through a transform to stdout&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;createReadStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;big.log&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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;stdout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// HTTP response is a writable stream&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;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chunk 1&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&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;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chunk 2&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&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;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;done&lt;/span&gt;&lt;span class="se"&gt;\n&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;Use &lt;code&gt;stream.pipeline&lt;/code&gt; (not &lt;code&gt;.pipe()&lt;/code&gt;) so errors propagate and resources clean up.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; &lt;code&gt;.pipe()&lt;/code&gt; doesn't forward errors — one stream can fail silently while the other keeps going. Use &lt;code&gt;pipeline()&lt;/code&gt; from &lt;code&gt;stream/promises&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 4 — Express
&lt;/h2&gt;

&lt;p&gt;Express is a minimal web framework: it routes HTTP requests to handler functions, with a &lt;strong&gt;middleware&lt;/strong&gt; pipeline in between.&lt;/p&gt;

&lt;h3&gt;
  
  
  A minimal server
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="k"&gt;from&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="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&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="c1"&gt;// body parser middleware&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="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;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;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;/users&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;name&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="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;201&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;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="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="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="mi"&gt;3000&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="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;http://localhost:3000&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;h3&gt;
  
  
  The middleware pipeline
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkrpfw0tv5c6eag8nhcqc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkrpfw0tv5c6eag8nhcqc.png" alt="Express: Request -&gt; Middleware -&gt; Route -&gt; Response" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every request flows through a chain of &lt;strong&gt;middleware&lt;/strong&gt; functions, each getting &lt;code&gt;(req, res, next)&lt;/code&gt; and calling &lt;code&gt;next()&lt;/code&gt; to pass control onward. One handler eventually sends the response.&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;// a logging middleware&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;use&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="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;`&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;method&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="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&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="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;                          &lt;span class="c1"&gt;// pass control to the next middleware/route&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// order matters: this runs before routes defined after it&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;/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;authMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getUsers&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// route-specific middleware&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Request and response objects
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;req.method&lt;/code&gt;, &lt;code&gt;req.url&lt;/code&gt;, &lt;code&gt;req.path&lt;/code&gt;, &lt;code&gt;req.query&lt;/code&gt;, &lt;code&gt;req.params&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;req.headers&lt;/code&gt;, &lt;code&gt;req.get('Authorization')&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;req.body&lt;/code&gt; (after &lt;code&gt;express.json()&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;res.json(obj)&lt;/code&gt;, &lt;code&gt;res.send(str)&lt;/code&gt;, &lt;code&gt;res.status(404).send(...)&lt;/code&gt;, &lt;code&gt;res.redirect(url)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Error handling
&lt;/h3&gt;

&lt;p&gt;A middleware with &lt;strong&gt;four arguments&lt;/strong&gt; &lt;code&gt;(err, req, res, next)&lt;/code&gt; is an error handler. Define it &lt;strong&gt;last&lt;/strong&gt;, after all routes:&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="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&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="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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stack&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="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;500&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="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pass errors to it with &lt;code&gt;next(err)&lt;/code&gt; or by throwing in an &lt;code&gt;async&lt;/code&gt; handler (wrap async routes in a helper — an unhandled rejection from a route handler won't reach Express automatically):&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;// wrap async handlers so rejections reach the error middleware&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wrap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&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;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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fn&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="k"&gt;catch&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="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;/users/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findUser&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="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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&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;not found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&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;user&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;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; A thrown error in an &lt;code&gt;async&lt;/code&gt; route handler, unhandled, becomes an unhandled rejection — not an Express error. Use &lt;code&gt;express-async-errors&lt;/code&gt; or the &lt;code&gt;wrap&lt;/code&gt; helper so it reaches your error middleware.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Routers
&lt;/h3&gt;

&lt;p&gt;For larger apps, split routes into &lt;code&gt;Router&lt;/code&gt; modules and mount them:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&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;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Router&lt;/span&gt;&lt;span class="p"&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;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="nx"&gt;listUsers&lt;/span&gt;&lt;span class="p"&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;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;/: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;getUser&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;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// mount at /users&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Stage 5 — Production
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Clustering
&lt;/h3&gt;

&lt;p&gt;A single Node process uses one CPU core. The &lt;strong&gt;cluster&lt;/strong&gt; module (or &lt;strong&gt;PM2&lt;/strong&gt;) forks one worker per core, all sharing a port — this is how you use a multi-core machine:&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cluster&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node:cluster&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;os&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node:os&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isPrimary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cpus&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fork&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// each worker runs the server&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="mi"&gt;3000&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;In practice, use PM2 (&lt;code&gt;pm2 start app.js -i max&lt;/code&gt;) or run behind a container orchestrator with one process per container — don't hand-roll clustering in production.&lt;/p&gt;

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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vitest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;supertest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET / returns ok&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;request&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="nf"&gt;expect&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;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&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;expect&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;body&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;&lt;strong&gt;Vitest&lt;/strong&gt; (unit/integration) + &lt;strong&gt;supertest&lt;/strong&gt; (HTTP) is the standard combo. For e2e, &lt;strong&gt;Playwright&lt;/strong&gt; drives a real browser.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploy and security
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PM2&lt;/strong&gt; for process management on a VM; &lt;strong&gt;Docker&lt;/strong&gt; + your orchestrator for containerized deploys.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security headers&lt;/strong&gt;: use &lt;code&gt;helmet&lt;/code&gt;. &lt;strong&gt;CORS&lt;/strong&gt;: use &lt;code&gt;cors&lt;/code&gt;. &lt;strong&gt;Rate limiting&lt;/strong&gt;: &lt;code&gt;express-rate-limit&lt;/code&gt;. &lt;strong&gt;Input validation&lt;/strong&gt;: &lt;code&gt;zod&lt;/code&gt; or &lt;code&gt;joi&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never trust &lt;code&gt;req.body&lt;/code&gt;&lt;/strong&gt; without validation; never interpolate user input into SQL/shell (injection).&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;NODE_ENV=production&lt;/code&gt; (faster V8 optimizations, less verbose errors).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Databases
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;SQL: &lt;code&gt;pg&lt;/code&gt; (raw), &lt;strong&gt;Prisma&lt;/strong&gt; (typed ORM), &lt;strong&gt;Drizzle&lt;/strong&gt; (typed, lightweight).&lt;/li&gt;
&lt;li&gt;MongoDB: &lt;strong&gt;Mongoose&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Cache: &lt;strong&gt;ioredis&lt;/strong&gt; / &lt;code&gt;node-redis&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The ecosystem
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F95uxt5ylzdyl33zei98r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F95uxt5ylzdyl33zei98r.png" alt="Node Toolchain + Ecosystem" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concern&lt;/th&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Runtime + packages&lt;/td&gt;
&lt;td&gt;node, npm, pnpm, nvm&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dev&lt;/td&gt;
&lt;td&gt;nodemon, tsx, vitest, eslint/prettier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frameworks&lt;/td&gt;
&lt;td&gt;Express (minimal), Fastify (fast + schema), Hono (edge), NestJS (structured DI)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DBs + deploy&lt;/td&gt;
&lt;td&gt;pg/Prisma, Mongoose, Redis, PM2/Docker&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Quick-Start Checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install Node&lt;/strong&gt; (LTS) via nvm or the installer; verify with &lt;code&gt;node -v&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Init a project&lt;/strong&gt;: &lt;code&gt;npm init&lt;/code&gt;, install Express, add a &lt;code&gt;"type": "module"&lt;/code&gt; + a &lt;code&gt;dev&lt;/code&gt; script.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write a 10-line server&lt;/strong&gt; with one &lt;code&gt;GET&lt;/code&gt; route; &lt;code&gt;node index.js&lt;/code&gt; and hit it with &lt;code&gt;curl&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add &lt;code&gt;express.json()&lt;/code&gt;&lt;/strong&gt; and a &lt;code&gt;POST&lt;/code&gt; route; test with &lt;code&gt;curl -d&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add a logging middleware&lt;/strong&gt; + an error-handling middleware (four-arg).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use async/await&lt;/strong&gt; with &lt;code&gt;try/catch&lt;/code&gt; (or wrap async routes) for DB calls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate input&lt;/strong&gt; with Zod before it touches your DB.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add helmet, cors, express-rate-limit&lt;/strong&gt; for baseline security.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test with Vitest + supertest&lt;/strong&gt; in CI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run behind PM2 or in Docker&lt;/strong&gt; with &lt;code&gt;NODE_ENV=production&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Common Pitfalls
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Blocking the event loop&lt;/strong&gt; — a sync loop or &lt;code&gt;readFileSync&lt;/code&gt; freezes all connections. Keep the loop free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unhandled promise rejections&lt;/strong&gt; — crash the process. &lt;code&gt;try/catch&lt;/code&gt; every &lt;code&gt;await&lt;/code&gt;, or attach &lt;code&gt;.catch()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;async&lt;/code&gt; route handlers that throw&lt;/strong&gt; — don't reach Express's error middleware without wrapping. Use &lt;code&gt;wrap()&lt;/code&gt; or &lt;code&gt;express-async-errors&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;.pipe()&lt;/code&gt; without error handling&lt;/strong&gt; — use &lt;code&gt;stream/pipeline&lt;/code&gt; so errors propagate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dev deps in &lt;code&gt;dependencies&lt;/code&gt;&lt;/strong&gt; — bloats production. Use &lt;code&gt;-D&lt;/code&gt; / &lt;code&gt;--save-dev&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not committing the lockfile&lt;/strong&gt; — non-reproducible installs. Commit &lt;code&gt;package-lock.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trusting &lt;code&gt;req.body&lt;/code&gt;&lt;/strong&gt; — always validate with Zod/joi; never build SQL/shell from it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single process on multi-core&lt;/strong&gt; — use clustering (PM2 &lt;code&gt;-i max&lt;/code&gt;) or one process per container.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;NODE_ENV&lt;/code&gt; unset in production&lt;/strong&gt; — slower V8, verbose errors. Set &lt;code&gt;NODE_ENV=production&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/docs/latest/api/" rel="noopener noreferrer"&gt;Node.js Docs&lt;/a&gt; — the standard library is large and well-documented&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/goldbergyoni/nodebestpractices" rel="noopener noreferrer"&gt;Node.js Best Practices&lt;/a&gt; — the community mega-list&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;Express Docs&lt;/a&gt; — routing, middleware, API&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://12factor.net/" rel="noopener noreferrer"&gt;12 Factor App&lt;/a&gt; — config, logs, process model for production&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.nodejsdesignpatterns.com/" rel="noopener noreferrer"&gt;Node.js Design Patterns&lt;/a&gt; by Mario Casciaro — the deep book&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Related guides
&lt;/h2&gt;

&lt;p&gt;Node + Express is the backend JS stack — these PyShine tutorials are its prerequisites and companions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-JavaScript-TypeScript-in-One-Post-Complete-Tutorial-Async-Types-Quick-Start/"&gt;Learn JavaScript + TypeScript in One Post&lt;/a&gt;&lt;/strong&gt; — Node &lt;em&gt;is&lt;/em&gt; JS; async/await and the event loop are JS concepts first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-REST-API-in-One-Post-Complete-Tutorial-Methods-Status-Codes-Production-Quick-Start/"&gt;Learn REST API in One Post&lt;/a&gt;&lt;/strong&gt; — Express implements REST; know methods, status codes, idempotency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-SQL-in-One-Post-Complete-Tutorial-Joins-Window-Functions-Transactions-Quick-Start/"&gt;Learn SQL in One Post&lt;/a&gt;&lt;/strong&gt; — what your Express handlers query (via &lt;code&gt;pg&lt;/code&gt;/Prisma).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Docker-in-One-Post-Complete-Tutorial-Dockerfile-Volumes-Compose-Quick-Start/"&gt;Learn Docker in One Post&lt;/a&gt;&lt;/strong&gt; — containerize and ship the Node server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-React-Next-js-in-One-Post-Complete-Tutorial-Components-Hooks-Server-Components-Quick-Start/"&gt;Learn React + Next.js in One Post&lt;/a&gt;&lt;/strong&gt; — the frontend that calls this backend.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Node's power is its simplicity: one language front-to-back, one thread, an event loop, and a tiny core you can hold in your head. The five stages here — runtime, modules, async, Express, production — cover everything from a "hello world" server to a clustered, tested, containerized API. The single most important habit is &lt;strong&gt;never block the loop&lt;/strong&gt;: once that's a reflex, the rest is standard web-backend work. Run every snippet above, write one endpoint, hit it with &lt;code&gt;curl&lt;/code&gt;, wrap it in Docker, and you've built your first production Node service.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://pyshine.com/Learn-Node-js-Express-in-One-Post-Complete-Tutorial-Event-Loop-Middleware-Quick-Start/" rel="noopener noreferrer"&gt;pyshine.com&lt;/a&gt;. The full tutorial with all 5 hand-drawn diagrams lives there — this cross-post is kept in sync via canonical URL.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>express</category>
      <category>backend</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Learn Observability in a Single Post: A Complete Tutorial From Metrics, Logs, and Traces to OpenTelemetry and SLO Alerting</title>
      <dc:creator>PyShine</dc:creator>
      <pubDate>Thu, 23 Jul 2026 12:30:59 +0000</pubDate>
      <link>https://dev.to/pyshine/learn-observability-in-a-single-post-a-complete-tutorial-from-metrics-logs-and-traces-to-1e1f</link>
      <guid>https://dev.to/pyshine/learn-observability-in-a-single-post-a-complete-tutorial-from-metrics-logs-and-traces-to-1e1f</guid>
      <description>&lt;h1&gt;
  
  
  Learn Observability in a Single Post: Complete Tutorial From Metrics, Logs, and Traces to OpenTelemetry and SLO Alerting
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Observability&lt;/strong&gt; is the ability to ask questions of your system from the outside, without shipping new code to answer them. Monitoring tells you &lt;em&gt;a&lt;/em&gt; thing is wrong; observability lets you find out &lt;em&gt;why&lt;/em&gt;, fast — across metrics, logs, and traces, correlated by a shared trace ID and labels. It's the difference between "the site is slow" and "the /checkout path is 3x slower because the payments DB is doing full-table scans." This single post teaches the whole subject in five stages, with hand-drawn diagrams and runnable snippets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning Roadmap
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk98ng7qhpvab0yt3ln4v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk98ng7qhpvab0yt3ln4v.png" alt="Observability Roadmap" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The roadmap moves from metrics (Stage 1), through logs (Stage 2) and traces (Stage 3), to the unified OpenTelemetry pipeline (Stage 4), and the SLO + alerting discipline that makes it actionable (Stage 5).&lt;/p&gt;




&lt;h2&gt;
  
  
  Stage 1 — Metrics
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The three pillars
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5iz2ck23lgxzslnqnnmt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5iz2ck23lgxzslnqnnmt.png" alt="The Three Pillars of Observability" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Observability rests on &lt;strong&gt;three pillars&lt;/strong&gt;: &lt;strong&gt;metrics&lt;/strong&gt; (numbers over time — &lt;em&gt;what&lt;/em&gt; + &lt;em&gt;how much&lt;/em&gt;), &lt;strong&gt;logs&lt;/strong&gt; (discrete events — &lt;em&gt;why&lt;/em&gt;), and &lt;strong&gt;traces&lt;/strong&gt; (a request's journey — &lt;em&gt;where time went&lt;/em&gt;). Together, correlated by labels and trace IDs, they let you answer any question.&lt;/p&gt;

&lt;h3&gt;
  
  
  Metric types
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;What it is&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Counter&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;monotonically increasing&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;http_requests_total&lt;/code&gt; (request count)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Gauge&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;a value that goes up and down&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;memory_bytes&lt;/code&gt;, &lt;code&gt;queue_depth&lt;/code&gt;, &lt;code&gt;active_connections&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Histogram&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;distribution of values in buckets&lt;/td&gt;
&lt;td&gt;request latency, with quantile estimation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;pre-computed quantiles (legacy)&lt;/td&gt;
&lt;td&gt;use histograms instead in most cases&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Prometheus client (Python)
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;prometheus_client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Histogram&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start_http_server&lt;/span&gt;

&lt;span class="n"&gt;REQUESTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http_requests_total&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;Total requests&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;route&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;method&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;LATENCY&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Histogram&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http_request_duration_seconds&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;Latency&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;route&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="nd"&gt;@LATENCY.time&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;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;REQUESTS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;GET&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Prometheus — the pull model
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl1gzkydcewdzgpf19tsv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl1gzkydcewdzgpf19tsv.png" alt="Prometheus Pull Model + PromQL + Grafana" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Prometheus &lt;strong&gt;scrapes&lt;/strong&gt; your apps: each app exposes a &lt;code&gt;/metrics&lt;/code&gt; endpoint, and Prometheus pulls from it on a schedule (15s by default). This pull model means no agent in your app pushing data — the app is dumb, Prometheus is smart.&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;# prometheus.yml&lt;/span&gt;
&lt;span class="na"&gt;scrape_configs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;job_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;my-app'&lt;/span&gt;
    &lt;span class="na"&gt;static_configs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[{&lt;/span&gt; &lt;span class="nv"&gt;targets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;app:8000'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt; &lt;span class="pi"&gt;}]&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;job_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;kubernetes-pods'&lt;/span&gt;
    &lt;span class="na"&gt;kubernetes_sd_configs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[{&lt;/span&gt; &lt;span class="nv"&gt;role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;pod&lt;/span&gt; &lt;span class="pi"&gt;}]&lt;/span&gt;   &lt;span class="c1"&gt;# auto-discover K8s pods&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  PromQL — query the time series
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# requests/sec over the last 5 minutes
rate(http_requests_total[5m])

# p99 latency
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))

# error rate
sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m]))

# per-route
sum by (route) (rate(http_requests_total[5m]))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Labels are dimensions.&lt;/strong&gt; Every metric carries labels (&lt;code&gt;route&lt;/code&gt;, &lt;code&gt;method&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;env&lt;/code&gt;); PromQL groups and filters by them. Design labels deliberately — they're how you slice the data.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; High-cardinality labels (a label per user ID, request ID, or email) blow up the time-series database — millions of series, Prometheus OOMs. Labels should have a small, bounded set of values. Put unique IDs in logs/traces, not metric labels.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 2 — Logs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Structured logs
&lt;/h3&gt;

&lt;p&gt;A log entry should be &lt;strong&gt;structured&lt;/strong&gt; (machine-parseable JSON with fields), not free text:&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="nl"&gt;"ts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"2026-07-14T12:00:01Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"level"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"msg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"payment failed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"trace_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"abc123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"user_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"u42"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"order_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"o99"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;49.99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"card_declined"&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;Fields (&lt;code&gt;user_id&lt;/code&gt;, &lt;code&gt;order_id&lt;/code&gt;, &lt;code&gt;trace_id&lt;/code&gt;) let you &lt;strong&gt;filter and correlate&lt;/strong&gt; — "show me all logs for trace &lt;code&gt;abc123&lt;/code&gt;" or "all payments for user &lt;code&gt;u42&lt;/code&gt;." Free text &lt;code&gt;"payment failed for user 42"&lt;/code&gt; is a string-search nightmare.&lt;/p&gt;

&lt;h3&gt;
  
  
  Levels
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;debug&lt;/code&gt; → &lt;code&gt;info&lt;/code&gt; → &lt;code&gt;warn&lt;/code&gt; → &lt;code&gt;error&lt;/code&gt; → &lt;code&gt;fatal&lt;/code&gt;. In production, ship &lt;code&gt;info&lt;/code&gt; and above; &lt;code&gt;debug&lt;/code&gt; is for development. &lt;strong&gt;Don't log at &lt;code&gt;error&lt;/code&gt; what's expected&lt;/strong&gt; (a 404, a retry) — it drowns real errors in noise and trains people to ignore the page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Log aggregation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Loki&lt;/strong&gt; — like Prometheus for logs: indexes labels (not full text), cheap, integrates with Grafana.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ELK&lt;/strong&gt; (Elasticsearch + Logstash + Kibana) — full-text indexing, powerful search, heavier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud&lt;/strong&gt;: Cloud Logging (GCP), CloudWatch Logs (AWS).&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; Logging sensitive data (PII, passwords, tokens) is a security incident. Scrub secrets before logging; structure logs so a scrubber can find fields by name.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 3 — Traces
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What a trace is
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;trace&lt;/strong&gt; is the end-to-end journey of one request through your system. It's a tree of &lt;strong&gt;spans&lt;/strong&gt;: each span is a unit of work (an HTTP call, a DB query, a function), with a start, duration, and attributes. Spans carry a &lt;strong&gt;trace ID&lt;/strong&gt; (shared across the whole request) and a &lt;strong&gt;span ID&lt;/strong&gt; (unique per span), and a parent span ID — the tree structure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;trace abc123 (HTTP GET /checkout)  ─── 220ms total
├── span: validate cart            ─── 5ms
├── span: POST /payments            ─── 180ms   ← the slow one
│   └── span: DB INSERT charge       ─── 175ms  ← the real cause
└── span: render receipt            ─── 3ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A trace shows you &lt;strong&gt;where time went&lt;/strong&gt; and the &lt;strong&gt;call graph&lt;/strong&gt; — the single best tool for "why is this slow?"&lt;/p&gt;

&lt;h3&gt;
  
  
  Distributed tracing
&lt;/h3&gt;

&lt;p&gt;In a microservice system, a trace spans services: service A calls B calls C. Each service contributes spans to the same trace (via propagated headers: &lt;code&gt;traceparent&lt;/code&gt;). OpenTelemetry (Stage 4) is how spans get created and propagated; Jaeger, Tempo, or Zipkin store and visualize them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sampling
&lt;/h3&gt;

&lt;p&gt;You can't trace 100% of traffic at scale (too much data). &lt;strong&gt;Sampling&lt;/strong&gt; traces a fraction:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Head-based&lt;/strong&gt; — the first service decides (random %), same decision for the whole trace. Simple, but misses rare errors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tail-based&lt;/strong&gt; — sample &lt;em&gt;after&lt;/em&gt; the trace completes (e.g. keep all errors, 1% of successes). Smarter, more expensive.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; If sampling is inconsistent across services, a trace breaks mid-journey. Use a &lt;strong&gt;consistent sampling decision&lt;/strong&gt; (head-based, propagated) so the whole trace is kept or dropped together.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 4 — OpenTelemetry
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The problem OTel solves
&lt;/h3&gt;

&lt;p&gt;Before OpenTelemetry, every vendor (Datadog, New Relic, Jaeger, Honeycomb) had its own instrumentation library. Switching backends meant re-instrumenting your whole codebase. &lt;strong&gt;OpenTelemetry (OTel)&lt;/strong&gt; is the vendor-neutral standard: instrument once, export to any backend.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqvhsrxowj3lr1q3lottu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqvhsrxowj3lr1q3lottu.png" alt="OpenTelemetry: Instrument -&gt; SDK -&gt; Collector" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The pipeline
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Instrumentation&lt;/strong&gt; — auto (library integrations that create spans/metrics for HTTP, DB, etc.) + manual (custom spans, attributes).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SDK&lt;/strong&gt; — configures the instrumentation, batches, and exports.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collector&lt;/strong&gt; — a standalone process that receives OTLP, processes (batch, filter, add attributes), and exports to backends (Prometheus, Jaeger, Loki, Datadog, any).
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Python: OTel SDK setup
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;opentelemetry&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;trace&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;opentelemetry.sdk.trace&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TracerProvider&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;opentelemetry.sdk.trace.export&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BatchSpanProcessor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OTLPSpanExporter&lt;/span&gt;

&lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_tracer_provider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TracerProvider&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_tracer_provider&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;add_span_processor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;BatchSpanProcessor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OTLPSpanExporter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;otel-collector:4317&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="c1"&gt;# manual span
&lt;/span&gt;&lt;span class="n"&gt;tracer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_tracer&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;with&lt;/span&gt; &lt;span class="n"&gt;tracer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start_as_current_span&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;process_payment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_attribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;charge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Collector
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;OTel Collector&lt;/strong&gt; is the heart of a production pipeline: it decouples your apps from the backends. Apps export OTLP to the collector; the collector fans out to Prometheus (metrics), Jaeger/Tempo (traces), Loki (logs) — or to a SaaS vendor. Change backends by reconfiguring the collector, not your apps.&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;# otel-collector config (simplified)&lt;/span&gt;
&lt;span class="na"&gt;receivers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;   &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;otlp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;protocols&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;grpc&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;0.0.0.0&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;4317&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="na"&gt;processors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;batch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{},&lt;/span&gt; &lt;span class="nv"&gt;resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;attributes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[{&lt;/span&gt; &lt;span class="nv"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;prod&lt;/span&gt; &lt;span class="pi"&gt;}]&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="na"&gt;exporters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;prometheus&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;0.0.0.0&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;8889&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;   &lt;span class="c1"&gt;# metrics -&amp;gt; Prometheus scrapes&lt;/span&gt;
  &lt;span class="na"&gt;otlp/tempo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;tempo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;4317&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;       &lt;span class="c1"&gt;# traces -&amp;gt; Tempo&lt;/span&gt;
  &lt;span class="na"&gt;loki&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;loki&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;3100&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;             &lt;span class="c1"&gt;# logs -&amp;gt; Loki&lt;/span&gt;
&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;pipelines&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;...&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; Don't point every app directly at every backend. Run a collector (or a gateway collector in front of it). It batches, retries, drops on overload, and lets you swap backends without touching apps.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 5 — SLOs + Alerting
&lt;/h2&gt;

&lt;h3&gt;
  
  
  SLI, SLO, error budget
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzy3046b2tb7258ic5xcp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzy3046b2tb7258ic5xcp.png" alt="SLOs, Error Budgets, Alerting, On-call" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SLI&lt;/strong&gt; (service-level indicator) — a measured metric: "99.5% of &lt;code&gt;/checkout&lt;/code&gt; requests complete in &amp;lt; 200ms."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SLO&lt;/strong&gt; (service-level objective) — the target for the SLI over a window: "99% over 30 days."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error budget&lt;/strong&gt; — the 1% gap (100% − 99%) = how much unreliability you can "afford." It's the room for deploys, experiments, and risk.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The error budget reframes reliability as a &lt;em&gt;product decision&lt;/em&gt;: if you're burning it slowly, you can ship faster; if you're burning it fast, you freeze feature work and fix reliability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Burn-rate alerting
&lt;/h3&gt;

&lt;p&gt;Don't alert on "CPU &amp;gt; 80%" — that's a &lt;strong&gt;cause&lt;/strong&gt; you guessed, and it may not matter. Alert on &lt;strong&gt;symptoms&lt;/strong&gt; (user impact) via &lt;strong&gt;burn rate&lt;/strong&gt;: how fast you're spending the error budget.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight prometheus"&gt;&lt;code&gt;&lt;span class="c"&gt;# page if spending budget 14x faster than allowed over 1h AND 5m&lt;/span&gt;
&lt;span class="c"&gt;# (multi-window multi-burn-rate — the SRE standard)&lt;/span&gt;
&lt;span class="n"&gt;job:slo_errors:ratio_rate5m&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;14&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="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;0.99&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;and&lt;/span&gt; &lt;span class="n"&gt;job:slo_errors:ratio_rate1h&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;14&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="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;0.99&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Multi-window burn-rate alerts fire only when the budget is genuinely at risk over both a short and long window — far fewer false pages than raw-threshold alerts.&lt;/p&gt;

&lt;h3&gt;
  
  
  On-call + runbooks
&lt;/h3&gt;

&lt;p&gt;An alert that pages a human must:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Be &lt;strong&gt;actionable&lt;/strong&gt; (the human can do something about it).&lt;/li&gt;
&lt;li&gt;Have a &lt;strong&gt;runbook&lt;/strong&gt; (the steps to diagnose and fix).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-recover&lt;/strong&gt; if possible (the alert should also fire when it self-resolves).&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; Alert fatigue is how on-call dies. If a page fires and the right response is "ignore it," you've trained the team to ignore &lt;em&gt;all&lt;/em&gt; pages — including the real one. Every noisy alert is a bug; fix it or delete it.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Quick-Start Checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Expose a &lt;code&gt;/metrics&lt;/code&gt; endpoint&lt;/strong&gt; (Prometheus format) with a counter + histogram.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run Prometheus&lt;/strong&gt; to scrape it; open the Prometheus UI and run a &lt;code&gt;rate()&lt;/code&gt; query.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add Grafana&lt;/strong&gt;, point it at Prometheus, build a dashboard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Emit structured JSON logs&lt;/strong&gt; with a &lt;code&gt;trace_id&lt;/code&gt; field; aggregate in Loki.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add OpenTelemetry&lt;/strong&gt; — auto-instrumentation for your framework; export to a collector.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run the OTel Collector&lt;/strong&gt; fanning out to Prometheus (metrics) + Tempo/Jaeger (traces).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Define one SLI + SLO&lt;/strong&gt; (e.g. 99% of &lt;code&gt;/api&lt;/code&gt; requests &amp;lt; 200ms over 30d).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set a burn-rate alert&lt;/strong&gt; on that SLO, paging to a channel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write a runbook&lt;/strong&gt; for the alert; test it by triggering the condition.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review alerts monthly&lt;/strong&gt; — delete or fix every noisy one.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Common Pitfalls
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;High-cardinality metric labels&lt;/strong&gt; (user ID, request ID) — explodes the TSDB; put those in logs/traces.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free-text logs&lt;/strong&gt; — unsearchable; emit structured JSON with fields.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logging secrets/PII&lt;/strong&gt; — a security incident; scrub before logging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cause-based alerts&lt;/strong&gt; ("CPU high") — alert on symptoms (user impact) instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alert fatigue&lt;/strong&gt; — every non-actionable page erodes trust; delete noisy alerts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No runbook&lt;/strong&gt; — a page with no instructions wastes on-call time; write the steps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inconsistent sampling&lt;/strong&gt; — breaks distributed traces; propagate one decision.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every app -&amp;gt; every backend&lt;/strong&gt; — use a collector so swapping backends is config, not code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;error&lt;/code&gt; level for expected events&lt;/strong&gt; — drowns real errors; log those at &lt;code&gt;info&lt;/code&gt;/&lt;code&gt;warn&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://opentelemetry.io/docs/" rel="noopener noreferrer"&gt;OpenTelemetry Docs&lt;/a&gt; — the standard&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://prometheus.io/docs/" rel="noopener noreferrer"&gt;Prometheus Docs&lt;/a&gt; — metrics + PromQL&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://grafana.com/docs/" rel="noopener noreferrer"&gt;Grafana Docs&lt;/a&gt; — dashboards + alerting&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://sre.google/sre-book/table-of-contents/" rel="noopener noreferrer"&gt;Google SRE Book&lt;/a&gt; — SLOs, error budgets, alerting (free)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.oreilly.com/library/view/observability-engineering/9781492076438/" rel="noopener noreferrer"&gt;Observability Engineering&lt;/a&gt; by Charity Majors et al — the modern reference&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Related guides
&lt;/h2&gt;

&lt;p&gt;Observability is the ops layer that watches the rest of the stack — these PyShine tutorials connect to it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Kubernetes-in-One-Post-Complete-Tutorial-Pods-Deployments-Services-Production-Quick-Start/"&gt;Learn Kubernetes in One Post&lt;/a&gt;&lt;/strong&gt; — Prometheus + Grafana are the K8s monitoring default; the kube-prometheus-stack Helm chart sets it up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Docker-in-One-Post-Complete-Tutorial-Dockerfile-Volumes-Compose-Quick-Start/"&gt;Learn Docker in One Post&lt;/a&gt;&lt;/strong&gt; — containerize Prometheus, Grafana, and the OTel collector with Compose.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-GitHub-Actions-in-One-Post-Complete-Tutorial-Workflows-Jobs-Runners-Secrets-Quick-Start/"&gt;Learn GitHub Actions in One Post&lt;/a&gt;&lt;/strong&gt; — alert on-call from CI when a deploy breaks an SLO.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-System-Design-in-One-Post-Complete-Tutorial-Scaling-CAP-Tradeoffs-Interview-Quick-Start/"&gt;Learn System Design in One Post&lt;/a&gt;&lt;/strong&gt; — SLOs and error budgets are system-design concepts applied to production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Python-in-One-Post-Complete-Tutorial-Async-Type-Hints-Quick-Start/"&gt;Learn Python in One Post&lt;/a&gt;&lt;/strong&gt; / &lt;strong&gt;&lt;a href="https://dev.to/Learn-Node-js-Express-in-One-Post-Complete-Tutorial-Event-Loop-Middleware-Quick-Start/"&gt;Learn Node.js in One Post&lt;/a&gt;&lt;/strong&gt; — instrument these backends with OTel.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Observability is what separates a system you &lt;em&gt;operate&lt;/em&gt; from one that &lt;em&gt;surprises&lt;/em&gt; you. The five stages here — metrics, logs, traces, OpenTelemetry, SLOs + alerting — cover everything from a single counter to a vendor-neutral, SLO-driven, burn-rate-alerted production setup. The two habits that pay off forever: &lt;strong&gt;emit structured logs with a trace ID&lt;/strong&gt; (so you can always follow a request), and &lt;strong&gt;alert on symptoms via burn rate, not on guessed causes&lt;/strong&gt; (so the page always means something). Expose one &lt;code&gt;/metrics&lt;/code&gt; endpoint, scrape it with Prometheus, draw one dashboard in Grafana — once you've watched a request's latency show up in a graph, the rest follows.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://pyshine.com/Learn-Observability-in-One-Post-Complete-Tutorial-Metrics-Logs-Traces-OpenTelemetry-Quick-Start/" rel="noopener noreferrer"&gt;pyshine.com&lt;/a&gt;. The full tutorial with all 5 hand-drawn diagrams lives there — this cross-post is kept in sync via canonical URL.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>observability</category>
      <category>opentelemetry</category>
      <category>prometheus</category>
      <category>grafana</category>
    </item>
    <item>
      <title>Learn Operating Systems in a Single Post: A Complete Tutorial From Processes and Scheduling to Virtual Memory and Concurrency</title>
      <dc:creator>PyShine</dc:creator>
      <pubDate>Thu, 23 Jul 2026 12:30:46 +0000</pubDate>
      <link>https://dev.to/pyshine/learn-operating-systems-in-a-single-post-a-complete-tutorial-from-processes-and-scheduling-to-2o6i</link>
      <guid>https://dev.to/pyshine/learn-operating-systems-in-a-single-post-a-complete-tutorial-from-processes-and-scheduling-to-2o6i</guid>
      <description>&lt;h1&gt;
  
  
  Learn Operating Systems in a Single Post: Complete Tutorial From Processes and Scheduling to Virtual Memory and Concurrency
&lt;/h1&gt;

&lt;p&gt;An operating system is the program that makes a computer usable: it manages the CPU, memory, disks, and devices so that dozens of programs can run at once without colliding, and so that a crash in one doesn't take down the rest. Whether you're debugging a hang, reasoning about a data race, or sizing a server, the OS concepts are the substrate under everything. This single post teaches the whole subject in five stages, with hand-drawn diagrams and runnable commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning Roadmap
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpbx4njjlhbuz0sw75km9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpbx4njjlhbuz0sw75km9.png" alt="Operating Systems Roadmap" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The roadmap moves from processes (Stage 1), to how the CPU is shared (Stage 2), to how memory is shared and faked (Stage 3), to the hardest part — concurrency (Stage 4), and finally I/O and filesystems (Stage 5).&lt;/p&gt;




&lt;h2&gt;
  
  
  Stage 1 — Processes
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;process&lt;/strong&gt; is a running program: an instance of an executable plus its address space, open files, registers, and scheduling state. The OS keeps each process's metadata in a &lt;strong&gt;Process Control Block (PCB)&lt;/strong&gt; — the PID, registers, program counter, stack pointer, open file table, memory map, and scheduling info.&lt;/p&gt;

&lt;h3&gt;
  
  
  Process states
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj2qvwm20ef1l3gqnnltp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj2qvwm20ef1l3gqnnltp.png" alt="Process States + Context Switch" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A process moves among states:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;New&lt;/strong&gt; → &lt;strong&gt;Ready&lt;/strong&gt; (admitted)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ready&lt;/strong&gt; → &lt;strong&gt;Running&lt;/strong&gt; (dispatched by the scheduler)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Running&lt;/strong&gt; → &lt;strong&gt;Ready&lt;/strong&gt; (time-slice expires, preempted)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Running&lt;/strong&gt; → &lt;strong&gt;Waiting/Blocked&lt;/strong&gt; (asks for I/O, or waits on a lock)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Waiting&lt;/strong&gt; → &lt;strong&gt;Ready&lt;/strong&gt; (I/O completes, lock released)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Running&lt;/strong&gt; → &lt;strong&gt;Terminated&lt;/strong&gt; (exit)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The context switch
&lt;/h3&gt;

&lt;p&gt;Switching the CPU from process A to process B means &lt;strong&gt;saving A's full state&lt;/strong&gt; (registers, PC, memory map) into A's PCB and &lt;strong&gt;loading B's state&lt;/strong&gt; from B's PCB. This is pure overhead — the CPU does no useful user work during a switch — so the scheduler balances "don't switch too often" against "don't let one process hog the CPU."&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;fork&lt;/code&gt;, &lt;code&gt;exec&lt;/code&gt;, &lt;code&gt;wait&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;On Unix, creating a process is two steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;fork()&lt;/code&gt;&lt;/strong&gt; — duplicates the calling process; the child gets a copy of the parent's memory (copy-on-write, so it's cheap until either writes).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;exec(path)&lt;/code&gt;&lt;/strong&gt; — replaces the current process image with a new program (the child now runs a different binary).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;wait()&lt;/code&gt;&lt;/strong&gt; — a parent blocks until a child exits (and reaps its exit status, preventing a zombie).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ps &lt;span class="nt"&gt;-ef&lt;/span&gt;                &lt;span class="c"&gt;# see processes (PID, PPID, state, command)&lt;/span&gt;
top / htop            &lt;span class="c"&gt;# live process view, sorted by CPU/mem&lt;/span&gt;
strace &lt;span class="nt"&gt;-p&lt;/span&gt; &amp;lt;pid&amp;gt;       &lt;span class="c"&gt;# trace the syscalls a process makes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; A child that exits but whose parent never &lt;code&gt;wait()&lt;/code&gt;s becomes a &lt;strong&gt;zombie&lt;/strong&gt; (it's done, but its entry stays until reaped). A parent that dies leaves children as &lt;strong&gt;orphans&lt;/strong&gt;, re-parented to &lt;code&gt;init&lt;/code&gt; (PID 1). The classic leak in long-running servers is not reaping children.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 2 — Scheduling
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;scheduler&lt;/strong&gt; decides which ready process runs next. Goals: fairness (no starvation), responsiveness (low latency for interactive work), throughput (high overall work/sec), and honoring priorities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Preemptive vs cooperative
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cooperative&lt;/strong&gt; — a process runs until it voluntarily yields (calls a blocking syscall). A buggy/infinite-loop process freezes the machine. (Early Windows, old Mac.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preemptive&lt;/strong&gt; — the OS sets a timer interrupt and forcibly takes the CPU back after a &lt;strong&gt;time slice&lt;/strong&gt; (quantum, ~1–10 ms). Every modern general-purpose OS is preemptive.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Algorithms
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Algorithm&lt;/th&gt;
&lt;th&gt;Idea&lt;/th&gt;
&lt;th&gt;Tradeoff&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FCFS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;first-come, first-served&lt;/td&gt;
&lt;td&gt;simple, but short jobs wait behind long ones (convoy effect)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Round-robin&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;each ready process gets a quantum, then rotates&lt;/td&gt;
&lt;td&gt;fair, responsive; context-switch overhead&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Priority&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;highest priority first&lt;/td&gt;
&lt;td&gt;starvation of low priority (fix: aging)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SJF / SRTF&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;shortest job first&lt;/td&gt;
&lt;td&gt;optimal throughput, but you can't know job length&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Multilevel feedback&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;queues by priority; demote CPU hogs, promote I/O-bound&lt;/td&gt;
&lt;td&gt;what real OSes approximate (Linux CFS)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; Priority inversion — a low-priority process holds a lock a high-priority process needs, and medium-priority processes keep running so the high one waits indefinitely. Fix with &lt;strong&gt;priority inheritance&lt;/strong&gt; (the lock holder temporarily inherits the waiter's priority). This bit the Mars Pathfinder rover in 1997.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stage 3 — Memory
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Virtual memory
&lt;/h3&gt;

&lt;p&gt;Every process sees its own &lt;strong&gt;virtual address space&lt;/strong&gt; (e.g. 0 to 2⁴⁸), as if it had the whole machine to itself. The OS + MMU translate virtual addresses to &lt;strong&gt;physical frames&lt;/strong&gt; via a &lt;strong&gt;page table&lt;/strong&gt;. This gives isolation (a process can't touch another's memory) and the illusion of more RAM than exists (via demand paging + swap).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr6t0ffviam8cpyvidliy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr6t0ffviam8cpyvidliy.png" alt="Virtual Memory: Pages, TLB, Faults" width="799" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Pages, TLB, page faults
&lt;/h3&gt;

&lt;p&gt;Memory is divided into fixed-size &lt;strong&gt;pages&lt;/strong&gt; (typically 4 KB); physical RAM into &lt;strong&gt;frames&lt;/strong&gt; of the same size. The page table maps &lt;strong&gt;virtual page number → physical frame number&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TLB (translation lookaside buffer)&lt;/strong&gt; — a hardware cache of recent translations. A TLB hit makes translation free; a miss walks the page table in RAM (slow). This is why page size and locality matter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Page fault&lt;/strong&gt; — the CPU accesses a virtual page not currently in RAM (it's on disk/swap). The OS pauses the process, fetches the frame from disk, updates the table, and retries. This is &lt;strong&gt;demand paging&lt;/strong&gt; — pages are loaded only when touched.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swap&lt;/strong&gt; — when RAM is full, the OS evicts pages to disk (swap space). A system that's swapping is catastrophically slow (disk is ~10,000× slower than RAM).&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; &lt;strong&gt;Thrashing&lt;/strong&gt; — if the working set (pages in active use) exceeds RAM, every access faults, the OS swaps in a page that immediately gets evicted, and the system spends all its time swapping instead of computing. The fix is more RAM or a smaller working set, not a faster CPU.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Replacement policies
&lt;/h3&gt;

&lt;p&gt;When a frame must be evicted, which one? &lt;strong&gt;LRU&lt;/strong&gt; (least recently used) is good but expensive to track exactly; OSes approximate it (clock algorithm, second-chance). &lt;strong&gt;FIFO&lt;/strong&gt; is simple but can evict a page that's about to be used. &lt;strong&gt;Belady's&lt;/strong&gt; (optimal, evict the one not used for longest) is unimplementable (you can't see the future) but is the benchmark.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stage 4 — Concurrency
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Threads vs processes
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;thread&lt;/strong&gt; is a unit of execution &lt;em&gt;within&lt;/em&gt; a process. Threads in the same process &lt;strong&gt;share memory&lt;/strong&gt; (code, heap, open files); each has its own stack and registers. Creating a thread is cheaper than a process (no address-space copy), but shared memory is the source of most concurrency bugs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvq5svig30at67c6a9691.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvq5svig30at67c6a9691.png" alt="Concurrency: Threads, Locks, Deadlock" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Race conditions and locks
&lt;/h3&gt;

&lt;p&gt;When two threads read-modify-write a shared variable without synchronization, the result depends on timing — a &lt;strong&gt;race condition&lt;/strong&gt;. &lt;code&gt;count++&lt;/code&gt; is not atomic: it's load → add → store, and a thread can be preempted between any two steps. The fix is a &lt;strong&gt;mutex&lt;/strong&gt; (mutual exclusion lock): only one thread holds it at a time, so the critical section runs atomically.&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;import&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;
&lt;span class="n"&gt;lock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;          &lt;span class="c1"&gt;# acquire; auto-release on exit
&lt;/span&gt;    &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Synchronization primitives
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Primitive&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mutex&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;one thread at a time in a critical section&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Semaphore&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;N threads at a time (counting)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Condition variable&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;a thread waits for a condition; another signals when it's met&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Read/write lock&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;many readers OR one writer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Atomic&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;lock-free single-word read-modify-write (&lt;code&gt;atomic_int&lt;/code&gt;, &lt;code&gt;compare_and_swap&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Barrier&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;all threads wait until everyone reaches a point&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; Hold a lock for the &lt;em&gt;shortest&lt;/em&gt; time possible. Long critical sections kill concurrency and scalability. If you must do slow work, copy the data out under the lock and do the work unlocked.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Deadlock
&lt;/h3&gt;

&lt;p&gt;Deadlock is when threads are stuck waiting on each other forever. The four &lt;strong&gt;Coffman conditions&lt;/strong&gt; that together cause it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Mutual exclusion&lt;/strong&gt; — a resource is held by one thread.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hold and wait&lt;/strong&gt; — a thread holds one resource while waiting for another.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No preemption&lt;/strong&gt; — you can't force-release a held resource.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Circular wait&lt;/strong&gt; — A waits on B, B waits on C, C waits on A.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Break any one condition to prevent deadlock. The common technique: &lt;strong&gt;acquire locks in a consistent global order&lt;/strong&gt; (so a circular wait can't form), or use &lt;strong&gt;lock timeouts&lt;/strong&gt; / &lt;strong&gt;try-lock&lt;/strong&gt; with backoff.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; The single most common deadlock cause is acquiring two locks in opposite orders in two code paths (&lt;code&gt;lock A then B&lt;/code&gt; vs &lt;code&gt;lock B then A&lt;/code&gt;). Pick a project-wide lock ordering and never violate it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Livelock and starvation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Livelock&lt;/strong&gt; — threads aren't blocked but keep reacting to each other and make no progress (two people in a hallway both stepping aside in sync forever).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Starvation&lt;/strong&gt; — a thread never gets scheduled (e.g. a low-priority thread behind high-priority ones). Fix with &lt;strong&gt;aging&lt;/strong&gt; (raise priority the longer a thread waits).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Stage 5 — I/O + Filesystems
&lt;/h2&gt;

&lt;h3&gt;
  
  
  File descriptors
&lt;/h3&gt;

&lt;p&gt;On Unix, &lt;strong&gt;everything is a file&lt;/strong&gt; — regular files, pipes, sockets, devices — all accessed via an integer &lt;strong&gt;file descriptor (fd)&lt;/strong&gt;. A process has an fd table; &lt;code&gt;read&lt;/code&gt;/&lt;code&gt;write&lt;/code&gt;/&lt;code&gt;close&lt;/code&gt; work on fds. fds 0/1/2 are stdin/stdout/stderr.&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;ls&lt;/span&gt; /proc/&lt;span class="nv"&gt;$$&lt;/span&gt;/fd        &lt;span class="c"&gt;# your process's open file descriptors&lt;/span&gt;
lsof &lt;span class="nt"&gt;-p&lt;/span&gt; &amp;lt;pid&amp;gt;          &lt;span class="c"&gt;# what files/sockets a process has open&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Buffers and the page cache
&lt;/h3&gt;

&lt;p&gt;The OS caches disk reads in the &lt;strong&gt;page cache&lt;/strong&gt; (RAM). A &lt;code&gt;read()&lt;/code&gt; may return from the cache (fast) or trigger a disk I/O (slow). Writes are buffered and flushed later — &lt;code&gt;fsync()&lt;/code&gt; forces a flush so the data survives a crash. This is why databases call &lt;code&gt;fsync&lt;/code&gt; on commit: otherwise a power loss could lose acknowledged writes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; A &lt;code&gt;write()&lt;/code&gt; returning success means "in the OS buffer," not "on disk." For durability you need &lt;code&gt;fsync()&lt;/code&gt; (or open with &lt;code&gt;O_SYNC&lt;/code&gt;). Losing acknowledged data on a power fault is a classic data-loss bug.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Inodes and filesystems
&lt;/h3&gt;

&lt;p&gt;A file's metadata (size, permissions, timestamps, block pointers) lives in an &lt;strong&gt;inode&lt;/strong&gt;; the directory is just a map from name → inode number. The filesystem (ext4, APFS, NTFS, XFS) manages how inodes and data blocks are laid out on disk. Hard links (same inode, multiple names) vs symlinks (a file containing another path).&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;/proc&lt;/code&gt; and introspection
&lt;/h3&gt;

&lt;p&gt;Linux exposes per-process and kernel state as virtual files under &lt;code&gt;/proc&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/proc/&amp;lt;pid&amp;gt;/status&lt;/code&gt; — memory, state, threads.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/proc/&amp;lt;pid&amp;gt;/maps&lt;/code&gt; — virtual memory layout.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/proc/meminfo&lt;/code&gt;, &lt;code&gt;/proc/cpuinfo&lt;/code&gt;, &lt;code&gt;/proc/loadavg&lt;/code&gt; — system-wide.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Syscalls
&lt;/h3&gt;

&lt;p&gt;The user/kernel boundary is crossed by &lt;strong&gt;syscalls&lt;/strong&gt;: &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;write&lt;/code&gt;, &lt;code&gt;open&lt;/code&gt;, &lt;code&gt;close&lt;/code&gt;, &lt;code&gt;fork&lt;/code&gt;, &lt;code&gt;exec&lt;/code&gt;, &lt;code&gt;mmap&lt;/code&gt;, &lt;code&gt;socket&lt;/code&gt;, &lt;code&gt;brk&lt;/code&gt;, &lt;code&gt;ioctl&lt;/code&gt;. Each is a (relatively expensive) context switch into kernel mode. Tools like &lt;code&gt;strace&lt;/code&gt; show every syscall a process makes — invaluable for debugging "what is my program actually doing?"&lt;/p&gt;




&lt;h2&gt;
  
  
  The Toolchain
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff2pqs8qtk2xolm3hqslj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff2pqs8qtk2xolm3hqslj.png" alt="Kernels, Syscalls, Tools" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Kernels&lt;/strong&gt;: Linux (monolithic + loadable modules), Windows NT (hybrid), macOS XNU (hybrid + Mach microkernel core), FreeBSD.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Syscalls&lt;/strong&gt;: the user/kernel API. &lt;code&gt;strace&lt;/code&gt;/&lt;code&gt;dtrace&lt;/code&gt;/&lt;code&gt;frace&lt;/code&gt; trace them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inspect&lt;/strong&gt;: &lt;code&gt;/proc&lt;/code&gt;, &lt;code&gt;strace&lt;/code&gt;, &lt;code&gt;lsof&lt;/code&gt;, &lt;code&gt;perf&lt;/code&gt;, &lt;code&gt;vmstat&lt;/code&gt;, &lt;code&gt;iostat&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shell + FS&lt;/strong&gt;: bash/sh (userland), inodes, fd tables, page cache.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Quick-Start Checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Learn process states&lt;/strong&gt; and the context switch — every perf conversation starts here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Understand fork/exec/wait&lt;/strong&gt; — how Unix spawns, and the zombie/orphan pitfalls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Know preemptive scheduling&lt;/strong&gt; and why round-robin + priorities approximate real OSes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Master virtual memory&lt;/strong&gt;: pages, TLB, page faults, swap, and why thrashing kills.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Know threads vs processes&lt;/strong&gt; — cheap vs isolated, and why shared memory causes races.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protect shared state with locks&lt;/strong&gt;, and acquire locks in a consistent global order.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name the four deadlock conditions&lt;/strong&gt; and how breaking one prevents it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remember &lt;code&gt;write()&lt;/code&gt; ≠ on-disk&lt;/strong&gt; — &lt;code&gt;fsync()&lt;/code&gt; for durability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;strace&lt;/code&gt;, &lt;code&gt;lsof&lt;/code&gt;, &lt;code&gt;/proc&lt;/code&gt;&lt;/strong&gt; when "what is my program doing?" isn't obvious.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reason about the page cache&lt;/strong&gt; — most "slow disk" problems are actually cache misses.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Common Pitfalls
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zombies / orphans&lt;/strong&gt; — not reaping children with &lt;code&gt;wait()&lt;/code&gt;. Fix with a SIGCHLD handler or explicit reaping.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Priority inversion&lt;/strong&gt; — a low-priority holder blocks a high-priority waiter. Fix with priority inheritance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thrashing&lt;/strong&gt; — working set &amp;gt; RAM; adding CPU doesn't help, adding RAM does.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Holding locks across I/O&lt;/strong&gt; — serializes all threads on a slow operation; copy-and-release instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lock-ordering deadlocks&lt;/strong&gt; — acquire locks in a consistent order across all code paths.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trusting &lt;code&gt;write()&lt;/code&gt; durability&lt;/strong&gt; — buffer ≠ disk; &lt;code&gt;fsync()&lt;/code&gt; to be sure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spinlocks on single-core&lt;/strong&gt; — a spinlock holding the only CPU starves everyone; use a blocking lock.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assuming atomicity&lt;/strong&gt; — &lt;code&gt;x++&lt;/code&gt; is not atomic; use an atomic primitive or a lock.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pages.cs.wisc.edu/~remzi/OSTEP/" rel="noopener noreferrer"&gt;Operating Systems: Three Easy Pieces&lt;/a&gt; by Arpaci-Dusseau — free, the modern standard textbook&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://man7.org/tlpi/" rel="noopener noreferrer"&gt;The Linux Programming Interface&lt;/a&gt; by Michael Kerrisk — the syscall bible&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://beej.us/guide/bgnet/" rel="noopener noreferrer"&gt;Beej's Guide to Network Programming&lt;/a&gt; — sockets and IPC&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://man7.org/linux/man-pages/" rel="noopener noreferrer"&gt;man pages&lt;/a&gt; — &lt;code&gt;man 2 fork&lt;/code&gt;, &lt;code&gt;man 2 mmap&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.kernel.org/doc/html/latest/" rel="noopener noreferrer"&gt;Linux Kernel docs&lt;/a&gt; — when you want the source of truth&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Related guides
&lt;/h2&gt;

&lt;p&gt;OS concepts underpin every systems topic — these PyShine tutorials apply them directly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Linux-CLI-in-One-Post-Complete-Tutorial-Files-Processes-Permissions-Quick-Start/"&gt;Learn Linux CLI in One Post&lt;/a&gt;&lt;/strong&gt; — processes, file descriptors, permissions are the userland surface of the OS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Computer-Networking-in-One-Post-Complete-Tutorial-OSI-TCP-UDP-HTTP-Quick-Start/"&gt;Learn Computer Networking in One Post&lt;/a&gt;&lt;/strong&gt; — sockets are file descriptors; the network stack is kernel-side OS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Bash-in-One-Post-Complete-Tutorial-Pipelines-Functions-Scripts-Quick-Start/"&gt;Learn Bash in One Post&lt;/a&gt;&lt;/strong&gt; — pipes, redirects, signals, and background jobs are OS primitives driven from the shell.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Rust-in-One-Post-Complete-Tutorial-Ownership-Borrow-Async-Quick-Start/"&gt;Learn Rust in One Post&lt;/a&gt;&lt;/strong&gt; — Rust's ownership model is a compile-time answer to the data races this stage is about.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Git-in-One-Post-Complete-Tutorial-Branches-Rebase-Workflows-Quick-Start/"&gt;Learn Go in One Post&lt;/a&gt;&lt;/strong&gt; — goroutines (M:N scheduled) are the language-level take on OS threads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/Learn-Docker-in-One-Post-Complete-Tutorial-Dockerfile-Volumes-Compose-Quick-Start/"&gt;Learn Docker in One Post&lt;/a&gt;&lt;/strong&gt; — containers are OS namespaces + cgroups; this is the underlying mechanism.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Operating systems is the subject where "it works on my machine" stops being an acceptable answer. The five stages here — processes, scheduling, memory, concurrency, I/O — are the mental model a senior engineer uses every time a server is slow, a program hangs, or a deploy misbehaves. Spend a day per stage, run &lt;code&gt;strace&lt;/code&gt; on a real process, watch a page fault, and write a program that deadlocks then fix it. The concepts only stick once you've felt the bugs they prevent.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://pyshine.com/Learn-Operating-Systems-in-One-Post-Complete-Tutorial-Processes-Memory-Threads-Quick-Start/" rel="noopener noreferrer"&gt;pyshine.com&lt;/a&gt;. The full tutorial with all 5 hand-drawn diagrams lives there — this cross-post is kept in sync via canonical URL.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>operatingsystems</category>
      <category>os</category>
      <category>processes</category>
      <category>virtualmemory</category>
    </item>
  </channel>
</rss>
