<?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: Tahsin Abrar</title>
    <description>The latest articles on DEV Community by Tahsin Abrar (@tahsin000).</description>
    <link>https://dev.to/tahsin000</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%2F1084553%2Fd57c59ef-8617-4868-a1e8-7fe07493b0be.png</url>
      <title>DEV Community: Tahsin Abrar</title>
      <link>https://dev.to/tahsin000</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tahsin000"/>
    <language>en</language>
    <item>
      <title>How to Check Laravel Page Memory Usage Without Guessing</title>
      <dc:creator>Tahsin Abrar</dc:creator>
      <pubDate>Fri, 18 Sep 2026 20:02:36 +0000</pubDate>
      <link>https://dev.to/tahsin000/how-to-check-laravel-page-memory-usage-without-guessing-3mli</link>
      <guid>https://dev.to/tahsin000/how-to-check-laravel-page-memory-usage-without-guessing-3mli</guid>
      <description>&lt;p&gt;A Laravel page once started feeling unusually heavy.&lt;/p&gt;

&lt;p&gt;The server was running, the page was loading, and there was no obvious error. But one question kept coming up:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How much memory is this page actually using?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tools like &lt;code&gt;htop&lt;/code&gt; were useful for checking the server, but they did not give me a simple answer for one specific Laravel request.&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%2Fykernsp0bhdfyty2rjun.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%2Fykernsp0bhdfyty2rjun.png" alt="diagram" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The easiest solution was already available in PHP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nb"&gt;memory_get_peak_usage&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With one small log entry, I could see the peak memory usage of each Laravel request.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Quick Solution
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public/index.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After Laravel handles the request, add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nf"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s1"&gt;'Peak Memory Usage: '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt;
    &lt;span class="nb"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;memory_get_peak_usage&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="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1024&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="mf"&gt;.&lt;/span&gt;
    &lt;span class="s1"&gt;' MB'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;handleRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;capture&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="nf"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s1"&gt;'Peak Memory Usage: '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt;
    &lt;span class="nb"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;memory_get_peak_usage&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="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1024&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="mf"&gt;.&lt;/span&gt;
    &lt;span class="s1"&gt;' MB'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now open the Laravel page you want to test.&lt;/p&gt;

&lt;p&gt;Then watch the log:&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;tail&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; storage/logs/laravel.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Refresh the page.&lt;/p&gt;

&lt;p&gt;You should see something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Peak Memory Usage: 74.38 MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the peak amount of memory PHP allocated while processing that request.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Is Useful
&lt;/h2&gt;

&lt;p&gt;Imagine checking several pages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Home        → 42 MB
Dashboard   → 55 MB
Users       → 63 MB
Reports     → 210 MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reports page immediately stands out.&lt;/p&gt;

&lt;p&gt;Instead of saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This page feels heavy.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;you now have something measurable:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This page reaches around 210 MB while the others stay below 70 MB.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That gives you a much better place to start debugging.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Real Laravel Example
&lt;/h2&gt;

&lt;p&gt;Suppose the reports page contains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your database has 100,000 users, Laravel may load all of them into memory.&lt;/p&gt;

&lt;p&gt;If the page only needs 50 users, use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For large background processing, you might use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$users&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Process 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;p&gt;After changing the code, test the page again.&lt;/p&gt;

&lt;p&gt;You may get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before → 210 MB
After  → 68 MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can clearly see whether the optimization helped.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Does &lt;code&gt;memory_get_peak_usage(true)&lt;/code&gt; Mean?
&lt;/h2&gt;

&lt;p&gt;This function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nb"&gt;memory_get_peak_usage&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;returns the highest amount of memory allocated during the current PHP request.&lt;/p&gt;

&lt;p&gt;PHP returns the value in bytes.&lt;/p&gt;

&lt;p&gt;So we convert it to megabytes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nb"&gt;memory_get_peak_usage&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="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And round it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nb"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;memory_get_peak_usage&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="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1024&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gives us an easy-to-read result like:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  Why Not Just Use &lt;code&gt;htop&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;htop&lt;/code&gt; is still very useful.&lt;/p&gt;

&lt;p&gt;Use it when you want to understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;total server memory&lt;/li&gt;
&lt;li&gt;CPU usage&lt;/li&gt;
&lt;li&gt;PHP-FPM workers&lt;/li&gt;
&lt;li&gt;MySQL usage&lt;/li&gt;
&lt;li&gt;overall server health&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But if your question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How much peak memory did this Laravel request use?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;then &lt;code&gt;memory_get_peak_usage(true)&lt;/code&gt; is much more direct.&lt;/p&gt;

&lt;p&gt;They solve different problems.&lt;/p&gt;




&lt;h2&gt;
  
  
  What to Check If Memory Is Too High
&lt;/h2&gt;

&lt;p&gt;If one page uses much more memory than others, start by checking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;large &lt;code&gt;Model::all()&lt;/code&gt; queries&lt;/li&gt;
&lt;li&gt;unnecessary Eloquent relationships&lt;/li&gt;
&lt;li&gt;huge collections&lt;/li&gt;
&lt;li&gt;large file or image processing&lt;/li&gt;
&lt;li&gt;PDF or Excel generation&lt;/li&gt;
&lt;li&gt;reports loading too much data&lt;/li&gt;
&lt;li&gt;loops that keep large amounts of data in memory&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main rule is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do not load everything into memory if you only need a small part of it.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Test More Than Once
&lt;/h2&gt;

&lt;p&gt;Do not rely on one request.&lt;/p&gt;

&lt;p&gt;Refresh the same page a few times:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request 1 → 71.8 MB
Request 2 → 69.9 MB
Request 3 → 70.2 MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Small differences are normal.&lt;/p&gt;

&lt;p&gt;What matters is the general pattern.&lt;/p&gt;

&lt;p&gt;If one page consistently stays around 70 MB and another stays around 200 MB, that difference is worth investigating.&lt;/p&gt;




&lt;h2&gt;
  
  
  Important: Remove the Logger After Testing
&lt;/h2&gt;

&lt;p&gt;This code is for debugging:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nf"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not leave it running forever on a busy production site.&lt;/p&gt;

&lt;p&gt;Otherwise every page request will create another log entry.&lt;/p&gt;

&lt;p&gt;A simple workflow is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Measure
↓
Find the expensive page
↓
Optimize
↓
Measure again
↓
Remove the logger
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;p&gt;Laravel performance debugging becomes much easier when you stop guessing and start measuring.&lt;/p&gt;

&lt;p&gt;If you only want to know how much peak memory a Laravel request uses, you do not need a complicated monitoring setup.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nb"&gt;memory_get_peak_usage&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;log the result, refresh the page, and check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;storage/logs/laravel.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A small measurement can quickly tell you which page deserves your attention.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Measure first. Optimize second.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>backend</category>
      <category>laravel</category>
      <category>performance</category>
      <category>php</category>
    </item>
    <item>
      <title>My Public IP Kept Changing While Connecting TablePlus to DigitalOcean - How I Fixed It</title>
      <dc:creator>Tahsin Abrar</dc:creator>
      <pubDate>Sun, 30 Aug 2026 18:10:25 +0000</pubDate>
      <link>https://dev.to/tahsin000/my-public-ip-kept-changing-while-connecting-tableplus-to-digitalocean-heres-how-i-fixed-it-56f4</link>
      <guid>https://dev.to/tahsin000/my-public-ip-kept-changing-while-connecting-tableplus-to-digitalocean-heres-how-i-fixed-it-56f4</guid>
      <description>&lt;p&gt;Recently, I ran into a small but confusing problem while connecting &lt;strong&gt;TablePlus&lt;/strong&gt; to a &lt;strong&gt;DigitalOcean Managed Database&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;At first, I thought something was wrong with TablePlus.&lt;/p&gt;

&lt;p&gt;It wasn’t.&lt;/p&gt;

&lt;p&gt;The real problem was my public IP address.&lt;/p&gt;

&lt;p&gt;Here’s what happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;I created a managed database on DigitalOcean and wanted to connect to it from my laptop using TablePlus.&lt;/p&gt;

&lt;p&gt;DigitalOcean has a &lt;strong&gt;Trusted Sources&lt;/strong&gt; option where you need to allow the IP addresses that can connect to your database.&lt;/p&gt;

&lt;p&gt;So I searched:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What is my IP?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I copied the IP, added it to DigitalOcean, and tried to connect.&lt;/p&gt;

&lt;p&gt;But things were not working as expected.&lt;/p&gt;

&lt;p&gt;Then I decided to check my public IP from the terminal.&lt;/p&gt;

&lt;p&gt;I ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl api.ipify.org
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and also:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl ifconfig.me
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That made things even more confusing.&lt;/p&gt;

&lt;p&gt;The output looked messy because the IP appeared together with some &lt;code&gt;curl&lt;/code&gt; progress information.&lt;/p&gt;

&lt;p&gt;For a moment, I wasn’t even sure which number was my actual IP.&lt;/p&gt;

&lt;h2&gt;
  
  
  First, I Cleaned Up the Command
&lt;/h2&gt;

&lt;p&gt;Instead of using plain &lt;code&gt;curl&lt;/code&gt;, I used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-4&lt;/span&gt; &lt;span class="nt"&gt;-sS&lt;/span&gt; https://ifconfig.me/ip &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the output was simple:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Much better.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;-4&lt;/code&gt; makes sure I get an IPv4 address, and &lt;code&gt;-sS&lt;/code&gt; removes the unnecessary progress output.&lt;/p&gt;

&lt;p&gt;But then I noticed something strange.&lt;/p&gt;

&lt;p&gt;A little later, I checked again and got something like:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;My public IP had changed.&lt;/p&gt;

&lt;p&gt;That was the actual problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Was My IP Changing?
&lt;/h2&gt;

&lt;p&gt;My internet connection was using a &lt;strong&gt;dynamic public IP&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Depending on your ISP, this can also happen when you are behind something like &lt;strong&gt;CGNAT&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So even though I was using the same laptop and the same internet connection, the public IP seen by DigitalOcean could change.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;might later become:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;If DigitalOcean only trusts the first IP, TablePlus will stop connecting after the IP changes.&lt;/p&gt;

&lt;p&gt;That explained why the connection sometimes worked and sometimes didn’t.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Solved It
&lt;/h2&gt;

&lt;p&gt;In my case, I needed to make sure DigitalOcean trusted the correct source address.&lt;/p&gt;

&lt;p&gt;For temporary development, the simplest solution is to check your current IP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-4&lt;/span&gt; &lt;span class="nt"&gt;-sS&lt;/span&gt; https://ifconfig.me/ip &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add that IP to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DigitalOcean
→ Database
→ Network Access
→ Trusted Sources
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After updating the trusted IP, I tried TablePlus again.&lt;/p&gt;

&lt;p&gt;And this time:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connected.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The database loaded normally.&lt;/p&gt;

&lt;h2&gt;
  
  
  What About Using &lt;code&gt;/24&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;While debugging this, I also learned about CIDR ranges such as:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;/24&lt;/code&gt; allows the whole range from:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



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

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

&lt;/div&gt;



&lt;p&gt;This can be useful if you &lt;strong&gt;know&lt;/strong&gt; your traffic can come from that whole range.&lt;/p&gt;

&lt;p&gt;But there is an important catch.&lt;/p&gt;

&lt;p&gt;If you see:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;and later:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;you should &lt;strong&gt;not automatically assume&lt;/strong&gt; that you should allow:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;That would allow many more IP addresses than just yours.&lt;/p&gt;

&lt;p&gt;For local development, I prefer allowing my current IP unless I know exactly which CIDR range I should trust.&lt;/p&gt;

&lt;p&gt;If your IP changes very often, a static IP, VPN with a fixed exit IP, or another stable connection can be a cleaner long-term solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;The funny thing is, I started debugging this as a TablePlus issue.&lt;/p&gt;

&lt;p&gt;Then I thought it was a DigitalOcean issue.&lt;/p&gt;

&lt;p&gt;But in the end, it was mostly a networking issue.&lt;/p&gt;

&lt;p&gt;If you ever face the same problem, check your public IP first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-4&lt;/span&gt; &lt;span class="nt"&gt;-sS&lt;/span&gt; https://ifconfig.me/ip &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then compare it with the IP in your DigitalOcean Trusted Sources.&lt;/p&gt;

&lt;p&gt;Sometimes a database connection problem has nothing to do with the database at all.&lt;/p&gt;

&lt;p&gt;And that was the small networking lesson I learned while trying to connect TablePlus to DigitalOcean.&lt;/p&gt;

</description>
      <category>digitalocean</category>
      <category>database</category>
      <category>networking</category>
      <category>devops</category>
    </item>
    <item>
      <title>How I Debugged a phpMyAdmin 500 Error While Importing a Large SQL File on Laragon</title>
      <dc:creator>Tahsin Abrar</dc:creator>
      <pubDate>Tue, 25 Aug 2026 12:28:37 +0000</pubDate>
      <link>https://dev.to/tahsin000/how-i-debugged-a-phpmyadmin-500-error-while-importing-a-large-sql-file-on-laragon-245i</link>
      <guid>https://dev.to/tahsin000/how-i-debugged-a-phpmyadmin-500-error-while-importing-a-large-sql-file-on-laragon-245i</guid>
      <description>&lt;p&gt;I recently ran into a weird issue while working on a Laravel project on Windows using &lt;strong&gt;Laragon&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Everything was working fine until I tried to import a database through phpMyAdmin.&lt;/p&gt;

&lt;p&gt;Instead of an SQL error, phpMyAdmin simply returned:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Internal Server Error
The server encountered an internal error or misconfiguration...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No useful message. Just HTTP 500.&lt;/p&gt;

&lt;p&gt;My SQL file was around &lt;strong&gt;97 MB&lt;/strong&gt;, so at first I thought it was probably a PHP upload limit issue.&lt;/p&gt;

&lt;p&gt;It wasn't that simple.&lt;/p&gt;

&lt;p&gt;Here is how I debugged it.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Check which PHP configuration is actually running
&lt;/h2&gt;

&lt;p&gt;From Laragon Terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php &lt;span class="nt"&gt;--ini&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I checked the important error settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php.exe &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"echo 'error_log=' . ini_get('error_log') . PHP_EOL;"&lt;/span&gt;
php.exe &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"echo 'log_errors=' . ini_get('log_errors') . PHP_EOL;"&lt;/span&gt;
php.exe &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"echo 'display_errors=' . ini_get('display_errors') . PHP_EOL;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My output was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;error_log=D:/C-data/laragon/tmp/php_errors.log
log_errors=1
display_errors=1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One small Laragon/Git Bash issue I also found was:&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;type &lt;/span&gt;php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php is aliased to `winpty php.exe'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because of that, commands like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php &lt;span class="nt"&gt;-i&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;sometimes returned:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stdout is not a tty
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using &lt;code&gt;php.exe&lt;/code&gt; directly avoids that problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Check the PHP error log
&lt;/h2&gt;

&lt;p&gt;My PHP error log was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;D:/C-data/laragon/tmp/php_errors.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I reproduced the import error and checked it:&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;tail&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 50 /d/C-data/laragon/tmp/php_errors.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing useful appeared.&lt;/p&gt;

&lt;p&gt;That was an important clue.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Make sure browser PHP and CLI PHP use the same php.ini
&lt;/h2&gt;

&lt;p&gt;I created a temporary file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="nb"&gt;phpinfo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then opened it through the browser.&lt;/p&gt;

&lt;p&gt;Important values were:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Server API: CGI/FastCGI
PHP Version: 8.4.4
Loaded Configuration File:
D:\C-data\laragon\bin\php\php-8.4.4-nts-Win32-vs17-x64\php.ini
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My PHP limits were already high enough:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;upload_max_filesize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;512M&lt;/span&gt;
&lt;span class="py"&gt;post_max_size&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;512M&lt;/span&gt;
&lt;span class="py"&gt;memory_limit&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;512M&lt;/span&gt;
&lt;span class="py"&gt;max_execution_time&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;36000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the 97 MB SQL file should have been allowed by PHP.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Check Apache logs
&lt;/h2&gt;

&lt;p&gt;I located the Apache error log with:&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;grep&lt;/span&gt; &lt;span class="nt"&gt;-Ri&lt;/span&gt; &lt;span class="s2"&gt;"ErrorLog"&lt;/span&gt; /d/C-data/laragon/etc/apache2 /d/C-data/laragon/bin/apache 2&amp;gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;D:/C-data/laragon/bin/apache/httpd-2.4.54-win64-VS16/logs/error.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&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;tail&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 50 /d/C-data/laragon/bin/apache/httpd-2.4.54-win64-VS16/logs/error.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Still nothing useful.&lt;/p&gt;

&lt;p&gt;So I checked the access log:&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;tail&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 30 /d/C-data/laragon/bin/apache/httpd-2.4.54-win64-VS16/logs/access.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally found:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /phpmyadmin/index.php?route=/import HTTP/1.1" 500 530
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the failure was definitely happening during the phpMyAdmin import request.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Check Laragon's FastCGI request limit
&lt;/h2&gt;

&lt;p&gt;Because Laragon was using &lt;code&gt;mod_fcgid&lt;/code&gt;, I searched its config:&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;grep&lt;/span&gt; &lt;span class="nt"&gt;-RniE&lt;/span&gt; &lt;span class="s2"&gt;"Fcgid|Timeout|LogLevel"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
/d/C-data/laragon/etc/apache2 &lt;span class="se"&gt;\&lt;/span&gt;
/d/C-data/laragon/bin/apache/httpd-2.4.54-win64-VS16/conf 2&amp;gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That led me to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;D:\C-data\laragon\etc\apache2\fcgid.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside I found:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;FcgidIOTimeout 36000
FcgidConnectTimeout 16
FcgidMaxRequestLen 81310720
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important one was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;FcgidMaxRequestLen 81310720
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is only around &lt;strong&gt;77.5 MiB&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;My SQL file was:&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; &lt;span class="nt"&gt;-lh&lt;/span&gt; &lt;span class="s2"&gt;"/c/Users/Asus/Downloads/shabujglobal-crm (1).sql"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

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

&lt;/div&gt;



&lt;p&gt;So PHP allowed &lt;code&gt;512M&lt;/code&gt;, but Apache FastCGI only allowed around &lt;code&gt;77.5 MiB&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That mismatch can cause the request to fail before phpMyAdmin can properly process the upload.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Increase &lt;code&gt;FcgidMaxRequestLen&lt;/code&gt;
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;D:\C-data\laragon\etc\apache2\fcgid.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;FcgidMaxRequestLen 81310720
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;FcgidMaxRequestLen 536870912
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gives FastCGI a &lt;strong&gt;512 MiB&lt;/strong&gt; request limit.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Save → Laragon → Restart All
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and retry the import.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. If the next error is “Maximum execution time of 300 seconds exceeded”
&lt;/h2&gt;

&lt;p&gt;After fixing the request-size limit, I hit another possible bottleneck:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Fatal error: Maximum execution time of 300 seconds exceeded
in DbiMysqli.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see this, &lt;strong&gt;do not edit &lt;code&gt;DbiMysqli.php&lt;/code&gt;&lt;/strong&gt;. That is only where the timeout becomes visible.&lt;/p&gt;

&lt;p&gt;Instead, open:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;D:\C-data\laragon\etc\apps\phpMyAdmin\config.inc.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$cfg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'ExecTimeLimit'&lt;/span&gt;&lt;span class="p"&gt;]&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the file contains a closing &lt;code&gt;?&amp;gt;&lt;/code&gt;, add the line before it.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Save → Laragon → Restart All
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and retry the import.&lt;/p&gt;

&lt;p&gt;Setting &lt;code&gt;ExecTimeLimit&lt;/code&gt; to &lt;code&gt;0&lt;/code&gt; removes phpMyAdmin's execution-time limit for operations such as large imports.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In my debugging session, this was the latest issue I reached. I had not yet fully confirmed the final import after changing this setting, so treat this as the next configuration to verify if your import dies exactly at 300 seconds.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The main lesson
&lt;/h2&gt;

&lt;p&gt;When phpMyAdmin gives you a generic &lt;code&gt;500 Internal Server Error&lt;/code&gt; while importing a large SQL file on Laragon, don't only check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="err"&gt;upload_max_filesize&lt;/span&gt;
&lt;span class="err"&gt;post_max_size&lt;/span&gt;
&lt;span class="err"&gt;memory_limit&lt;/span&gt;
&lt;span class="err"&gt;max_execution_time&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also check these two layers:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$cfg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'ExecTimeLimit'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my case, the debugging path was basically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;97 MB SQL file
↓
PHP limits looked fine
↓
No useful PHP error log
↓
Apache access log confirmed /import returned 500
↓
FastCGI request limit was smaller than the SQL file
↓
After that, phpMyAdmin's 300-second execution limit became the next bottleneck
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the part that can easily be missed: &lt;strong&gt;PHP may allow a large upload while Apache/FastCGI or phpMyAdmin still blocks it for a completely different reason.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And if you create a temporary &lt;code&gt;phpinfo()&lt;/code&gt; file while debugging, delete it afterward.&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>mysql</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Deploy Laravel and Vue to cPanel Automatically with GitHub Actions</title>
      <dc:creator>Tahsin Abrar</dc:creator>
      <pubDate>Thu, 30 Jul 2026 11:36:52 +0000</pubDate>
      <link>https://dev.to/tahsin000/deploy-laravel-and-vue-to-cpanel-automatically-with-github-actions-43jd</link>
      <guid>https://dev.to/tahsin000/deploy-laravel-and-vue-to-cpanel-automatically-with-github-actions-43jd</guid>
      <description>&lt;h1&gt;
  
  
  Automatically Deploy Laravel and Vue to cPanel with GitHub Actions
&lt;/h1&gt;

&lt;p&gt;Uploading a ZIP file to cPanel after every small code change becomes frustrating very quickly.&lt;/p&gt;

&lt;p&gt;You fix a bug, build the Vue frontend, create an archive, open cPanel File Manager, upload it, extract it, run migrations, clear Laravel caches, and finally check whether the application still works.&lt;/p&gt;

&lt;p&gt;The code change may take two minutes. The deployment takes much longer.&lt;/p&gt;

&lt;p&gt;A better approach is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Push the code to GitHub and let GitHub Actions build and deploy the application to cPanel automatically.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After the initial setup, deployment becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Fix checkout issue"&lt;/span&gt;
git push origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub Actions handles the remaining work.&lt;/p&gt;




&lt;h2&gt;
  
  
  The deployment architecture
&lt;/h2&gt;

&lt;p&gt;This guide uses a &lt;strong&gt;push-based deployment&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%2F6hoeub11eqkriael3mlv.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%2F6hoeub11eqkriael3mlv.png" alt="diagram" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The cPanel server does &lt;strong&gt;not&lt;/strong&gt; clone or pull the private repository. Therefore, it does not need a GitHub deploy key, personal access token, or account-level GitHub SSH key.&lt;/p&gt;

&lt;p&gt;GitHub Actions checks out its own repository with the workflow's built-in &lt;code&gt;GITHUB_TOKEN&lt;/code&gt;. The workflow only needs a separate SSH key for this direction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GitHub Actions → cPanel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps the setup simpler and avoids storing an unnecessary GitHub repository credential on the production server.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the workflow will do
&lt;/h2&gt;

&lt;p&gt;Every push to the &lt;code&gt;main&lt;/code&gt; branch will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check out the private repository.&lt;/li&gt;
&lt;li&gt;Install Laravel's production dependencies.&lt;/li&gt;
&lt;li&gt;Install frontend dependencies and build the Vue/Vite assets.&lt;/li&gt;
&lt;li&gt;Package the application without &lt;code&gt;.env&lt;/code&gt;, &lt;code&gt;storage&lt;/code&gt;, or server-managed files.&lt;/li&gt;
&lt;li&gt;Connect to cPanel through SSH.&lt;/li&gt;
&lt;li&gt;Upload and extract the new application files.&lt;/li&gt;
&lt;li&gt;Preserve the production &lt;code&gt;.env&lt;/code&gt;, uploaded files, logs, and SSL challenge files.&lt;/li&gt;
&lt;li&gt;Run database migrations and Laravel optimization commands.&lt;/li&gt;
&lt;li&gt;Signal existing queue workers to restart.&lt;/li&gt;
&lt;li&gt;Check a public production URL when one is configured.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is a practical deployment for small and medium applications. It is not a zero-downtime or automatic-rollback system.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick reference (read this first)
&lt;/h2&gt;

&lt;p&gt;Everything below is one GitHub secret. No separate "variables" — one place, one mental model, less context-switching.&lt;/p&gt;

&lt;p&gt;Run each command where noted, take the output, paste it into the matching GitHub secret in Step 7. Replace &lt;code&gt;PORT&lt;/code&gt;, &lt;code&gt;HOST&lt;/code&gt;, and &lt;code&gt;USER&lt;/code&gt; with your own values — get &lt;code&gt;CPANEL_HOST&lt;/code&gt;, &lt;code&gt;CPANEL_PORT&lt;/code&gt;, and &lt;code&gt;CPANEL_USER&lt;/code&gt; first (rows 3–5), then use those same values in the commands below them.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Secret&lt;/th&gt;
&lt;th&gt;What it is&lt;/th&gt;
&lt;th&gt;Where to run it&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CPANEL_USER&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;cPanel username&lt;/td&gt;
&lt;td&gt;cPanel Terminal&lt;/td&gt;
&lt;td&gt;&lt;code&gt;whoami&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CPANEL_HOST&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;cPanel server hostname&lt;/td&gt;
&lt;td&gt;cPanel dashboard&lt;/td&gt;
&lt;td&gt;Look under &lt;strong&gt;General Information&lt;/strong&gt;, or ask your host&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CPANEL_PORT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;SSH port&lt;/td&gt;
&lt;td&gt;cPanel dashboard&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Security → SSH Access&lt;/strong&gt; (usually &lt;code&gt;22&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;APP_DIR&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Absolute path to app folder&lt;/td&gt;
&lt;td&gt;cPanel Terminal&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cd ~/example.com &amp;amp;&amp;amp; pwd&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PHP_BIN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Path to CLI PHP executable&lt;/td&gt;
&lt;td&gt;cPanel Terminal&lt;/td&gt;
&lt;td&gt;&lt;code&gt;command -v php&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CPANEL_SSH_PRIVATE_KEY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Deploy SSH private key&lt;/td&gt;
&lt;td&gt;Local machine&lt;/td&gt;
&lt;td&gt;Generate once (Step 4): &lt;code&gt;ssh-keygen -t ed25519 -C "github-actions-to-cpanel" -f ~/.ssh/deploy-keys/cpanel_production -N ""&lt;/code&gt; then read it: &lt;code&gt;cat ~/.ssh/deploy-keys/cpanel_production&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CPANEL_KNOWN_HOSTS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Verified SSH host fingerprint&lt;/td&gt;
&lt;td&gt;Local machine&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ssh-keyscan -p PORT HOST &amp;gt; cpanel_known_hosts&lt;/code&gt; then &lt;code&gt;cat cpanel_known_hosts&lt;/code&gt; — e.g. &lt;code&gt;ssh-keyscan -p 22 server123.hosting-company.com &amp;gt; cpanel_known_hosts&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;APP_URL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Public site URL&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Your domain, e.g. &lt;code&gt;https://example.com&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HEALTHCHECK_URL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Optional public health-check URL&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;APP_URL&lt;/code&gt; + &lt;code&gt;/up&lt;/code&gt;, e.g. &lt;code&gt;https://example.com/up&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;CPANEL_KNOWN_HOSTS&lt;/code&gt; needs the real &lt;code&gt;HOST&lt;/code&gt; and &lt;code&gt;PORT&lt;/code&gt; filled in, not the placeholder text — that is the value most people get wrong (it fails as "Host key verification failed" later, see Common errors). Verify the fingerprint against your host before trusting it (Step 6 has the full command with &lt;code&gt;ssh-keygen -lf&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Full explanation of each value, and why, is in Steps 1–7 below.&lt;/p&gt;




&lt;h2&gt;
  
  
  Before you start
&lt;/h2&gt;

&lt;p&gt;You need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Laravel application using Vue and Vite.&lt;/li&gt;
&lt;li&gt;A private GitHub repository.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;composer.lock&lt;/code&gt; and &lt;code&gt;package-lock.json&lt;/code&gt; committed to the repository.&lt;/li&gt;
&lt;li&gt;SSH access to the cPanel account.&lt;/li&gt;
&lt;li&gt;A domain whose document root can point to Laravel's &lt;code&gt;public&lt;/code&gt; directory.&lt;/li&gt;
&lt;li&gt;The correct command-line PHP executable for the cPanel account.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some shared-hosting providers disable SSH, symbolic links, long-running queue workers, or custom document roots. Confirm those features with your hosting provider before continuing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Prepare the application directory
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cPanel → Advanced → Terminal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the cPanel username and home directory:&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;whoami
echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the Laravel application directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/example.com"&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/example.com"&lt;/span&gt;
&lt;span class="nb"&gt;pwd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/home/exampleuser/example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save this complete path. It will become the GitHub variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;APP_DIR=/home/exampleuser/example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configure the domain document root as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/home/exampleuser/example.com/public
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not point the domain to the Laravel project root. Only the &lt;code&gt;public&lt;/code&gt; directory should be web-accessible.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Create the production &lt;code&gt;.env&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The workflow will never upload &lt;code&gt;.env&lt;/code&gt; from GitHub.&lt;/p&gt;

&lt;p&gt;Create the production file directly on cPanel:&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;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/example.com"&lt;/span&gt;

&lt;span class="nb"&gt;umask &lt;/span&gt;077
&lt;span class="nb"&gt;touch&lt;/span&gt; .env
&lt;span class="nb"&gt;chmod &lt;/span&gt;600 .env

nano .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A minimal example looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;APP_NAME="My Application"
APP_ENV=production
APP_KEY=base64:YOUR_APPLICATION_KEY
APP_DEBUG=false
APP_URL=https://example.com

LOG_CHANNEL=stack
LOG_LEVEL=error

DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=exampleuser_database
DB_USERNAME=exampleuser_dbuser
DB_PASSWORD=YOUR_DATABASE_PASSWORD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the mail, cache, session, queue, API, and other values required by your application.&lt;/p&gt;

&lt;p&gt;Generate an application key from a trusted local copy of the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan key:generate &lt;span class="nt"&gt;--show&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the generated value into the production &lt;code&gt;.env&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Never replace an existing production &lt;code&gt;APP_KEY&lt;/code&gt; unless you understand the consequences. Changing it can invalidate encrypted cookies and make existing encrypted data unreadable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Find the correct PHP executable
&lt;/h2&gt;

&lt;p&gt;In cPanel Terminal, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; php
php &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On some servers, the correct binary may look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/opt/cpanel/ea-php84/root/usr/bin/php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test the selected binary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/opt/cpanel/ea-php84/root/usr/bin/php &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the working path as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PHP_BIN=/opt/cpanel/ea-php84/root/usr/bin/php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use the PHP version required by your project. The PHP version used to build Composer dependencies in GitHub Actions should match the production server as closely as possible.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Generate the deployment SSH key
&lt;/h2&gt;

&lt;p&gt;Generate this key on your trusted local computer, not inside the repository and not on the cPanel server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.ssh/deploy-keys"&lt;/span&gt;
&lt;span class="nb"&gt;chmod &lt;/span&gt;700 &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.ssh/deploy-keys"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create an Ed25519 key pair:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-t&lt;/span&gt; ed25519 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"github-actions-to-cpanel"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.ssh/deploy-keys/cpanel_production"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-N&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cpanel_production       ← Private key
cpanel_production.pub   ← Public key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key locations will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Private key → GitHub Actions secret
Public key  → cPanel authorized keys
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The private key must never be committed to the repository.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5: Authorize the public key in cPanel
&lt;/h2&gt;

&lt;p&gt;Display the public key locally:&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;cat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.ssh/deploy-keys/cpanel_production.pub"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the complete line.&lt;/p&gt;

&lt;p&gt;In cPanel, open:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Security
→ SSH Access
→ Manage SSH Keys
→ Import Key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste the public key and import it. Then select:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Importing and authorizing may be separate actions in cPanel.&lt;/p&gt;

&lt;p&gt;You can also add the public key from cPanel Terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.ssh"&lt;/span&gt;
&lt;span class="nb"&gt;chmod &lt;/span&gt;700 &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.ssh"&lt;/span&gt;

nano &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.ssh/authorized_keys"&lt;/span&gt;
&lt;span class="nb"&gt;chmod &lt;/span&gt;600 &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.ssh/authorized_keys"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste the public key on its own line.&lt;/p&gt;

&lt;h3&gt;
  
  
  Optional key restrictions
&lt;/h3&gt;

&lt;p&gt;After the deployment works, you may restrict the key in &lt;code&gt;authorized_keys&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;no-agent-forwarding,no-port-forwarding,no-X11-forwarding,no-pty ssh-ed25519 AAAAC3... github-actions-to-cpanel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These options disable common SSH features that the deployment does not need. Test the normal key first because hosting configurations vary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test the connection
&lt;/h3&gt;

&lt;p&gt;From your local computer, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.ssh/deploy-keys/cpanel_production"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; YOUR_SSH_PORT &lt;span class="se"&gt;\&lt;/span&gt;
  YOUR_CPANEL_USER@YOUR_CPANEL_HOST
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.ssh/deploy-keys/cpanel_production"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 22 &lt;span class="se"&gt;\&lt;/span&gt;
  exampleuser@server123.hosting-company.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not continue until this connection works.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 6: Verify and save the SSH host key
&lt;/h2&gt;

&lt;p&gt;Do not make the workflow trust whatever SSH key it receives during deployment.&lt;/p&gt;

&lt;p&gt;From a trusted computer, collect the server's public host keys:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keyscan &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; YOUR_SSH_PORT &lt;span class="se"&gt;\&lt;/span&gt;
  YOUR_CPANEL_HOST &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; cpanel_known_hosts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Display their fingerprints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-lf&lt;/span&gt; cpanel_known_hosts &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-E&lt;/span&gt; sha256
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the fingerprint with your hosting provider or hosting control panel. After verification, copy the complete contents of &lt;code&gt;cpanel_known_hosts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If the hosting provider later changes the server's SSH host key, the deployment will fail until this value is updated. That failure is safer than silently trusting an unexpected server.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 7: Add GitHub secrets
&lt;/h2&gt;

&lt;p&gt;Open the repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Settings
→ Secrets and variables
→ Actions
→ Secrets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add every value below as a &lt;strong&gt;secret&lt;/strong&gt; (not a repository variable). One list, one context — the workflow only ever reads &lt;code&gt;secrets.*&lt;/code&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Secret&lt;/th&gt;
&lt;th&gt;Example / value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CPANEL_SSH_PRIVATE_KEY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Complete private deployment key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CPANEL_KNOWN_HOSTS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Verified contents of &lt;code&gt;cpanel_known_hosts&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;APP_DIR&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/home/exampleuser/example.com&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CPANEL_HOST&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;server123.hosting-company.com&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CPANEL_PORT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;22&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CPANEL_USER&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;exampleuser&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PHP_BIN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/opt/cpanel/ea-php84/root/usr/bin/php&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;APP_URL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://example.com&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HEALTHCHECK_URL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;https://example.com/up&lt;/code&gt; (optional)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Display the private key locally:&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;cat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.ssh/deploy-keys/cpanel_production"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the complete value, including:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-----BEGIN OPENSSH PRIVATE KEY-----
...
-----END OPENSSH PRIVATE KEY-----
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not paste the &lt;code&gt;.pub&lt;/code&gt; key into &lt;code&gt;CPANEL_SSH_PRIVATE_KEY&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CPANEL_KNOWN_HOSTS&lt;/code&gt;, &lt;code&gt;APP_DIR&lt;/code&gt;, &lt;code&gt;CPANEL_HOST&lt;/code&gt;, &lt;code&gt;CPANEL_PORT&lt;/code&gt;, &lt;code&gt;CPANEL_USER&lt;/code&gt;, &lt;code&gt;PHP_BIN&lt;/code&gt;, &lt;code&gt;APP_URL&lt;/code&gt;, and &lt;code&gt;HEALTHCHECK_URL&lt;/code&gt; are not confidential by nature, but storing them as secrets keeps every deployment input in one place instead of split across &lt;code&gt;vars&lt;/code&gt; and &lt;code&gt;secrets&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;APP_URL&lt;/code&gt; is the public application URL used during the frontend build. &lt;code&gt;HEALTHCHECK_URL&lt;/code&gt; is optional; a lightweight public health endpoint is better than a page that requires authentication.&lt;/p&gt;

&lt;h3&gt;
  
  
  Optional production environment
&lt;/h3&gt;

&lt;p&gt;On GitHub plans that support environments for private repositories, you can move the same secrets and variables into a protected environment named &lt;code&gt;production&lt;/code&gt;. Then add this line to the deployment job:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A protected environment can add approvals and restrict which branches may deploy. If your plan does not support those features for a private repository, repository-level secrets and variables still work.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 8: Add the GitHub Actions workflow
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.github/workflows/deploy-cpanel.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy Laravel and Vue to cPanel&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&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;concurrency&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production-cpanel&lt;/span&gt;
  &lt;span class="na"&gt;cancel-in-progress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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;APP_DIR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.APP_DIR }}&lt;/span&gt;
  &lt;span class="na"&gt;CPANEL_HOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.CPANEL_HOST }}&lt;/span&gt;
  &lt;span class="na"&gt;CPANEL_PORT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.CPANEL_PORT || '22' }}&lt;/span&gt;
  &lt;span class="na"&gt;CPANEL_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.CPANEL_USER }}&lt;/span&gt;
  &lt;span class="na"&gt;PHP_BIN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.PHP_BIN }}&lt;/span&gt;
  &lt;span class="na"&gt;APP_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.APP_URL }}&lt;/span&gt;
  &lt;span class="na"&gt;HEALTHCHECK_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.HEALTHCHECK_URL }}&lt;/span&gt;
  &lt;span class="na"&gt;NODE_VERSION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;24"&lt;/span&gt;
  &lt;span class="na"&gt;NODE_OPTIONS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;--max-old-space-size=4096&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;build-and-deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build and deploy production&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;timeout-minutes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;35&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout repository&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v7&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;fetch-depth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
          &lt;span class="na"&gt;persist-credentials&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up PHP&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;shivammathur/setup-php@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;php-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8.4"&lt;/span&gt;
          &lt;span class="na"&gt;coverage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;none&lt;/span&gt;
          &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;composer:v2&lt;/span&gt;
          &lt;span class="na"&gt;extensions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mbstring, xml, ctype, iconv, intl, pdo_mysql, bcmath, curl, fileinfo, gd, openssl, zip&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 production PHP dependencies&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;COMPOSER_ALLOW_SUPERUSER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1"&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;composer validate --no-check-publish&lt;/span&gt;

          &lt;span class="s"&gt;composer install \&lt;/span&gt;
            &lt;span class="s"&gt;--no-dev \&lt;/span&gt;
            &lt;span class="s"&gt;--prefer-dist \&lt;/span&gt;
            &lt;span class="s"&gt;--no-interaction \&lt;/span&gt;
            &lt;span class="s"&gt;--no-progress \&lt;/span&gt;
            &lt;span class="s"&gt;--optimize-autoloader&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Node.js&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v7&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.NODE_VERSION }}&lt;/span&gt;
          &lt;span class="na"&gt;cache&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;cache-dependency-path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;package-lock.json&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 frontend dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci --no-audit --no-fund&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build frontend assets&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;VITE_APP_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.APP_URL }}&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Verify the build&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;test -f artisan&lt;/span&gt;
          &lt;span class="s"&gt;test -f vendor/autoload.php&lt;/span&gt;
          &lt;span class="s"&gt;test -d public/build&lt;/span&gt;
          &lt;span class="s"&gt;test -f public/build/manifest.json&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;Validate deployment configuration&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;SSH_PRIVATE_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.CPANEL_SSH_PRIVATE_KEY }}&lt;/span&gt;
          &lt;span class="na"&gt;SSH_KNOWN_HOSTS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.CPANEL_KNOWN_HOSTS }}&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;set -Eeuo pipefail&lt;/span&gt;

          &lt;span class="s"&gt;: "${APP_DIR:?Missing APP_DIR variable}"&lt;/span&gt;
          &lt;span class="s"&gt;: "${CPANEL_HOST:?Missing CPANEL_HOST variable}"&lt;/span&gt;
          &lt;span class="s"&gt;: "${CPANEL_PORT:?Missing CPANEL_PORT variable}"&lt;/span&gt;
          &lt;span class="s"&gt;: "${CPANEL_USER:?Missing CPANEL_USER variable}"&lt;/span&gt;
          &lt;span class="s"&gt;: "${PHP_BIN:?Missing PHP_BIN variable}"&lt;/span&gt;
          &lt;span class="s"&gt;: "${SSH_PRIVATE_KEY:?Missing CPANEL_SSH_PRIVATE_KEY secret}"&lt;/span&gt;
          &lt;span class="s"&gt;: "${SSH_KNOWN_HOSTS:?Missing CPANEL_KNOWN_HOSTS secret}"&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;Configure SSH&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;SSH_PRIVATE_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.CPANEL_SSH_PRIVATE_KEY }}&lt;/span&gt;
          &lt;span class="na"&gt;SSH_KNOWN_HOSTS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.CPANEL_KNOWN_HOSTS }}&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;install -m 700 -d "$HOME/.ssh"&lt;/span&gt;

          &lt;span class="s"&gt;printf '%s\n' "$SSH_PRIVATE_KEY" &amp;gt; "$HOME/.ssh/id_ed25519"&lt;/span&gt;
          &lt;span class="s"&gt;chmod 600 "$HOME/.ssh/id_ed25519"&lt;/span&gt;

          &lt;span class="s"&gt;printf '%s\n' "$SSH_KNOWN_HOSTS" &amp;gt; "$HOME/.ssh/known_hosts"&lt;/span&gt;
          &lt;span class="s"&gt;chmod 600 "$HOME/.ssh/known_hosts"&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;Package the application&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;tar -czf /tmp/app-deploy.tar.gz \&lt;/span&gt;
            &lt;span class="s"&gt;--exclude='./.git' \&lt;/span&gt;
            &lt;span class="s"&gt;--exclude='./.github' \&lt;/span&gt;
            &lt;span class="s"&gt;--exclude='./node_modules' \&lt;/span&gt;
            &lt;span class="s"&gt;--exclude='./.env' \&lt;/span&gt;
            &lt;span class="s"&gt;--exclude='./.env.*' \&lt;/span&gt;
            &lt;span class="s"&gt;--exclude='./storage' \&lt;/span&gt;
            &lt;span class="s"&gt;--exclude='./public/storage' \&lt;/span&gt;
            &lt;span class="s"&gt;--exclude='./public/hot' \&lt;/span&gt;
            &lt;span class="s"&gt;--exclude='./public/.well-known' \&lt;/span&gt;
            &lt;span class="s"&gt;--exclude='./.user.ini' \&lt;/span&gt;
            &lt;span class="s"&gt;--exclude='./php.ini' \&lt;/span&gt;
            &lt;span class="s"&gt;--exclude='./tests' \&lt;/span&gt;
            &lt;span class="s"&gt;.&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to cPanel&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;set -Eeuo pipefail&lt;/span&gt;

          &lt;span class="s"&gt;SSH=(&lt;/span&gt;
            &lt;span class="s"&gt;ssh&lt;/span&gt;
            &lt;span class="s"&gt;-i "$HOME/.ssh/id_ed25519"&lt;/span&gt;
            &lt;span class="s"&gt;-p "$CPANEL_PORT"&lt;/span&gt;
            &lt;span class="s"&gt;-o BatchMode=yes&lt;/span&gt;
            &lt;span class="s"&gt;-o ConnectTimeout=15&lt;/span&gt;
            &lt;span class="s"&gt;-o IdentitiesOnly=yes&lt;/span&gt;
            &lt;span class="s"&gt;-o StrictHostKeyChecking=yes&lt;/span&gt;
            &lt;span class="s"&gt;-o UserKnownHostsFile="$HOME/.ssh/known_hosts"&lt;/span&gt;
            &lt;span class="s"&gt;"$CPANEL_USER@$CPANEL_HOST"&lt;/span&gt;
          &lt;span class="s"&gt;)&lt;/span&gt;

          &lt;span class="s"&gt;SCP=(&lt;/span&gt;
            &lt;span class="s"&gt;scp&lt;/span&gt;
            &lt;span class="s"&gt;-i "$HOME/.ssh/id_ed25519"&lt;/span&gt;
            &lt;span class="s"&gt;-P "$CPANEL_PORT"&lt;/span&gt;
            &lt;span class="s"&gt;-o BatchMode=yes&lt;/span&gt;
            &lt;span class="s"&gt;-o ConnectTimeout=15&lt;/span&gt;
            &lt;span class="s"&gt;-o IdentitiesOnly=yes&lt;/span&gt;
            &lt;span class="s"&gt;-o StrictHostKeyChecking=yes&lt;/span&gt;
            &lt;span class="s"&gt;-o UserKnownHostsFile="$HOME/.ssh/known_hosts"&lt;/span&gt;
          &lt;span class="s"&gt;)&lt;/span&gt;

          &lt;span class="s"&gt;"${SSH[@]}" \&lt;/span&gt;
            &lt;span class="s"&gt;"mkdir -p '$APP_DIR' &amp;amp;&amp;amp; test -f '$APP_DIR/.env' &amp;amp;&amp;amp; test -x '$PHP_BIN'" || {&lt;/span&gt;
              &lt;span class="s"&gt;echo '::error::APP_DIR, production .env, or PHP_BIN is invalid.'&lt;/span&gt;
              &lt;span class="s"&gt;exit 1&lt;/span&gt;
            &lt;span class="s"&gt;}&lt;/span&gt;

          &lt;span class="s"&gt;"${SSH[@]}" \&lt;/span&gt;
            &lt;span class="s"&gt;"cd '$APP_DIR' &amp;amp;&amp;amp; if [ -f artisan ]; then '$PHP_BIN' artisan down --retry=60 || true; fi"&lt;/span&gt;

          &lt;span class="s"&gt;bring_application_up() {&lt;/span&gt;
            &lt;span class="s"&gt;"${SSH[@]}" \&lt;/span&gt;
              &lt;span class="s"&gt;"cd '$APP_DIR' &amp;amp;&amp;amp; if [ -f artisan ]; then '$PHP_BIN' artisan up; fi"&lt;/span&gt;
          &lt;span class="s"&gt;}&lt;/span&gt;

          &lt;span class="s"&gt;remote_update_started=0&lt;/span&gt;

          &lt;span class="s"&gt;handle_failure() {&lt;/span&gt;
            &lt;span class="s"&gt;status=$?&lt;/span&gt;

            &lt;span class="s"&gt;if [ "$status" -ne 0 ]; then&lt;/span&gt;
              &lt;span class="s"&gt;if [ "$remote_update_started" -eq 0 ]; then&lt;/span&gt;
                &lt;span class="s"&gt;bring_application_up || true&lt;/span&gt;
              &lt;span class="s"&gt;else&lt;/span&gt;
                &lt;span class="s"&gt;echo '::warning::Deployment failed after the remote update started.'&lt;/span&gt;
                &lt;span class="s"&gt;echo '::warning::The application may remain in maintenance mode for inspection.'&lt;/span&gt;
              &lt;span class="s"&gt;fi&lt;/span&gt;
            &lt;span class="s"&gt;fi&lt;/span&gt;
          &lt;span class="s"&gt;}&lt;/span&gt;

          &lt;span class="s"&gt;trap handle_failure EXIT&lt;/span&gt;

          &lt;span class="s"&gt;"${SCP[@]}" \&lt;/span&gt;
            &lt;span class="s"&gt;/tmp/app-deploy.tar.gz \&lt;/span&gt;
            &lt;span class="s"&gt;"$CPANEL_USER@$CPANEL_HOST:$APP_DIR/app-deploy.tar.gz"&lt;/span&gt;

          &lt;span class="s"&gt;remote_update_started=1&lt;/span&gt;

          &lt;span class="s"&gt;"${SSH[@]}" \&lt;/span&gt;
            &lt;span class="s"&gt;"APP_DIR='$APP_DIR' PHP_BIN='$PHP_BIN' bash -se" &amp;lt;&amp;lt;'REMOTE'&lt;/span&gt;
          &lt;span class="s"&gt;set -Eeuo pipefail&lt;/span&gt;

          &lt;span class="s"&gt;cd "$APP_DIR"&lt;/span&gt;

          &lt;span class="s"&gt;test -f app-deploy.tar.gz&lt;/span&gt;

          &lt;span class="s"&gt;tar -xzf app-deploy.tar.gz --overwrite&lt;/span&gt;
          &lt;span class="s"&gt;rm app-deploy.tar.gz&lt;/span&gt;

          &lt;span class="s"&gt;test -f .env&lt;/span&gt;
          &lt;span class="s"&gt;test -f artisan&lt;/span&gt;
          &lt;span class="s"&gt;test -f vendor/autoload.php&lt;/span&gt;
          &lt;span class="s"&gt;test -f public/build/manifest.json&lt;/span&gt;

          &lt;span class="s"&gt;mkdir -p \&lt;/span&gt;
            &lt;span class="s"&gt;storage/app/public \&lt;/span&gt;
            &lt;span class="s"&gt;storage/framework/cache/data \&lt;/span&gt;
            &lt;span class="s"&gt;storage/framework/sessions \&lt;/span&gt;
            &lt;span class="s"&gt;storage/framework/views \&lt;/span&gt;
            &lt;span class="s"&gt;storage/logs \&lt;/span&gt;
            &lt;span class="s"&gt;bootstrap/cache&lt;/span&gt;

          &lt;span class="s"&gt;chmod -R ug+rwX storage bootstrap/cache&lt;/span&gt;

          &lt;span class="s"&gt;"$PHP_BIN" artisan package:discover --ansi&lt;/span&gt;
          &lt;span class="s"&gt;"$PHP_BIN" artisan config:clear&lt;/span&gt;
          &lt;span class="s"&gt;"$PHP_BIN" artisan route:clear&lt;/span&gt;
          &lt;span class="s"&gt;"$PHP_BIN" artisan view:clear&lt;/span&gt;
          &lt;span class="s"&gt;"$PHP_BIN" artisan event:clear || true&lt;/span&gt;
          &lt;span class="s"&gt;"$PHP_BIN" artisan migrate --force&lt;/span&gt;

          &lt;span class="s"&gt;if [ ! -L public/storage ]; then&lt;/span&gt;
            &lt;span class="s"&gt;"$PHP_BIN" artisan storage:link&lt;/span&gt;
          &lt;span class="s"&gt;fi&lt;/span&gt;

          &lt;span class="s"&gt;"$PHP_BIN" artisan optimize&lt;/span&gt;
          &lt;span class="s"&gt;"$PHP_BIN" artisan queue:restart || true&lt;/span&gt;

          &lt;span class="s"&gt;chmod -R ug+rwX storage bootstrap/cache&lt;/span&gt;
          &lt;span class="s"&gt;REMOTE&lt;/span&gt;

          &lt;span class="s"&gt;bring_application_up&lt;/span&gt;
          &lt;span class="s"&gt;trap - EXIT&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;Check the production URL&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;${{ secrets.HEALTHCHECK_URL != '' }}&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;curl \&lt;/span&gt;
            &lt;span class="s"&gt;--fail \&lt;/span&gt;
            &lt;span class="s"&gt;--silent \&lt;/span&gt;
            &lt;span class="s"&gt;--show-error \&lt;/span&gt;
            &lt;span class="s"&gt;--location \&lt;/span&gt;
            &lt;span class="s"&gt;--retry 5 \&lt;/span&gt;
            &lt;span class="s"&gt;--retry-delay 5 \&lt;/span&gt;
            &lt;span class="s"&gt;--retry-connrefused \&lt;/span&gt;
            &lt;span class="s"&gt;--max-time 30 \&lt;/span&gt;
            &lt;span class="s"&gt;"$HEALTHCHECK_URL" &amp;gt; /dev/null&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;Write deployment summary&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;echo '## Deployment completed'&lt;/span&gt;
            &lt;span class="s"&gt;echo&lt;/span&gt;
            &lt;span class="s"&gt;echo "- Directory: \`$APP_DIR\`"&lt;/span&gt;
            &lt;span class="s"&gt;echo '- Composer dependencies built on GitHub Actions'&lt;/span&gt;
            &lt;span class="s"&gt;echo '- Vue and Vite assets built on GitHub Actions'&lt;/span&gt;
            &lt;span class="s"&gt;echo '- Production .env and storage preserved'&lt;/span&gt;
          &lt;span class="s"&gt;} &amp;gt;&amp;gt; "$GITHUB_STEP_SUMMARY"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The example uses PHP 8.4 and Node.js 24. Change both versions to match your application and production server.&lt;/p&gt;

&lt;p&gt;The workflow gives &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; only read access to repository contents. It also disables persisted checkout credentials because the remaining steps do not need authenticated Git commands.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 9: Run the first deployment
&lt;/h2&gt;

&lt;p&gt;Commit the workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add .github/workflows/deploy-cpanel.yml
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Add automatic cPanel deployment"&lt;/span&gt;
git push origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GitHub repository → Actions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Select the workflow and follow the logs.&lt;/p&gt;

&lt;p&gt;After it finishes, verify the application from cPanel:&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;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/example.com"&lt;/span&gt;

&lt;span class="nv"&gt;PHP_BIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/opt/cpanel/ea-php84/root/usr/bin/php

&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PHP_BIN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; artisan about
&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PHP_BIN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; artisan migrate:status

&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; public/build
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; public/storage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open the production URL.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the workflow preserves
&lt;/h2&gt;

&lt;p&gt;The deployment archive excludes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.env
.env.*
storage/
public/storage/
public/.well-known/
.user.ini
php.ini
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prevents the workflow from replacing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Production credentials and API keys.&lt;/li&gt;
&lt;li&gt;User-uploaded files.&lt;/li&gt;
&lt;li&gt;Application logs and sessions.&lt;/li&gt;
&lt;li&gt;The public storage symbolic link.&lt;/li&gt;
&lt;li&gt;Server-managed SSL challenge files.&lt;/li&gt;
&lt;li&gt;Hosting-specific PHP configuration files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The workflow includes Composer's &lt;code&gt;vendor&lt;/code&gt; directory and Vite's &lt;code&gt;public/build&lt;/code&gt; directory because both are built on GitHub Actions before deployment.&lt;/p&gt;




&lt;h2&gt;
  
  
  Important security notes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Do not add a GitHub deploy key to cPanel for this workflow
&lt;/h3&gt;

&lt;p&gt;The server does not run &lt;code&gt;git pull&lt;/code&gt;. GitHub Actions checks out the repository and sends a prepared archive to cPanel.&lt;/p&gt;

&lt;p&gt;Adding a cPanel-to-GitHub key would create an unnecessary credential on the production server. If the server were compromised, that credential could allow the attacker to clone the repository it belongs to.&lt;/p&gt;

&lt;h3&gt;
  
  
  Never put secrets in &lt;code&gt;VITE_*&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Values prefixed with &lt;code&gt;VITE_&lt;/code&gt; may become part of the browser's JavaScript bundle.&lt;/p&gt;

&lt;p&gt;Safe examples:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Unsafe examples:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Only put public frontend configuration in &lt;code&gt;VITE_*&lt;/code&gt; variables.&lt;/p&gt;

&lt;h3&gt;
  
  
  Protect the production workflow
&lt;/h3&gt;

&lt;p&gt;A person who can modify a production workflow may try to use the secrets available to that workflow.&lt;/p&gt;

&lt;p&gt;At minimum:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Protect the &lt;code&gt;main&lt;/code&gt; branch.&lt;/li&gt;
&lt;li&gt;Require pull requests and reviews.&lt;/li&gt;
&lt;li&gt;Require review for changes inside &lt;code&gt;.github/workflows/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Consider a &lt;code&gt;CODEOWNERS&lt;/code&gt; rule for workflow files.&lt;/li&gt;
&lt;li&gt;Use a protected &lt;code&gt;production&lt;/code&gt; environment when your GitHub plan supports it.&lt;/li&gt;
&lt;li&gt;Keep &lt;code&gt;permissions: contents: read&lt;/code&gt; unless more access is genuinely required.&lt;/li&gt;
&lt;li&gt;Review third-party actions and consider pinning them to full commit SHAs.&lt;/li&gt;
&lt;li&gt;Use Dependabot to keep action versions updated.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Back up before risky migrations
&lt;/h3&gt;

&lt;p&gt;The workflow runs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan migrate &lt;span class="nt"&gt;--force&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A code rollback does not restore deleted or modified database data. Back up the database before destructive or difficult-to-reverse migrations.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;queue:restart&lt;/code&gt; does not start a queue worker
&lt;/h3&gt;

&lt;p&gt;The command only tells existing workers to exit gracefully after finishing their current job. A process manager, hosting feature, or scheduled command must already be running the workers.&lt;/p&gt;

&lt;p&gt;On shared hosting, you may need a cPanel cron job instead of a continuously running worker.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common errors
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;Permission denied (publickey)&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Check that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The deployment public key was imported and authorized in cPanel.&lt;/li&gt;
&lt;li&gt;The matching private key was saved in &lt;code&gt;CPANEL_SSH_PRIVATE_KEY&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CPANEL_USER&lt;/code&gt;, &lt;code&gt;CPANEL_HOST&lt;/code&gt;, and &lt;code&gt;CPANEL_PORT&lt;/code&gt; are correct.&lt;/li&gt;
&lt;li&gt;The hosting account allows SSH access.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Test locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-vvv&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.ssh/deploy-keys/cpanel_production"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; YOUR_SSH_PORT &lt;span class="se"&gt;\&lt;/span&gt;
  YOUR_CPANEL_USER@YOUR_CPANEL_HOST
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;Host key verification failed&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The value in &lt;code&gt;CPANEL_KNOWN_HOSTS&lt;/code&gt; does not match the server.&lt;/p&gt;

&lt;p&gt;Do not disable strict host checking. Confirm whether the hosting provider intentionally changed the SSH host key, verify the new fingerprint, and then update the secret.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;Production .env is missing&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;.env&lt;/code&gt; inside &lt;code&gt;APP_DIR&lt;/code&gt;, not inside &lt;code&gt;public&lt;/code&gt;:&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;cd&lt;/span&gt; /home/YOUR_CPANEL_USER/YOUR_APP_DIRECTORY

&lt;span class="nb"&gt;touch&lt;/span&gt; .env
&lt;span class="nb"&gt;chmod &lt;/span&gt;600 .env
nano .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;public/build/manifest.json&lt;/code&gt; is missing
&lt;/h3&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm ci
npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Confirm that Vite creates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public/build/manifest.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your project uses a different Vite output directory, update the workflow checks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Laravel returns HTTP 500
&lt;/h3&gt;

&lt;p&gt;Check the log:&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;tail&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 100 storage/logs/laravel.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then inspect the environment, permissions, PHP extensions, database connection, and cached configuration.&lt;/p&gt;

&lt;p&gt;If a failed deployment left the application in maintenance mode, bring it back only after fixing the problem:&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="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PHP_BIN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; artisan up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;storage:link&lt;/code&gt; fails
&lt;/h3&gt;

&lt;p&gt;Check whether &lt;code&gt;public/storage&lt;/code&gt; already exists as a normal directory or whether the hosting provider blocks symbolic links:&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; &lt;span class="nt"&gt;-la&lt;/span&gt; public/storage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remove or rename an incorrect directory only after confirming it does not contain files that must be preserved.&lt;/p&gt;




&lt;h2&gt;
  
  
  A note about deleted files
&lt;/h2&gt;

&lt;p&gt;This workflow extracts the new archive over the existing application.&lt;/p&gt;

&lt;p&gt;Files with matching names are replaced, but a file deleted from Git may remain on the server. This is one limitation of the simple archive-based approach.&lt;/p&gt;

&lt;p&gt;For many small applications, that trade-off is acceptable. When the application grows, move to release directories and a &lt;code&gt;current&lt;/code&gt; symbolic link:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;releases/
├── 20260730-120001/
├── 20260730-123500/
└── 20260730-130800/

current -&amp;gt; releases/20260730-130800
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That architecture makes atomic switching, cleanup, and code rollback easier, but it requires a more advanced deployment workflow and a shared storage directory.&lt;/p&gt;




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

&lt;p&gt;Manual cPanel deployment works, but it becomes slow and error-prone when deployments are frequent.&lt;/p&gt;

&lt;p&gt;With this setup, the regular process becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Describe the change"&lt;/span&gt;
git push origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub Actions will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check out the private repository with its built-in token.&lt;/li&gt;
&lt;li&gt;Install Laravel's production dependencies.&lt;/li&gt;
&lt;li&gt;Build the Vue and Vite assets.&lt;/li&gt;
&lt;li&gt;Upload the application to cPanel through SSH.&lt;/li&gt;
&lt;li&gt;Preserve &lt;code&gt;.env&lt;/code&gt;, storage, uploads, logs, and server-managed files.&lt;/li&gt;
&lt;li&gt;Run migrations and optimize Laravel.&lt;/li&gt;
&lt;li&gt;Signal existing queue workers to restart.&lt;/li&gt;
&lt;li&gt;Check the production website.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most importantly, the cPanel server does not need access to the private GitHub repository. It only receives the deployment created by GitHub Actions.&lt;/p&gt;

&lt;p&gt;The first setup requires care around SSH keys, host verification, server paths, PHP versions, and production secrets. After that, deployments become repeatable, predictable, and much less stressful.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>githubactions</category>
      <category>cpanel</category>
      <category>vue</category>
    </item>
    <item>
      <title>Mid-Year Backend Reset: My H2 Goals for Speed, Security, and Better Docs</title>
      <dc:creator>Tahsin Abrar</dc:creator>
      <pubDate>Fri, 03 Jul 2026 20:47:52 +0000</pubDate>
      <link>https://dev.to/tahsin000/mid-year-backend-reset-my-h2-goals-for-speed-security-and-better-docs-14ap</link>
      <guid>https://dev.to/tahsin000/mid-year-backend-reset-my-h2-goals-for-speed-security-and-better-docs-14ap</guid>
      <description>&lt;p&gt;July always feels like a natural pause point.&lt;/p&gt;

&lt;p&gt;The first half of the year is already behind us. Some features shipped. Some bugs were fixed. Some ideas worked well. A few things probably stayed in the backlog longer than expected.&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%2Fynzp2bycdiwjz6xnr8ap.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%2Fynzp2bycdiwjz6xnr8ap.png" alt="Diagram" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For me, this is not about making a huge roadmap or setting unrealistic goals. It is more about asking a simple question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What backend systems do I want to make better before the year ends?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After thinking about my recent work, I found myself coming back to three areas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Performance&lt;/li&gt;
&lt;li&gt;Security&lt;/li&gt;
&lt;li&gt;Documentation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These are not flashy goals. They are not always visible to users. But they are the kind of improvements that make a backend codebase healthier, safer, and easier to work with over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I Like Doing a Mid-Year Engineering Reset
&lt;/h2&gt;

&lt;p&gt;At the start of the year, goals often feel exciting. We plan new projects, new features, new tools, and new habits.&lt;/p&gt;

&lt;p&gt;But by the middle of the year, reality has already happened.&lt;/p&gt;

&lt;p&gt;Urgent fixes appear. Product priorities change. Some technical debt gets ignored because there is always something more important to ship.&lt;/p&gt;

&lt;p&gt;That is why I like the idea of an H2 engineering reset.&lt;/p&gt;

&lt;p&gt;It gives me a chance to review the systems I work on with a fresh mind. Instead of only asking, “What should we build next?” I can also ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is slowing us down?&lt;/li&gt;
&lt;li&gt;What keeps breaking?&lt;/li&gt;
&lt;li&gt;What is hard to understand?&lt;/li&gt;
&lt;li&gt;What would make the next six months easier?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This kind of reset is useful because backend quality is not built in one big moment. It is built through small, careful improvements repeated over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Goal 1: Improve Performance
&lt;/h2&gt;

&lt;p&gt;Performance is one of those things that is easy to ignore until users start feeling the pain.&lt;/p&gt;

&lt;p&gt;A page loads a little slower. An API takes a few extra seconds. A database query works fine with 100 records but becomes painful with 100,000 records.&lt;/p&gt;

&lt;p&gt;At first, these issues may not look urgent. But slowly, they make the product feel heavy.&lt;/p&gt;

&lt;p&gt;For the second half of the year, I want to be more intentional about backend performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where I Want to Focus
&lt;/h3&gt;

&lt;p&gt;For Laravel projects, this means looking closely at a few common areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Slow database queries&lt;/li&gt;
&lt;li&gt;Missing indexes&lt;/li&gt;
&lt;li&gt;N+1 query problems&lt;/li&gt;
&lt;li&gt;Heavy API responses&lt;/li&gt;
&lt;li&gt;Unnecessary background jobs&lt;/li&gt;
&lt;li&gt;Cacheable data that is being fetched again and again&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A simple example is a dashboard page.&lt;/p&gt;

&lt;p&gt;Maybe the dashboard shows user stats, recent orders, payment data, and notifications. At first, everything works fine. But after a few months, the page starts taking longer to load.&lt;/p&gt;

&lt;p&gt;The problem may not be the whole system. It may be one query that loads too much data, or one relationship that is not eager loaded properly.&lt;/p&gt;

&lt;p&gt;Small fixes can make a big difference.&lt;/p&gt;

&lt;h3&gt;
  
  
  Practical Steps I Want to Take
&lt;/h3&gt;

&lt;p&gt;My performance reset will be simple:&lt;/p&gt;

&lt;p&gt;First, I want to identify the slowest endpoints. I do not want to guess. I want to measure.&lt;/p&gt;

&lt;p&gt;Then, I want to review the database queries behind those endpoints. Are they doing too much? Are they using indexes properly? Are they loading relationships in a clean way?&lt;/p&gt;

&lt;p&gt;Finally, I want to use caching where it actually makes sense.&lt;/p&gt;

&lt;p&gt;Not everything needs to be cached. But data that does not change often should not be rebuilt on every request.&lt;/p&gt;

&lt;p&gt;The goal is not to make everything perfect. The goal is to make the most used parts of the system faster and more reliable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Goal 2: Strengthen Security
&lt;/h2&gt;

&lt;p&gt;Security is not a one-time task.&lt;/p&gt;

&lt;p&gt;It is not something we finish after adding authentication or installing a package. It needs regular review, especially as an application grows.&lt;/p&gt;

&lt;p&gt;New routes are added. New permissions are created. New integrations are connected. Over time, small gaps can appear.&lt;/p&gt;

&lt;p&gt;That is why security is my second H2 backend goal.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Areas I Want to Recheck
&lt;/h3&gt;

&lt;p&gt;In Laravel apps, I want to review things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication flow&lt;/li&gt;
&lt;li&gt;Authorization rules&lt;/li&gt;
&lt;li&gt;Role and permission checks&lt;/li&gt;
&lt;li&gt;API token usage&lt;/li&gt;
&lt;li&gt;Form request validation&lt;/li&gt;
&lt;li&gt;File upload handling&lt;/li&gt;
&lt;li&gt;Sensitive data exposure&lt;/li&gt;
&lt;li&gt;Environment configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One real-life situation many developers face is permission logic becoming scattered.&lt;/p&gt;

&lt;p&gt;For example, one controller checks if a user is an admin. Another checks if the user owns the resource. Another uses a policy. Another has the logic written directly inside the method.&lt;/p&gt;

&lt;p&gt;Everything may work, but it becomes harder to trust.&lt;/p&gt;

&lt;p&gt;When permission logic is not consistent, future changes become risky.&lt;/p&gt;

&lt;h3&gt;
  
  
  Practical Steps I Want to Take
&lt;/h3&gt;

&lt;p&gt;For the second half of the year, I want to clean up authorization logic and move more checks into proper Laravel policies or gates where possible.&lt;/p&gt;

&lt;p&gt;I also want to review validation rules more carefully.&lt;/p&gt;

&lt;p&gt;Good validation is not only about showing nice error messages. It protects the system from bad data, unexpected input, and edge cases.&lt;/p&gt;

&lt;p&gt;Another important step is checking what data gets returned from APIs.&lt;/p&gt;

&lt;p&gt;Sometimes an API response includes more fields than the frontend actually needs. That can accidentally expose internal or sensitive information.&lt;/p&gt;

&lt;p&gt;So the security goal is simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Make access clear, input strict, and output intentional.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That one sentence is easy to remember, and it covers a lot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Goal 3: Improve Documentation
&lt;/h2&gt;

&lt;p&gt;Documentation is usually the easiest thing to delay.&lt;/p&gt;

&lt;p&gt;When we are busy, we tell ourselves, “I will document this later.”&lt;/p&gt;

&lt;p&gt;But later often becomes never.&lt;/p&gt;

&lt;p&gt;Then after a few months, someone asks:&lt;/p&gt;

&lt;p&gt;“How does this job work?”&lt;br&gt;
“Why does this API behave this way?”&lt;br&gt;
“What happens when this webhook fails?”&lt;br&gt;
“Where is this config coming from?”&lt;/p&gt;

&lt;p&gt;And suddenly, the missing documentation becomes expensive.&lt;/p&gt;

&lt;p&gt;For H2, I want to treat documentation as part of the backend system, not as an extra task.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I Want to Document Better
&lt;/h3&gt;

&lt;p&gt;I do not want to write huge documents that nobody reads. I want useful documentation that helps developers move faster.&lt;/p&gt;

&lt;p&gt;That includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API behavior&lt;/li&gt;
&lt;li&gt;Important business rules&lt;/li&gt;
&lt;li&gt;Queue jobs&lt;/li&gt;
&lt;li&gt;Scheduled commands&lt;/li&gt;
&lt;li&gt;Webhook flows&lt;/li&gt;
&lt;li&gt;Environment variables&lt;/li&gt;
&lt;li&gt;Setup steps&lt;/li&gt;
&lt;li&gt;Common debugging notes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, if a payment webhook updates an order status, that flow should be easy to understand.&lt;/p&gt;

&lt;p&gt;A developer should be able to read a short note and know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which event comes from the payment provider&lt;/li&gt;
&lt;li&gt;Which route receives it&lt;/li&gt;
&lt;li&gt;Which job processes it&lt;/li&gt;
&lt;li&gt;Which tables are updated&lt;/li&gt;
&lt;li&gt;What happens if the webhook fails&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This does not need a 20-page document. A clear Markdown file can be enough.&lt;/p&gt;

&lt;h3&gt;
  
  
  Practical Steps I Want to Take
&lt;/h3&gt;

&lt;p&gt;My documentation reset will start with the most confusing parts of the system.&lt;/p&gt;

&lt;p&gt;I want to document the areas where I have previously had to explain the same thing more than once. That is usually a good sign that documentation is missing.&lt;/p&gt;

&lt;p&gt;I also want to keep docs close to the code when possible.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API notes inside an &lt;code&gt;/docs&lt;/code&gt; folder&lt;/li&gt;
&lt;li&gt;Setup instructions in &lt;code&gt;README.md&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Complex service explanations near the related module&lt;/li&gt;
&lt;li&gt;Short comments only where the code needs context&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Good documentation does not explain every line of code. It explains the decisions, flows, and important details that are not obvious.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping the Reset Realistic
&lt;/h2&gt;

&lt;p&gt;The biggest mistake with planning is trying to fix everything at once.&lt;/p&gt;

&lt;p&gt;That usually leads to frustration.&lt;/p&gt;

&lt;p&gt;So I want to keep this H2 reset small and realistic.&lt;/p&gt;

&lt;p&gt;Instead of saying, “Improve the whole backend,” I can say:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Optimize the top 3 slowest endpoints&lt;/li&gt;
&lt;li&gt;Review authorization for the most sensitive modules&lt;/li&gt;
&lt;li&gt;Document the 5 most confusing backend flows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That feels much more doable.&lt;/p&gt;

&lt;p&gt;It also creates visible progress.&lt;/p&gt;

&lt;p&gt;A backend system improves when we choose specific problems and solve them carefully.&lt;/p&gt;

</description>
      <category>backenddevelopment</category>
      <category>laravel</category>
      <category>engineeringgoals</category>
      <category>buildinpublic</category>
    </item>
    <item>
      <title>Redis on Windows with Laragon and Laravel: The PATH Issue That Looks Like a Redis Issue</title>
      <dc:creator>Tahsin Abrar</dc:creator>
      <pubDate>Fri, 26 Jun 2026 13:19:09 +0000</pubDate>
      <link>https://dev.to/tahsin000/redis-on-windows-with-laragon-and-laravel-the-path-issue-that-looks-like-a-redis-issue-4omd</link>
      <guid>https://dev.to/tahsin000/redis-on-windows-with-laragon-and-laravel-the-path-issue-that-looks-like-a-redis-issue-4omd</guid>
      <description>&lt;p&gt;A few days ago, I was working on a Laravel project on Windows. The project needed Redis for cache and queue handling, and since I was using Laragon, I thought the setup would be simple.&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%2F3swjtgeqcopo8t5q8rpv.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%2F3swjtgeqcopo8t5q8rpv.png" alt="Diagram" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Laragon already had Redis inside its &lt;code&gt;bin&lt;/code&gt; folder. I started Redis, opened the terminal, and ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-cli ping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It returned:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Perfect.&lt;/p&gt;

&lt;p&gt;Then I moved to my Laravel project folder, opened Git Bash, and tried the same command again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-cli ping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This time, I got:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash: redis-cli: &lt;span class="nb"&gt;command &lt;/span&gt;not found
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first, it looked like Redis was not installed properly. Then I wondered if Redis only worked inside Laragon’s &lt;code&gt;www&lt;/code&gt; folder. Maybe my Laravel project was outside the correct directory?&lt;/p&gt;

&lt;p&gt;But the real problem was much simpler.&lt;/p&gt;

&lt;p&gt;It was not a Redis problem.&lt;/p&gt;

&lt;p&gt;It was not a Laravel problem.&lt;/p&gt;

&lt;p&gt;It was not a project folder problem.&lt;/p&gt;

&lt;p&gt;It was a PATH problem.&lt;/p&gt;

&lt;p&gt;In this post, I’ll walk through the full Redis setup on Windows using Laragon, how to make &lt;code&gt;redis-cli&lt;/code&gt; work from Git Bash, and how to connect it properly with a Laravel project.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Situation
&lt;/h2&gt;

&lt;p&gt;My Laravel project was not inside Laragon’s default &lt;code&gt;www&lt;/code&gt; folder. It was somewhere like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;C:&lt;span class="se"&gt;\U&lt;/span&gt;sers&lt;span class="se"&gt;\A&lt;/span&gt;sus&lt;span class="se"&gt;\D&lt;/span&gt;ownloads&lt;span class="se"&gt;\a&lt;/span&gt;romablendbd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But Laragon was installed here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;D:&lt;span class="se"&gt;\C&lt;/span&gt;&lt;span class="nt"&gt;-data&lt;/span&gt;&lt;span class="se"&gt;\l&lt;/span&gt;aragon
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I opened Laragon’s own terminal or Cmder, this worked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-cli ping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

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

&lt;/div&gt;



&lt;p&gt;But inside Git Bash from my Laravel project folder, the same command failed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash: redis-cli: &lt;span class="nb"&gt;command &lt;/span&gt;not found
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where the confusion started.&lt;/p&gt;

&lt;p&gt;Redis itself does not care where your Laravel project is located. Redis runs as a server, usually on:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;So any project can connect to it, whether the project is inside &lt;code&gt;www&lt;/code&gt;, &lt;code&gt;Downloads&lt;/code&gt;, &lt;code&gt;Desktop&lt;/code&gt;, or another drive.&lt;/p&gt;

&lt;p&gt;The only issue was that Git Bash did not know where &lt;code&gt;redis-cli.exe&lt;/code&gt; was located.&lt;/p&gt;

&lt;p&gt;Laragon’s terminal automatically adds Laragon tools to its PATH. Git Bash does not.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Find the Redis CLI File
&lt;/h2&gt;

&lt;p&gt;First, we need to find the actual &lt;code&gt;redis-cli.exe&lt;/code&gt; file inside Laragon.&lt;/p&gt;

&lt;p&gt;In Git Bash, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find /d/C-data/laragon/bin &lt;span class="nt"&gt;-iname&lt;/span&gt; &lt;span class="s2"&gt;"redis-cli.exe"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your Laragon path may be different. For example, if Laragon is installed in &lt;code&gt;C:\laragon&lt;/code&gt;, you may need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find /c/laragon/bin &lt;span class="nt"&gt;-iname&lt;/span&gt; &lt;span class="s2"&gt;"redis-cli.exe"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my case, the result was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/d/C-data/laragon/bin/redis/redis-x64-5.0.14.1/redis-cli.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This confirmed that Redis CLI was already installed. Git Bash simply could not find it globally.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Test Redis Using the Full Path
&lt;/h2&gt;

&lt;p&gt;Before changing PATH settings, it’s always good to test the command directly.&lt;/p&gt;

&lt;p&gt;I ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/d/C-data/laragon/bin/redis/redis-x64-5.0.14.1/redis-cli.exe ping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the output was:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;That was the important moment.&lt;/p&gt;

&lt;p&gt;It confirmed three things:&lt;/p&gt;

&lt;p&gt;Redis was installed.&lt;/p&gt;

&lt;p&gt;Redis server was running.&lt;/p&gt;

&lt;p&gt;Git Bash could reach Redis when I used the full path.&lt;/p&gt;

&lt;p&gt;So the server was fine. The port was fine. The Laravel folder location was fine.&lt;/p&gt;

&lt;p&gt;Only the command shortcut was missing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Add Redis CLI to Git Bash PATH
&lt;/h2&gt;

&lt;p&gt;To make &lt;code&gt;redis-cli&lt;/code&gt; available from any folder in Git Bash, I added the Redis folder to &lt;code&gt;~/.bashrc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is the command I used:&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;echo&lt;/span&gt; &lt;span class="s1"&gt;'export PATH="$PATH:/d/C-data/laragon/bin/redis/redis-x64-5.0.14.1"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bashrc
&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, I tested again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-cli ping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This time, it worked:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Now I could run &lt;code&gt;redis-cli&lt;/code&gt; from any folder, including my Laravel project folder.&lt;/p&gt;

&lt;p&gt;This is the clean fix for the &lt;code&gt;redis-cli: command not found&lt;/code&gt; issue in Git Bash.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Small Redis CLI Mistake That Can Confuse You
&lt;/h2&gt;

&lt;p&gt;At one point, I entered the Redis shell by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the terminal changed to something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;127.0.0.1:6379&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside this prompt, I tried:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-cli ping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That was wrong.&lt;/p&gt;

&lt;p&gt;When you are inside the Redis shell, you should only write Redis commands.&lt;/p&gt;

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

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

&lt;/div&gt;



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

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

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-cli ping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Because &lt;code&gt;redis-cli&lt;/code&gt; is a terminal command. It starts the Redis command-line tool.&lt;/p&gt;

&lt;p&gt;But once you are already inside Redis CLI, you only need to type Redis commands like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ping
&lt;span class="nb"&gt;set &lt;/span&gt;name laragon
get name
&lt;span class="nb"&gt;exit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So there are two valid ways to test Redis.&lt;/p&gt;

&lt;p&gt;From the normal terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-cli ping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or from inside the Redis shell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

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

&lt;/div&gt;



&lt;p&gt;Both are correct, but they are used in different places.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Make Sure Redis Server Is Running
&lt;/h2&gt;

&lt;p&gt;If you installed the full version of Laragon, Redis is usually included inside the Laragon &lt;code&gt;bin&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;A common Redis path looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;C:&lt;span class="se"&gt;\l&lt;/span&gt;aragon&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="se"&gt;\r&lt;/span&gt;edis&lt;span class="se"&gt;\r&lt;/span&gt;edis-x64-3.2.100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or in my case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;D:&lt;span class="se"&gt;\C&lt;/span&gt;&lt;span class="nt"&gt;-data&lt;/span&gt;&lt;span class="se"&gt;\l&lt;/span&gt;aragon&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="se"&gt;\r&lt;/span&gt;edis&lt;span class="se"&gt;\r&lt;/span&gt;edis-x64-5.0.14.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can start Redis by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-server.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or from Git Bash, using the full path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/d/C-data/laragon/bin/redis/redis-x64-5.0.14.1/redis-server.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the Redis server is running, keep that terminal open.&lt;/p&gt;

&lt;p&gt;To stop the server later, press:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Ctrl + C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Laragon may also let you manage Redis from its menu depending on your installation.&lt;/p&gt;

&lt;p&gt;One important note: Redis native Windows support is limited, and many Windows setups use older Redis builds. For the latest Redis versions, Docker, WSL, or Laradock can be a better option. But for local Laravel development, Laragon’s Redis works well enough in many cases.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5: Configure Laravel &lt;code&gt;.env&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;After Redis worked in the terminal, the next step was Laravel.&lt;/p&gt;

&lt;p&gt;In the Laravel project, I opened the &lt;code&gt;.env&lt;/code&gt; file and checked the Redis settings.&lt;/p&gt;

&lt;p&gt;For my setup, I used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REDIS_CLIENT=predis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to use Redis for cache, also check your cache setting.&lt;/p&gt;

&lt;p&gt;For newer Laravel versions:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;For older Laravel versions:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;The key point is this:&lt;/p&gt;

&lt;p&gt;Laravel does not need the &lt;code&gt;redis-cli&lt;/code&gt; command to connect to Redis.&lt;/p&gt;

&lt;p&gt;Laravel connects to Redis through PHP using the host and port:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;So even if &lt;code&gt;redis-cli&lt;/code&gt; was not available in Git Bash, Laravel could still connect if the Redis client package or PHP extension was correctly installed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 6: Install Laravel Dependencies
&lt;/h2&gt;

&lt;p&gt;If this is an existing Laravel project, run:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This installs the dependencies listed in &lt;code&gt;composer.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In my case, Laravel was configured to use Predis:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;But when I tested Redis in Laravel, I got this error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Class "Predis\Client" not found
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That means Laravel wanted to use Predis, but the package was not installed.&lt;/p&gt;

&lt;p&gt;The fix was simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require predis/predis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After installing Predis, I cleared Laravel’s cached config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan config:clear
php artisan cache:clear
php artisan optimize:clear
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This step is important because Laravel may keep old &lt;code&gt;.env&lt;/code&gt; or config values in cache.&lt;/p&gt;




&lt;h2&gt;
  
  
  Predis vs PhpRedis
&lt;/h2&gt;

&lt;p&gt;Laravel can use Redis in two common ways.&lt;/p&gt;

&lt;p&gt;The first option is Predis.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;For this, install the Composer package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require predis/predis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is often the easiest option when you are working on Windows and want a quick local setup.&lt;/p&gt;

&lt;p&gt;The second option is PhpRedis.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;For this, you need the PHP Redis extension enabled.&lt;/p&gt;

&lt;p&gt;In Laragon, the Redis PHP extension does not always come enabled by default. You may need to download the correct &lt;code&gt;php_redis.dll&lt;/code&gt; file that matches your PHP version, architecture, and thread-safety build.&lt;/p&gt;

&lt;p&gt;You can check your PHP version from Laragon. Then download the matching Redis extension DLL from PECL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://pecl.php.net/package/redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After downloading, copy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php_redis.dll
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Into your PHP extension folder, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;C:&lt;span class="se"&gt;\l&lt;/span&gt;aragon&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="se"&gt;\p&lt;/span&gt;hp&lt;span class="se"&gt;\p&lt;/span&gt;hp-8.x.x&lt;span class="se"&gt;\e&lt;/span&gt;xt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add this line to your &lt;code&gt;php.ini&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;extension&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;php_redis.dll&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart Laragon after making the change.&lt;/p&gt;

&lt;p&gt;For many local projects, Predis is simpler. For better performance in some production setups, PhpRedis is commonly used.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 7: Test Redis from Laravel Tinker
&lt;/h2&gt;

&lt;p&gt;Now came the final test.&lt;/p&gt;

&lt;p&gt;From the Laravel project folder, I ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan optimize:clear
php artisan tinker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside Tinker, I first tried:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Redis&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;ping&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But I got:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Class "Redis" not found
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This does not always mean Redis is broken. It can simply mean the Redis facade was not imported in Tinker.&lt;/p&gt;

&lt;p&gt;The safer way is to use the full namespace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;\Illuminate\Support\Facades\Redis&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;ping&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or use Laravel’s service container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nf"&gt;app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'redis'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;ping&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="s2"&gt;"PONG"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I saw &lt;code&gt;"PONG"&lt;/code&gt; from Laravel Tinker, the setup was finally complete.&lt;/p&gt;

&lt;p&gt;At that point, Redis was working in three places:&lt;/p&gt;

&lt;p&gt;From Laragon terminal.&lt;/p&gt;

&lt;p&gt;From Git Bash.&lt;/p&gt;

&lt;p&gt;From Laravel itself.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Errors and What They Really Mean
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;bash: redis-cli: command not found&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This means your terminal cannot find &lt;code&gt;redis-cli.exe&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It does not mean Redis is not installed.&lt;/p&gt;

&lt;p&gt;Fix it by adding the Redis folder to Git Bash PATH:&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;echo&lt;/span&gt; &lt;span class="s1"&gt;'export PATH="$PATH:/d/C-data/laragon/bin/redis/redis-x64-5.0.14.1"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bashrc
&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-cli ping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;code&gt;Class "Predis\Client" not found&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This means Laravel is using Predis, but the package is missing.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require predis/predis
php artisan optimize:clear
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;code&gt;Class "Redis" not found&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This may happen in Tinker when the Redis facade is not imported.&lt;/p&gt;

&lt;p&gt;Use the full namespace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;\Illuminate\Support\Facades\Redis&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;ping&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nf"&gt;app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'redis'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;ping&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Redis Works in &lt;code&gt;www&lt;/code&gt; but Not in Another Folder
&lt;/h3&gt;

&lt;p&gt;This is usually not a folder issue.&lt;/p&gt;

&lt;p&gt;Laragon terminal automatically sets PATH for Laragon tools. Git Bash does not.&lt;/p&gt;

&lt;p&gt;Redis runs on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;127.0.0.1:6379
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So your Laravel project can be anywhere as long as Redis is running and Laravel is configured correctly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Working Setup
&lt;/h2&gt;

&lt;p&gt;Here is the final setup that worked for me.&lt;/p&gt;

&lt;p&gt;Redis CLI path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/d/C-data/laragon/bin/redis/redis-x64-5.0.14.1/redis-cli.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Git Bash PATH fix:&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;echo&lt;/span&gt; &lt;span class="s1"&gt;'export PATH="$PATH:/d/C-data/laragon/bin/redis/redis-x64-5.0.14.1"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bashrc
&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Redis terminal test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-cli ping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

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

&lt;/div&gt;



&lt;p&gt;Laravel &lt;code&gt;.env&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REDIS_CLIENT=predis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
CACHE_STORE=redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install Predis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require predis/predis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clear Laravel config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan config:clear
php artisan cache:clear
php artisan optimize:clear
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test in Tinker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan tinker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;\Illuminate\Support\Facades\Redis&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;ping&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="s2"&gt;"PONG"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>php</category>
      <category>windows</category>
      <category>redis</category>
      <category>laravel</category>
    </item>
    <item>
      <title>How to Create a GitHub Pull Request from the Terminal</title>
      <dc:creator>Tahsin Abrar</dc:creator>
      <pubDate>Tue, 23 Jun 2026 09:04:54 +0000</pubDate>
      <link>https://dev.to/tahsin000/how-to-create-a-github-pull-request-from-the-terminal-3a0g</link>
      <guid>https://dev.to/tahsin000/how-to-create-a-github-pull-request-from-the-terminal-3a0g</guid>
      <description>&lt;p&gt;Pull Requests are a normal part of working with GitHub. You write code in a branch, push it to GitHub, then open a Pull Request so your team can review and merge it.&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%2Fe1ksfwgqujfzxzi6uvmf.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%2Fe1ksfwgqujfzxzi6uvmf.png" alt="Diagram" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most developers create Pull Requests from the GitHub website. That works fine.&lt;/p&gt;

&lt;p&gt;But once you get comfortable with the terminal, you can do the whole flow without leaving your editor or command line.&lt;/p&gt;

&lt;p&gt;In this post, we will go through a simple and practical workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;update your local &lt;code&gt;main&lt;/code&gt; branch&lt;/li&gt;
&lt;li&gt;create a new feature branch&lt;/li&gt;
&lt;li&gt;commit your changes&lt;/li&gt;
&lt;li&gt;push the branch to GitHub&lt;/li&gt;
&lt;li&gt;create a Pull Request from the terminal using GitHub CLI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s use a real example: you are building a login page.&lt;/p&gt;




&lt;h2&gt;
  
  
  First, Know the Difference: &lt;code&gt;git pull&lt;/code&gt; vs Pull Request
&lt;/h2&gt;

&lt;p&gt;A lot of beginners get confused here.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git pull&lt;/code&gt; and Pull Request are not the same thing.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;git pull&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;git pull&lt;/code&gt; means you are taking the latest code from GitHub and bringing it into your local project.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git pull origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This updates your local branch with the latest code from the remote &lt;code&gt;main&lt;/code&gt; branch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pull Request
&lt;/h3&gt;

&lt;p&gt;A Pull Request means you are asking to merge your branch changes into another branch, usually &lt;code&gt;main&lt;/code&gt; or &lt;code&gt;develop&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So the simple idea is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git pull  = bring latest code to your computer
Pull Request = ask to merge your code into main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To create a Pull Request from the terminal, the usual flow is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;push your branch → create PR with GitHub CLI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 1: Update Your Main Branch
&lt;/h2&gt;

&lt;p&gt;Before starting new work, always get the latest code from the main branch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout main
git pull origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This helps you avoid working on old code.&lt;/p&gt;

&lt;p&gt;Think of it like this: before building your new feature, you are making sure your project is fresh and up to date.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Create a New Branch
&lt;/h2&gt;

&lt;p&gt;Now create a new branch for your work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; feature/login-page
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;feature/login-page&lt;/code&gt; is your working branch.&lt;/p&gt;

&lt;p&gt;Good branch names are short, clear, and meaningful.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;feature/navbar
fix/login-error
update/readme
feature/login-page
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A clear branch name helps your teammates understand what you are working on before they even open the code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Make Your Code Changes
&lt;/h2&gt;

&lt;p&gt;Now do your actual work.&lt;/p&gt;

&lt;p&gt;For example, you may add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a login page layout&lt;/li&gt;
&lt;li&gt;email and password fields&lt;/li&gt;
&lt;li&gt;a submit button&lt;/li&gt;
&lt;li&gt;basic styling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After changing the code, check the current Git status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This shows which files were changed, added, or deleted.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Add Your Files
&lt;/h2&gt;

&lt;p&gt;To add all changed files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;.&lt;/code&gt; means Git will add all changed files in the current project.&lt;/p&gt;

&lt;p&gt;If you only want to add one file, use the file path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add src/App.jsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is useful when you changed many files but only want to commit some of them.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5: Commit Your Changes
&lt;/h2&gt;

&lt;p&gt;Now create a commit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Add login page UI"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A good commit message should be short but clear.&lt;/p&gt;

&lt;p&gt;Good examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Fix navbar responsiveness"&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Update README installation steps"&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Add user login form"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Avoid unclear messages like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"changes"&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"update"&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"fix"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your future self and your teammates will thank you for writing clear commit messages.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 6: Push Your Branch to GitHub
&lt;/h2&gt;

&lt;p&gt;Now push your branch to GitHub:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin feature/login-page
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also push the current branch like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin HEAD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is very handy because you do not need to type the full branch name.&lt;/p&gt;

&lt;p&gt;After this, your local branch exists on GitHub too.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 7: Install GitHub CLI
&lt;/h2&gt;

&lt;p&gt;To create a Pull Request from the terminal, you need GitHub CLI.&lt;/p&gt;

&lt;p&gt;GitHub CLI gives you the &lt;code&gt;gh&lt;/code&gt; command.&lt;/p&gt;

&lt;h3&gt;
  
  
  On Windows
&lt;/h3&gt;

&lt;p&gt;Open PowerShell or Windows Terminal and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;winget &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--id&lt;/span&gt; GitHub.cli &lt;span class="nt"&gt;--source&lt;/span&gt; winget
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After installing, close the terminal and open a new one.&lt;/p&gt;

&lt;p&gt;Then check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  On macOS
&lt;/h3&gt;

&lt;p&gt;If you use Homebrew, run:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Then check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see the version number, GitHub CLI is installed correctly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 8: Login to GitHub CLI
&lt;/h2&gt;

&lt;p&gt;You only need to do this once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh auth login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see some options. In most cases, choose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GitHub.com
HTTPS
Yes
Login with a web browser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A browser window may open for login and authorization.&lt;/p&gt;

&lt;p&gt;After login, check if everything is working:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh auth status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you are logged in, you can create Pull Requests from the terminal without opening the GitHub website.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 9: Create a Pull Request from the Terminal
&lt;/h2&gt;

&lt;p&gt;The easiest way is interactive mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh &lt;span class="nb"&gt;pr &lt;/span&gt;create
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub CLI will ask you questions like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Title:
Body:
Base branch:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The base branch is usually:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Or, if your team uses &lt;code&gt;develop&lt;/code&gt;, then use:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;After you answer the questions, GitHub CLI creates the Pull Request and shows you the PR URL.&lt;/p&gt;




&lt;h2&gt;
  
  
  Create a Pull Request in One Command
&lt;/h2&gt;

&lt;p&gt;You can also create the Pull Request in one line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh &lt;span class="nb"&gt;pr &lt;/span&gt;create &lt;span class="nt"&gt;--base&lt;/span&gt; main &lt;span class="nt"&gt;--head&lt;/span&gt; feature/login-page &lt;span class="nt"&gt;--title&lt;/span&gt; &lt;span class="s2"&gt;"Add login page UI"&lt;/span&gt; &lt;span class="nt"&gt;--body&lt;/span&gt; &lt;span class="s2"&gt;"This PR adds the login page UI with form fields and basic styling."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s understand this command:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This is the branch where you want to merge your code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--head feature/login-page
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is your feature branch.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This is the Pull Request title.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This is the Pull Request description.&lt;/p&gt;

&lt;p&gt;If you are already inside the feature branch, you can skip &lt;code&gt;--head&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh &lt;span class="nb"&gt;pr &lt;/span&gt;create &lt;span class="nt"&gt;--base&lt;/span&gt; main &lt;span class="nt"&gt;--title&lt;/span&gt; &lt;span class="s2"&gt;"Add login page UI"&lt;/span&gt; &lt;span class="nt"&gt;--body&lt;/span&gt; &lt;span class="s2"&gt;"This PR adds the login page UI with form fields and basic styling."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What Should You Write in a Pull Request?
&lt;/h2&gt;

&lt;p&gt;A good Pull Request should explain two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What changed?&lt;/li&gt;
&lt;li&gt;How did you test it?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is a simple example.&lt;/p&gt;

&lt;h3&gt;
  
  
  PR Title
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Add login page UI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  PR Body
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Summary&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Added login page layout
&lt;span class="p"&gt;-&lt;/span&gt; Added email and password input fields
&lt;span class="p"&gt;-&lt;/span&gt; Added submit button styling

&lt;span class="gu"&gt;## Testing&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Ran the app locally
&lt;span class="p"&gt;-&lt;/span&gt; Checked the login page in browser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is clear, professional, and easy to review.&lt;/p&gt;

&lt;p&gt;Your reviewer does not need to guess what you did.&lt;/p&gt;




&lt;h2&gt;
  
  
  Best Way to Write a Multiline PR Body
&lt;/h2&gt;

&lt;p&gt;Sometimes you want a clean Pull Request body with headings and bullet points.&lt;/p&gt;

&lt;p&gt;You may try to paste multiline Markdown directly inside &lt;code&gt;--body&lt;/code&gt;, but different shells can behave differently.&lt;/p&gt;

&lt;p&gt;The safest and cleanest way is to use a body file.&lt;/p&gt;

&lt;p&gt;Create a file named:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pr-body.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Put it in your project root directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-project/
├── src/
├── public/
├── package.json
├── README.md
└── pr-body.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside &lt;code&gt;pr-body.md&lt;/code&gt;, write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Summary&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Added login page layout
&lt;span class="p"&gt;-&lt;/span&gt; Added email and password fields
&lt;span class="p"&gt;-&lt;/span&gt; Added submit button styling

&lt;span class="gu"&gt;## Testing&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Ran the app locally
&lt;span class="p"&gt;-&lt;/span&gt; Checked login page in browser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create the Pull Request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh &lt;span class="nb"&gt;pr &lt;/span&gt;create &lt;span class="nt"&gt;--base&lt;/span&gt; main &lt;span class="nt"&gt;--head&lt;/span&gt; feature/login-page &lt;span class="nt"&gt;--title&lt;/span&gt; &lt;span class="s2"&gt;"Add login page UI"&lt;/span&gt; &lt;span class="nt"&gt;--body-file&lt;/span&gt; pr-body.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is usually the best option for real projects.&lt;/p&gt;

&lt;p&gt;It keeps your command clean and your PR description easy to edit.&lt;/p&gt;

&lt;p&gt;After creating the Pull Request, you can delete &lt;code&gt;pr-body.md&lt;/code&gt; if you do not want to keep it in the project.&lt;/p&gt;




&lt;h2&gt;
  
  
  One-Line Multiline Body Without a File
&lt;/h2&gt;

&lt;p&gt;If you really want to write the body directly in the command, here are safe options.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bash, Git Bash, or macOS Terminal
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh &lt;span class="nb"&gt;pr &lt;/span&gt;create &lt;span class="nt"&gt;--base&lt;/span&gt; main &lt;span class="nt"&gt;--head&lt;/span&gt; feature/login-page &lt;span class="nt"&gt;--title&lt;/span&gt; &lt;span class="s2"&gt;"Add login page UI"&lt;/span&gt; &lt;span class="nt"&gt;--body&lt;/span&gt; &lt;span class="s1"&gt;$'## Summary&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;- Added login page layout&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;- Added email and password fields&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s1"&gt;## Testing&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;- Ran the app locally&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;- Checked login page in browser'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;\n&lt;/code&gt; means a new line.&lt;/p&gt;

&lt;h3&gt;
  
  
  Windows PowerShell
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;gh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--head&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;feature/login-page&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Add login page UI"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--body&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"## Summary&lt;/span&gt;&lt;span class="se"&gt;`n&lt;/span&gt;&lt;span class="s2"&gt;- Added login page layout&lt;/span&gt;&lt;span class="se"&gt;`n&lt;/span&gt;&lt;span class="s2"&gt;- Added email and password fields&lt;/span&gt;&lt;span class="se"&gt;`n`n&lt;/span&gt;&lt;span class="s2"&gt;## Testing&lt;/span&gt;&lt;span class="se"&gt;`n&lt;/span&gt;&lt;span class="s2"&gt;- Ran the app locally&lt;/span&gt;&lt;span class="se"&gt;`n&lt;/span&gt;&lt;span class="s2"&gt;- Checked login page in browser"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In PowerShell, newline is written as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Still, for most real work, I recommend using &lt;code&gt;--body-file&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It is simpler and less error-prone.&lt;/p&gt;




&lt;h2&gt;
  
  
  Check Your Pull Request
&lt;/h2&gt;

&lt;p&gt;After creating the Pull Request, you can check its status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh &lt;span class="nb"&gt;pr &lt;/span&gt;status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To see Pull Requests in the repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh &lt;span class="nb"&gt;pr &lt;/span&gt;list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To view the current branch’s Pull Request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh &lt;span class="nb"&gt;pr &lt;/span&gt;view
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To open it in the browser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh &lt;span class="nb"&gt;pr &lt;/span&gt;view &lt;span class="nt"&gt;--web&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Opening the browser is optional. You do not need it to create the PR.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Full Practical Workflow
&lt;/h2&gt;

&lt;p&gt;Here is the complete flow you can use every day:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout main
git pull origin main

git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; feature/my-work

&lt;span class="c"&gt;# after code changes&lt;/span&gt;
git status
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Add my work"&lt;/span&gt;
git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin HEAD

gh &lt;span class="nb"&gt;pr &lt;/span&gt;create &lt;span class="nt"&gt;--base&lt;/span&gt; main &lt;span class="nt"&gt;--title&lt;/span&gt; &lt;span class="s2"&gt;"Add my work"&lt;/span&gt; &lt;span class="nt"&gt;--body&lt;/span&gt; &lt;span class="s2"&gt;"Added my work and tested locally."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a cleaner Pull Request body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh &lt;span class="nb"&gt;pr &lt;/span&gt;create &lt;span class="nt"&gt;--base&lt;/span&gt; main &lt;span class="nt"&gt;--title&lt;/span&gt; &lt;span class="s2"&gt;"Add my work"&lt;/span&gt; &lt;span class="nt"&gt;--body-file&lt;/span&gt; pr-body.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the core workflow.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Problems and Fixes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Problem 1: &lt;code&gt;gh: command not found&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This means GitHub CLI is not installed, or your terminal has not refreshed yet.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;winget &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--id&lt;/span&gt; GitHub.cli &lt;span class="nt"&gt;--source&lt;/span&gt; winget
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then close the terminal and open it again.&lt;/p&gt;

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

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

&lt;/div&gt;



&lt;p&gt;Then check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Problem 2: You Are Not Logged In
&lt;/h3&gt;

&lt;p&gt;If you see a message saying you are not logged in, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh auth login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh auth status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Problem 3: Current Branch Is Not Pushed
&lt;/h3&gt;

&lt;p&gt;If GitHub CLI says your branch is not pushed yet, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin HEAD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then try again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh &lt;span class="nb"&gt;pr &lt;/span&gt;create
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Problem 4: Pull Request Is Created from the Wrong Branch
&lt;/h3&gt;

&lt;p&gt;First, check your current branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git branch &lt;span class="nt"&gt;--show-current&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are on the wrong branch, switch to the correct one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout feature/login-page
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create the Pull Request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh &lt;span class="nb"&gt;pr &lt;/span&gt;create &lt;span class="nt"&gt;--base&lt;/span&gt; main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






</description>
      <category>git</category>
      <category>github</category>
      <category>cli</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Stop Guessing in Controllers: Debug MySQL Directly</title>
      <dc:creator>Tahsin Abrar</dc:creator>
      <pubDate>Wed, 20 May 2026 21:33:32 +0000</pubDate>
      <link>https://dev.to/tahsin000/stop-putting-dd-everywhere-debug-the-database-from-the-source-instead-4n8o</link>
      <guid>https://dev.to/tahsin000/stop-putting-dd-everywhere-debug-the-database-from-the-source-instead-4n8o</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftrsm9ndz7n8osm2hi1wt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftrsm9ndz7n8osm2hi1wt.png" alt="diagram" width="800" height="878"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every backend developer has done this at some point.&lt;/p&gt;

&lt;p&gt;A request fails.&lt;/p&gt;

&lt;p&gt;Something is not inserting into the database.&lt;/p&gt;

&lt;p&gt;And suddenly the codebase turns into this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nf"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="nf"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$campaign&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You add logs in controllers.&lt;/p&gt;

&lt;p&gt;Then services.&lt;/p&gt;

&lt;p&gt;Then repositories.&lt;/p&gt;

&lt;p&gt;Then queue workers.&lt;/p&gt;

&lt;p&gt;Then event listeners.&lt;/p&gt;

&lt;p&gt;And after two hours, you are still confused.&lt;/p&gt;

&lt;p&gt;Because the real problem is not where you are looking.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Day I Realized Controller Debugging Wasn’t Enough
&lt;/h2&gt;

&lt;p&gt;A few months ago, a developer on a team I worked with faced a strange issue.&lt;/p&gt;

&lt;p&gt;A simple form submission was supposed to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create a user&lt;/li&gt;
&lt;li&gt;assign a campaign&lt;/li&gt;
&lt;li&gt;generate a lead&lt;/li&gt;
&lt;li&gt;push a welcome email into queue&lt;/li&gt;
&lt;li&gt;write an activity log&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pretty normal workflow.&lt;/p&gt;

&lt;p&gt;But randomly, some users were being created without campaign data.&lt;/p&gt;

&lt;p&gt;Sometimes the queue job worked.&lt;/p&gt;

&lt;p&gt;Sometimes it didn’t.&lt;/p&gt;

&lt;p&gt;Sometimes the transaction rolled back silently.&lt;/p&gt;

&lt;p&gt;The first reaction?&lt;/p&gt;

&lt;p&gt;Start adding logs everywhere.&lt;/p&gt;

&lt;p&gt;Inside controllers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Controller hit'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside services:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Campaign assigned'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside queue workers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Email queued'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside transactions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="no"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;beginTransaction&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code became a forest of debugging statements.&lt;/p&gt;

&lt;p&gt;Still no clear answer.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Problem
&lt;/h2&gt;

&lt;p&gt;Here’s what most developers forget:&lt;/p&gt;

&lt;p&gt;No matter how beautiful your architecture is…&lt;/p&gt;

&lt;p&gt;No matter whether you use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Laravel&lt;/li&gt;
&lt;li&gt;Raw PHP&lt;/li&gt;
&lt;li&gt;Node.js&lt;/li&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;li&gt;Java&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the end of the day, every query goes to one place:&lt;/p&gt;

&lt;p&gt;MySQL.&lt;/p&gt;

&lt;p&gt;Always.&lt;/p&gt;

&lt;p&gt;Your application is just the messenger.&lt;/p&gt;

&lt;p&gt;The database sees everything.&lt;/p&gt;

&lt;p&gt;That realization changes how you debug systems.&lt;/p&gt;




&lt;h2&gt;
  
  
  Instead of Guessing, Watch the Database Directly
&lt;/h2&gt;

&lt;p&gt;The moment we enabled MySQL General Query Log, everything became obvious.&lt;/p&gt;

&lt;p&gt;We literally watched the queries execute live.&lt;/p&gt;

&lt;p&gt;One terminal command showed the full story.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;GLOBAL&lt;/span&gt; &lt;span class="n"&gt;general_log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'ON'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&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;tail&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; /var/lib/mysql/hostname.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And suddenly we could see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;campaigns&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;ROLLBACK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last line explained everything.&lt;/p&gt;

&lt;p&gt;The transaction was rolling back because another process locked a table for a few seconds.&lt;/p&gt;

&lt;p&gt;No controller log would have shown the full picture that clearly.&lt;/p&gt;




&lt;h2&gt;
  
  
  This Is Why Framework-Level Debugging Often Fails
&lt;/h2&gt;

&lt;p&gt;Modern applications are no longer simple.&lt;/p&gt;

&lt;p&gt;A single request may involve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;queues&lt;/li&gt;
&lt;li&gt;events&lt;/li&gt;
&lt;li&gt;transactions&lt;/li&gt;
&lt;li&gt;scheduled jobs&lt;/li&gt;
&lt;li&gt;caching&lt;/li&gt;
&lt;li&gt;background workers&lt;/li&gt;
&lt;li&gt;third-party APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the time you debug from inside the controller, the actual issue may already be happening somewhere else entirely.&lt;/p&gt;

&lt;p&gt;This is why developers sometimes spend hours debugging “application logic” when the real problem is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a deadlock&lt;/li&gt;
&lt;li&gt;a lock wait&lt;/li&gt;
&lt;li&gt;a slow query&lt;/li&gt;
&lt;li&gt;missing index&lt;/li&gt;
&lt;li&gt;rollback&lt;/li&gt;
&lt;li&gt;transaction conflict&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And MySQL already knows all of this.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Most Useful MySQL Debugging Tools
&lt;/h2&gt;

&lt;p&gt;Honestly, there are four MySQL features every backend developer should know.&lt;/p&gt;

&lt;p&gt;Not just DBAs.&lt;/p&gt;

&lt;p&gt;Actual application developers.&lt;/p&gt;

&lt;p&gt;Because these tools solve real-world production headaches.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. General Query Log
&lt;/h2&gt;

&lt;p&gt;See everything.&lt;/p&gt;

&lt;p&gt;This is the closest thing to “watching the database think.”&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;GLOBAL&lt;/span&gt; &lt;span class="n"&gt;general_log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'ON'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now every query gets logged.&lt;/p&gt;

&lt;p&gt;You can literally submit a form and watch the database flow in real time.&lt;/p&gt;

&lt;p&gt;This becomes incredibly useful when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one request touches multiple tables&lt;/li&gt;
&lt;li&gt;transactions fail&lt;/li&gt;
&lt;li&gt;duplicate queries happen&lt;/li&gt;
&lt;li&gt;hidden queries execute behind ORM magic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Especially in large Laravel applications where Eloquent sometimes hides too much.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Slow Query Log
&lt;/h2&gt;

&lt;p&gt;Find hidden performance problems.&lt;/p&gt;

&lt;p&gt;This one saves applications.&lt;/p&gt;

&lt;p&gt;Seriously.&lt;/p&gt;

&lt;p&gt;Sometimes developers optimize controllers endlessly while the real problem is one terrible query.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;GLOBAL&lt;/span&gt; &lt;span class="n"&gt;slow_query_log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'ON'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;GLOBAL&lt;/span&gt; &lt;span class="n"&gt;long_query_time&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now MySQL logs anything slower than one second.&lt;/p&gt;

&lt;p&gt;This helps identify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;missing indexes&lt;/li&gt;
&lt;li&gt;N+1 problems&lt;/li&gt;
&lt;li&gt;huge scans&lt;/li&gt;
&lt;li&gt;inefficient joins&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I once saw a dashboard drop from 12 seconds to under 800ms just because a slow query log exposed a missing index.&lt;/p&gt;

&lt;p&gt;The application code itself was completely fine.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. InnoDB Status
&lt;/h2&gt;

&lt;p&gt;Understand deadlocks &amp;amp; locks.&lt;/p&gt;

&lt;p&gt;This command feels like magic the first time you use it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SHOW&lt;/span&gt; &lt;span class="n"&gt;ENGINE&lt;/span&gt; &lt;span class="n"&gt;INNODB&lt;/span&gt; &lt;span class="n"&gt;STATUS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your application ever experiences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;hanging requests&lt;/li&gt;
&lt;li&gt;frozen queues&lt;/li&gt;
&lt;li&gt;stuck inserts&lt;/li&gt;
&lt;li&gt;transaction conflicts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This command can immediately reveal:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



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

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

&lt;/div&gt;



&lt;p&gt;And suddenly the mystery disappears.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. General Log Table Audit
&lt;/h2&gt;

&lt;p&gt;This is where debugging becomes much more practical.&lt;/p&gt;

&lt;p&gt;Most developers enable General Query Log and only think about the log file.&lt;/p&gt;

&lt;p&gt;But MySQL can also write general logs into a table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;general_log&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That means you can inspect logs using normal SQL.&lt;/p&gt;

&lt;p&gt;You can filter by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;latest queries&lt;/li&gt;
&lt;li&gt;specific table name&lt;/li&gt;
&lt;li&gt;specific command type&lt;/li&gt;
&lt;li&gt;specific MySQL thread ID&lt;/li&gt;
&lt;li&gt;insert/update/delete queries&lt;/li&gt;
&lt;li&gt;commit or rollback queries&lt;/li&gt;
&lt;li&gt;transaction flow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is much better than randomly placing &lt;code&gt;Log::info()&lt;/code&gt; everywhere.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisite: Make Sure General Log Writes to Table
&lt;/h2&gt;

&lt;p&gt;Before querying &lt;code&gt;mysql.general_log&lt;/code&gt;, check where MySQL is writing logs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SHOW&lt;/span&gt; &lt;span class="n"&gt;VARIABLES&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'log_output'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SHOW&lt;/span&gt; &lt;span class="n"&gt;VARIABLES&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'general_log'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;log_output&lt;/code&gt; is only &lt;code&gt;FILE&lt;/code&gt;, logs will go to a file.&lt;/p&gt;

&lt;p&gt;If you want to query logs from a table, enable table output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;GLOBAL&lt;/span&gt; &lt;span class="n"&gt;log_output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'TABLE'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;GLOBAL&lt;/span&gt; &lt;span class="n"&gt;general_log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'ON'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want both file and table logging:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;GLOBAL&lt;/span&gt; &lt;span class="n"&gt;log_output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'TABLE,FILE'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;GLOBAL&lt;/span&gt; &lt;span class="n"&gt;general_log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'ON'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now MySQL will write General Query Log entries into:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;general_log&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Important note:&lt;/p&gt;

&lt;p&gt;You need enough MySQL permission to run &lt;code&gt;SET GLOBAL&lt;/code&gt; and read from &lt;code&gt;mysql.general_log&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is usually something you do in a local, staging, or temporary production debugging session with proper access.&lt;/p&gt;




&lt;h2&gt;
  
  
  View Latest Queries from General Log Table
&lt;/h2&gt;

&lt;p&gt;Once General Query Log is enabled with table output, you can inspect the latest queries like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;event_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;command_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;argument&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;general_log&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;event_time&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives you the real database activity.&lt;/p&gt;

&lt;p&gt;Not what you think Laravel executed.&lt;/p&gt;

&lt;p&gt;Not what your controller expected.&lt;/p&gt;

&lt;p&gt;Not what your service class assumed.&lt;/p&gt;

&lt;p&gt;What MySQL actually received.&lt;/p&gt;




&lt;h2&gt;
  
  
  Filter Only Actual SQL Queries
&lt;/h2&gt;

&lt;p&gt;The general log contains different command types.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Connect&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Query&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Prepare&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Execute&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Quit&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most of the time, you only care about actual SQL statements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;event_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;command_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;argument&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;general_log&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;command_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Query'&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;event_time&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This removes connection noise and focuses on real queries.&lt;/p&gt;




&lt;h2&gt;
  
  
  Find Queries for a Specific Table
&lt;/h2&gt;

&lt;p&gt;Suppose your issue is related to the &lt;code&gt;users&lt;/code&gt; table.&lt;/p&gt;

&lt;p&gt;You can filter only queries that touched &lt;code&gt;users&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;event_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;command_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;argument&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;general_log&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'%users%'&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;event_time&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For campaign-related debugging:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;event_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;command_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;argument&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;general_log&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'%campaigns%'&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;event_time&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is extremely useful when one request touches multiple tables.&lt;/p&gt;

&lt;p&gt;For example, one form submission may touch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;users&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;campaigns&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;leads&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jobs&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;activity_logs&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of checking five different PHP files, you can ask MySQL directly:&lt;/p&gt;

&lt;p&gt;“What happened to this table?”&lt;/p&gt;




&lt;h2&gt;
  
  
  Check Only INSERT Queries
&lt;/h2&gt;

&lt;p&gt;If your form submission is supposed to create a user, check whether the &lt;code&gt;INSERT&lt;/code&gt; query actually reached MySQL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;event_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;command_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;argument&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;general_log&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;command_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Query'&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'INSERT%'&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;event_time&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Specific table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;event_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;command_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;argument&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;general_log&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;command_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Query'&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'INSERT%'&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'%users%'&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;event_time&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can answer important questions:&lt;/p&gt;

&lt;p&gt;Did the insert query happen?&lt;/p&gt;

&lt;p&gt;Did it happen once?&lt;/p&gt;

&lt;p&gt;Did it happen multiple times?&lt;/p&gt;

&lt;p&gt;Did it happen before rollback?&lt;/p&gt;

&lt;p&gt;Did another process insert something unexpectedly?&lt;/p&gt;

&lt;p&gt;That is the kind of answer controller logs often fail to provide.&lt;/p&gt;




&lt;h2&gt;
  
  
  Check UPDATE and DELETE Queries
&lt;/h2&gt;

&lt;p&gt;For update issues:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;event_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;command_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;argument&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;general_log&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;command_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Query'&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'UPDATE%'&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;event_time&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For delete issues:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;event_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;command_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;argument&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;general_log&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;command_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Query'&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'DELETE%'&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;event_time&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a specific table update:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;event_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;command_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;argument&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;general_log&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;command_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Query'&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'UPDATE%'&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'%campaigns%'&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;event_time&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This helps you catch accidental updates or deletes triggered by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;model observers&lt;/li&gt;
&lt;li&gt;queue jobs&lt;/li&gt;
&lt;li&gt;event listeners&lt;/li&gt;
&lt;li&gt;cron jobs&lt;/li&gt;
&lt;li&gt;scheduled commands&lt;/li&gt;
&lt;li&gt;background workers&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Check COMMIT and ROLLBACK
&lt;/h2&gt;

&lt;p&gt;This is one of the most important parts.&lt;/p&gt;

&lt;p&gt;Sometimes the query runs successfully.&lt;/p&gt;

&lt;p&gt;But the transaction rolls back later.&lt;/p&gt;

&lt;p&gt;To check transaction result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;event_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;command_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;argument&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;general_log&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;LOWER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'commit'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'rollback'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;event_time&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ROLLBACK&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;after your insert or update queries, then your problem is not the insert query itself.&lt;/p&gt;

&lt;p&gt;Your problem is somewhere inside the transaction.&lt;/p&gt;

&lt;p&gt;Maybe an exception happened.&lt;/p&gt;

&lt;p&gt;Maybe a lock wait happened.&lt;/p&gt;

&lt;p&gt;Maybe another process created a conflict.&lt;/p&gt;

&lt;p&gt;Maybe a queue or event triggered something unexpected.&lt;/p&gt;

&lt;p&gt;This is exactly why debugging only from the controller is not enough.&lt;/p&gt;




&lt;h2&gt;
  
  
  Trace One Request Using Thread ID
&lt;/h2&gt;

&lt;p&gt;This is where things become really powerful.&lt;/p&gt;

&lt;p&gt;Every MySQL connection has a &lt;code&gt;thread_id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you find one suspicious query, copy its &lt;code&gt;thread_id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then filter the full flow for that connection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;event_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;command_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;argument&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;general_log&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;thread_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12345&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;event_time&lt;/span&gt; &lt;span class="k"&gt;ASC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can see the query sequence in order.&lt;/p&gt;

&lt;p&gt;Example output may look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;START&lt;/span&gt; &lt;span class="n"&gt;TRANSACTION&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;campaigns&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;leads&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;ROLLBACK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That tells the real story.&lt;/p&gt;

&lt;p&gt;Not guesswork.&lt;/p&gt;

&lt;p&gt;Not random logs.&lt;/p&gt;

&lt;p&gt;The actual database flow.&lt;/p&gt;




&lt;h2&gt;
  
  
  Trace Transaction Start, Commit, and Rollback
&lt;/h2&gt;

&lt;p&gt;If you only want transaction-related statements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;event_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;command_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;argument&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;general_log&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;LOWER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'start transaction%'&lt;/span&gt;
   &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="k"&gt;LOWER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'begin'&lt;/span&gt;
   &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="k"&gt;LOWER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'commit'&lt;/span&gt;
   &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="k"&gt;LOWER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'rollback'&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;event_time&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a specific thread:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;event_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;command_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;argument&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;general_log&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;thread_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12345&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;LOWER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'start transaction%'&lt;/span&gt;
        &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="k"&gt;LOWER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'begin'&lt;/span&gt;
        &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="k"&gt;LOWER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'commit'&lt;/span&gt;
        &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="k"&gt;LOWER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'rollback'&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;event_time&lt;/span&gt; &lt;span class="k"&gt;ASC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is very useful when a form submission works sometimes and fails randomly.&lt;/p&gt;

&lt;p&gt;Because now you can see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;when the transaction started&lt;/li&gt;
&lt;li&gt;which queries happened inside it&lt;/li&gt;
&lt;li&gt;whether it committed&lt;/li&gt;
&lt;li&gt;whether it rolled back&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Can We Filter POST Requests from MySQL?
&lt;/h2&gt;

&lt;p&gt;Not directly.&lt;/p&gt;

&lt;p&gt;MySQL does not know whether the original HTTP request was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GET&lt;/li&gt;
&lt;li&gt;POST&lt;/li&gt;
&lt;li&gt;PUT&lt;/li&gt;
&lt;li&gt;PATCH&lt;/li&gt;
&lt;li&gt;DELETE&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;MySQL only sees SQL.&lt;/p&gt;

&lt;p&gt;So from the database side, you usually filter write operations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSERT
UPDATE
DELETE
COMMIT
ROLLBACK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, a POST request that creates a user usually results in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A PATCH request may result in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A delete action may result in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So instead of searching for “POST” inside MySQL, search for the SQL operation caused by that POST request.&lt;/p&gt;




&lt;h2&gt;
  
  
  Application-Level Request Tracking Example
&lt;/h2&gt;

&lt;p&gt;If you want to connect application request logs with MySQL logs, add a request ID at application level.&lt;/p&gt;

&lt;p&gt;Laravel example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Str&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Log&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$requestId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;request&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;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'X-Request-Id'&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;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;Str&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;withContext&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="s1"&gt;'request_id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$requestId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'method'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;method&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="s1"&gt;'path'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Request started'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now your Laravel logs can tell you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;request_id: 7e71e1d8-3d9b-45e5-8a80-ef98c0d9c101
method: POST
path: /users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you can add a temporary MySQL session marker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="no"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;statement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"SET @debug_request_id = ?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$requestId&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This statement will also appear inside the General Query Log.&lt;/p&gt;

&lt;p&gt;Now search for that marker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;event_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;command_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;argument&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;general_log&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'%debug_request_id%'&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;event_time&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you find the &lt;code&gt;thread_id&lt;/code&gt;, inspect all queries from that same thread:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;event_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;command_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;argument&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;general_log&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;thread_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12345&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;event_time&lt;/span&gt; &lt;span class="k"&gt;ASC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives you a bridge between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Laravel request&lt;/li&gt;
&lt;li&gt;controller/service logs&lt;/li&gt;
&lt;li&gt;actual MySQL queries&lt;/li&gt;
&lt;li&gt;transaction commit/rollback result&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is much better than guessing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example: Debugging a Failed User Creation
&lt;/h2&gt;

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

&lt;ul&gt;
&lt;li&gt;user submits form&lt;/li&gt;
&lt;li&gt;Laravel receives POST request&lt;/li&gt;
&lt;li&gt;application starts transaction&lt;/li&gt;
&lt;li&gt;user is inserted&lt;/li&gt;
&lt;li&gt;campaign is assigned&lt;/li&gt;
&lt;li&gt;lead is generated&lt;/li&gt;
&lt;li&gt;something fails&lt;/li&gt;
&lt;li&gt;transaction rolls back&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From application logs, you may only see:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;But from MySQL general log, you can check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;event_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;command_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;argument&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;general_log&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'%users%'&lt;/span&gt;
   &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'%campaigns%'&lt;/span&gt;
   &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'%leads%'&lt;/span&gt;
   &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="k"&gt;LOWER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'commit'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'rollback'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;event_time&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you may discover:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;campaigns&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;leads&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;ROLLBACK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the problem is clear.&lt;/p&gt;

&lt;p&gt;The user insert happened.&lt;/p&gt;

&lt;p&gt;The campaign update happened.&lt;/p&gt;

&lt;p&gt;The lead insert happened.&lt;/p&gt;

&lt;p&gt;But the transaction rolled back.&lt;/p&gt;

&lt;p&gt;So the debugging direction changes immediately.&lt;/p&gt;

&lt;p&gt;You stop asking:&lt;/p&gt;

&lt;p&gt;“Why did user insert fail?”&lt;/p&gt;

&lt;p&gt;And start asking:&lt;/p&gt;

&lt;p&gt;“What caused the rollback?”&lt;/p&gt;

&lt;p&gt;That is a huge difference.&lt;/p&gt;




&lt;h2&gt;
  
  
  Clean General Log Table
&lt;/h2&gt;

&lt;p&gt;Do not let &lt;code&gt;mysql.general_log&lt;/code&gt; grow forever.&lt;/p&gt;

&lt;p&gt;After debugging, clean it.&lt;/p&gt;

&lt;p&gt;First, disable General Query Log:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;GLOBAL&lt;/span&gt; &lt;span class="n"&gt;general_log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'OFF'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then truncate the table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;TRUNCATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;general_log&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you still need debugging, enable it again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;GLOBAL&lt;/span&gt; &lt;span class="n"&gt;general_log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'ON'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Full cleanup flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;GLOBAL&lt;/span&gt; &lt;span class="n"&gt;general_log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'OFF'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;TRUNCATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;general_log&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;GLOBAL&lt;/span&gt; &lt;span class="n"&gt;general_log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'ON'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Important note:&lt;/p&gt;

&lt;p&gt;Do not use this as permanent production logging.&lt;/p&gt;

&lt;p&gt;This is for temporary debugging.&lt;/p&gt;




&lt;h2&gt;
  
  
  Disable General Query Log After Debugging
&lt;/h2&gt;

&lt;p&gt;This is the part developers often forget.&lt;/p&gt;

&lt;p&gt;After investigation, turn it off:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;GLOBAL&lt;/span&gt; &lt;span class="n"&gt;general_log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'OFF'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can verify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SHOW&lt;/span&gt; &lt;span class="n"&gt;VARIABLES&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'general_log'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the value is &lt;code&gt;OFF&lt;/code&gt;, logging is disabled.&lt;/p&gt;




&lt;h2&gt;
  
  
  One Important Thing Most Developers Ignore
&lt;/h2&gt;

&lt;p&gt;Do not leave &lt;code&gt;general_log&lt;/code&gt; permanently enabled in production.&lt;/p&gt;

&lt;p&gt;That is a bad idea.&lt;/p&gt;

&lt;p&gt;Because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;logs become massive&lt;/li&gt;
&lt;li&gt;storage grows quickly&lt;/li&gt;
&lt;li&gt;performance can suffer&lt;/li&gt;
&lt;li&gt;sensitive query data may appear in logs&lt;/li&gt;
&lt;li&gt;debugging tables can become noisy very fast&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The smarter workflow is temporary debugging.&lt;/p&gt;




&lt;h2&gt;
  
  
  Temporary Debugging Workflow
&lt;/h2&gt;

&lt;p&gt;Enable table logging:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;GLOBAL&lt;/span&gt; &lt;span class="n"&gt;log_output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'TABLE'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;GLOBAL&lt;/span&gt; &lt;span class="n"&gt;general_log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'ON'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reproduce the issue.&lt;/p&gt;

&lt;p&gt;Check recent queries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;event_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;command_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;argument&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;general_log&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;event_time&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Filter by table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;event_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;command_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;argument&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;general_log&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'%users%'&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;event_time&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Filter by transaction result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;event_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;command_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;argument&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;general_log&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;LOWER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'commit'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'rollback'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;event_time&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Trace one thread:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;event_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;command_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;argument&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;general_log&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;thread_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12345&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;event_time&lt;/span&gt; &lt;span class="k"&gt;ASC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then disable logging:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;GLOBAL&lt;/span&gt; &lt;span class="n"&gt;general_log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'OFF'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And clean the table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;TRUNCATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;general_log&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the workflow.&lt;/p&gt;

&lt;p&gt;Enable.&lt;/p&gt;

&lt;p&gt;Reproduce.&lt;/p&gt;

&lt;p&gt;Inspect.&lt;/p&gt;

&lt;p&gt;Filter.&lt;/p&gt;

&lt;p&gt;Understand.&lt;/p&gt;

&lt;p&gt;Disable.&lt;/p&gt;

&lt;p&gt;Clean.&lt;/p&gt;

&lt;p&gt;That is how you stop guessing and start debugging from the place that sees everything:&lt;/p&gt;

</description>
      <category>mysql</category>
      <category>debugging</category>
      <category>backend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Stack Pointer vs Base Pointer: A Friendly Guide to How Function Calls Work</title>
      <dc:creator>Tahsin Abrar</dc:creator>
      <pubDate>Mon, 18 May 2026 11:38:49 +0000</pubDate>
      <link>https://dev.to/tahsin000/stack-pointer-vs-base-pointer-a-friendly-guide-to-how-function-calls-work-35nc</link>
      <guid>https://dev.to/tahsin000/stack-pointer-vs-base-pointer-a-friendly-guide-to-how-function-calls-work-35nc</guid>
      <description>&lt;p&gt;Have you ever called a function and wondered what really happens inside the computer?&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&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="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
    &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;add&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="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sum&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;We know the output will be:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;But inside the machine, a lot of quiet work happens.&lt;/p&gt;

&lt;p&gt;The CPU needs to remember:&lt;/p&gt;

&lt;p&gt;Where did this function start?&lt;/p&gt;

&lt;p&gt;Where should it return?&lt;/p&gt;

&lt;p&gt;Where are the arguments?&lt;/p&gt;

&lt;p&gt;Where are the local variables?&lt;/p&gt;

&lt;p&gt;Which function is currently running?&lt;/p&gt;

&lt;p&gt;This is where the &lt;strong&gt;stack&lt;/strong&gt;, &lt;strong&gt;stack frame&lt;/strong&gt;, &lt;strong&gt;stack pointer&lt;/strong&gt;, and &lt;strong&gt;base pointer&lt;/strong&gt; come in.&lt;/p&gt;

&lt;p&gt;Let’s break them down in a simple way.&lt;/p&gt;




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

&lt;h2&gt;
  
  
  First, What Is a Stack?
&lt;/h2&gt;

&lt;p&gt;A stack is a special area of memory used while a program is running.&lt;/p&gt;

&lt;p&gt;Think of it like a stack of plates.&lt;/p&gt;

&lt;p&gt;You put a plate on top.&lt;/p&gt;

&lt;p&gt;You remove the top plate first.&lt;/p&gt;

&lt;p&gt;You cannot remove a plate from the middle without disturbing the others.&lt;/p&gt;

&lt;p&gt;In programming, the stack works in a similar way.&lt;/p&gt;

&lt;p&gt;When a function is called, the program creates a small memory area for that function. This small area is called a &lt;strong&gt;stack frame&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When the function finishes, its stack frame is removed.&lt;/p&gt;

&lt;p&gt;So if &lt;code&gt;main()&lt;/code&gt; calls &lt;code&gt;add()&lt;/code&gt;, the stack may look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;add() stack frame
main() stack frame
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;add()&lt;/code&gt; is on top because it is currently running.&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;add()&lt;/code&gt; finishes, its stack frame is removed, and the program returns to &lt;code&gt;main()&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is a Stack Frame?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;stack frame&lt;/strong&gt; is the memory space a function gets while it is running.&lt;/p&gt;

&lt;p&gt;It usually stores things like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Function arguments
Return address
Old base pointer
Local variables
Temporary values
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For our &lt;code&gt;add()&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&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="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The stack frame may contain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x = 10
y = 4
return address
old base pointer
result = 14
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact layout depends on the CPU, compiler, operating system, and calling convention. But the main idea is the same:&lt;/p&gt;

&lt;p&gt;A function needs a private workspace while it runs.&lt;/p&gt;

&lt;p&gt;That workspace is its stack frame.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Quick Note About Memory Addresses
&lt;/h2&gt;

&lt;p&gt;Before we go deeper, let’s clear up one common confusion.&lt;/p&gt;

&lt;p&gt;On most modern systems, memory is &lt;strong&gt;byte-addressable&lt;/strong&gt;. That means every byte has its own address.&lt;/p&gt;

&lt;p&gt;So memory addresses can look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0, 1, 2, 3, 4, 5, 6, 7, 8 ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But when we draw memory in larger chunks, like 4-byte chunks on a 32-bit-style example, we often label them like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0, 4, 8, 12, 16 ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This does &lt;strong&gt;not&lt;/strong&gt; mean addresses &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;2&lt;/code&gt;, and &lt;code&gt;3&lt;/code&gt; do not exist.&lt;/p&gt;

&lt;p&gt;It simply means we are drawing memory in 4-byte blocks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Address 0  -&amp;gt; byte 1 of first block
Address 1  -&amp;gt; byte 2 of first block
Address 2  -&amp;gt; byte 3 of first block
Address 3  -&amp;gt; byte 4 of first block

Address 4  -&amp;gt; byte 1 of second block
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this article, we will use a simple 32-bit mental model where each slot is 4 bytes.&lt;/p&gt;

&lt;p&gt;So our stack addresses may move like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;80
76
72
68
64
60
56
52
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In many systems, the stack grows downward, which means the address gets smaller as new data is pushed onto the stack.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is the Stack Pointer?
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;stack pointer&lt;/strong&gt;, often called &lt;code&gt;SP&lt;/code&gt;, points to the current top of the stack.&lt;/p&gt;

&lt;p&gt;Imagine you are stacking plates.&lt;/p&gt;

&lt;p&gt;The stack pointer is like your finger pointing at the top plate.&lt;/p&gt;

&lt;p&gt;When a new value is pushed onto the stack, the stack pointer moves.&lt;/p&gt;

&lt;p&gt;When a value is popped from the stack, the stack pointer moves back.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before push:

Address 76 -&amp;gt; old value
Address 72 -&amp;gt; top of stack  &amp;lt;- SP

Push new value:

Address 76 -&amp;gt; old value
Address 72 -&amp;gt; old top
Address 68 -&amp;gt; new value     &amp;lt;- SP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because our example stack grows downward, pushing data makes &lt;code&gt;SP&lt;/code&gt; move from &lt;code&gt;72&lt;/code&gt; to &lt;code&gt;68&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So the stack pointer is dynamic.&lt;/p&gt;

&lt;p&gt;It keeps changing as the stack grows and shrinks.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is the Base Pointer?
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;base pointer&lt;/strong&gt;, often called &lt;code&gt;BP&lt;/code&gt; or frame pointer, points to a stable location inside the current function’s stack frame.&lt;/p&gt;

&lt;p&gt;Unlike the stack pointer, the base pointer usually stays fixed while the function is running.&lt;/p&gt;

&lt;p&gt;Why do we need that?&lt;/p&gt;

&lt;p&gt;Because the stack pointer keeps moving.&lt;/p&gt;

&lt;p&gt;If the program only used &lt;code&gt;SP&lt;/code&gt;, it would be hard to find local variables and arguments after more values are pushed or popped.&lt;/p&gt;

&lt;p&gt;The base pointer solves this problem.&lt;/p&gt;

&lt;p&gt;It gives the function a fixed reference point.&lt;/p&gt;

&lt;p&gt;From that fixed point, the program can find values using offsets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BP + 8   -&amp;gt; first argument
BP + 12  -&amp;gt; second argument
BP - 4   -&amp;gt; first local variable
BP - 8   -&amp;gt; second local variable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the base pointer helps the program answer questions like:&lt;/p&gt;

&lt;p&gt;Where is &lt;code&gt;x&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Where is &lt;code&gt;y&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Where is &lt;code&gt;result&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Where should I return after this function ends?&lt;/p&gt;




&lt;h2&gt;
  
  
  Stack Pointer vs Base Pointer
&lt;/h2&gt;

&lt;p&gt;Here is the simple difference:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Register&lt;/th&gt;
&lt;th&gt;Meaning&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;Stack Pointer&lt;/td&gt;
&lt;td&gt;Points to the current top of the stack&lt;/td&gt;
&lt;td&gt;Changes often&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Base Pointer&lt;/td&gt;
&lt;td&gt;Points to a fixed place in the current stack frame&lt;/td&gt;
&lt;td&gt;Usually stays fixed during the function&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A simple way to remember it:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SP&lt;/code&gt; tracks movement.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;BP&lt;/code&gt; gives stability.&lt;/p&gt;

&lt;p&gt;The stack pointer is like a moving bookmark.&lt;/p&gt;

&lt;p&gt;The base pointer is like an anchor.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Happens When &lt;code&gt;main()&lt;/code&gt; Runs?
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
    &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;add&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="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sum&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;When &lt;code&gt;main()&lt;/code&gt; starts, the program creates a stack frame for &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Inside that frame, it stores local variables such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a = 10
sum = ?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first, &lt;code&gt;sum&lt;/code&gt; does not have its final value because &lt;code&gt;add(a, 4)&lt;/code&gt; has not returned yet.&lt;/p&gt;

&lt;p&gt;So the stack may look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;main stack frame
----------------
return address
old BP
a = 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now &lt;code&gt;main()&lt;/code&gt; calls &lt;code&gt;add(a, 4)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That means the program needs a new stack frame for &lt;code&gt;add()&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Happens When &lt;code&gt;add()&lt;/code&gt; Is Called?
&lt;/h2&gt;

&lt;p&gt;This line is important:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;add&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="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The program needs to call &lt;code&gt;add()&lt;/code&gt; with two values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x = 10
y = 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So it creates a new stack frame for &lt;code&gt;add()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A simplified stack frame may look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;add stack frame
---------------
y = 4
x = 10
return address
old BP
result = 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The order can vary depending on the system, but the idea is the same.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;add()&lt;/code&gt; function needs:&lt;/p&gt;

&lt;p&gt;Its arguments: &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;A return address: where to go back after &lt;code&gt;add()&lt;/code&gt; finishes&lt;/p&gt;

&lt;p&gt;The old base pointer: so the caller’s stack frame can be restored&lt;/p&gt;

&lt;p&gt;Its local variable: &lt;code&gt;result&lt;/code&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Do We Need a Return Address?
&lt;/h2&gt;

&lt;p&gt;When &lt;code&gt;main()&lt;/code&gt; calls &lt;code&gt;add()&lt;/code&gt;, the CPU jumps to the code for &lt;code&gt;add()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But after &lt;code&gt;add()&lt;/code&gt; finishes, the CPU must know where to go back.&lt;/p&gt;

&lt;p&gt;It needs to return to this line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;add&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="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More specifically, it needs to return to the next step after the function call, so the returned value can be stored in &lt;code&gt;sum&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That “go back here” location is called the &lt;strong&gt;return address&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Without a return address, the program would get lost.&lt;/p&gt;

&lt;p&gt;It would finish &lt;code&gt;add()&lt;/code&gt; and then have no idea where to continue.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Save the Old Base Pointer?
&lt;/h2&gt;

&lt;p&gt;Before &lt;code&gt;add()&lt;/code&gt; starts, &lt;code&gt;main()&lt;/code&gt; already has its own base pointer.&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;add()&lt;/code&gt; starts, it gets a new base pointer for its own stack frame.&lt;/p&gt;

&lt;p&gt;But when &lt;code&gt;add()&lt;/code&gt; finishes, the program must restore the old base pointer so &lt;code&gt;main()&lt;/code&gt; can continue correctly.&lt;/p&gt;

&lt;p&gt;That is why the old base pointer is saved inside the new stack frame.&lt;/p&gt;

&lt;p&gt;Think of it like leaving a breadcrumb.&lt;/p&gt;

&lt;p&gt;Before entering a new function, the program says:&lt;/p&gt;

&lt;p&gt;“Let me save where I came from, so I can restore it later.”&lt;/p&gt;

&lt;p&gt;When the function ends, the old base pointer is loaded back.&lt;/p&gt;

&lt;p&gt;Now the caller’s stack frame becomes active again.&lt;/p&gt;




&lt;h2&gt;
  
  
  How &lt;code&gt;add()&lt;/code&gt; Finds &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;, and &lt;code&gt;result&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Inside &lt;code&gt;add()&lt;/code&gt;, we have this line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;result&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;y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CPU does not understand variable names like humans do.&lt;/p&gt;

&lt;p&gt;It does not think:&lt;/p&gt;

&lt;p&gt;“Oh, &lt;code&gt;x&lt;/code&gt; means 10 and &lt;code&gt;y&lt;/code&gt; means 4.”&lt;/p&gt;

&lt;p&gt;Instead, the compiler maps variables to memory locations.&lt;/p&gt;

&lt;p&gt;Using the base pointer, the program can find values by offsets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BP + 8   -&amp;gt; x
BP + 12  -&amp;gt; y
BP - 4   -&amp;gt; result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So when the function needs &lt;code&gt;x&lt;/code&gt;, it looks at something like:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;When it needs &lt;code&gt;y&lt;/code&gt;, it looks at:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;When it needs to store &lt;code&gt;result&lt;/code&gt;, it may use:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;So the line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;result&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;y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;becomes something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;read value at BP + 8
read value at BP + 12
add them
store the answer at BP - 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x = 10
y = 4

result = 14
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Returning Back to &lt;code&gt;main()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Now &lt;code&gt;add()&lt;/code&gt; reaches this line:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;The function returns &lt;code&gt;14&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then the &lt;code&gt;add()&lt;/code&gt; stack frame is no longer needed.&lt;/p&gt;

&lt;p&gt;So the program removes it from the stack.&lt;/p&gt;

&lt;p&gt;The stack pointer moves back.&lt;/p&gt;

&lt;p&gt;The old base pointer is restored.&lt;/p&gt;

&lt;p&gt;The return address tells the CPU where to continue.&lt;/p&gt;

&lt;p&gt;Now we are back inside &lt;code&gt;main()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The returned value &lt;code&gt;14&lt;/code&gt; is stored in &lt;code&gt;sum&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;14&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then this line runs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we see:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  A Simple Visual Summary
&lt;/h2&gt;

&lt;p&gt;Here is a simplified version of what happens.&lt;/p&gt;

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

&lt;p&gt;Before calling &lt;code&gt;add()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;main stack frame
----------------
a = 10
sum = ?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While &lt;code&gt;add()&lt;/code&gt; is running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;add stack frame
---------------
x = 10
y = 4
result = 14

main stack frame
----------------
a = 10
sum = ?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After &lt;code&gt;add()&lt;/code&gt; returns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;main stack frame
----------------
a = 10
sum = 14
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then &lt;code&gt;main()&lt;/code&gt; prints:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  Does This Always Work Exactly Like This?
&lt;/h2&gt;

&lt;p&gt;Not always.&lt;/p&gt;

&lt;p&gt;This article uses a simplified model to make the concept easy to understand.&lt;/p&gt;

&lt;p&gt;Real systems can be more complex.&lt;/p&gt;

&lt;p&gt;Modern compilers may optimize away the base pointer.&lt;/p&gt;

&lt;p&gt;Function arguments may be passed through registers instead of the stack.&lt;/p&gt;

&lt;p&gt;Go uses goroutine stacks, which can grow and move.&lt;/p&gt;

&lt;p&gt;The exact stack layout depends on architecture, compiler version, and calling convention.&lt;/p&gt;

&lt;p&gt;But the core idea is still useful:&lt;/p&gt;

&lt;p&gt;Functions need stack frames.&lt;/p&gt;

&lt;p&gt;The stack pointer tracks the top of the stack.&lt;/p&gt;

&lt;p&gt;The base pointer gives a stable reference point inside a function frame.&lt;/p&gt;

&lt;p&gt;Return addresses help the program continue from the correct place.&lt;/p&gt;

&lt;p&gt;Old base pointers help restore the caller’s frame.&lt;/p&gt;

&lt;p&gt;Once you understand this model, debugging, assembly, recursion, memory layout, and low-level programming all become much less mysterious.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Real-Life Way to Remember It
&lt;/h2&gt;

&lt;p&gt;Imagine you are reading a book and solving exercises.&lt;/p&gt;

&lt;p&gt;You are on Chapter 5.&lt;/p&gt;

&lt;p&gt;Suddenly, Chapter 5 says:&lt;/p&gt;

&lt;p&gt;“Before continuing, go solve Example 2 from Chapter 3.”&lt;/p&gt;

&lt;p&gt;So you place a bookmark in Chapter 5.&lt;/p&gt;

&lt;p&gt;Then you go to Chapter 3 and solve the example.&lt;/p&gt;

&lt;p&gt;After finishing, you return to the bookmark in Chapter 5.&lt;/p&gt;

&lt;p&gt;In this story:&lt;/p&gt;

&lt;p&gt;The bookmark is like the return address.&lt;/p&gt;

&lt;p&gt;Your current page position is like the stack pointer.&lt;/p&gt;

&lt;p&gt;The start of your current exercise notes is like the base pointer.&lt;/p&gt;

&lt;p&gt;The notes for each exercise are like stack frames.&lt;/p&gt;

&lt;p&gt;Every function call is like temporarily jumping into another task, while carefully remembering how to come back.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>computerscience</category>
      <category>go</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How to Connect a Namecheap Domain to a DigitalOcean Droplet with Nginx</title>
      <dc:creator>Tahsin Abrar</dc:creator>
      <pubDate>Sat, 16 May 2026 15:31:38 +0000</pubDate>
      <link>https://dev.to/tahsin000/how-to-connect-a-namecheap-domain-to-a-digitalocean-droplet-with-nginx-2mok</link>
      <guid>https://dev.to/tahsin000/how-to-connect-a-namecheap-domain-to-a-digitalocean-droplet-with-nginx-2mok</guid>
      <description>&lt;p&gt;Buying a domain is exciting. Creating a server is exciting too.&lt;/p&gt;

&lt;p&gt;But the moment you try to connect both of them, things can feel confusing.&lt;/p&gt;

&lt;p&gt;You bought your domain from &lt;strong&gt;Namecheap&lt;/strong&gt;. You created a VPS on &lt;strong&gt;DigitalOcean&lt;/strong&gt;. Now you expect your website to open when someone visits your domain.&lt;/p&gt;

&lt;p&gt;But unlike shared hosting or cPanel hosting, DigitalOcean does not automatically connect everything for you.&lt;/p&gt;

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

&lt;p&gt;You need to set up two important things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;DNS&lt;/strong&gt; : so your domain points to your server&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nginx&lt;/strong&gt; : so your server knows how to serve your website&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this guide, we will walk through the full setup in a simple and beginner-friendly way.&lt;/p&gt;

&lt;p&gt;By the end, your domain will point to your DigitalOcean Droplet, Nginx will serve your website, and HTTPS will be enabled.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Big Picture
&lt;/h2&gt;

&lt;p&gt;Before touching any settings, let’s understand the flow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Namecheap Domain
        ↓
DNS points to DigitalOcean IP
        ↓
DigitalOcean Droplet
        ↓
Nginx Web Server
        ↓
Your Website
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your domain is like a human-friendly address.&lt;/p&gt;

&lt;p&gt;Your DigitalOcean Droplet is the actual server.&lt;/p&gt;

&lt;p&gt;DNS connects the domain to the server.&lt;/p&gt;

&lt;p&gt;Nginx receives the request and serves your website files or forwards traffic to your app.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Create a DigitalOcean Droplet
&lt;/h2&gt;

&lt;p&gt;First, create a Droplet on DigitalOcean.&lt;/p&gt;

&lt;p&gt;For a beginner project or test website, this setup is usually enough:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ubuntu 22.04 LTS
Basic Droplet
1 GB RAM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the Droplet is created, DigitalOcean will give you a public IP address.&lt;/p&gt;

&lt;p&gt;It will look something like this:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Keep this IP address safe. You will need it in the next step.&lt;/p&gt;

&lt;p&gt;This IP is where your domain will point.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Point Your Namecheap Domain to DigitalOcean
&lt;/h2&gt;

&lt;p&gt;Now go to your Namecheap account.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Domain List
→ Manage
→ Advanced DNS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are two common ways to connect your domain.&lt;/p&gt;




&lt;h2&gt;
  
  
  Option A: Use A Records
&lt;/h2&gt;

&lt;p&gt;This is the easiest method for beginners.&lt;/p&gt;

&lt;p&gt;Add these DNS records:&lt;/p&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;Host&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A Record&lt;/td&gt;
&lt;td&gt;@&lt;/td&gt;
&lt;td&gt;Your DigitalOcean IP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A Record&lt;/td&gt;
&lt;td&gt;www&lt;/td&gt;
&lt;td&gt;Your DigitalOcean IP&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Example:&lt;/p&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;Host&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A Record&lt;/td&gt;
&lt;td&gt;@&lt;/td&gt;
&lt;td&gt;159.89.xxx.xxx&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A Record&lt;/td&gt;
&lt;td&gt;www&lt;/td&gt;
&lt;td&gt;159.89.xxx.xxx&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You can keep TTL as the default value.&lt;/p&gt;

&lt;p&gt;Here is what this does:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;So both the root domain and the &lt;code&gt;www&lt;/code&gt; version will go to the same Droplet.&lt;/p&gt;

&lt;p&gt;For most simple projects, this is the best starting point.&lt;/p&gt;




&lt;h2&gt;
  
  
  Option B: Use DigitalOcean Nameservers
&lt;/h2&gt;

&lt;p&gt;Another option is to manage DNS from DigitalOcean instead of Namecheap.&lt;/p&gt;

&lt;p&gt;In DigitalOcean, go to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Networking
→ Domains
→ Add Domain
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add your domain there.&lt;/p&gt;

&lt;p&gt;DigitalOcean will give you nameservers like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ns1.digitalocean.com
ns2.digitalocean.com
ns3.digitalocean.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then go back to Namecheap:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Domain
→ Manage
→ Nameservers
→ Custom DNS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add those three DigitalOcean nameservers and save.&lt;/p&gt;

&lt;p&gt;This method is useful when you want to manage all DNS records from DigitalOcean, especially if you have multiple subdomains or services.&lt;/p&gt;




&lt;h2&gt;
  
  
  Which DNS Method Should You Choose?
&lt;/h2&gt;

&lt;p&gt;For beginners, use &lt;strong&gt;A Records&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It is simple, clear, and easy to debug.&lt;/p&gt;

&lt;p&gt;Use DigitalOcean nameservers when your setup becomes larger, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;api.example.com
app.example.com
blog.example.com
admin.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For now, we will continue with the beginner-friendly A Record method.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Wait for DNS Propagation
&lt;/h2&gt;

&lt;p&gt;DNS changes are not always instant.&lt;/p&gt;

&lt;p&gt;Sometimes they work in a few minutes. Sometimes they take longer.&lt;/p&gt;

&lt;p&gt;Usually, it can take:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;5 minutes to 1 hour
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In some cases, it may take up to:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;You can use tools like DNS Checker to see whether your domain is pointing to the correct server IP.&lt;/p&gt;

&lt;p&gt;A common beginner mistake is changing DNS and immediately thinking something is broken. Sometimes nothing is broken. DNS just needs a little time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Connect to Your Server with SSH
&lt;/h2&gt;

&lt;p&gt;Now connect to your DigitalOcean Droplet.&lt;/p&gt;

&lt;p&gt;On Mac or Linux, open your terminal.&lt;/p&gt;

&lt;p&gt;On Windows, you can use PowerShell or PuTTY.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh root@YOUR_SERVER_IP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh root@159.89.xxx.xxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first time you connect, your terminal may ask for confirmation. Type:&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;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then enter your password or use your SSH key, depending on how you created the Droplet.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5: Install Nginx
&lt;/h2&gt;

&lt;p&gt;Once you are inside the server, update the package list:&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;sudo &lt;/span&gt;apt update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then install Nginx:&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;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;nginx &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check if Nginx is running:&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;sudo &lt;/span&gt;systemctl status nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything is working, you should see that Nginx is active.&lt;/p&gt;

&lt;p&gt;At this point, if you open your server IP in the browser, you may see the default Nginx welcome page.&lt;/p&gt;

&lt;p&gt;That means your web server is working.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 6: Configure the Firewall
&lt;/h2&gt;

&lt;p&gt;Ubuntu servers often use &lt;code&gt;ufw&lt;/code&gt; for firewall management.&lt;/p&gt;

&lt;p&gt;Allow Nginx traffic:&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;sudo &lt;/span&gt;ufw allow &lt;span class="s1"&gt;'Nginx Full'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also allow SSH so you do not lock yourself out:&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;sudo &lt;/span&gt;ufw allow OpenSSH
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then enable the firewall:&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;sudo &lt;/span&gt;ufw &lt;span class="nb"&gt;enable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can check the firewall status with:&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;sudo &lt;/span&gt;ufw status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see that HTTP, HTTPS, and SSH traffic are allowed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 7: Create a Website Folder
&lt;/h2&gt;

&lt;p&gt;Now create a folder for your website.&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;sudo mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /var/www/myproject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a test HTML file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /var/www/myproject/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Hello from DigitalOcean&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CTRL + X
Y
Enter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This simple file will help us confirm that the domain and Nginx setup are working.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 8: Create an Nginx Server Block
&lt;/h2&gt;

&lt;p&gt;An Nginx server block tells Nginx how to handle traffic for a specific domain.&lt;/p&gt;

&lt;p&gt;Create a new config file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/nginx/sites-available/myproject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste this configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;example.com&lt;/span&gt; &lt;span class="s"&gt;www.example.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;root&lt;/span&gt; &lt;span class="n"&gt;/var/www/myproject&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;index&lt;/span&gt; &lt;span class="s"&gt;index.html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;try_files&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt;&lt;span class="n"&gt;/&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="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;Replace this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;example.com&lt;/span&gt; &lt;span class="s"&gt;www.example.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With your real domain.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;mycoolsite.com&lt;/span&gt; &lt;span class="s"&gt;www.mycoolsite.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This config says:&lt;/p&gt;

&lt;p&gt;“When someone visits this domain, serve files from &lt;code&gt;/var/www/myproject&lt;/code&gt;.”&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 9: Enable the Site
&lt;/h2&gt;

&lt;p&gt;Nginx keeps available site configs in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/etc/nginx/sites-available/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But it only uses configs that are linked in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/etc/nginx/sites-enabled/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we need to enable the site:&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;sudo ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 10: Test and Reload Nginx
&lt;/h2&gt;

&lt;p&gt;Before restarting Nginx, always test the config:&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;sudo &lt;/span&gt;nginx &lt;span class="nt"&gt;-t&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything is fine, you should see something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;syntax is ok
test is successful
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now reload Nginx:&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;sudo &lt;/span&gt;systemctl reload nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open your domain in the browser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://yourdomain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Great. Your domain is now connected to your Droplet.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 11: Add HTTPS with Certbot
&lt;/h2&gt;

&lt;p&gt;A production website should use HTTPS.&lt;/p&gt;

&lt;p&gt;For that, we can use Certbot with Let’s Encrypt.&lt;/p&gt;

&lt;p&gt;Install Certbot:&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;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;certbot python3-certbot-nginx &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;certbot &lt;span class="nt"&gt;--nginx&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Certbot will ask you to choose the domain.&lt;/p&gt;

&lt;p&gt;Select your domain and allow redirect to HTTPS.&lt;/p&gt;

&lt;p&gt;After that, your site should work with:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Certbot also sets up automatic renewal, so your SSL certificate can renew before it expires.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Architecture
&lt;/h2&gt;

&lt;p&gt;Your setup now looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Namecheap
   ↓
DNS A Record
   ↓
DigitalOcean Droplet IP
   ↓
Nginx
   ↓
Website Files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a common real-world setup used by many developers.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Feels Different from cPanel Hosting
&lt;/h2&gt;

&lt;p&gt;If you are coming from cPanel hosting, DigitalOcean may feel harder at first.&lt;/p&gt;

&lt;p&gt;That is normal.&lt;/p&gt;

&lt;p&gt;With cPanel hosting, the hosting company usually handles many things for you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DNS
Apache or Nginx
SSL
PHP
File manager
Email tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You often just change nameservers and upload your files.&lt;/p&gt;

&lt;p&gt;But with a DigitalOcean VPS, you manage the server yourself.&lt;/p&gt;

&lt;p&gt;That means you are responsible for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Nginx
Firewall
SSL
App runtime
Deployment
Security
Logs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The benefit is flexibility.&lt;/p&gt;

&lt;p&gt;You can run Node.js, Laravel, Docker, PostgreSQL, Redis, background workers, multiple apps, and more.&lt;/p&gt;

&lt;p&gt;The tradeoff is that you need to understand the server setup.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Real-Life Example
&lt;/h2&gt;

&lt;p&gt;Imagine you built a small portfolio website.&lt;/p&gt;

&lt;p&gt;You bought:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;from Namecheap.&lt;/p&gt;

&lt;p&gt;Then you created a DigitalOcean Droplet with this IP:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;In Namecheap, you add:&lt;/p&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;Host&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A Record&lt;/td&gt;
&lt;td&gt;@&lt;/td&gt;
&lt;td&gt;159.89.100.50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A Record&lt;/td&gt;
&lt;td&gt;www&lt;/td&gt;
&lt;td&gt;159.89.100.50&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Then on your server, your Nginx config looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;myportfolio.com&lt;/span&gt; &lt;span class="s"&gt;www.myportfolio.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;root&lt;/span&gt; &lt;span class="n"&gt;/var/www/myportfolio&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;index&lt;/span&gt; &lt;span class="s"&gt;index.html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;try_files&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt;&lt;span class="n"&gt;/&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="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;After reloading Nginx and setting up SSL, visitors can open:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;And see your website.&lt;/p&gt;

&lt;p&gt;That is the full journey from domain to live website.&lt;/p&gt;

</description>
      <category>nginx</category>
      <category>dohackathon</category>
      <category>dns</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Hubs, Switches, and Routers Explained Like You're Debugging a Real Network</title>
      <dc:creator>Tahsin Abrar</dc:creator>
      <pubDate>Mon, 11 May 2026 06:48:03 +0000</pubDate>
      <link>https://dev.to/tahsin000/hubs-switches-and-routers-explained-like-youre-debugging-a-real-network-4co5</link>
      <guid>https://dev.to/tahsin000/hubs-switches-and-routers-explained-like-youre-debugging-a-real-network-4co5</guid>
      <description>&lt;p&gt;Have you ever connected your laptop to Wi-Fi, opened a browser, typed a URL, and wondered:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"How does my message actually reach the right computer?"&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;As developers, we often work with APIs, servers, ports, IP addresses, localhost, Docker networks, cloud servers, and routers. But networking can feel confusing because many explanations jump straight into heavy terms.&lt;/p&gt;

&lt;p&gt;So let's slow down and make it simple.&lt;/p&gt;

&lt;p&gt;In this post, we'll understand three important network devices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hub&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Switch&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Router&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We'll also see how data moves from one computer to another inside a local network, and how your computer decides whether to send data directly to another device or through the router.&lt;/p&gt;

&lt;p&gt;This article is based on the provided networking class transcript about hubs, switches, routers, MAC tables, and internal communication. &lt;/p&gt;




&lt;h2&gt;
  
  
  First, Imagine a Small Room Full of Computers
&lt;/h2&gt;

&lt;p&gt;Imagine five computers connected in the same room.&lt;/p&gt;

&lt;p&gt;One computer wants to send a message to another computer.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Computer A wants to send data to Computer D
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That sounds simple. But the network has to answer some important questions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Who sent the data?
Who should receive it?
Are both devices in the same network?
Should the data go to another device first?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where hubs, switches, and routers come in.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Hub: The Loud but Not-So-Smart Device
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;hub&lt;/strong&gt; is one of the simplest network devices.&lt;/p&gt;

&lt;p&gt;You can think of it like a loudspeaker.&lt;/p&gt;

&lt;p&gt;When one computer sends data to a hub, the hub does not check who the data is for. It simply forwards the data to every other connected port.&lt;/p&gt;

&lt;p&gt;So if Computer A sends data through a hub, the hub sends it to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Computer B
Computer C
Computer D
Computer E
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even if the message was only meant for Computer D.&lt;/p&gt;

&lt;p&gt;The other computers receive the data, check it, and then ignore it if it is not meant for them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why is a hub considered "not smart"?
&lt;/h3&gt;

&lt;p&gt;Because a hub works at the &lt;strong&gt;physical layer&lt;/strong&gt;, also called &lt;strong&gt;Layer 1&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It only understands electrical signals or bits.&lt;/p&gt;

&lt;p&gt;It does not understand:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MAC addresses
IP addresses
Ports
Applications
Actual message content
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So a hub cannot make smart forwarding decisions.&lt;/p&gt;

&lt;p&gt;It just repeats the signal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simple way to remember a hub
&lt;/h3&gt;

&lt;p&gt;A hub says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I don't know who needs this, so I'll send it to everyone."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is why hubs are rarely used in modern networks.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Switch: A Smarter Device That Learns
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;switch&lt;/strong&gt; is much smarter than a hub.&lt;/p&gt;

&lt;p&gt;A switch works at the &lt;strong&gt;data link layer&lt;/strong&gt;, also called &lt;strong&gt;Layer 2&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That means a switch can understand &lt;strong&gt;MAC addresses&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A MAC address is like the hardware address of a network device. Every network interface has one.&lt;/p&gt;

&lt;p&gt;For example, imagine five devices connected to a switch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Port 1 -&amp;gt; Computer A
Port 2 -&amp;gt; Computer B
Port 3 -&amp;gt; Computer C
Port 4 -&amp;gt; Computer D
Port 5 -&amp;gt; Computer E
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each computer has a MAC address:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Computer A -&amp;gt; MAC A
Computer B -&amp;gt; MAC B
Computer C -&amp;gt; MAC C
Computer D -&amp;gt; MAC D
Computer E -&amp;gt; MAC E
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now Computer A wants to send data to Computer D.&lt;/p&gt;

&lt;p&gt;The Ethernet frame may look like this in a simplified way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source MAC: A
Destination MAC: D
Data: Hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the switch receives this frame, it checks the &lt;strong&gt;source MAC address&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MAC A came from Port 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then it saves that information in a table.&lt;/p&gt;

&lt;p&gt;This table is commonly called:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MAC address table
CAM table
Forwarding database
Bridge table
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Different books and vendors may use different names, but the idea is the same.&lt;/p&gt;

&lt;p&gt;The switch keeps a record like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MAC Address    Port
A              1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What Happens When the Switch Does Not Know the Destination?
&lt;/h2&gt;

&lt;p&gt;Now the switch checks the destination MAC address:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Destination MAC: D
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But imagine this is the first time the switch has seen Computer D.&lt;/p&gt;

&lt;p&gt;So the switch does not yet know which port leads to MAC D.&lt;/p&gt;

&lt;p&gt;What does it do?&lt;/p&gt;

&lt;p&gt;It &lt;strong&gt;floods&lt;/strong&gt; the frame.&lt;/p&gt;

&lt;p&gt;That means it sends the frame to every port except the port it came from.&lt;/p&gt;

&lt;p&gt;So the frame goes to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Port 2
Port 3
Port 4
Port 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Computer B receives it and says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;This is not for me.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Computer C says the same.&lt;/p&gt;

&lt;p&gt;Computer E says the same.&lt;/p&gt;

&lt;p&gt;But Computer D checks the destination MAC and says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;This is mine.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So Computer D accepts the frame.&lt;/p&gt;




&lt;h2&gt;
  
  
  How the Switch Learns Over Time
&lt;/h2&gt;

&lt;p&gt;Now Computer D replies to Computer A.&lt;/p&gt;

&lt;p&gt;The reply frame looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source MAC: D
Destination MAC: A
Data: Hello back
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The switch receives the frame from Port 4.&lt;/p&gt;

&lt;p&gt;It checks the source MAC address and learns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MAC D came from Port 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the switch table becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MAC Address    Port
A              1
D              4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next time Computer A sends data to Computer D, the switch does not need to flood the frame.&lt;/p&gt;

&lt;p&gt;It already knows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MAC D is on Port 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So it sends the frame only to Port 4.&lt;/p&gt;

&lt;p&gt;That is why a switch is more efficient than a hub.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simple way to remember a switch
&lt;/h3&gt;

&lt;p&gt;A switch says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I’ll learn where devices are, then send data only where it needs to go."&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Hub vs Switch in One Simple Example
&lt;/h2&gt;

&lt;p&gt;Imagine a classroom.&lt;/p&gt;

&lt;p&gt;A hub is like a student who receives a note and shouts it to the whole class.&lt;/p&gt;

&lt;p&gt;A switch is like a helpful class monitor who learns where everyone sits and quietly gives the note to the right person.&lt;/p&gt;

&lt;p&gt;That is the main difference.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where Does the Router Fit In?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;router&lt;/strong&gt; works at the &lt;strong&gt;network layer&lt;/strong&gt;, also called &lt;strong&gt;Layer 3&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That means a router understands &lt;strong&gt;IP addresses&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A switch mainly cares about MAC addresses inside a local network.&lt;/p&gt;

&lt;p&gt;A router cares about moving data between different networks.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your laptop -&amp;gt; your home network
Your home network -&amp;gt; the internet
The internet -&amp;gt; another server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The router is the device that connects your local network to other networks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simple way to remember a router
&lt;/h3&gt;

&lt;p&gt;A router says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"This data needs to go outside this network. I know where to send it next."&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Your Home Router Is Usually More Than Just a Router
&lt;/h2&gt;

&lt;p&gt;This part is important.&lt;/p&gt;

&lt;p&gt;The device we casually call a "router" at home is usually not just a router.&lt;/p&gt;

&lt;p&gt;It often contains multiple things inside one box:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Router
Switch
Wi-Fi access point
DHCP server
Firewall/NAT features
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So when you plug an Ethernet cable into your home router, you are usually plugging it into the &lt;strong&gt;switch part&lt;/strong&gt; of the device.&lt;/p&gt;

&lt;p&gt;When your laptop connects through Wi-Fi, it connects through the wireless access point part.&lt;/p&gt;

&lt;p&gt;The real routing happens when data needs to leave your local network and go somewhere else, like the internet.&lt;/p&gt;




&lt;h2&gt;
  
  
  LAN Interface and WAN Interface
&lt;/h2&gt;

&lt;p&gt;A home router usually has two sides:&lt;/p&gt;

&lt;h3&gt;
  
  
  LAN side
&lt;/h3&gt;

&lt;p&gt;This is your local network.&lt;/p&gt;

&lt;p&gt;Your laptop, phone, printer, TV, and other home devices live here.&lt;/p&gt;

&lt;p&gt;Example local IP addresses:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Your router may have a local IP like:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This is often called the &lt;strong&gt;default gateway&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  WAN side
&lt;/h3&gt;

&lt;p&gt;This is the side connected to your internet provider.&lt;/p&gt;

&lt;p&gt;The router gets a public or provider-side IP address on this side.&lt;/p&gt;

&lt;p&gt;So your router sits between:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your private home network
The outside internet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  How Does a Computer Decide Where to Send Data?
&lt;/h2&gt;

&lt;p&gt;Now comes a very important question.&lt;/p&gt;

&lt;p&gt;Suppose your computer wants to send data to another IP address.&lt;/p&gt;

&lt;p&gt;How does it know whether the destination is inside the same local network or outside?&lt;/p&gt;

&lt;p&gt;It uses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Its own IP address
The destination IP address
The subnet mask
The default gateway
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usually, your computer gets these from DHCP.&lt;/p&gt;

&lt;p&gt;A DHCP server may give your device:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IP address:       192.168.1.10
Subnet mask:      255.255.255.0
Default gateway:  192.168.1.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now your computer can make a decision.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example 1: Sending Data Inside the Same Network
&lt;/h2&gt;

&lt;p&gt;Let's say:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Computer A IP: 192.168.1.10
Computer C IP: 192.168.1.11
Subnet mask:   255.255.255.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Computer A wants to send data to Computer C.&lt;/p&gt;

&lt;p&gt;It checks whether both IP addresses belong to the same network.&lt;/p&gt;

&lt;p&gt;With this subnet mask, both addresses are part of:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;So Computer A understands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Computer C is in my local network.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That means Computer A does not need to send the data to the router for routing.&lt;/p&gt;

&lt;p&gt;Instead, it sends an Ethernet frame directly toward Computer C's MAC address.&lt;/p&gt;

&lt;p&gt;Simplified frame:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source MAC: A
Destination MAC: C
Source IP: 192.168.1.10
Destination IP: 192.168.1.11
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The switch receives the frame and forwards it to Computer C.&lt;/p&gt;

&lt;p&gt;The router part does not need to be involved.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example 2: Sending Data Outside the Network
&lt;/h2&gt;

&lt;p&gt;Now imagine Computer A wants to send data to:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;That IP is not inside the local network &lt;code&gt;192.168.1.0/24&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So Computer A understands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;This destination is outside my network.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now something interesting happens.&lt;/p&gt;

&lt;p&gt;The destination IP stays as:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;But the destination MAC address becomes the MAC address of the router.&lt;/p&gt;

&lt;p&gt;Simplified frame:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source MAC: A
Destination MAC: Router
Source IP: 192.168.1.10
Destination IP: 8.8.8.8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Because inside the local network, the computer can only deliver frames to local devices by MAC address.&lt;/p&gt;

&lt;p&gt;To reach the outside world, it sends the frame to the default gateway first.&lt;/p&gt;

&lt;p&gt;The router receives it, looks at the destination IP, and then decides where to send it next.&lt;/p&gt;




&lt;h2&gt;
  
  
  Important Detail: MAC Address Changes, IP Address Stays
&lt;/h2&gt;

&lt;p&gt;This is one of the most useful networking ideas to understand.&lt;/p&gt;

&lt;p&gt;When data moves across networks, the IP packet is trying to reach the final IP address.&lt;/p&gt;

&lt;p&gt;But at each local network hop, the MAC address may change.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your laptop -&amp;gt; Router
Router -&amp;gt; ISP device
ISP device -&amp;gt; next router
Next router -&amp;gt; destination server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each step may use a different source and destination MAC address.&lt;/p&gt;

&lt;p&gt;But the destination IP is still the final server's IP.&lt;/p&gt;

&lt;p&gt;That is why:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Switches care about MAC addresses.
Routers care about IP addresses.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  A Developer-Friendly Example
&lt;/h2&gt;

&lt;p&gt;Imagine you are building a backend API.&lt;/p&gt;

&lt;p&gt;Your laptop is running a frontend app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:5173
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another computer on the same Wi-Fi is running an API server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://192.168.1.25:3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When your laptop calls that API, it checks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Am I in the same network as 192.168.1.25?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If yes, your laptop sends the frame toward that device's MAC address.&lt;/p&gt;

&lt;p&gt;The switch or Wi-Fi access point handles local delivery.&lt;/p&gt;

&lt;p&gt;The router does not need to send the traffic to the internet.&lt;/p&gt;

&lt;p&gt;Now imagine your app calls:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;That server is outside your local network.&lt;/p&gt;

&lt;p&gt;So your laptop sends the frame to the router's MAC address.&lt;/p&gt;

&lt;p&gt;The router then forwards the packet toward the internet.&lt;/p&gt;

&lt;p&gt;This is happening all the time while you code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Comparison: Hub vs Switch vs Router
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Device&lt;/th&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Understands&lt;/th&gt;
&lt;th&gt;Main Job&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hub&lt;/td&gt;
&lt;td&gt;Layer 1&lt;/td&gt;
&lt;td&gt;Bits/signals&lt;/td&gt;
&lt;td&gt;Sends data to all ports&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Switch&lt;/td&gt;
&lt;td&gt;Layer 2&lt;/td&gt;
&lt;td&gt;MAC addresses&lt;/td&gt;
&lt;td&gt;Sends frames inside a local network&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Router&lt;/td&gt;
&lt;td&gt;Layer 3&lt;/td&gt;
&lt;td&gt;IP addresses&lt;/td&gt;
&lt;td&gt;Sends packets between networks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Common Terms You Should Remember
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Frame
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;frame&lt;/strong&gt; belongs to the data link layer.&lt;/p&gt;

&lt;p&gt;It contains MAC address information.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source MAC
Destination MAC
Payload
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Packet
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;packet&lt;/strong&gt; belongs to the network layer.&lt;/p&gt;

&lt;p&gt;It contains IP address information.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source IP
Destination IP
Payload
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Segment
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;segment&lt;/strong&gt; usually belongs to TCP at the transport layer.&lt;/p&gt;

&lt;p&gt;It contains port information.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source port
Destination port
Data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  MAC address table
&lt;/h3&gt;

&lt;p&gt;A switch uses this table to remember which MAC address is connected to which port.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MAC Address    Port
A              1
C              3
D              4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Default gateway
&lt;/h3&gt;

&lt;p&gt;The default gateway is usually your router's local IP address.&lt;/p&gt;

&lt;p&gt;Your computer sends data to the default gateway when the destination is outside the local network.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Simple Mental Model
&lt;/h2&gt;

&lt;p&gt;Here is the easiest way to remember everything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hub:
"I will send it to everyone."

Switch:
"I will send it to the correct local device if I know where it is."

Router:
"I will send it to another network."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Once you understand this, many networking topics become easier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DHCP
ARP
Subnetting
NAT
Docker networking
Kubernetes networking
Cloud VPCs
Firewalls
Load balancers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>networking</category>
      <category>beginners</category>
      <category>computerscience</category>
      <category>webdev</category>
    </item>
    <item>
      <title>DNS Made Simple: What Really Happens Before Your Browser Opens a Website</title>
      <dc:creator>Tahsin Abrar</dc:creator>
      <pubDate>Thu, 23 Apr 2026 16:25:15 +0000</pubDate>
      <link>https://dev.to/tahsin000/dns-made-simple-what-really-happens-before-your-browser-opens-a-website-2281</link>
      <guid>https://dev.to/tahsin000/dns-made-simple-what-really-happens-before-your-browser-opens-a-website-2281</guid>
      <description>&lt;p&gt;We use domain names every day.&lt;/p&gt;

&lt;p&gt;We type &lt;code&gt;google.com&lt;/code&gt;, &lt;code&gt;facebook.com&lt;/code&gt;, or &lt;code&gt;linkedin.com&lt;/code&gt; into a browser, press Enter, and the website opens in seconds. It feels simple. Almost boring.&lt;/p&gt;

&lt;p&gt;But under the hood, something very important happens before your browser can even start talking to that website.&lt;/p&gt;

&lt;p&gt;That thing is &lt;strong&gt;DNS&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And here is the part many developers miss early on: if you want to understand &lt;strong&gt;TLS/SSL&lt;/strong&gt;, networking, deployment, or even why a request is slow, you need to understand DNS first.&lt;/p&gt;

&lt;p&gt;Because before secure communication begins, your browser has to answer one basic question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Where is this website actually hosted?”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's break it down in the simplest possible way.&lt;/p&gt;




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

&lt;h2&gt;
  
  
  First, let's understand the URL
&lt;/h2&gt;

&lt;p&gt;Take this URL:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;It has a few parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;https&lt;/code&gt; → the scheme or protocol&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;blog&lt;/code&gt; → the subdomain&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;example&lt;/code&gt; → the main domain&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.com&lt;/code&gt; → the top-level domain (TLD)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Another example:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;https&lt;/code&gt; is the protocol&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;engineering&lt;/code&gt; is the subdomain&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;linkedin&lt;/code&gt; is the domain&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.com&lt;/code&gt; is the TLD&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This structure matters because DNS works with these names.&lt;/p&gt;

&lt;p&gt;Before we go into DNS, we need to understand one thing clearly:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;a domain name is not the real machine address.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is the human-friendly name for that machine.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why domain names exist
&lt;/h2&gt;

&lt;p&gt;Humans are good at remembering words.&lt;/p&gt;

&lt;p&gt;Machines are good at working with numbers.&lt;/p&gt;

&lt;p&gt;That is the heart of the whole idea.&lt;/p&gt;

&lt;p&gt;You can easily remember:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;But remembering something like this is much harder:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;That number is an IP address.&lt;/p&gt;

&lt;p&gt;An IP address is the real network address of a machine or server.&lt;/p&gt;

&lt;p&gt;So when you type a domain name into a browser, your system has to find the IP address behind that name.&lt;/p&gt;

&lt;p&gt;That translation is what DNS does.&lt;/p&gt;




&lt;h2&gt;
  
  
  A simple real-life example
&lt;/h2&gt;

&lt;p&gt;Think about your home address.&lt;/p&gt;

&lt;p&gt;If someone knows your address, they can find your house.&lt;/p&gt;

&lt;p&gt;Computers work in a similar way.&lt;/p&gt;

&lt;p&gt;Every machine connected to a network needs an address. On the internet, that address is the &lt;strong&gt;IP address&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now imagine you built an app locally on your laptop. Maybe it runs on:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;That works on your own machine because your machine knows what &lt;code&gt;localhost&lt;/code&gt; means.&lt;/p&gt;

&lt;p&gt;But if you deploy that app to a server on AWS, DigitalOcean, or anywhere else, people cannot visit it using &lt;code&gt;localhost&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;They need the address of that server.&lt;/p&gt;

&lt;p&gt;That real address is the IP address.&lt;/p&gt;

&lt;p&gt;But asking users to remember IP addresses is a terrible experience.&lt;/p&gt;

&lt;p&gt;So instead of telling people:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;we give the server a domain name like:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Now people can remember the name, and machines can still connect using the IP.&lt;/p&gt;

&lt;p&gt;That mapping between a human-friendly name and a machine-friendly IP is the whole point of DNS.&lt;/p&gt;




&lt;h2&gt;
  
  
  So what is DNS?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;DNS stands for Domain Name System.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's keep it simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DNS is the system that converts a domain name into an IP address.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You type &lt;code&gt;facebook.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;DNS finds the IP address behind &lt;code&gt;facebook.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Your browser uses that IP to contact the correct server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is called a &lt;strong&gt;system&lt;/strong&gt; because it is not just one thing.&lt;/p&gt;

&lt;p&gt;It involves multiple parts working together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;your browser&lt;/li&gt;
&lt;li&gt;your operating system&lt;/li&gt;
&lt;li&gt;DNS caches&lt;/li&gt;
&lt;li&gt;a DNS resolver&lt;/li&gt;
&lt;li&gt;root name servers&lt;/li&gt;
&lt;li&gt;TLD name servers&lt;/li&gt;
&lt;li&gt;authoritative name servers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is why it is not called just "domain name lookup.”&lt;/p&gt;

&lt;p&gt;It is a &lt;strong&gt;system&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Before DNS goes to the internet, it checks cache
&lt;/h2&gt;

&lt;p&gt;This is one of the most useful things to understand.&lt;/p&gt;

&lt;p&gt;When you visit a website, your computer does not always start from scratch.&lt;/p&gt;

&lt;p&gt;It first checks whether the answer is already stored somewhere.&lt;/p&gt;

&lt;p&gt;This stored answer is called &lt;strong&gt;cache&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Think of cache like a shortcut memory.&lt;/p&gt;

&lt;p&gt;If the system already knows the IP address for a domain, it can skip a lot of work.&lt;/p&gt;

&lt;p&gt;That makes everything faster.&lt;/p&gt;

&lt;p&gt;Usually, the lookup goes through these layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Browser cache&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operating system cache&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DNS resolver cache&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;If not found, then the full DNS lookup starts&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That is why websites often open very quickly the second time you visit them.&lt;/p&gt;




&lt;h2&gt;
  
  
  The full DNS journey, step by step
&lt;/h2&gt;

&lt;p&gt;Now let's walk through what actually happens when you type:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;into your browser.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The browser checks its own cache
&lt;/h3&gt;

&lt;p&gt;Your browser first asks:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Do I already know the IP for this domain?”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If yes, great. It uses that IP immediately.&lt;/p&gt;

&lt;p&gt;If not, it moves to the next step.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. The operating system checks its cache
&lt;/h3&gt;

&lt;p&gt;If the browser does not have the answer, your operating system checks whether it has that domain-to-IP mapping stored.&lt;/p&gt;

&lt;p&gt;If the OS already knows it, it returns the IP to the browser.&lt;/p&gt;

&lt;p&gt;If not, the request continues.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. The system asks a DNS resolver
&lt;/h3&gt;

&lt;p&gt;Now the request goes to a &lt;strong&gt;DNS resolver&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In many cases, this resolver belongs to your ISP, though it could also be a public DNS service.&lt;/p&gt;

&lt;p&gt;Its job is to find the answer for you.&lt;/p&gt;

&lt;p&gt;And just like the browser and OS, the resolver also checks its own cache first.&lt;/p&gt;

&lt;p&gt;If the resolver already knows the IP for &lt;code&gt;facebook.com&lt;/code&gt;, it returns it immediately.&lt;/p&gt;

&lt;p&gt;If not, now the real DNS lookup begins.&lt;/p&gt;




&lt;h2&gt;
  
  
  The resolver starts asking other DNS servers
&lt;/h2&gt;

&lt;p&gt;This is where many learners get confused, but the logic is actually very clean.&lt;/p&gt;

&lt;p&gt;The resolver does not magically know every IP address in the world.&lt;/p&gt;

&lt;p&gt;Instead, it asks the right servers in the right order.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. It asks a root name server
&lt;/h3&gt;

&lt;p&gt;The resolver asks a root name server something like:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"I need information about &lt;code&gt;.com&lt;/code&gt;. Where should I go next?”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Notice something important:&lt;/p&gt;

&lt;p&gt;It is &lt;strong&gt;not&lt;/strong&gt; asking for the final IP address yet.&lt;/p&gt;

&lt;p&gt;It is asking where the &lt;code&gt;.com&lt;/code&gt; information is managed.&lt;/p&gt;

&lt;p&gt;The root server replies with the address of the &lt;strong&gt;TLD name server&lt;/strong&gt; for &lt;code&gt;.com&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. It asks the TLD name server
&lt;/h3&gt;

&lt;p&gt;Now the resolver goes to the &lt;code&gt;.com&lt;/code&gt; TLD server and asks:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Who is responsible for &lt;code&gt;facebook.com&lt;/code&gt;?”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Again, this server usually does not return the final website IP directly.&lt;/p&gt;

&lt;p&gt;Instead, it returns the address of the &lt;strong&gt;authoritative name server&lt;/strong&gt; for that domain.&lt;/p&gt;

&lt;p&gt;That server is the source of truth for the domain's DNS records.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. It asks the authoritative name server
&lt;/h3&gt;

&lt;p&gt;Now the resolver asks the authoritative name server:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"What is the IP address for &lt;code&gt;facebook.com&lt;/code&gt;?”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This server returns the actual DNS record, such as the IP address.&lt;/p&gt;

&lt;p&gt;Now the resolver finally has the answer it needs.&lt;/p&gt;




&lt;h3&gt;
  
  
  7. The answer comes back and gets cached
&lt;/h3&gt;

&lt;p&gt;Once the resolver gets the IP address, it does two useful things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it returns the answer to your operating system&lt;/li&gt;
&lt;li&gt;it stores the answer in cache for future requests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then the OS may cache it too.&lt;/p&gt;

&lt;p&gt;Then the browser may cache it too.&lt;/p&gt;

&lt;p&gt;That means the next lookup can be much faster.&lt;/p&gt;




&lt;h3&gt;
  
  
  8. The browser can finally contact the server
&lt;/h3&gt;

&lt;p&gt;Now your browser has the IP address.&lt;/p&gt;

&lt;p&gt;At this point, it can finally open a network connection to the actual server and send the real HTTP or HTTPS request.&lt;/p&gt;

&lt;p&gt;That is the moment when the website request truly begins.&lt;/p&gt;

&lt;p&gt;So yes, DNS happens &lt;strong&gt;before&lt;/strong&gt; the browser can talk to the web server.&lt;/p&gt;

&lt;p&gt;And that is exactly why DNS matters when learning TLS/SSL.&lt;/p&gt;




&lt;h2&gt;
  
  
  A simple mental model
&lt;/h2&gt;

&lt;p&gt;If all the server names sound too abstract, use this mental model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Root server&lt;/strong&gt; → "I do not know the full answer, but I know who handles &lt;code&gt;.com&lt;/code&gt;.”&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TLD server&lt;/strong&gt; → "I do not know the full answer, but I know who handles &lt;code&gt;facebook.com&lt;/code&gt;.”&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authoritative server&lt;/strong&gt; → "I am responsible for this domain. Here is the actual answer.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the chain.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why DNS is called "resolution”
&lt;/h2&gt;

&lt;p&gt;You may hear the phrase:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DNS resolution&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This simply means:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;the process of resolving a domain name into an IP address&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So if someone says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The DNS resolution failed”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;they mean:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The system could not turn the domain name into an IP address”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No IP, no connection.&lt;br&gt;
No connection, no website.&lt;/p&gt;


&lt;h2&gt;
  
  
  Where subdomains fit into this
&lt;/h2&gt;

&lt;p&gt;Let's say you have a domain like:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;You can create subdomains like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;blog.example.com
api.example.com
admin.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is useful because one domain can support multiple services.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;blog.example.com&lt;/code&gt; → blog website&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;api.example.com&lt;/code&gt; → backend API&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;admin.example.com&lt;/code&gt; → internal admin dashboard&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Same parent domain.&lt;br&gt;
Different subdomains.&lt;br&gt;
Different purposes.&lt;/p&gt;

&lt;p&gt;That is why learning domain structure matters before learning DNS deeply.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why websites feel fast after the first visit
&lt;/h2&gt;

&lt;p&gt;A lot of developers notice this but do not always connect it to DNS.&lt;/p&gt;

&lt;p&gt;The first request may take a bit longer because the system needs to find the IP.&lt;/p&gt;

&lt;p&gt;Later requests are faster because the answer may already exist in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;browser cache&lt;/li&gt;
&lt;li&gt;OS cache&lt;/li&gt;
&lt;li&gt;resolver cache&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That means the system can skip most of the lookup chain.&lt;/p&gt;

&lt;p&gt;So if a website opens instantly the second time, caching is often part of the reason.&lt;/p&gt;




&lt;h2&gt;
  
  
  Does DNS use TCP or UDP?
&lt;/h2&gt;

&lt;p&gt;In simple learning material, DNS is often explained with &lt;strong&gt;UDP&lt;/strong&gt;, and that is a good starting point.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Because UDP is lightweight and fast. It does not need a full connection setup like TCP.&lt;/p&gt;

&lt;p&gt;For many standard DNS queries, that makes it a great fit.&lt;/p&gt;

&lt;p&gt;A simple way to think about it is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DNS wants to ask a quick question&lt;/li&gt;
&lt;li&gt;get a quick answer&lt;/li&gt;
&lt;li&gt;and move on&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That said, in real systems, DNS can also use TCP in some cases.&lt;/p&gt;

&lt;p&gt;But when you are first learning how DNS feels fast and lightweight, starting with UDP gives you the right intuition.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why DNS matters before TLS/SSL
&lt;/h2&gt;

&lt;p&gt;This is the part many people skip.&lt;/p&gt;

&lt;p&gt;They jump into HTTPS, SSL certificates, and TLS handshakes without asking a more basic question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How did the browser even find the server in the first place?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before secure communication starts, the browser needs to know where to connect.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;resolve the domain name into an IP address&lt;/li&gt;
&lt;li&gt;connect to the server&lt;/li&gt;
&lt;li&gt;then begin TLS/SSL and HTTP communication&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So if DNS is unclear, TLS/SSL will always feel a little foggy too.&lt;/p&gt;

&lt;p&gt;Understanding DNS first makes the next networking topics much easier.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why developers should care about this
&lt;/h2&gt;

&lt;p&gt;It is easy to think:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Do I really need to know all this? I can just build apps.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can. For a while.&lt;/p&gt;

&lt;p&gt;But sooner or later, deeper understanding starts to matter.&lt;/p&gt;

&lt;p&gt;Maybe:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;your production request is slow&lt;/li&gt;
&lt;li&gt;your domain is not pointing to the right server&lt;/li&gt;
&lt;li&gt;your subdomain is broken&lt;/li&gt;
&lt;li&gt;your SSL setup is failing&lt;/li&gt;
&lt;li&gt;your infrastructure behaves differently across environments&lt;/li&gt;
&lt;li&gt;a tool's official docs feel harder than they should&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where fundamentals help.&lt;/p&gt;

&lt;p&gt;When you understand DNS, you stop treating networking like magic.&lt;/p&gt;

&lt;p&gt;You start seeing the path.&lt;/p&gt;

&lt;p&gt;And once you can see the path, debugging becomes easier.&lt;/p&gt;




&lt;h2&gt;
  
  
  A small story every developer can relate to
&lt;/h2&gt;

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

&lt;p&gt;You deploy your app.&lt;br&gt;
The code is fine.&lt;br&gt;
The server is running.&lt;br&gt;
But the site still does not open.&lt;/p&gt;

&lt;p&gt;At first, you think:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;is the backend broken?&lt;/li&gt;
&lt;li&gt;is the port wrong?&lt;/li&gt;
&lt;li&gt;is Nginx failing?&lt;/li&gt;
&lt;li&gt;is HTTPS misconfigured?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the real problem turns out to be simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;the domain is not resolving correctly.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That one small DNS issue can make the whole app feel "down.”&lt;/p&gt;

&lt;p&gt;This is why solid developers do not only learn frameworks.&lt;/p&gt;

&lt;p&gt;They learn what happens around the request too.&lt;/p&gt;




&lt;h2&gt;
  
  
  The big lesson: do not skip the basics
&lt;/h2&gt;

&lt;p&gt;A lot of hard topics become easier when your basics are strong.&lt;/p&gt;

&lt;p&gt;Docker makes more sense.&lt;br&gt;
Kubernetes makes more sense.&lt;br&gt;
TLS/SSL makes more sense.&lt;br&gt;
Load balancers, CDNs, proxies, reverse proxies, and hosting all make more sense.&lt;/p&gt;

&lt;p&gt;Not because they are easy.&lt;/p&gt;

&lt;p&gt;But because you already understand the ground they stand on.&lt;/p&gt;

&lt;p&gt;Many developers struggle with official docs not because their English is bad, but because the underlying computer science concepts are still shaky.&lt;/p&gt;

&lt;p&gt;That is normal.&lt;/p&gt;

&lt;p&gt;And the fix is not shortcuts.&lt;/p&gt;

&lt;p&gt;The fix is going back, learning the core ideas properly, and revisiting them again and again until they feel natural.&lt;/p&gt;

&lt;p&gt;That is how real confidence is built.&lt;/p&gt;

</description>
      <category>dns</category>
      <category>networking</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
