<?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: Md Abu Musa</title>
    <description>The latest articles on DEV Community by Md Abu Musa (@musamuhammad).</description>
    <link>https://dev.to/musamuhammad</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%2F370086%2F60077e5a-d02f-4c5f-a268-c286e72b985b.png</url>
      <title>DEV Community: Md Abu Musa</title>
      <link>https://dev.to/musamuhammad</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/musamuhammad"/>
    <language>en</language>
    <item>
      <title>Getting Started with MongoDB and Laravel 13 on Ubuntu 24.04: A Practical Setup Guide</title>
      <dc:creator>Md Abu Musa</dc:creator>
      <pubDate>Sun, 18 Oct 2026 16:21:19 +0000</pubDate>
      <link>https://dev.to/musamuhammad/getting-started-with-mongodb-and-laravel-13-on-ubuntu-2404-a-practical-setup-guide-3n8</link>
      <guid>https://dev.to/musamuhammad/getting-started-with-mongodb-and-laravel-13-on-ubuntu-2404-a-practical-setup-guide-3n8</guid>
      <description>&lt;p&gt;Relational databases are the default for most Laravel projects, and for good reason. But many real systems also hold data that does not fit neatly into rows and columns: product catalogs with varying attributes, event logs, user activity feeds, and content with nested structures. MongoDB's document model handles these cases naturally, and the official Laravel integration lets you work with it using the Eloquent patterns you already know.&lt;/p&gt;

&lt;p&gt;This guide walks through a complete, working practice environment on a fresh Ubuntu 24.04 machine: MongoDB 8.0, the PHP MongoDB extension, a new Laravel 13 project, and your first CRUD and aggregation queries. It also covers the one build error that trips up many developers during the extension install, so you can avoid losing an hour to it.&lt;/p&gt;

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

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

&lt;ul&gt;
&lt;li&gt;MongoDB 8.0 running as a system service&lt;/li&gt;
&lt;li&gt;The PHP &lt;code&gt;mongodb&lt;/code&gt; extension compiled and enabled&lt;/li&gt;
&lt;li&gt;A Laravel 13 project connected to MongoDB through &lt;code&gt;mongodb/laravel-mongodb&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;Product&lt;/code&gt; model with create, read, update, and delete operations working&lt;/li&gt;
&lt;li&gt;A first aggregation pipeline running from Laravel&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt; Ubuntu 24.04, a user with &lt;code&gt;sudo&lt;/code&gt; access, and basic familiarity with PHP and the terminal. Ubuntu 24.04 ships with PHP 8.3, which satisfies Laravel 13's requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Install MongoDB 8.0
&lt;/h2&gt;

&lt;p&gt;MongoDB is not in Ubuntu's default repositories, so add the official MongoDB repository first.&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-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; gnupg curl

curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://www.mongodb.org/static/pgp/server-8.0.asc | &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nb"&gt;sudo &lt;/span&gt;gpg &lt;span class="nt"&gt;-o&lt;/span&gt; /usr/share/keyrings/mongodb-server-8.0.gpg &lt;span class="nt"&gt;--dearmor&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.0 multiverse"&lt;/span&gt; | &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/apt/sources.list.d/mongodb-org-8.0.list

&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; mongodb-org
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; mongod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify that the service is running and responding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl status mongod &lt;span class="nt"&gt;--no-pager&lt;/span&gt;
mongosh &lt;span class="nt"&gt;--eval&lt;/span&gt; &lt;span class="s1"&gt;'db.runCommand({ ping: 1 })'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see &lt;code&gt;Active: active (running)&lt;/code&gt; and &lt;code&gt;{ ok: 1 }&lt;/code&gt;. If &lt;code&gt;mongod&lt;/code&gt; fails to start, &lt;code&gt;sudo journalctl -u mongod -n 50&lt;/code&gt; will show why.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Prepare PHP
&lt;/h2&gt;

&lt;p&gt;Install the PHP packages Laravel needs, plus the build tools required to compile the MongoDB extension.&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; &lt;span class="nt"&gt;-y&lt;/span&gt; php8.3-cli php8.3-xml php8.3-mbstring php8.3-curl &lt;span class="se"&gt;\&lt;/span&gt;
  php8.3-zip php8.3-sqlite3 php8.3-dev php-pear libssl-dev pkg-config unzip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install Composer if you do not already have 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;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; composer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Install the PHP MongoDB Extension
&lt;/h2&gt;

&lt;p&gt;The Laravel package is built on the official &lt;code&gt;mongodb&lt;/code&gt; PHP extension, so nothing works without it. Install it through PECL:&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;pecl channel-update pecl.php.net
&lt;span class="nb"&gt;yes&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; | &lt;span class="nb"&gt;sudo &lt;/span&gt;pecl &lt;span class="nb"&gt;install &lt;/span&gt;mongodb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then enable 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;echo&lt;/span&gt; &lt;span class="s2"&gt;"extension=mongodb.so"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/php/8.3/mods-available/mongodb.ini
&lt;span class="nb"&gt;sudo &lt;/span&gt;phpenmod mongodb
php &lt;span class="nt"&gt;--ri&lt;/span&gt; mongodb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the last command prints &lt;code&gt;MongoDB support =&amp;gt; enabled&lt;/code&gt; along with a version number, the extension is ready.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Pitfall: Do Not Answer "yes" to PECL's Prompts
&lt;/h3&gt;

&lt;p&gt;During installation, PECL asks several configuration questions. The safe approach is to accept the default for every one of them by pressing Enter, which is exactly what &lt;code&gt;yes ''&lt;/code&gt; does above.&lt;/p&gt;

&lt;p&gt;A common mistake is answering &lt;code&gt;yes&lt;/code&gt; to these three:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Enable developer flags?&lt;/strong&gt; This turns on strict compiler settings that can turn harmless warnings into build failures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable code coverage?&lt;/strong&gt; Unnecessary for normal use.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use system libraries for libbson, libmongoc, and libmongocrypt?&lt;/strong&gt; This is the one that breaks most builds. Ubuntu's packaged &lt;code&gt;libbson&lt;/code&gt; is older than the version the extension requires, so the build stops with an error like &lt;code&gt;Could not find system library for libbson &amp;gt;= 2.5.6&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With the defaults, the extension compiles against its own bundled libraries and builds cleanly. If you already ran the install with the wrong answers, run &lt;code&gt;sudo phpdismod mongodb&lt;/code&gt; to silence the load warnings, clear the cache with &lt;code&gt;sudo pecl clear-cache&lt;/code&gt;, and reinstall with the defaults.&lt;/p&gt;

&lt;p&gt;Also note that the PHP CLI and PHP-FPM read separate configuration. If you later serve the app through FPM or Apache, restart that service after enabling the extension.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Create the Laravel Project
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer create-project laravel/laravel mongo-practice
&lt;span class="nb"&gt;cd &lt;/span&gt;mongo-practice
composer require mongodb/laravel-mongodb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Composer selects a compatible version of the package automatically. If it reports a version conflict with Laravel 13, check the package's releases page for the supported version range.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Configure the Connection
&lt;/h2&gt;

&lt;p&gt;Add your connection details to &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;MONGODB_URI=mongodb://127.0.0.1:27017
MONGODB_DATABASE=practice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add a &lt;code&gt;mongodb&lt;/code&gt; connection to the &lt;code&gt;connections&lt;/code&gt; array in &lt;code&gt;config/database.php&lt;/code&gt;:&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="s1"&gt;'mongodb'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'driver'&lt;/span&gt;   &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'mongodb'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'dsn'&lt;/span&gt;      &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'MONGODB_URI'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'mongodb://127.0.0.1:27017'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s1"&gt;'database'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'MONGODB_DATABASE'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'practice'&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;Leave &lt;code&gt;DB_CONNECTION&lt;/code&gt; set to &lt;code&gt;sqlite&lt;/code&gt; for now. Laravel's sessions, cache, and migrations will keep using the default database, while only the models you explicitly point at MongoDB will use the &lt;code&gt;mongodb&lt;/code&gt; connection. This separation keeps a practice project simple and avoids surprises.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Create Your First Model
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan make:model Product
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace the generated class with a MongoDB-aware model:&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="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Models&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;MongoDB\Laravel\Eloquent\Model&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Model&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'mongodb'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'products'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$fillable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'price'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'category'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'tags'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'specs'&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;The key difference from a standard Eloquent model is the base class. Import &lt;code&gt;MongoDB\Laravel\Eloquent\Model&lt;/code&gt; instead of &lt;code&gt;Illuminate\Database\Eloquent\Model&lt;/code&gt;. Everything else, including &lt;code&gt;$fillable&lt;/code&gt;, casts, and query builder methods, will feel familiar.&lt;/p&gt;

&lt;p&gt;MongoDB creates the database and collection automatically on the first write, so there is no migration to run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: Practice with Tinker
&lt;/h2&gt;

&lt;p&gt;Open Laravel's REPL:&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;h3&gt;
  
  
  Create
&lt;/h3&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;App\Models\Product&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="s1"&gt;'name'&lt;/span&gt;     &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Laptop'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'price'&lt;/span&gt;    &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;85000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'category'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'electronics'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'tags'&lt;/span&gt;     &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'work'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'portable'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="s1"&gt;'specs'&lt;/span&gt;    &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'ram'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'16GB'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'storage'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'512GB'&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;Notice that &lt;code&gt;tags&lt;/code&gt; is an array and &lt;code&gt;specs&lt;/code&gt; is a nested object. In a relational database, these would typically need extra tables or JSON columns. Here they are first-class values.&lt;/p&gt;

&lt;h3&gt;
  
  
  Read
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'price'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50000&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;get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'specs.ram'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'16GB'&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;first&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// dot notation for nested fields&lt;/span&gt;
&lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;whereIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'tags'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'work'&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;get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;      &lt;span class="c1"&gt;// match inside arrays&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Update and Delete
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Laptop'&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;update&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'price'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;80000&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Laptop'&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;delete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Verify in the MongoDB Shell
&lt;/h3&gt;

&lt;p&gt;Open a second terminal and inspect the raw documents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;mongosh&lt;/span&gt;
&lt;span class="nx"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;practice&lt;/span&gt;
&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;pretty&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 the most valuable habit for learning. Run a query in Laravel, then look at what actually landed in MongoDB. Seeing both sides builds an accurate mental model of how documents are stored.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 8: Your First Aggregation Pipeline
&lt;/h2&gt;

&lt;p&gt;Aggregation is where MongoDB becomes a serious analytics tool. A pipeline passes documents through ordered stages, each transforming the data. This example calculates the average price per category:&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;Product&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$collection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$collection&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;aggregate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'$group'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'_id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'$category'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'avgPrice'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'$avg'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'$price'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="s1"&gt;'count'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'$sum'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;]],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'$sort'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'avgPrice'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
&lt;span class="p"&gt;]))&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;$group&lt;/code&gt; stage buckets documents by category and computes the aggregates, and &lt;code&gt;$sort&lt;/code&gt; orders the results. From here, the stages worth learning next are &lt;code&gt;$match&lt;/code&gt; (filtering early, which improves performance), &lt;code&gt;$project&lt;/code&gt; (reshaping output), &lt;code&gt;$unwind&lt;/code&gt; (flattening arrays), and &lt;code&gt;$lookup&lt;/code&gt; (joining collections).&lt;/p&gt;

&lt;h2&gt;
  
  
  Troubleshooting Reference
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Likely Cause and Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Class "MongoDB\Client" not found&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The extension is not enabled for the PHP binary you are using. Run &lt;code&gt;sudo phpenmod mongodb&lt;/code&gt; and restart FPM if applicable.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;pecl install&lt;/code&gt; fails with a libbson error&lt;/td&gt;
&lt;td&gt;You answered &lt;code&gt;yes&lt;/code&gt; to the system-libraries prompt. Reinstall using the defaults.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PHP warns it cannot load &lt;code&gt;mongodb.so&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;The &lt;code&gt;.ini&lt;/code&gt; file exists but the extension was never built. Run &lt;code&gt;sudo phpdismod mongodb&lt;/code&gt;, then reinstall.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;mongod&lt;/code&gt; will not start&lt;/td&gt;
&lt;td&gt;Check &lt;code&gt;sudo journalctl -u mongod -n 50&lt;/code&gt; for the specific error.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Queries return nothing&lt;/td&gt;
&lt;td&gt;Confirm the database name in &lt;code&gt;.env&lt;/code&gt; matches the one you are inspecting in &lt;code&gt;mongosh&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Where to Go Next
&lt;/h2&gt;

&lt;p&gt;With a working environment, the most productive next steps are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Data modeling.&lt;/strong&gt; Learn when to embed documents versus reference them. This decision shapes performance more than any other.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Indexing.&lt;/strong&gt; Create indexes for your query patterns and use &lt;code&gt;explain()&lt;/code&gt; to confirm they are used.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deeper aggregation.&lt;/strong&gt; Build multi-stage pipelines with &lt;code&gt;$match&lt;/code&gt;, &lt;code&gt;$lookup&lt;/code&gt;, and &lt;code&gt;$unwind&lt;/code&gt; against realistic seeded data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transactions and replica sets.&lt;/strong&gt; Multi-document transactions require a replica set, even in local development.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Setting up MongoDB with Laravel on Ubuntu comes down to three moving parts: the database service, the PHP extension, and the Laravel package. Most of the friction sits in the extension build, and it disappears once you accept PECL's defaults. From there, you work with documents through the same Eloquent interface you already use every day, while gaining flexible schemas, nested data, and a powerful aggregation framework.&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>laravel</category>
      <category>ubuntu</category>
      <category>database</category>
    </item>
    <item>
      <title>Mastering Redis from the Command Line: A Hands-On Practice Guide</title>
      <dc:creator>Md Abu Musa</dc:creator>
      <pubDate>Tue, 13 Oct 2026 12:51:02 +0000</pubDate>
      <link>https://dev.to/musamuhammad/mastering-redis-from-the-command-line-a-hands-on-practice-guide-2hi9</link>
      <guid>https://dev.to/musamuhammad/mastering-redis-from-the-command-line-a-hands-on-practice-guide-2hi9</guid>
      <description>&lt;p&gt;The fastest way to learn Redis is to type commands, watch the replies, and break things on purpose.&lt;/p&gt;

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

&lt;p&gt;Open a terminal, run &lt;code&gt;redis-cli&lt;/code&gt;, and confirm the server answers. Use &lt;code&gt;FLUSHDB&lt;/code&gt; between sections for a clean slate, but only on a practice instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PING                  # PONG
INFO server
INFO memory
INFO keyspace
SELECT 1              # switch to database 1
DBSIZE
CONFIG GET maxmemory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two shell flags are worth learning on day one: &lt;code&gt;redis-cli -n 2 PING&lt;/code&gt; targets a specific database, and &lt;code&gt;redis-cli --raw GET key&lt;/code&gt; prints values without quoting or escaping.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core data types
&lt;/h2&gt;

&lt;p&gt;Most real Redis usage is built from six structures. Run every command, and note each return value: &lt;code&gt;OK&lt;/code&gt;, &lt;code&gt;(integer)&lt;/code&gt;, or &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Strings
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SET user:1:name "Musa"
GET user:1:name
SET counter 10
INCR counter              # 11
INCRBY counter 5          # 16
APPEND user:1:name " Abu"
MSET a 1 b 2 c 3
MGET a b c
SET lock:x 1 NX EX 30     # only if absent, 30s TTL
SET k v XX                # only if present
GETEX k EX 60
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Keys and expiry
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EXISTS user:1:name
TYPE user:1:name
EXPIRE user:1:name 60
TTL user:1:name
PERSIST user:1:name
UNLINK k                  # asynchronous delete
SCAN 0 MATCH user:* COUNT 100
OBJECT ENCODING counter   # int, embstr or raw
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare &lt;code&gt;KEYS *&lt;/code&gt; with &lt;code&gt;SCAN&lt;/code&gt;, and never use &lt;code&gt;KEYS&lt;/code&gt; in production: it blocks the server while it walks the whole keyspace. Then set a 5-second TTL and run &lt;code&gt;TTL&lt;/code&gt; repeatedly to watch the key expire.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hashes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HSET user:1 name Musa age 30 city Dhaka
HGET user:1 name
HMGET user:1 name city
HGETALL user:1
HINCRBY user:1 age 1
HEXISTS user:1 city
HDEL user:1 city
HSCAN user:1 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Lists
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RPUSH queue job1 job2 job3
LPUSH queue job0
LRANGE queue 0 -1
LPOP queue
LTRIM queue 0 99
BLPOP queue 10            # blocking pop; try from a second terminal
LMOVE queue processing LEFT RIGHT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a reliable queue, move each job with &lt;code&gt;LMOVE queue processing&lt;/code&gt;, process it, then remove it with &lt;code&gt;LREM processing 1 job&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sets
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SADD tags:post1 redis db cache
SADD tags:post2 redis golang
SISMEMBER tags:post1 redis
SINTER tags:post1 tags:post2
SUNION tags:post1 tags:post2
SDIFF tags:post1 tags:post2
SPOP tags:post1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Sorted sets
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ZADD leaderboard 100 alice 250 bob 175 carol
ZRANGE leaderboard 0 -1 WITHSCORES
ZRANGE leaderboard 0 2 REV WITHSCORES    # top 3 (Redis 6.2+)
ZRANK leaderboard alice
ZINCRBY leaderboard 50 alice
ZRANGEBYSCORE leaderboard 100 200
ZREM leaderboard carol
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sorted sets are the most versatile structure on this list: leaderboards, priority queues, time-ordered indexes and rate limiters all reduce to them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond the basics
&lt;/h2&gt;

&lt;p&gt;These structures trade generality for extreme efficiency, and each solves one problem very well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bitmaps, HyperLogLog and geo
&lt;/h3&gt;

&lt;p&gt;Bitmaps track yes/no flags per user ID in a few bytes each. HyperLogLog counts unique items approximately in about 12 KB, however many there are. Geo commands store coordinates and answer distance and radius queries.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SETBIT login:2026-10-12 1001 1
GETBIT login:2026-10-12 1001
BITCOUNT login:2026-10-12
BITOP AND active:both login:day1 login:day2

PFADD visitors:today u1 u2 u3 u1
PFCOUNT visitors:today          # 3
PFMERGE visitors:week visitors:d1 visitors:d2

GEOADD shops 90.4125 23.8103 "dhaka-a" 91.8123 22.3569 "ctg-a"
GEODIST shops dhaka-a ctg-a km
GEOSEARCH shops FROMLONLAT 90.4 23.8 BYRADIUS 50 km ASC
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Streams are an append-only log with consumer groups, which makes them the durable alternative to Pub/Sub and lists for event processing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;XADD orders * user 1 amount 500
XLEN orders
XRANGE orders - +
XREAD BLOCK 5000 STREAMS orders $

XGROUP CREATE orders workers $ MKSTREAM
XREADGROUP GROUP workers w1 COUNT 1 STREAMS orders &amp;gt;
XACK orders workers &amp;lt;id&amp;gt;
XPENDING orders workers
XCLAIM orders workers w2 60000 &amp;lt;id&amp;gt;
XTRIM orders MAXLEN ~ 1000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use two terminals: one producer, one consumer-group worker. Kill the worker before it runs &lt;code&gt;XACK&lt;/code&gt;, then recover the unacknowledged message with &lt;code&gt;XPENDING&lt;/code&gt; and &lt;code&gt;XCLAIM&lt;/code&gt;. That exercise teaches more about delivery guarantees than any documentation page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Messaging and atomicity
&lt;/h2&gt;

&lt;p&gt;Redis is single-threaded for command execution, so a single command is always atomic. The tools below extend that guarantee to groups of commands.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pub/Sub
&lt;/h3&gt;

&lt;p&gt;In terminal A, subscribe. In terminal B, publish.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Terminal A
SUBSCRIBE news
PSUBSCRIBE news:*

# Terminal B
PUBLISH news "hello"
PUBSUB CHANNELS
PUBSUB NUMSUB news
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pub/Sub is fire-and-forget: a subscriber that connects late misses earlier messages. Confirm this yourself, then contrast it with Streams, which keep history.&lt;/p&gt;

&lt;h3&gt;
  
  
  Transactions
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MULTI
SET balance 100
DECRBY balance 30
EXEC

WATCH balance             # optimistic locking
MULTI
DECRBY balance 10
EXEC                      # nil if another client changed balance
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Trigger a &lt;code&gt;WATCH&lt;/code&gt; failure by modifying &lt;code&gt;balance&lt;/code&gt; from a second terminal before &lt;code&gt;EXEC&lt;/code&gt;. Also note that Redis transactions have no rollback: if one command fails at runtime, the others still run.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lua scripting
&lt;/h3&gt;

&lt;p&gt;A Lua script runs as one atomic unit, which is the right tool for read-modify-write logic that &lt;code&gt;WATCH&lt;/code&gt; makes clumsy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="n"&gt;EVAL&lt;/span&gt; &lt;span class="s2"&gt;"return redis.call('GET', KEYS[1])"&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;

&lt;span class="o"&gt;#&lt;/span&gt; &lt;span class="n"&gt;Safe&lt;/span&gt; &lt;span class="n"&gt;unlock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;delete&lt;/span&gt; &lt;span class="n"&gt;only&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="n"&gt;matches&lt;/span&gt;
&lt;span class="n"&gt;EVAL&lt;/span&gt; &lt;span class="s2"&gt;"if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end"&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;token123&lt;/span&gt;

&lt;span class="n"&gt;SCRIPT&lt;/span&gt; &lt;span class="n"&gt;LOAD&lt;/span&gt; &lt;span class="s2"&gt;"return 'hi'"&lt;/span&gt;
&lt;span class="n"&gt;EVALSHA&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;sha&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running Redis
&lt;/h2&gt;

&lt;p&gt;Knowing the commands is half the job. The other half is knowing how Redis behaves when memory fills, a process restarts, or a client misbehaves.&lt;/p&gt;

&lt;h3&gt;
  
  
  Persistence
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CONFIG GET save
BGSAVE
LASTSAVE
CONFIG SET appendonly yes
BGREWRITEAOF
INFO persistence
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set a key, run &lt;code&gt;SHUTDOWN SAVE&lt;/code&gt;, restart with &lt;code&gt;sudo systemctl restart redis-server&lt;/code&gt;, and check that the key survived. Then repeat with persistence disabled and watch the data disappear.&lt;/p&gt;

&lt;h3&gt;
  
  
  Memory and eviction
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CONFIG SET maxmemory 10mb
CONFIG SET maxmemory-policy allkeys-lru
MEMORY USAGE user:1
INFO stats                # evicted_keys, keyspace_hits, keyspace_misses
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





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

&lt;/div&gt;



&lt;p&gt;Fill memory with a loop and watch &lt;code&gt;evicted_keys&lt;/code&gt; climb. Try &lt;code&gt;noeviction&lt;/code&gt;, &lt;code&gt;volatile-lru&lt;/code&gt; and &lt;code&gt;allkeys-lfu&lt;/code&gt; to see how each policy changes which keys survive.&lt;/p&gt;

&lt;h3&gt;
  
  
  Monitoring and debugging
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MONITOR                   # live command stream; development only
SLOWLOG GET 10
CONFIG SET slowlog-log-slower-than 1000
CLIENT LIST
LATENCY DOCTOR
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-cli &lt;span class="nt"&gt;--latency&lt;/span&gt;
redis-cli &lt;span class="nt"&gt;--stat&lt;/span&gt;
redis-benchmark &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 100000 &lt;span class="nt"&gt;-c&lt;/span&gt; 50
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Security and ACLs
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CONFIG SET requirepass strongpass
AUTH strongpass
ACL SETUSER reader on &amp;gt;readpass ~cache:* +get +mget
ACL LIST
AUTH reader readpass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Log in as &lt;code&gt;reader&lt;/code&gt; and confirm that &lt;code&gt;SET&lt;/code&gt; fails with &lt;code&gt;NOPERM&lt;/code&gt;. Least-privilege users are one of the cheapest hardening steps Redis offers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Replication on one machine
&lt;/h3&gt;

&lt;p&gt;Copy the config, change the port, data directory and pidfile, then start a replica:&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 cp&lt;/span&gt; /etc/redis/redis.conf /etc/redis/redis-6380.conf
redis-server /etc/redis/redis-6380.conf &lt;span class="nt"&gt;--replicaof&lt;/span&gt; 127.0.0.1 6379
&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;INFO replication
WAIT 1 100
REPLICAOF NO ONE          # promote the replica
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Write on the primary and read on the replica. Then try writing to the replica to see the read-only error.&lt;/p&gt;

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

&lt;p&gt;Once the commands feel natural, combine them into the patterns production systems actually use.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Commands&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cache-aside&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;GET product:5&lt;/code&gt;; on a miss, &lt;code&gt;SET product:5 &amp;lt;json&amp;gt; EX 300&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fixed-window rate limiter&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;INCR rate:user1:202610121530&lt;/code&gt;, then &lt;code&gt;EXPIRE&lt;/code&gt; it to 60 seconds; reject above the limit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Distributed lock&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;SET lock:order:9 &amp;lt;token&amp;gt; NX PX 10000&lt;/code&gt;; release with the Lua compare-and-delete script&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Leaderboard&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ZINCRBY&lt;/code&gt; to score, &lt;code&gt;ZRANGE ... REV&lt;/code&gt; to read the top N&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Session store&lt;/td&gt;
&lt;td&gt;Hash &lt;code&gt;session:&amp;lt;id&amp;gt;&lt;/code&gt;, with &lt;code&gt;EXPIRE&lt;/code&gt; refreshed on each request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unique visitors&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;PFADD&lt;/code&gt; and &lt;code&gt;PFCOUNT&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Daily active users&lt;/td&gt;
&lt;td&gt;One bitmap per date, combined with &lt;code&gt;BITOP&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Job queue&lt;/td&gt;
&lt;td&gt;List with &lt;code&gt;BLPOP&lt;/code&gt;, or Streams with consumer groups&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Idempotency key&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SET idem:&amp;lt;key&amp;gt; 1 NX EX 86400&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The distributed lock deserves special care. Always store a unique token as the value and release with the Lua script, so one client can never delete a lock another client now holds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges
&lt;/h2&gt;

&lt;p&gt;Try these without looking anything up. Each one forces you to combine commands you have already met.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build a sliding-window rate limiter with a sorted set, using &lt;code&gt;ZADD&lt;/code&gt;, &lt;code&gt;ZREMRANGEBYSCORE&lt;/code&gt; and &lt;code&gt;ZCARD&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Keep a "recently viewed, last 10 items" list per user with &lt;code&gt;LPUSH&lt;/code&gt; and &lt;code&gt;LTRIM&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Implement a delayed job queue with a sorted set scored by run timestamp.&lt;/li&gt;
&lt;li&gt;Build autocomplete with &lt;code&gt;ZRANGEBYLEX&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Write a Lua script that decrements stock atomically and refuses to go below zero.&lt;/li&gt;
&lt;li&gt;Compare the memory used by 10,000 small keys against one hash with 10,000 fields, using &lt;code&gt;MEMORY USAGE&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The last exercise tends to surprise people: small hashes use a compact encoding, so the single hash is often far cheaper.&lt;/p&gt;

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

&lt;p&gt;Redis rewards hands-on practice more than reading. Work through the sections in order, break things deliberately (kill a worker mid-stream, fill memory, fail a &lt;code&gt;WATCH&lt;/code&gt;), and finish with the challenges.&lt;/p&gt;

</description>
      <category>redis</category>
      <category>cache</category>
      <category>database</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Zero-Downtime Schema Changes in PostgreSQL: Adding Columns and Indexes to a 200M-Row Table</title>
      <dc:creator>Md Abu Musa</dc:creator>
      <pubDate>Thu, 08 Oct 2026 06:05:46 +0000</pubDate>
      <link>https://dev.to/musamuhammad/zero-downtime-schema-changes-in-postgresql-adding-columns-and-indexes-to-a-200m-row-table-36b</link>
      <guid>https://dev.to/musamuhammad/zero-downtime-schema-changes-in-postgresql-adding-columns-and-indexes-to-a-200m-row-table-36b</guid>
      <description>&lt;p&gt;You have a PostgreSQL table with &lt;strong&gt;200 million rows&lt;/strong&gt;. It's serving live traffic. Now you need to add a column or an index.&lt;/p&gt;

&lt;p&gt;Run the wrong command and every &lt;code&gt;INSERT&lt;/code&gt;, &lt;code&gt;UPDATE&lt;/code&gt;, and &lt;code&gt;DELETE&lt;/code&gt; hangs until it finishes. On a table this size, that can be hours. Here is how to do it safely.&lt;/p&gt;

&lt;h2&gt;
  
  
  The core problem: locks
&lt;/h2&gt;

&lt;p&gt;Every DDL statement (&lt;code&gt;CREATE&lt;/code&gt;, &lt;code&gt;ALTER&lt;/code&gt;, &lt;code&gt;DROP&lt;/code&gt;, &lt;code&gt;TRUNCATE&lt;/code&gt;) takes a lock on the table. What matters is &lt;strong&gt;which lock&lt;/strong&gt; and &lt;strong&gt;for how long&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Analogy:&lt;/strong&gt; You need to install a divider on a busy highway. Closing the entire road (an &lt;code&gt;ACCESS EXCLUSIVE&lt;/code&gt; lock) causes a traffic jam. Working one lane at a time (light locks, small batches) keeps traffic moving.&lt;/p&gt;

&lt;p&gt;There is a second, sneakier danger: the &lt;strong&gt;lock queue&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If your &lt;code&gt;ALTER TABLE&lt;/code&gt; waits behind a long-running query, every new query queues up &lt;em&gt;behind your ALTER&lt;/em&gt;. A harmless migration can freeze the whole application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1: Adding a column
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Case 1: Nullable column, no default (safest)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;notes&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This only changes catalog metadata. No rows are rewritten, so it finishes in milliseconds, even with 200M rows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Case 2: Column with a default
&lt;/h3&gt;

&lt;p&gt;On &lt;strong&gt;PostgreSQL 11+&lt;/strong&gt;, a constant default is also instant:&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;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="s1"&gt;'pending'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Postgres stores the default in the catalog and serves it virtually when reading old rows.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;On &lt;strong&gt;PG 10 or older&lt;/strong&gt;, this rewrites the entire table. Use the batch approach below.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Volatile defaults&lt;/strong&gt; such as &lt;code&gt;now()&lt;/code&gt; or &lt;code&gt;gen_random_uuid()&lt;/code&gt; still trigger a full rewrite on any version.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Case 3: Adding a NOT NULL column
&lt;/h3&gt;

&lt;p&gt;Don't do &lt;code&gt;ADD COLUMN ... NOT NULL&lt;/code&gt; directly. Do it in steps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- 1. Add nullable column (instant)&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;region_id&lt;/span&gt; &lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- 2. Start writing the value for new rows from your application&lt;/span&gt;

&lt;span class="c1"&gt;-- 3. Backfill old rows in batches (see below)&lt;/span&gt;

&lt;span class="c1"&gt;-- 4. Add a CHECK constraint without scanning the table&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;
  &lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="k"&gt;CONSTRAINT&lt;/span&gt; &lt;span class="n"&gt;region_id_not_null&lt;/span&gt;
  &lt;span class="k"&gt;CHECK&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;region_id&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;VALID&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- 5. Validate it. This scans the table but does not block writes.&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="n"&gt;VALIDATE&lt;/span&gt; &lt;span class="k"&gt;CONSTRAINT&lt;/span&gt; &lt;span class="n"&gt;region_id_not_null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- 6. On PG 12+, SET NOT NULL is now instant because a validated CHECK exists&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;region_id&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- 7. Drop the redundant CHECK&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;CONSTRAINT&lt;/span&gt; &lt;span class="n"&gt;region_id_not_null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Backfilling old rows
&lt;/h3&gt;

&lt;p&gt;Never run one giant &lt;code&gt;UPDATE&lt;/code&gt; on 200M rows. It creates a huge transaction, bloats the WAL, causes replication lag, and leaves a pile of dead tuples.&lt;/p&gt;

&lt;p&gt;Update in small batches instead:&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;orders&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;region_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;
  &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;region_id&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
  &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;
  &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;SKIP&lt;/span&gt; &lt;span class="n"&gt;LOCKED&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it in a loop until zero rows are affected. Here's a Go example:&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;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`
        UPDATE orders SET region_id = 1
        WHERE id IN (
            SELECT id FROM orders
            WHERE region_id IS NULL
            LIMIT 10000
            FOR UPDATE SKIP LOCKED
        )`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RowsAffected&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// let autovacuum and replicas breathe&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The short sleep between batches keeps replication lag and vacuum pressure under control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: Adding an index
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The wrong way
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;idx_orders_user_id&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This takes a &lt;code&gt;SHARE&lt;/code&gt; lock, which blocks all writes for the entire build. On 200M rows, that can mean hours of effective downtime.&lt;/p&gt;

&lt;h3&gt;
  
  
  The right way: &lt;code&gt;CONCURRENTLY&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;CONCURRENTLY&lt;/span&gt; &lt;span class="n"&gt;idx_orders_user_id&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Postgres scans the table twice and picks up changes made in between, without blocking writes. It takes roughly 2-3x longer, but your app keeps running.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rules for &lt;code&gt;CONCURRENTLY&lt;/code&gt;
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rule&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cannot run inside a transaction block&lt;/td&gt;
&lt;td&gt;Many migration tools wrap migrations in a transaction by default, so you must disable that&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A failed build leaves an &lt;strong&gt;INVALID&lt;/strong&gt; index&lt;/td&gt;
&lt;td&gt;It slows writes and is useless for reads, so clean it up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Uses a lot of CPU and I/O&lt;/td&gt;
&lt;td&gt;Run it off-peak&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Laravel example&lt;/strong&gt; (disable the wrapping transaction):&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AddUserIdIndexToOrders&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Migration&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nv"&gt;$withinTransaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&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="s1"&gt;'CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_orders_user_id ON orders(user_id)'&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;down&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&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="s1"&gt;'DROP INDEX CONCURRENTLY IF EXISTS idx_orders_user_id'&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;h3&gt;
  
  
  Cleaning up a failed build
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Find invalid indexes&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;indexrelid&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;regclass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indisvalid&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_index&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;indisvalid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Drop and retry&lt;/span&gt;
&lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;CONCURRENTLY&lt;/span&gt; &lt;span class="n"&gt;idx_orders_user_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;CONCURRENTLY&lt;/span&gt; &lt;span class="n"&gt;idx_orders_user_id&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Unique indexes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;CONCURRENTLY&lt;/span&gt; &lt;span class="n"&gt;idx_orders_ref&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reference_no&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Optionally attach it as a constraint (instant)&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;
  &lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="k"&gt;CONSTRAINT&lt;/span&gt; &lt;span class="n"&gt;uniq_orders_ref&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt; &lt;span class="k"&gt;USING&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;idx_orders_ref&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 3: Production safety checklist
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Always set &lt;code&gt;lock_timeout&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This is the single most important habit. It prevents the lock-queue disaster:&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="n"&gt;lock_timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'3s'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;notes&lt;/span&gt; &lt;span class="nb"&gt;text&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 lock isn't acquired within 3 seconds, the &lt;code&gt;ALTER&lt;/code&gt; fails on its own instead of freezing your app. Then you simply retry.&lt;/p&gt;

&lt;p&gt;For a long &lt;code&gt;CREATE INDEX CONCURRENTLY&lt;/code&gt;, also make sure &lt;code&gt;statement_timeout&lt;/code&gt; won't kill 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="n"&gt;statement_timeout&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;h3&gt;
  
  
  2. Check for long-running transactions first
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;xact_start&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_stat_activity&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;xact_start&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&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;duration&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;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An old open transaction can make your DDL wait, and everyone queues behind it.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Monitor index build progress
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;phase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;blocks_done&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;blocks_total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;blocks_done&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="k"&gt;nullif&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blocks_total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;pct&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_stat_progress_create_index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Check disk space and replication
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Make sure you have enough free disk. An index on 200M rows can be several GB or more.&lt;/li&gt;
&lt;li&gt;Watch replication lag if you have replicas.&lt;/li&gt;
&lt;li&gt;Temporarily raising &lt;code&gt;maintenance_work_mem&lt;/code&gt; speeds up the build:
&lt;/li&gt;
&lt;/ul&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="n"&gt;maintenance_work_mem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'2GB'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Rehearse first
&lt;/h3&gt;

&lt;p&gt;Run the migration on a staging copy with production-sized data and time it before touching production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 4: When the simple way isn't enough
&lt;/h2&gt;

&lt;p&gt;Everything above works because PostgreSQL can do those changes online. But some changes force a &lt;strong&gt;full table rewrite&lt;/strong&gt; that PostgreSQL cannot do without blocking writes: changing a column's data type, re-partitioning a table, or reclaiming heavy bloat.&lt;/p&gt;

&lt;p&gt;For these, use the &lt;strong&gt;shadow table&lt;/strong&gt; pattern (also called an online schema change). Tools like &lt;code&gt;gh-ost&lt;/code&gt;, &lt;code&gt;pg-osc&lt;/code&gt;, &lt;code&gt;pgroll&lt;/code&gt;, and &lt;code&gt;pg_repack&lt;/code&gt; are built on this idea.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Analogy:&lt;/strong&gt; You want to renovate a shop that can't close. You build an identical new shop next door with the improvements, move the stock over gradually while mirroring every new sale into both shops, and then swap the signboards in one quick moment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create the copy with the change applied
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;orders_new&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="k"&gt;INCLUDING&lt;/span&gt; &lt;span class="k"&gt;DEFAULTS&lt;/span&gt; &lt;span class="k"&gt;INCLUDING&lt;/span&gt; &lt;span class="k"&gt;CONSTRAINTS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;orders_new&lt;/span&gt; &lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;region_id&lt;/span&gt; &lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;-- or change a column type, etc.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The table is empty, so this is instant. Don't create indexes yet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Mirror live changes with a trigger
&lt;/h3&gt;

&lt;p&gt;Before copying any data, make sure every new write to &lt;code&gt;orders&lt;/code&gt; is also applied to &lt;code&gt;orders_new&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;CREATE&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="n"&gt;orders_sync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;RETURNS&lt;/span&gt; &lt;span class="k"&gt;trigger&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="err"&gt;$$&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
  &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;TG_OP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'DELETE'&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt;
    &lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders_new&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;OLD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="k"&gt;OLD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;ELSE&lt;/span&gt;
    &lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;orders_new&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="cm"&gt;/* , ...all columns */&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;CONFLICT&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;DO&lt;/span&gt; &lt;span class="k"&gt;UPDATE&lt;/span&gt;
      &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EXCLUDED&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EXCLUDED&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="err"&gt;$$&lt;/span&gt; &lt;span class="k"&gt;LANGUAGE&lt;/span&gt; &lt;span class="n"&gt;plpgsql&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TRIGGER&lt;/span&gt; &lt;span class="n"&gt;orders_sync_trg&lt;/span&gt;
&lt;span class="k"&gt;AFTER&lt;/span&gt; &lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;
&lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;EACH&lt;/span&gt; &lt;span class="k"&gt;ROW&lt;/span&gt; &lt;span class="k"&gt;EXECUTE&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="n"&gt;orders_sync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The trigger comes first so no change can slip through the gap while you copy. Note that the &lt;code&gt;ON CONFLICT (id)&lt;/code&gt; clause requires a primary key or unique index on &lt;code&gt;id&lt;/code&gt; in &lt;code&gt;orders_new&lt;/code&gt;, which &lt;code&gt;INCLUDING CONSTRAINTS&lt;/code&gt; does not copy. Create that one index up front.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Backfill old rows in small batches
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;orders_new&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;last_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;id&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;
&lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;CONFLICT&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;DO&lt;/span&gt; &lt;span class="k"&gt;NOTHING&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Loop with a short sleep, moving &lt;code&gt;last_id&lt;/code&gt; forward each time. &lt;code&gt;ON CONFLICT DO NOTHING&lt;/code&gt; ensures the trigger's newer version of a row is never overwritten by an older copied one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Build the remaining indexes on the new table
&lt;/h3&gt;

&lt;p&gt;It's faster to build indexes after the data is loaded. Nobody reads from &lt;code&gt;orders_new&lt;/code&gt; yet, so a plain &lt;code&gt;CREATE INDEX&lt;/code&gt; is fine here, with no &lt;code&gt;CONCURRENTLY&lt;/code&gt; needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Verify
&lt;/h3&gt;

&lt;p&gt;Compare row counts and spot-check data. Run &lt;code&gt;ANALYZE orders_new&lt;/code&gt; so the query planner has fresh statistics.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Swap in one short transaction
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;BEGIN&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;LOCAL&lt;/span&gt; &lt;span class="n"&gt;lock_timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'3s'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;LOCK&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="k"&gt;ACCESS&lt;/span&gt; &lt;span class="k"&gt;EXCLUSIVE&lt;/span&gt; &lt;span class="k"&gt;MODE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="k"&gt;RENAME&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;orders_old&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;orders_new&lt;/span&gt; &lt;span class="k"&gt;RENAME&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This takes milliseconds. If it times out, just retry. Afterward, drop the trigger and keep &lt;code&gt;orders_old&lt;/code&gt; for a few days as a rollback option.&lt;/p&gt;

&lt;h3&gt;
  
  
  What makes this tricky
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sequences and ownership:&lt;/strong&gt; the new table needs the same sequence for &lt;code&gt;id&lt;/code&gt;, with correct ownership.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Foreign keys:&lt;/strong&gt; other tables pointing to &lt;code&gt;orders&lt;/code&gt; must be re-pointed, and adding FKs can itself be slow (use &lt;code&gt;NOT VALID&lt;/code&gt;, then &lt;code&gt;VALIDATE&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Views, permissions, triggers, partitions:&lt;/strong&gt; all must be recreated on the new table.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write overhead:&lt;/strong&gt; every write happens twice during the process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disk space:&lt;/strong&gt; you temporarily need roughly double the table size, plus indexes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hard-coded table names or prepared plans&lt;/strong&gt; in application code can be affected by the rename.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Should you use it?
&lt;/h3&gt;

&lt;p&gt;For adding a plain column or index, no. It adds risk and cost with no benefit.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Best approach&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Nullable column, or column with constant default&lt;/td&gt;
&lt;td&gt;Plain &lt;code&gt;ALTER TABLE&lt;/code&gt; (instant)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add an index&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CREATE INDEX CONCURRENTLY&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Change a column's type, or any change that forces a full rewrite&lt;/td&gt;
&lt;td&gt;Shadow table&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reclaim heavy table bloat&lt;/td&gt;
&lt;td&gt;Shadow table (&lt;code&gt;pg_repack&lt;/code&gt; works this way)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Re-partition a large table&lt;/td&gt;
&lt;td&gt;Shadow table&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The shadow table is the heavy tool for changes PostgreSQL can't do online by itself. Reach for it only when the simple way isn't enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cheat sheet
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Safe approach&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Nullable column&lt;/td&gt;
&lt;td&gt;Plain &lt;code&gt;ADD COLUMN&lt;/code&gt; (instant)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Column with constant default&lt;/td&gt;
&lt;td&gt;Plain &lt;code&gt;ADD COLUMN&lt;/code&gt; on PG 11+ (instant)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NOT NULL column&lt;/td&gt;
&lt;td&gt;Add nullable, batch backfill, &lt;code&gt;CHECK ... NOT VALID&lt;/code&gt;, &lt;code&gt;VALIDATE&lt;/code&gt;, &lt;code&gt;SET NOT NULL&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Index&lt;/td&gt;
&lt;td&gt;Always &lt;code&gt;CREATE INDEX CONCURRENTLY&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Any DDL&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;lock_timeout&lt;/code&gt; first&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bulk data change&lt;/td&gt;
&lt;td&gt;Small batches with a short sleep, never one giant &lt;code&gt;UPDATE&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Column type change, re-partitioning, heavy bloat&lt;/td&gt;
&lt;td&gt;Shadow table: copy, mirror with a trigger, swap names&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Small locks, small transactions, small batches.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Zero-downtime migrations are not about clever tricks. They are about never holding a heavy lock for long, and never letting your DDL wait in a queue that blocks everyone else.&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>database</category>
      <category>backend</category>
      <category>devops</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Md Abu Musa</dc:creator>
      <pubDate>Sat, 13 Jun 2026 11:28:45 +0000</pubDate>
      <link>https://dev.to/musamuhammad/-5fka</link>
      <guid>https://dev.to/musamuhammad/-5fka</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://dev.to/musamuhammad/how-to-remove-aws-cli-configuration-from-ubuntu-1013" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" 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%2Fedsvyvp6bu09a7gkbqak.png" height="427" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://dev.to/musamuhammad/how-to-remove-aws-cli-configuration-from-ubuntu-1013" rel="noopener noreferrer" class="c-link"&gt;
            How to Remove AWS CLI Configuration from Ubuntu - DEV Community
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Introduction   The AWS Command Line Interface (AWS CLI) is a powerful tool that enables...
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" 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%2F8j7kvp660rqzt99zui8e.png" width="300" height="299"&gt;
          dev.to
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>How to Remove AWS CLI Configuration from Ubuntu</title>
      <dc:creator>Md Abu Musa</dc:creator>
      <pubDate>Sat, 13 Jun 2026 11:20:29 +0000</pubDate>
      <link>https://dev.to/musamuhammad/how-to-remove-aws-cli-configuration-from-ubuntu-1013</link>
      <guid>https://dev.to/musamuhammad/how-to-remove-aws-cli-configuration-from-ubuntu-1013</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The AWS Command Line Interface (AWS CLI) is a powerful tool that enables developers and system administrators to interact with Amazon Web Services directly from the terminal. During setup, users typically configure AWS CLI using the &lt;code&gt;aws configure&lt;/code&gt; command, which stores credentials and default settings locally on the system.&lt;/p&gt;

&lt;p&gt;There are situations where you may need to remove or update your AWS configuration, such as rotating credentials, switching AWS accounts, decommissioning a development environment, or enhancing security. This guide explains how to safely remove AWS CLI configuration from an Ubuntu system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding AWS CLI Configuration Files
&lt;/h2&gt;

&lt;p&gt;When you run:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;AWS CLI stores configuration data in the following files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/.aws/credentials
~/.aws/config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  credentials file
&lt;/h3&gt;

&lt;p&gt;Contains sensitive authentication information:&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="nn"&gt;[default]&lt;/span&gt;
&lt;span class="py"&gt;aws_access_key_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;YOUR_ACCESS_KEY&lt;/span&gt;
&lt;span class="py"&gt;aws_secret_access_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;YOUR_SECRET_KEY&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  config file
&lt;/h3&gt;

&lt;p&gt;Contains region and output preferences:&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="nn"&gt;[default]&lt;/span&gt;
&lt;span class="py"&gt;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;ap-northeast-2&lt;/span&gt;
&lt;span class="py"&gt;output&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Method 1: Remove All AWS CLI Configuration
&lt;/h2&gt;

&lt;p&gt;If you want to completely remove all configured AWS credentials and settings, delete both files:&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;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; ~/.aws/credentials ~/.aws/config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will remove:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS Access Key ID&lt;/li&gt;
&lt;li&gt;AWS Secret Access Key&lt;/li&gt;
&lt;li&gt;Default Region&lt;/li&gt;
&lt;li&gt;Output Format Preferences&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Verify Removal
&lt;/h3&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;aws configure list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the configuration has been removed successfully, AWS CLI will no longer display configured credentials or region information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Method 2: Remove a Specific AWS Profile
&lt;/h2&gt;

&lt;p&gt;AWS CLI supports multiple profiles for managing different AWS accounts.&lt;/p&gt;

&lt;h3&gt;
  
  
  View Existing Profiles
&lt;/h3&gt;

&lt;p&gt;Check your configuration files:&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; ~/.aws/credentials
&lt;span class="nb"&gt;cat&lt;/span&gt; ~/.aws/config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Edit the Files
&lt;/h3&gt;

&lt;p&gt;Open the files with a text editor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano ~/.aws/credentials
nano ~/.aws/config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remove the profile section you no longer need.&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 ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[development]&lt;/span&gt;
&lt;span class="py"&gt;aws_access_key_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;EXAMPLE&lt;/span&gt;
&lt;span class="py"&gt;aws_secret_access_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;EXAMPLE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the file after removing the profile.&lt;/p&gt;

&lt;h2&gt;
  
  
  Method 3: Uninstall AWS CLI from Ubuntu
&lt;/h2&gt;

&lt;p&gt;If you no longer need AWS CLI, you can uninstall it completely.&lt;/p&gt;

&lt;h3&gt;
  
  
  Determine Installation Method
&lt;/h3&gt;

&lt;p&gt;First, check the AWS CLI installation path:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Check the installed version:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Remove AWS CLI Installed via APT
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt remove awscli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Remove AWS CLI Installed via AWS Installer
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /usr/local/aws-cli
&lt;span class="nb"&gt;sudo rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; /usr/local/bin/aws
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Security Best Practices
&lt;/h2&gt;

&lt;p&gt;When removing AWS credentials:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rotate credentials if they were exposed or shared.&lt;/li&gt;
&lt;li&gt;Use IAM roles whenever possible instead of long-term access keys.&lt;/li&gt;
&lt;li&gt;Regularly audit configured AWS profiles.&lt;/li&gt;
&lt;li&gt;Avoid storing credentials in scripts or source code repositories.&lt;/li&gt;
&lt;li&gt;Use AWS Secrets Manager or environment variables for sensitive workloads.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Removing AWS CLI configuration on Ubuntu is a straightforward process. Whether you need to clear credentials, delete a specific profile, or uninstall AWS CLI entirely, understanding where AWS stores its configuration helps maintain a secure and organized development environment. Regular credential management is an essential part of AWS security best practices and helps protect your cloud resources from unauthorized access.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cli</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>cURL: The Swiss Army Knife of Data Transfer</title>
      <dc:creator>Md Abu Musa</dc:creator>
      <pubDate>Mon, 26 Jan 2026 06:30:13 +0000</pubDate>
      <link>https://dev.to/musamuhammad/curl-the-swiss-army-knife-of-data-transfer-6pl</link>
      <guid>https://dev.to/musamuhammad/curl-the-swiss-army-knife-of-data-transfer-6pl</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;curl&lt;/code&gt; (Client URL) is one of the most powerful and widely used command-line tools in software engineering. It enables data transfer between a client and a server using various network protocols. From testing REST APIs to downloading files, debugging HTTP requests, and automating workflows, &lt;code&gt;curl&lt;/code&gt; is an essential tool for developers, system administrators, and DevOps engineers.&lt;/p&gt;

&lt;p&gt;This blog explores what &lt;code&gt;curl&lt;/code&gt; is, how it works, its most common use cases, and practical examples that you can apply in real-world scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What Is cURL?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;curl&lt;/code&gt; is an open-source command-line tool and library (&lt;code&gt;libcurl&lt;/code&gt;) used to transfer data to or from a server using URLs. It supports a wide range of protocols, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP / HTTPS&lt;/li&gt;
&lt;li&gt;FTP / FTPS&lt;/li&gt;
&lt;li&gt;SCP / SFTP&lt;/li&gt;
&lt;li&gt;SMTP / POP3 / IMAP&lt;/li&gt;
&lt;li&gt;LDAP&lt;/li&gt;
&lt;li&gt;MQTT&lt;/li&gt;
&lt;li&gt;FILE&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tool is available by default on most Linux and macOS systems and can be installed easily on Windows.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why cURL Is Important&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;curl&lt;/code&gt; is popular because it is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lightweight and fast&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scriptable&lt;/strong&gt; (perfect for automation)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Protocol-agnostic&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Widely supported&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ideal for API testing and debugging&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In backend development and DevOps, &lt;code&gt;curl&lt;/code&gt; is often the first tool used to verify whether a service or endpoint is working correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Basic cURL Syntax&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="o"&gt;[&lt;/span&gt;options] URL
&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;curl https://example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sends a basic &lt;strong&gt;HTTP GET request&lt;/strong&gt; and prints the response body to the terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Common HTTP Operations with cURL&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. GET Request&lt;/strong&gt;
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;Used to retrieve data from a server.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. POST Request&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://api.example.com/users &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"name":"Musa","email":"musa@example.com"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Used to send data to the server, commonly for creating resources.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. PUT Request&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; PUT https://api.example.com/users/1 &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"name":"Updated Name"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Used to update existing resources.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4. DELETE Request&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; DELETE https://api.example.com/users/1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Used to delete a resource.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Working with Headers&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Send Custom Headers&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer TOKEN"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Accept: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     https://api.example.com/profile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;View Response Headers&lt;/strong&gt;
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Authentication with cURL&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Basic Authentication&lt;/strong&gt;
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Bearer Token Authentication&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer YOUR_TOKEN"&lt;/span&gt; https://api.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Handling JSON Responses&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To pretty-print JSON responses, combine &lt;code&gt;curl&lt;/code&gt; with &lt;code&gt;jq&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;curl https://api.example.com/users | jq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is extremely useful when debugging APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;File Upload and Download&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Download a File&lt;/strong&gt;
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Upload a File&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="s2"&gt;"file=@image.png"&lt;/span&gt; https://api.example.com/upload
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Debugging and Verbose Mode&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Verbose Output&lt;/strong&gt;
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;This shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Request headers&lt;/li&gt;
&lt;li&gt;Response headers&lt;/li&gt;
&lt;li&gt;TLS handshake details&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Very useful for debugging network issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Timeouts and Retries&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Set Timeout&lt;/strong&gt;
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Retry on Failure&lt;/strong&gt;
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Following Redirects&lt;/strong&gt;
&lt;/h2&gt;



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

&lt;/div&gt;



&lt;p&gt;By default, &lt;code&gt;curl&lt;/code&gt; does not follow redirects unless explicitly told.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Using cURL in Automation and Scripts&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;curl&lt;/code&gt; is commonly used in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CI/CD pipelines&lt;/li&gt;
&lt;li&gt;Health checks&lt;/li&gt;
&lt;li&gt;Cron jobs&lt;/li&gt;
&lt;li&gt;Shell scripts&lt;/li&gt;
&lt;li&gt;Server monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example health check:&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;-f&lt;/span&gt; https://api.example.com/health &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Security Best Practices&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Avoid exposing tokens in terminal history&lt;/li&gt;
&lt;li&gt;Use environment variables for credentials&lt;/li&gt;
&lt;li&gt;Prefer HTTPS over HTTP&lt;/li&gt;
&lt;li&gt;Validate SSL certificates (avoid &lt;code&gt;-k&lt;/code&gt; in production)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;cURL vs Postman&lt;/strong&gt;
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;cURL&lt;/th&gt;
&lt;th&gt;Postman&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Command-line&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Automation&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GUI&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lightweight&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CI/CD friendly&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Best practice:&lt;/strong&gt; Use Postman for exploration and &lt;code&gt;curl&lt;/code&gt; for automation and production debugging.&lt;/p&gt;

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

&lt;p&gt;&lt;code&gt;curl&lt;/code&gt; is an indispensable tool for modern software engineering. Its simplicity, flexibility, and power make it ideal for API testing, system administration, and automation tasks. Mastering &lt;code&gt;curl&lt;/code&gt; significantly improves your ability to debug, test, and interact with network services efficiently.&lt;/p&gt;

&lt;p&gt;Whether you are a backend engineer, DevOps professional, or software architect, &lt;code&gt;curl&lt;/code&gt; deserves a permanent place in your toolkit.&lt;/p&gt;

</description>
      <category>api</category>
      <category>cli</category>
      <category>networking</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Ubuntu Server Resource Monitoring via Command Line</title>
      <dc:creator>Md Abu Musa</dc:creator>
      <pubDate>Sat, 13 Dec 2025 14:52:54 +0000</pubDate>
      <link>https://dev.to/musamuhammad/ubuntu-server-resource-monitoring-via-command-line-1e42</link>
      <guid>https://dev.to/musamuhammad/ubuntu-server-resource-monitoring-via-command-line-1e42</guid>
      <description>&lt;p&gt;Monitoring system resources is a &lt;strong&gt;critical responsibility for backend engineers, DevOps engineers, and system administrators&lt;/strong&gt;. Whether you are running a Laravel API, Node.js app, Docker containers, or an AWS EC2 instance, understanding how your Ubuntu server consumes &lt;strong&gt;CPU, memory, disk, and network resources&lt;/strong&gt; helps you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Detect performance bottlenecks early&lt;/li&gt;
&lt;li&gt;Prevent unexpected downtime&lt;/li&gt;
&lt;li&gt;Optimize application performance&lt;/li&gt;
&lt;li&gt;Make informed scaling decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This blog provides a &lt;strong&gt;professional, practical, and production-oriented guide&lt;/strong&gt; to checking system resource usage on an &lt;strong&gt;Ubuntu Server using only command-line tools&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Why Resource Monitoring Matters
&lt;/h2&gt;

&lt;p&gt;In real-world production environments, issues like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Slow API responses&lt;/li&gt;
&lt;li&gt;Sudden 504 Gateway Timeout errors&lt;/li&gt;
&lt;li&gt;Random application crashes&lt;/li&gt;
&lt;li&gt;Server freeze or reboot&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;are often &lt;strong&gt;symptoms of resource exhaustion&lt;/strong&gt; rather than application bugs.&lt;/p&gt;

&lt;p&gt;Regular monitoring helps answer critical questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is CPU overloaded?&lt;/li&gt;
&lt;li&gt;Is RAM exhausted or swapping?&lt;/li&gt;
&lt;li&gt;Is disk space full?&lt;/li&gt;
&lt;li&gt;Is disk I/O causing delays?&lt;/li&gt;
&lt;li&gt;Which process is consuming the most resources?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Quick System Health Overview
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Command
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;h3&gt;
  
  
  What it shows
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;System running time&lt;/li&gt;
&lt;li&gt;Number of logged-in users&lt;/li&gt;
&lt;li&gt;Load average (1, 5, 15 minutes)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How to interpret load average
&lt;/h3&gt;

&lt;p&gt;If your server has &lt;strong&gt;4 CPU cores&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Load average ≈ 4 → normal&lt;/li&gt;
&lt;li&gt;Load average &amp;gt; 4 → CPU under pressure&lt;/li&gt;
&lt;li&gt;Load average &amp;gt;&amp;gt; 4 → serious performance issue&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the &lt;strong&gt;fastest health check command&lt;/strong&gt; you should use first.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Real-Time CPU and Memory Monitoring
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Using &lt;code&gt;top&lt;/code&gt;
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;h4&gt;
  
  
  Key metrics
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;%CPU&lt;/code&gt; → CPU usage per process&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;%MEM&lt;/code&gt; → Memory usage per process&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;load average&lt;/code&gt; → overall CPU load&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Useful shortcuts
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Shift + P&lt;/code&gt; → sort by CPU usage&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Shift + M&lt;/code&gt; → sort by memory usage&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;q&lt;/code&gt; → quit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;top&lt;/code&gt; is available by default on all Ubuntu servers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using &lt;code&gt;htop&lt;/code&gt; (Recommended)
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;h4&gt;
  
  
  Why &lt;code&gt;htop&lt;/code&gt; is better
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Color-coded CPU and memory bars&lt;/li&gt;
&lt;li&gt;Easy process killing&lt;/li&gt;
&lt;li&gt;Tree view of processes&lt;/li&gt;
&lt;li&gt;Mouse support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For daily production monitoring, &lt;strong&gt;htop is strongly recommended&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Memory (RAM) Usage Analysis
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Command
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key fields explained
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;total&lt;/code&gt; → Total RAM&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;used&lt;/code&gt; → Used memory&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;available&lt;/code&gt; → Memory available for new processes&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Important&lt;/strong&gt;: Always focus on &lt;code&gt;available&lt;/code&gt;, not &lt;code&gt;free&lt;/code&gt;. Linux uses free memory for caching, which is normal and healthy.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If &lt;code&gt;available&lt;/code&gt; memory is very low, your server may start swapping or killing processes.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Disk Usage Monitoring
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Overall disk usage
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;df&lt;/span&gt; &lt;span class="nt"&gt;-h&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Total disk size&lt;/li&gt;
&lt;li&gt;Used space&lt;/li&gt;
&lt;li&gt;Available space&lt;/li&gt;
&lt;li&gt;Mount points&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ If disk usage reaches &lt;strong&gt;90%+&lt;/strong&gt;, services like MySQL, Redis, or Docker may fail.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Directory-wise disk usage
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;du&lt;/span&gt; &lt;span class="nt"&gt;-sh&lt;/span&gt; /path/to/directory
&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;&lt;span class="nb"&gt;du&lt;/span&gt; &lt;span class="nt"&gt;-sh&lt;/span&gt; /var/www
&lt;span class="nb"&gt;du&lt;/span&gt; &lt;span class="nt"&gt;-sh&lt;/span&gt; /var/log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This helps identify &lt;strong&gt;which folders are consuming disk space&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. CPU Information and Core Count
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Command
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;Provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CPU architecture&lt;/li&gt;
&lt;li&gt;Number of cores&lt;/li&gt;
&lt;li&gt;Threads per core&lt;/li&gt;
&lt;li&gt;CPU model&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Knowing the core count is essential for correctly interpreting &lt;strong&gt;load average&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Network Usage Monitoring
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Basic network statistics
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ip &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nb"&gt;link&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Shows transmitted and received packets per network interface.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real-time network monitoring
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;Useful when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;APIs feel slow&lt;/li&gt;
&lt;li&gt;Upload/download speed is suspicious&lt;/li&gt;
&lt;li&gt;External service calls timeout&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  8. Disk I/O Performance (Often Overlooked)
&lt;/h2&gt;

&lt;p&gt;High disk I/O wait can slow down applications even when CPU and RAM look normal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Command
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;sysstat
iostat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High &lt;code&gt;%iowait&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Slow read/write rates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is critical for &lt;strong&gt;database-heavy applications&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Identify Resource-Hungry Processes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Top memory-consuming processes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ps aux &lt;span class="nt"&gt;--sort&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;-%mem | &lt;span class="nb"&gt;head&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Top CPU-consuming processes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ps aux &lt;span class="nt"&gt;--sort&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;-%cpu | &lt;span class="nb"&gt;head&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is extremely useful during &lt;strong&gt;production incidents&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. One-Command Live Summary
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Command
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;Updates every second and shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CPU usage&lt;/li&gt;
&lt;li&gt;Memory usage&lt;/li&gt;
&lt;li&gt;Swap activity&lt;/li&gt;
&lt;li&gt;Disk I/O&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A powerful command for &lt;strong&gt;advanced troubleshooting&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  11. Recommended Monitoring Workflow (Production)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;uptime&lt;/code&gt; → Quick health check&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;htop&lt;/code&gt; → Live CPU &amp;amp; memory monitoring&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;free -h&lt;/code&gt; → Memory availability&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;df -h&lt;/code&gt; → Disk usage&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;iostat&lt;/code&gt; → Disk I/O issues&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ps aux&lt;/code&gt; → Identify problematic processes&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  12. Conclusion
&lt;/h2&gt;

&lt;p&gt;Command-line monitoring tools are &lt;strong&gt;lightweight, fast, and reliable&lt;/strong&gt;, making them perfect for Ubuntu servers in production.&lt;/p&gt;

&lt;p&gt;By mastering these commands, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Debug performance issues confidently&lt;/li&gt;
&lt;li&gt;Reduce downtime&lt;/li&gt;
&lt;li&gt;Communicate system health clearly to your team&lt;/li&gt;
&lt;li&gt;Grow from a backend engineer into a strong DevOps-aware professional&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Regular monitoring is not optional — &lt;strong&gt;it is a core engineering habit&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>ubuntu</category>
      <category>linux</category>
      <category>devops</category>
      <category>performance</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Md Abu Musa</dc:creator>
      <pubDate>Fri, 12 Dec 2025 03:32:21 +0000</pubDate>
      <link>https://dev.to/musamuhammad/-p6k</link>
      <guid>https://dev.to/musamuhammad/-p6k</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://dev.to/musamuhammad/why-your-ec2-server-suddenly-stops-responding-and-how-to-bulletproof-laravel-node-apps-13l8" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" 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%2F630uyswrkehkdh9zypas.png" height="533" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://dev.to/musamuhammad/why-your-ec2-server-suddenly-stops-responding-and-how-to-bulletproof-laravel-node-apps-13l8" rel="noopener noreferrer" class="c-link"&gt;
            Why Your EC2 Server Suddenly Stops Responding — And How to Bulletproof Laravel &amp;amp; Node Apps - DEV Community
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Managing multiple Laravel and Node.js applications on a single EC2 instance is common in small and...
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" 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%2F8j7kvp660rqzt99zui8e.png" width="300" height="299"&gt;
          dev.to
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>devops</category>
      <category>node</category>
      <category>performance</category>
      <category>aws</category>
    </item>
    <item>
      <title>Why Your EC2 Server Suddenly Stops Responding — And How to Bulletproof Laravel &amp; Node Apps</title>
      <dc:creator>Md Abu Musa</dc:creator>
      <pubDate>Tue, 09 Dec 2025 16:50:34 +0000</pubDate>
      <link>https://dev.to/musamuhammad/why-your-ec2-server-suddenly-stops-responding-and-how-to-bulletproof-laravel-node-apps-13l8</link>
      <guid>https://dev.to/musamuhammad/why-your-ec2-server-suddenly-stops-responding-and-how-to-bulletproof-laravel-node-apps-13l8</guid>
      <description>&lt;p&gt;Managing multiple Laravel and Node.js applications on a single EC2 instance is common in small and mid-sized teams. However, when several applications share the same resources, one heavy operation can freeze the entire server — causing all domains to go down at the same time.&lt;/p&gt;

&lt;p&gt;Recently, we faced a similar issue:&lt;br&gt;
&lt;strong&gt;all test and development domains stopped responding simultaneously&lt;/strong&gt;, even though no code changes were deployed on some of them. The root cause was not immediately clear.&lt;/p&gt;

&lt;p&gt;After detailed inspection, the problem turned out to be resource exhaustion caused by a Node build process running directly on the server.&lt;/p&gt;

&lt;p&gt;This article explains &lt;strong&gt;why this happens&lt;/strong&gt;, &lt;strong&gt;how to diagnose it&lt;/strong&gt;, and &lt;strong&gt;what steps you should take to prevent it permanently&lt;/strong&gt;.&lt;/p&gt;
&lt;h1&gt;
  
  
  &lt;strong&gt;What Actually Happened?&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;According to the internal investigation, the issue was caused by:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“The server was unable to load the build and hung the system.”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When someone runs &lt;code&gt;npm run build&lt;/code&gt; or &lt;code&gt;yarn build&lt;/code&gt; directly inside an EC2 instance — especially an instance with limited RAM (1–2GB) — Node consumes a large amount of memory to compile and optimize frontend assets.&lt;/p&gt;

&lt;p&gt;As memory usage increases, the server begins to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Swap aggressively&lt;/li&gt;
&lt;li&gt;Kill processes&lt;/li&gt;
&lt;li&gt;Freeze PHP-FPM&lt;/li&gt;
&lt;li&gt;Stall Nginx worker processes&lt;/li&gt;
&lt;li&gt;Hang SSH access&lt;/li&gt;
&lt;li&gt;Stop responding to all HTTP requests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because all Laravel apps, Node apps, queue workers, and socket services run under the same OS, the entire system becomes unresponsive.&lt;/p&gt;
&lt;h1&gt;
  
  
  &lt;strong&gt;Why a Node Build Freezes Small EC2 Instances&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Node.js build tools like Vite, Webpack, or Next.js require high memory to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Minify large JS bundles&lt;/li&gt;
&lt;li&gt;Optimize images&lt;/li&gt;
&lt;li&gt;Handle TypeScript&lt;/li&gt;
&lt;li&gt;Perform tree-shaking&lt;/li&gt;
&lt;li&gt;Build multiple targets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On servers with &lt;strong&gt;low memory&lt;/strong&gt;, this triggers:&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;1. 100% CPU consumption&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Node compilers go full throttle.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;2. RAM exhaustion&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Node often needs &lt;strong&gt;512 MB – 2 GB&lt;/strong&gt; per build.&lt;br&gt;
This is too heavy for small EC2 instances.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;3. Out-of-Memory (OOM) kills&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The kernel automatically kills PHP-FPM or MySQL first instead of Node.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;4. Nginx stops responding&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Since PHP-FPM dies, Nginx returns 502/504 or hangs completely.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;5. SSH becomes slow&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If swap memory also fills up, the OS stops scheduling tasks.&lt;/p&gt;

&lt;p&gt;This chain reaction brings down &lt;strong&gt;every domain&lt;/strong&gt; hosted on the server.&lt;/p&gt;
&lt;h1&gt;
  
  
  &lt;strong&gt;How to Prevent This Problem in the Future&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Here are practical and immediate measures to avoid similar outages.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;1. Never Build Frontend Code on Production or Test Servers&lt;/strong&gt;
&lt;/h2&gt;

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

&lt;ul&gt;
&lt;li&gt;Build locally&lt;/li&gt;
&lt;li&gt;Build in CI/CD&lt;/li&gt;
&lt;li&gt;Upload only the final &lt;code&gt;dist/&lt;/code&gt; or &lt;code&gt;build/&lt;/code&gt; folder&lt;/li&gt;
&lt;li&gt;Deploy the compiled assets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This alone prevents 80% of such incidents.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;2. Add a 2GB Swap File&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If you're using a small EC2 instance (t2.micro, t3.small, etc.), create a swap 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;fallocate &lt;span class="nt"&gt;-l&lt;/span&gt; 2G /swapfile
&lt;span class="nb"&gt;sudo chmod &lt;/span&gt;600 /swapfile
&lt;span class="nb"&gt;sudo &lt;/span&gt;mkswap /swapfile
&lt;span class="nb"&gt;sudo &lt;/span&gt;swapon /swapfile
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"/swapfile swap swap defaults 0 0"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; /etc/fstab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Swap helps the OS avoid crashing when memory runs out.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;3. Limit Node.js Memory Usage (PM2 Protection)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If apps are running under PM2, apply memory protection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pm2 restart &amp;lt;app&amp;gt; &lt;span class="nt"&gt;--max-memory-restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;300M
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or apply to all:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pm2 restart all &lt;span class="nt"&gt;--max-memory-restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;300M
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prevents any single Node app from consuming all memory.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;4. Restart PHP-FPM &amp;amp; Nginx During High Load&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If the server slows down or freezes:&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 restart php8.1-fpm
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This often restores service instantly.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;5. Monitor Real-Time Resource Usage with htop&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Install:&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;htop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;htop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This lets you identify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which process is consuming CPU&lt;/li&gt;
&lt;li&gt;Which service is consuming RAM&lt;/li&gt;
&lt;li&gt;Stuck or zombie processes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;6. Use PM2 Startup to Ensure Node Apps Auto-Restart on Reboot&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pm2 startup
pm2 save
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures Node apps come back automatically after a server reboot.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;7. Use a Deployment Pipeline&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The most reliable long-term solution:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub Actions&lt;/li&gt;
&lt;li&gt;GitLab CI&lt;/li&gt;
&lt;li&gt;Bitbucket Pipelines&lt;/li&gt;
&lt;li&gt;Jenkins&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Build assets &lt;strong&gt;before deploying&lt;/strong&gt;, not on the server.&lt;/p&gt;

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

&lt;p&gt;When multiple applications share a single EC2 instance, one heavy task — such as a Node build — can overload system resources and freeze the entire machine. This can bring down all domains and services at once.&lt;/p&gt;

&lt;p&gt;To prevent this, teams should:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Avoid running builds directly on servers&lt;/li&gt;
&lt;li&gt;Add swap memory&lt;/li&gt;
&lt;li&gt;Limit Node memory usage&lt;/li&gt;
&lt;li&gt;Monitor resource consumption&lt;/li&gt;
&lt;li&gt;Use CI/CD pipelines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By applying these preventive measures, you ensure stable performance and avoid sudden downtime in development, test, or even production environments.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>node</category>
      <category>performance</category>
      <category>aws</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Md Abu Musa</dc:creator>
      <pubDate>Thu, 02 Oct 2025 13:04:28 +0000</pubDate>
      <link>https://dev.to/musamuhammad/-37f1</link>
      <guid>https://dev.to/musamuhammad/-37f1</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://dev.to/musamuhammad/how-i-optimized-a-laravel-api-287x-faster-from-27s-to-under-100ms-4cd7" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" 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%2Fqc7y1cz3dwo3fyx9xf70.png" height="323" class="m-0" width="799"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://dev.to/musamuhammad/how-i-optimized-a-laravel-api-287x-faster-from-27s-to-under-100ms-4cd7" rel="noopener noreferrer" class="c-link"&gt;
            How I Optimized a Laravel API 287x Faster: From 27s to Under 100ms - DEV Community
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Transforming a sluggish patient list API into a lightning-fast, production-ready endpoint through...
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" 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%2F8j7kvp660rqzt99zui8e.png" width="300" height="299"&gt;
          dev.to
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>laravel</category>
      <category>performance</category>
      <category>productivity</category>
      <category>mysql</category>
    </item>
    <item>
      <title>How I Optimized a Laravel API 287x Faster: From 27s to Under 100ms</title>
      <dc:creator>Md Abu Musa</dc:creator>
      <pubDate>Thu, 02 Oct 2025 13:01:22 +0000</pubDate>
      <link>https://dev.to/musamuhammad/how-i-optimized-a-laravel-api-287x-faster-from-27s-to-under-100ms-4cd7</link>
      <guid>https://dev.to/musamuhammad/how-i-optimized-a-laravel-api-287x-faster-from-27s-to-under-100ms-4cd7</guid>
      <description>&lt;p&gt;&lt;em&gt;Transforming a sluggish patient list API into a lightning-fast, production-ready endpoint through strategic database optimization and response streamlining.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem: A Performance Nightmare
&lt;/h2&gt;

&lt;p&gt;Picture this: You're working on a healthcare application with a patient list API that's taking &lt;strong&gt;27+ seconds&lt;/strong&gt; to load just 600 patients. Users are frustrated, the database is overwhelmed, and your server costs are skyrocketing. This was the reality I faced when analyzing our &lt;code&gt;patientList&lt;/code&gt; API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initial Performance Metrics (The Bad News)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Response Time&lt;/strong&gt;: 27.43 seconds 😱&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database Queries&lt;/strong&gt;: 4,440+ queries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model Instantiations&lt;/strong&gt;: 5,320+ objects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory Usage&lt;/strong&gt;: 20MB&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User Experience&lt;/strong&gt;: Completely unusable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The API was suffering from the classic &lt;strong&gt;N+1 query problem&lt;/strong&gt; on steroids, with additional issues like unnecessary data transfer and missing database indexes.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Investigation: Root Cause Analysis
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. The N+1 Query Monster
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// The problematic code (simplified)&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;$patientData&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$key&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$pd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$pd&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;userInfo&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;user_uuid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;           &lt;span class="c1"&gt;// Query 1 per patient&lt;/span&gt;
    &lt;span class="nv"&gt;$pd&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;officeInfo&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;office_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;       &lt;span class="c1"&gt;// Query 2 per patient&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;findPatientDefaultData&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;span class="c1"&gt;// Query 3 per patient&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;findPatientInsurance&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;span class="c1"&gt;// Query 4 per patient&lt;/span&gt;
    &lt;span class="c1"&gt;// ... and so on&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For 600 patients, this meant &lt;strong&gt;4,440+ individual database queries&lt;/strong&gt; just in the foreach loop!&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Unnecessary Data Transfer
&lt;/h3&gt;

&lt;p&gt;The API was returning 27+ fields per patient, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Personal details (SSN, addresses, BMI, weight)&lt;/li&gt;
&lt;li&gt;Insurance information&lt;/li&gt;
&lt;li&gt;Questionnaire data&lt;/li&gt;
&lt;li&gt;Profile assets&lt;/li&gt;
&lt;li&gt;Referral information&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most of this data wasn't being used by the frontend.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Missing Database Indexes
&lt;/h3&gt;

&lt;p&gt;Critical columns lacked proper indexing, causing full table scans on every query.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solution: A Multi-Layered Optimization Strategy
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Phase 1: Eliminate N+1 Queries with Eager Loading
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before: N+1 queries&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;$patientData&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$key&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$pd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$pd&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;userInfo&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;user_uuid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Individual query per patient&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// After: Batch loading with eager loading&lt;/span&gt;
&lt;span class="nv"&gt;$query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PatientUnderOffice&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="s1"&gt;'userInfo:id,user_uuid,email,type'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'officeInfo:id,office_name'&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;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'dentist_office_id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$dentist_office_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Only load clinical visits in batch (for last_clinical_visit field)&lt;/span&gt;
&lt;span class="nv"&gt;$clinicalVisits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;VisitFormMiscellaneousNote&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'patient_profile_id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'date'&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;whereIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'patient_profile_id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$patientProfileIds&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;whereIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&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;$query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$patientProfileIds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$query&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'MAX(id)'&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;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'visit_form_miscellaneous_notes'&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;whereIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'patient_profile_id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$patientProfileIds&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;groupBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'patient_profile_id'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&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;keyBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'patient_profile_id'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Phase 2: Streamline Response Structure
&lt;/h3&gt;

&lt;p&gt;I identified that the frontend only needed 15 essential fields out of 42 total fields. Here's what I removed:&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="c1"&gt;// Removed 27 unnecessary fields:&lt;/span&gt;
&lt;span class="nv"&gt;$removedFields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'referred_by'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'assets'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'referral_type'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'referred_time'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'referred_note'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'dentist_office'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'gender'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'marital_status'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'height'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'ssn'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'address_one'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'address_two'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'city'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'state'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'zipCode'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'bmi'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'weight'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'self_pay_status'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'created_at'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'updated_at'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'employer_details'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'questionnaire_id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'symptoms'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'epworth'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'treatment'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'history'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'insurance'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'temp_updated_value'&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// Kept only essential fields:&lt;/span&gt;
&lt;span class="nv"&gt;$essentialFields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'user_id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'user_uuid'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'patient_profile_id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'dentist_office_id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'title'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'first_name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'middle_name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'last_name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'preferred_name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'type'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'dob'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'phone_numbers'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'status'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'last_clinical_visit'&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Phase 3: Add Strategic Database Indexes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Migration: Add performance indexes&lt;/span&gt;
&lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'patient_under_offices'&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="kt"&gt;Blueprint&lt;/span&gt; &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'dentist_office_id'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'status'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'created_at'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'first_name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'last_name'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'phone_numbers(50)'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'patient_profile_id'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'users'&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="kt"&gt;Blueprint&lt;/span&gt; &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user_uuid'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// ... and more strategic indexes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Phase 4: Optimize Model Relationships
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Optimized relationships with selective field loading&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;userInfo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;belongsTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'App\Models\User'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'user_id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'id'&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;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'user_uuid'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'type'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;officeInfo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;belongsTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'App\Models\DentistOfficeProfile'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'dentist_office_id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'id'&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;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'office_name'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Results: From Nightmare to Dream
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Performance Transformation
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;th&gt;Improvement&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Response Time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;27.43s&lt;/td&gt;
&lt;td&gt;95.72ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;99.7% faster&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Database Queries&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4,440+&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;99.8% reduction&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Model Instantiations&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;5,320+&lt;/td&gt;
&lt;td&gt;1,796&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;66% reduction&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Memory Usage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;20MB&lt;/td&gt;
&lt;td&gt;8MB&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;60% reduction&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Response Size&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Large&lt;/td&gt;
&lt;td&gt;~2KB&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;70% smaller&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Real-World Impact
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;User Experience&lt;/strong&gt;: From completely unusable to instant loading&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server Costs&lt;/strong&gt;: Massive reduction in database load&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: Can now handle 10x more concurrent users&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintenance&lt;/strong&gt;: Cleaner, more focused codebase&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Key Lessons Learned
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Always Profile Before Optimizing
&lt;/h3&gt;

&lt;p&gt;Use Laravel Debugbar or similar tools to identify the real bottlenecks. Don't guess!&lt;/p&gt;

&lt;h3&gt;
  
  
  2. N+1 Queries Are Performance Killers
&lt;/h3&gt;

&lt;p&gt;Eager loading and batch queries should be your first optimization targets.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Less Data = Better Performance
&lt;/h3&gt;

&lt;p&gt;Only return what the frontend actually needs. Every unnecessary field costs bandwidth and processing time.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Database Indexes Are Critical
&lt;/h3&gt;

&lt;p&gt;Proper indexing can make the difference between a query taking 1ms vs 1000ms.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Measure Everything
&lt;/h3&gt;

&lt;p&gt;Before and after metrics are crucial for proving the value of your optimizations.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tools and Techniques Used
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Laravel Debugbar&lt;/strong&gt;: For performance profiling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Eager Loading&lt;/strong&gt;: &lt;code&gt;with()&lt;/code&gt; method for relationship optimization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch Queries&lt;/strong&gt;: &lt;code&gt;whereIn()&lt;/code&gt; for bulk data loading&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Selective Field Loading&lt;/strong&gt;: &lt;code&gt;select()&lt;/code&gt; to limit data transfer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database Indexes&lt;/strong&gt;: Strategic indexing for query optimization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Response Streamlining&lt;/strong&gt;: Removing unnecessary data fields&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;This optimization transformed a completely unusable API into a lightning-fast, production-ready endpoint. The key was taking a systematic approach:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Profile&lt;/strong&gt; to identify bottlenecks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Eliminate&lt;/strong&gt; N+1 queries with eager loading&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streamline&lt;/strong&gt; the response structure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Index&lt;/strong&gt; the database properly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Measure&lt;/strong&gt; the results&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The result? An API that's &lt;strong&gt;287x faster&lt;/strong&gt; and uses &lt;strong&gt;99.8% fewer database queries&lt;/strong&gt;. Sometimes the biggest performance wins come from the simplest optimizations.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>performance</category>
      <category>productivity</category>
      <category>mysql</category>
    </item>
    <item>
      <title>Deploy Laravel on AWS EC2 with RDS MySQL and NGINX</title>
      <dc:creator>Md Abu Musa</dc:creator>
      <pubDate>Tue, 05 Aug 2025 16:50:13 +0000</pubDate>
      <link>https://dev.to/musamuhammad/deploy-laravel-on-aws-ec2-with-rds-mysql-and-nginx-4bpo</link>
      <guid>https://dev.to/musamuhammad/deploy-laravel-on-aws-ec2-with-rds-mysql-and-nginx-4bpo</guid>
      <description>&lt;p&gt;Setting up a Laravel application on AWS is a powerful way to scale your web applications in a secure and cloud-native environment. This guide walks you through deploying Laravel on an &lt;strong&gt;Ubuntu-based EC2 instance&lt;/strong&gt;, connecting it to an &lt;strong&gt;Amazon RDS MySQL database&lt;/strong&gt;, and using &lt;strong&gt;NGINX&lt;/strong&gt; as the web server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Make sure you have the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ AWS EC2 instance (Ubuntu 22.04+ recommended)&lt;/li&gt;
&lt;li&gt;✅ Amazon RDS MySQL database (accessible to EC2)&lt;/li&gt;
&lt;li&gt;✅ Security Groups properly configured (EC2 &amp;lt;-&amp;gt; RDS: port 3306)&lt;/li&gt;
&lt;li&gt;✅ NGINX installed on EC2&lt;/li&gt;
&lt;li&gt;✅ SSH terminal access to EC2 (e.g., Termius)&lt;/li&gt;
&lt;li&gt;✅ Laravel knowledge (Composer installed)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Update Your Server &amp;amp; Install PHP and Required Extensions
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;php php-fpm php-mysql php-xml php-mbstring php-curl php-zip unzip curl git &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Install Composer (PHP Dependency Manager)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~
curl &lt;span class="nt"&gt;-sS&lt;/span&gt; https://getcomposer.org/installer | php
&lt;span class="nb"&gt;sudo mv &lt;/span&gt;composer.phar /usr/local/bin/composer
composer &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Create Laravel Project
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /var/www/
&lt;span class="nb"&gt;sudo &lt;/span&gt;composer create-project laravel/laravel myapp
&lt;span class="nb"&gt;sudo chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; ubuntu:ubuntu myapp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Tip: Replace &lt;code&gt;myapp&lt;/code&gt; with your desired app folder name.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 4: Configure Laravel to Use Amazon RDS
&lt;/h2&gt;

&lt;p&gt;Edit the &lt;code&gt;.env&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano /var/www/myapp/.env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update the DB connection settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DB_CONNECTION=mysql
DB_HOST=your-rds-endpoint.amazonaws.com
DB_PORT=3306
DB_DATABASE=yourdbname
DB_USERNAME=yourdbuser
DB_PASSWORD=yourdbpassword
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Generate Laravel App Key &amp;amp; Run Migration
&lt;/h2&gt;

&lt;p&gt;Ensure the Laravel CLI (&lt;code&gt;artisan&lt;/code&gt;) has permission to write logs:&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 chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; ubuntu:ubuntu /var/www/myapp
&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;cd&lt;/span&gt; /var/www/myapp
php artisan key:generate
php artisan migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ You should see success messages for both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Stop Apache (If Installed) &amp;amp; Configure NGINX
&lt;/h2&gt;

&lt;p&gt;Apache often comes pre-installed — stop and disable 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;sudo &lt;/span&gt;systemctl stop apache2
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl disable apache2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a new NGINX 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;nano /etc/nginx/sites-available/laravel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste the following (replace &lt;code&gt;&amp;lt;your-ip&amp;gt;&lt;/code&gt; and &lt;code&gt;php8.3&lt;/code&gt; if needed):&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;&amp;lt;your-ec2-public-ip&amp;gt;&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/myapp/public&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.php&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="n"&gt;/index.php?&lt;/span&gt;&lt;span class="nv"&gt;$query_string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt; &lt;span class="sr"&gt;\.php$&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;include&lt;/span&gt; &lt;span class="nc"&gt;snippets/fastcgi-php&lt;/span&gt;&lt;span class="s"&gt;.conf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;fastcgi_pass&lt;/span&gt; &lt;span class="s"&gt;unix:/run/php/php8.3-fpm.sock&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;fastcgi_param&lt;/span&gt; &lt;span class="s"&gt;SCRIPT_FILENAME&lt;/span&gt; &lt;span class="nv"&gt;$document_root$fastcgi_script_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;include&lt;/span&gt; &lt;span class="s"&gt;fastcgi_params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt; &lt;span class="sr"&gt;/\.ht&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;deny&lt;/span&gt; &lt;span class="s"&gt;all&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;Enable the Laravel 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/laravel /etc/nginx/sites-enabled/
&lt;span class="nb"&gt;sudo rm&lt;/span&gt; /etc/nginx/sites-enabled/default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test and restart 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;nginx &lt;span class="nt"&gt;-t&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 7: Set Folder Permissions for Runtime
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; www-data:www-data /var/www/myapp
&lt;span class="nb"&gt;sudo chmod&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; 775 /var/www/myapp/storage
&lt;span class="nb"&gt;sudo chmod&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; 775 /var/www/myapp/bootstrap/cache
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 8: Visit Your Application
&lt;/h2&gt;

&lt;p&gt;Go to your EC2 public IP in a 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://&amp;lt;your-ec2-public-ip&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see the &lt;strong&gt;Laravel welcome page&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>ec2</category>
      <category>rds</category>
      <category>nginx</category>
    </item>
  </channel>
</rss>
