<?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: Shahid</title>
    <description>The latest articles on DEV Community by Shahid (@shahidkhans).</description>
    <link>https://dev.to/shahidkhans</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%2F390826%2Fc318a4d2-fa44-4e3e-8712-91e92d3dd84c.png</url>
      <title>DEV Community: Shahid</title>
      <link>https://dev.to/shahidkhans</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shahidkhans"/>
    <language>en</language>
    <item>
      <title>The Most Overlooked Part in Docker Compose</title>
      <dc:creator>Shahid</dc:creator>
      <pubDate>Tue, 11 Aug 2026 07:35:52 +0000</pubDate>
      <link>https://dev.to/shahidkhans/the-most-overlooked-part-in-docker-compose-39li</link>
      <guid>https://dev.to/shahidkhans/the-most-overlooked-part-in-docker-compose-39li</guid>
      <description>&lt;p&gt;A Docker container can be &lt;strong&gt;running&lt;/strong&gt; while the application inside it is completely unavailable. This is one of the most common misunderstandings in Docker Compose.&lt;/p&gt;

&lt;p&gt;The container process may still exist, but the web server may not have started, the database may still be initializing, or the application may be unable to respond to requests. That is why a Compose file should define a meaningful &lt;code&gt;healthcheck&lt;/code&gt;, not just a &lt;code&gt;restart&lt;/code&gt; policy.&lt;/p&gt;

&lt;p&gt;A health check executes a command inside the container. If that command returns exit code &lt;code&gt;0&lt;/code&gt;, Docker marks the container as healthy; any non-zero exit code indicates failure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running Is Not Ready
&lt;/h2&gt;

&lt;p&gt;Consider this simple Compose file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-app:latest&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000:3000"&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Docker may report the container as running immediately after the process starts. That does not necessarily mean the application is ready to receive traffic.&lt;/p&gt;

&lt;p&gt;The application might still be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Loading configuration.&lt;/li&gt;
&lt;li&gt;Running database migrations.&lt;/li&gt;
&lt;li&gt;Compiling an extension.&lt;/li&gt;
&lt;li&gt;Waiting for PostgreSQL.&lt;/li&gt;
&lt;li&gt;Starting an HTTP server.&lt;/li&gt;
&lt;li&gt;Connecting to an external service.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without a health check, Docker has no reliable way to distinguish “the process exists” from “the application works.”&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic Health Check
&lt;/h2&gt;

&lt;p&gt;A health check can test the application’s HTTP endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-app:latest&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000:3000"&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;[&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;curl"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--fail"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--silent"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--show-error"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://127.0.0.1:3000/"&lt;/span&gt;
        &lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
      &lt;span class="na"&gt;start_period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;60s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command runs &lt;strong&gt;inside&lt;/strong&gt; the container. Therefore, the check must use the container port, &lt;code&gt;3000&lt;/code&gt;, rather than necessarily using the host port mapping.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;start_period&lt;/code&gt; gives the application time to start before failures count against it. The &lt;code&gt;interval&lt;/code&gt; controls how often Docker checks the service, &lt;code&gt;timeout&lt;/code&gt; limits how long an individual check may run, and &lt;code&gt;retries&lt;/code&gt; controls how many consecutive failures are allowed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choose the Right Option
&lt;/h2&gt;

&lt;p&gt;The most overlooked detail is that the health-check command must exist inside the image. Minimal images often do not contain &lt;code&gt;curl&lt;/code&gt;, &lt;code&gt;wget&lt;/code&gt;, Bash, or network tools. A health check can be perfectly written and still fail because its executable is missing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 1: curl
&lt;/h3&gt;

&lt;p&gt;If the image contains &lt;code&gt;curl&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;[&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;curl"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--fail"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--silent"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--show-error"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://127.0.0.1:3000/"&lt;/span&gt;
    &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;
  &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
  &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
  &lt;span class="na"&gt;start_period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;60s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a Debian-based image such as &lt;code&gt;node:20-slim&lt;/code&gt;, install it in the Dockerfile:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nt"&gt;--no-install-recommends&lt;/span&gt; curl &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Slim images intentionally contain fewer utilities, so installing &lt;code&gt;curl&lt;/code&gt; explicitly is expected. &lt;a href="https://github.com/nodejs/docker-node/issues/1185" rel="noopener noreferrer"&gt;github&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 2: Node.js
&lt;/h3&gt;

&lt;p&gt;For a Node application, Node itself can perform the check without installing another package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;[&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;node"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-e"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;require('http').get('http://127.0.0.1:3000/',r=&amp;gt;process.exit(r.statusCode&amp;gt;=200&amp;amp;&amp;amp;r.statusCode&amp;lt;400?0:1)).on('error',()=&amp;gt;process.exit(1))"&lt;/span&gt;
    &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;
  &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
  &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
  &lt;span class="na"&gt;start_period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;60s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a useful option for &lt;code&gt;node:20-slim&lt;/code&gt;, especially when the only purpose of &lt;code&gt;curl&lt;/code&gt; would be the health check.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 3: wget
&lt;/h3&gt;

&lt;p&gt;If the image already includes &lt;code&gt;wget&lt;/code&gt;, use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;[&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wget"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--quiet"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--tries=1"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--spider"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://127.0.0.1:3000/"&lt;/span&gt;
    &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;
  &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
  &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
  &lt;span class="na"&gt;start_period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;60s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Always test the command manually before relying on it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &amp;lt;container-name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  wget &lt;span class="nt"&gt;--quiet&lt;/span&gt; &lt;span class="nt"&gt;--tries&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nt"&gt;--spider&lt;/span&gt; http://127.0.0.1:3000/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Option 4: PostgreSQL
&lt;/h3&gt;

&lt;p&gt;A database should have its own health check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-app-db&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;change-this-password&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;[&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD-SHELL"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pg_isready&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-U&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;postgres&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-d&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;my-app-db"&lt;/span&gt;
        &lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
      &lt;span class="na"&gt;start_period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;20s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pg_isready&lt;/code&gt; is included in the PostgreSQL image, so no additional package is required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Startup Order Matters
&lt;/h2&gt;

&lt;p&gt;A health check becomes more useful when combined with a health-based dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_healthy&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;[&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;node"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-e"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;require('http').get('http://127.0.0.1:3000/',r=&amp;gt;process.exit(r.statusCode&amp;gt;=200&amp;amp;&amp;amp;r.statusCode&amp;lt;400?0:1)).on('error',()=&amp;gt;process.exit(1))"&lt;/span&gt;
        &lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
      &lt;span class="na"&gt;start_period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;60s&lt;/span&gt;

  &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;[&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD-SHELL"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pg_isready&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-U&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;postgres&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-d&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;my-app-db"&lt;/span&gt;
        &lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;condition: service_healthy&lt;/code&gt;, Compose waits for the database health check to pass before starting the application. &lt;a href="https://last9.io/blog/docker-compose-health-checks/" rel="noopener noreferrer"&gt;last9&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For an my-app-db deployment, the application health check can test port &lt;code&gt;3000&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;HOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0&lt;/span&gt;
  &lt;span class="na"&gt;PORT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The health check should use:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



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

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

&lt;/div&gt;



&lt;p&gt;unless the application actually listens on port &lt;code&gt;80&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test Before You Trust It
&lt;/h2&gt;

&lt;p&gt;A health check should be tested manually inside the container. For the Node-based check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &amp;lt;container-name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
node &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"require('http').get('http://127.0.0.1:3000/',r=&amp;gt;{console.log('HTTP',r.statusCode);process.exit(r.statusCode&amp;gt;=200&amp;amp;&amp;amp;r.statusCode&amp;lt;400?0:1)}).on('error',e=&amp;gt;{console.error(e.message);process.exit(1)})"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A successful result might be:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Then inspect the health status:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;For detailed results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker inspect &amp;lt;container-name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | jq &lt;span class="s1"&gt;'.[0].State.Health'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The health state normally moves through:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;If checks continue to fail, Docker eventually reports:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;The inspection output includes the failing command and its output, which often reveals simple problems such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl: executable file not found
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Health Checks Do Not Restart Containers
&lt;/h2&gt;

&lt;p&gt;A health check reports the state of a container. It does not automatically restart a container merely because it becomes unhealthy. &lt;a href="https://forums.docker.com/t/docker-compose-container-doesnt-stop-when-healthcheck-is-supposed-to-fail/141352" rel="noopener noreferrer"&gt;forums.docker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use a restart policy for processes that exit:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;But treat health status and restart behavior as separate concerns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;healthcheck&lt;/code&gt; answers: “Is the application responding correctly?”&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;restart&lt;/code&gt; answers: “What should Docker do if the container process exits?”&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;depends_on&lt;/code&gt; answers: “Should another service wait for this dependency?”&lt;/li&gt;
&lt;li&gt;Monitoring answers: “Who should be alerted when the service is unhealthy?”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This distinction is why health checks are easy to overlook but important to design properly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Compose Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-app&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000:3000"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;HOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0&lt;/span&gt;
      &lt;span class="na"&gt;PORT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;
      &lt;span class="na"&gt;DB_HOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;database&lt;/span&gt;
      &lt;span class="na"&gt;DB_PORT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5432&lt;/span&gt;
      &lt;span class="na"&gt;DB_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myapp&lt;/span&gt;
      &lt;span class="na"&gt;DB_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="na"&gt;DB_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;change-this-password&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_healthy&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;[&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;node"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-e"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;require('http').get('http://127.0.0.1:3000/',r=&amp;gt;process.exit(r.statusCode&amp;gt;=200&amp;amp;&amp;amp;r.statusCode&amp;lt;400?0:1)).on('error',()=&amp;gt;process.exit(1))"&lt;/span&gt;
        &lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
      &lt;span class="na"&gt;start_period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;60s&lt;/span&gt;

  &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myapp&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;change-this-password&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;[&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD-SHELL"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pg_isready&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-U&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;postgres&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-d&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;myapp"&lt;/span&gt;
        &lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
      &lt;span class="na"&gt;start_period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;20s&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;postgres-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The best health check is not the most complicated one. It is the smallest command that verifies the condition users actually need: that the service is ready to do its job.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>containers</category>
    </item>
    <item>
      <title>PostgreSQL psql Backslash Commands: A Practical Guide</title>
      <dc:creator>Shahid</dc:creator>
      <pubDate>Sun, 09 Aug 2026 05:41:11 +0000</pubDate>
      <link>https://dev.to/shahidkhans/postgresql-psql-backslash-commands-a-practical-guide-59dg</link>
      <guid>https://dev.to/shahidkhans/postgresql-psql-backslash-commands-a-practical-guide-59dg</guid>
      <description>&lt;p&gt;When working with PostgreSQL from the terminal, &lt;code&gt;psql&lt;/code&gt; provides special commands that begin with a backslash, such as &lt;code&gt;\l&lt;/code&gt;, &lt;code&gt;\dt&lt;/code&gt;, and &lt;code&gt;\d&lt;/code&gt;. These are called &lt;strong&gt;meta-commands&lt;/strong&gt; or &lt;strong&gt;backslash commands&lt;/strong&gt;; they are processed by the &lt;code&gt;psql&lt;/code&gt; client rather than sent to the PostgreSQL server as SQL. &lt;a href="https://www.postgresql.org/docs/current/app-psql.html" rel="noopener noreferrer"&gt;postgresql&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This guide explains the most useful commands for viewing databases, tables, schemas, users, permissions, query results, and configuration.&lt;/p&gt;

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

&lt;p&gt;Connect to PostgreSQL from your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-h&lt;/span&gt; localhost &lt;span class="nt"&gt;-p&lt;/span&gt; 5432
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-U postgres&lt;/code&gt; specifies the PostgreSQL user.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-d postgres&lt;/code&gt; specifies the database.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-h localhost&lt;/code&gt; specifies the server host.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-p 5432&lt;/code&gt; specifies the port.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On Linux, you may also connect as the operating-system &lt;code&gt;postgres&lt;/code&gt; user:&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; &lt;span class="nt"&gt;-u&lt;/span&gt; postgres psql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A successful connection displays a prompt similar to:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;The prompt changes when you connect to another database:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Help and exiting
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Show all &lt;code&gt;psql&lt;/code&gt; commands
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;This displays the complete list of available &lt;code&gt;psql&lt;/code&gt; meta-commands.&lt;/p&gt;

&lt;p&gt;You can also display help for a category:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\? commands
\? options
\? variables
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Get help for SQL commands
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;Show the syntax for a specific SQL command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\h CREATE TABLE
\h ALTER USER
\h GRANT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Exit &lt;code&gt;psql&lt;/code&gt;
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;You can also press &lt;code&gt;Ctrl+D&lt;/code&gt; on Linux and macOS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Databases and connections
&lt;/h2&gt;

&lt;h3&gt;
  
  
  List all databases
&lt;/h3&gt;



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

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Name    |  Owner   | Encoding | Collate |  Ctype  | Access privileges
-----------+----------+----------+---------+---------+-------------------
 myapp_db  | postgres | UTF8     | C.UTF-8 | C.UTF-8 |
 postgres  | postgres | UTF8     | C.UTF-8 | C.UTF-8 |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Show additional information such as database size:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Connect to another database
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;You can specify both a database and a user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\c myapp_db app_user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a remote database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\c myapp_db app_user db.example.com 5432
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Show the current connection
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\conninfo
&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 plaintext"&gt;&lt;code&gt;You are connected to database "myapp_db" as user "app_user" on host "localhost" at port "5432".
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Show or change client encoding
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;Set UTF-8 encoding:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Schemas and tables
&lt;/h2&gt;

&lt;h3&gt;
  
  
  List schemas
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;Show schemas with descriptions and access privileges:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  List tables
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;This lists tables visible through the current &lt;code&gt;search_path&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;List tables in all schemas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\dt *.*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;List tables in a particular schema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\dt myapp.*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Show extra information, such as table size:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Describe a table
&lt;/h3&gt;



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

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;Column names.&lt;/li&gt;
&lt;li&gt;Data types.&lt;/li&gt;
&lt;li&gt;Nullable status.&lt;/li&gt;
&lt;li&gt;Default values.&lt;/li&gt;
&lt;li&gt;Indexes.&lt;/li&gt;
&lt;li&gt;Primary keys.&lt;/li&gt;
&lt;li&gt;Foreign keys.&lt;/li&gt;
&lt;li&gt;Constraints.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a table in a specific schema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\d myapp.users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Show more detailed information:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\d+ myapp.users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                                      Table "myapp.users"
 Column |           Type           | Collation | Nullable |              Default
--------+--------------------------+-----------+----------+-----------------------------------
 id     | bigint                   |           | not null | generated by default as identity
 email  | text                     |           | not null |
 name   | text                     |           |          |
Indexes:
    "users_pkey" PRIMARY KEY, btree (id)
    "users_email_key" UNIQUE CONSTRAINT, btree (email)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  List all relations
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;This can show tables, views, sequences, and other relation-like objects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Views, indexes, sequences, and functions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  List views
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;Describe a view:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\d myapp.active_users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Show the SQL definition of a view:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\sv myapp.active_users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  List materialized views
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;h3&gt;
  
  
  List indexes
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;Describe indexes for a table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\d myapp.users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  List sequences
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;h3&gt;
  
  
  List functions
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;List functions matching a pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\df *email*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Describe a particular function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\df myapp.calculate_total
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Users, roles, and permissions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  List users and roles
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;Show additional role information:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; Role name  | Attributes | Member of
------------+------------+-----------
 app_user   |            | {}
 postgres   | Superuser  | {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Show table privileges
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;You can also use:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Show privileges for a specific table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\dp myapp.users
&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 plaintext"&gt;&lt;code&gt;                              Access privileges
 Schema | Name  | Type  | Access privileges
--------+-------+-------+-------------------
 myapp  | users | table | app_user=arwdDxt/app_owner
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The privilege letters generally represent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;r&lt;/code&gt;: &lt;code&gt;SELECT&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;a&lt;/code&gt;: &lt;code&gt;INSERT&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;w&lt;/code&gt;: &lt;code&gt;UPDATE&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;d&lt;/code&gt;: &lt;code&gt;DELETE&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;D&lt;/code&gt;: &lt;code&gt;TRUNCATE&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;x&lt;/code&gt;: &lt;code&gt;REFERENCES&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;t&lt;/code&gt;: &lt;code&gt;TRIGGER&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Show object descriptions
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;Show the description of a specific object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\dd myapp.users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Viewing table data
&lt;/h2&gt;

&lt;p&gt;Backslash commands show metadata. To view actual rows, use SQL.&lt;/p&gt;

&lt;p&gt;Display all rows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;myapp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Display selected columns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;myapp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Limit the result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;myapp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&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;Sort the result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;myapp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;created_at&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;Count rows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;myapp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The SQL statement must end with a semicolon:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;myapp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;psql&lt;/code&gt; meta-command such as &lt;code&gt;\dt&lt;/code&gt; normally does not require a semicolon:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Improving query output
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Toggle expanded output
&lt;/h3&gt;

&lt;p&gt;Normal output is displayed horizontally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * FROM myapp.users LIMIT 1;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For wide rows, use expanded output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\x
SELECT * FROM myapp.users LIMIT 1;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Toggle it back:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;You can let &lt;code&gt;psql&lt;/code&gt; decide automatically:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Show query execution time
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;Now each query displays its execution time.&lt;/p&gt;

&lt;p&gt;Disable it with:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Show only rows without headers
&lt;/h3&gt;



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

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;myapp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Toggle tuple-only output off:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Change the output format
&lt;/h3&gt;

&lt;p&gt;Use expanded output:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Use unaligned output, which is useful for scripts:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Set a particular output format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\pset format aligned
\pset format unaligned
\pset format csv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set a display value for &lt;code&gt;NULL&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;\pset null '(none)'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running SQL files
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Execute a SQL file
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\i /path/to/schema.sql
&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 plaintext"&gt;&lt;code&gt;\i /home/admin/migrations/001_create_users.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a file relative to the current script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\ir migrations/001_create_users.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is useful for running database setup scripts and migrations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Redirect output to a file
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\o query_output.txt
SELECT * FROM myapp.users;
\o
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first &lt;code&gt;\o&lt;/code&gt; starts writing output to the file. The second &lt;code&gt;\o&lt;/code&gt; returns output to the terminal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Export data with &lt;code&gt;\copy&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Export a query result to CSV:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\copy (
  SELECT id, email, name
  FROM myapp.users
) TO '/tmp/users.csv' WITH CSV HEADER
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Import CSV data into a table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\copy myapp.users(email, name)
FROM '/tmp/users.csv'
WITH CSV HEADER
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;\copy&lt;/code&gt; reads and writes files on the machine running the &lt;code&gt;psql&lt;/code&gt; client, which is different from server-side SQL &lt;code&gt;COPY&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Query history and editing
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Show command history
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;You can also use:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Save history to a file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\s /tmp/psql-history.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Clear the current query buffer
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;This is useful if you started writing a SQL command but no longer want to execute it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Edit the current query
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;This opens the current query buffer in your configured text editor.&lt;/p&gt;

&lt;p&gt;You can set an editor before launching &lt;code&gt;psql&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;EDITOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nano
psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; myapp_db
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Execute the query buffer
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;This runs the SQL currently stored in the query buffer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shell and file-system commands
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Run an operating-system command
&lt;/h3&gt;

&lt;p&gt;On Linux or macOS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\! pwd
\! ls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Windows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\! cd
\! dir
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Change the client working directory
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;Check the current client working directory:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This affects local file commands such as &lt;code&gt;\i&lt;/code&gt; and &lt;code&gt;\copy&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Variables and prompts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  List &lt;code&gt;psql&lt;/code&gt; variables
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;Set a variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\set environment 'development'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\echo :environment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

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

&lt;/div&gt;



&lt;p&gt;Variables can be used in SQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\set user_id 10

SELECT *
FROM myapp.users
WHERE id = :user_id;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For string values, quote the value appropriately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\set email '''alice@example.com'''

SELECT *
FROM myapp.users
WHERE email = :email;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For application scripts, use parameterized queries rather than manually constructing SQL strings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automatic query execution
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Repeat a query
&lt;/h3&gt;

&lt;p&gt;Run a query every five seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT COUNT(*) FROM myapp.users
\watch 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stop the repeating query with:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Execute query output as SQL
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT 'CREATE TABLE test(id integer);'
\gexec
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;\gexec&lt;/code&gt; executes each value returned by the query as SQL. Use it carefully, especially in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  A complete inspection workflow
&lt;/h2&gt;

&lt;p&gt;The following sequence is useful when investigating a database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Show the current connection
\conninfo

-- List all databases
\l

-- Connect to the application database
\c myapp_db

-- List schemas
\dn+

-- List tables in the application schema
\dt myapp.*

-- Describe a table
\d+ myapp.users

-- List views
\dv myapp.*

-- List indexes
\di myapp.*

-- List sequences
\ds myapp.*

-- List users and roles
\du+

-- Show table privileges
\dp myapp.users

-- Show query execution time
\timing on

-- Inspect some rows
SELECT *
FROM myapp.users
LIMIT 10;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h3&gt;
  
  
  Using a backslash command outside &lt;code&gt;psql&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This will not work directly in a normal shell:&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="se"&gt;\d&lt;/span&gt;t
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start &lt;code&gt;psql&lt;/code&gt; first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;psql &lt;span class="nt"&gt;-U&lt;/span&gt; app_user &lt;span class="nt"&gt;-d&lt;/span&gt; myapp_db
&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 plaintext"&gt;&lt;code&gt;\dt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding a semicolon incorrectly
&lt;/h3&gt;

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

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

&lt;/div&gt;



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

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

&lt;/div&gt;



&lt;p&gt;SQL commands, however, require a semicolon:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;myapp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Expecting tables from another database
&lt;/h3&gt;

&lt;p&gt;Tables belong to a specific database. First connect to the correct database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\c myapp_db
\dt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Not seeing a table
&lt;/h3&gt;

&lt;p&gt;The table may be in another schema. Try:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\dt *.*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or describe it with its full name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\d myapp.users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may also lack the privileges required to see or access it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick reference
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\l&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List databases&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\l&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\c&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Connect to a database&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\c myapp_db&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\conninfo&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show connection details&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\conninfo&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\dn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List schemas&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\dn&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\dt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List tables&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\dt myapp.*&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\d&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Describe an object&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\d myapp.users&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\dv&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List views&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\dv&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\di&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List indexes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\di&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\ds&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List sequences&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\ds&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\df&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List functions&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\df&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\du&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List users and roles&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\du&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;\dp&lt;/code&gt; or &lt;code&gt;\z&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Show privileges&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\dp myapp.users&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\x&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Toggle expanded output&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\x auto&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\timing&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Toggle query timing&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\timing on&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\i&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Execute a SQL file&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\i setup.sql&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\copy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Import or export CSV&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\copy users TO 'users.csv' CSV&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\e&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Edit the query buffer&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\e&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\r&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Clear the query buffer&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\r&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\?&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show &lt;code&gt;psql&lt;/code&gt; help&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\?&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\h&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show SQL help&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\h CREATE TABLE&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\q&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Exit &lt;code&gt;psql&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\q&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The most important commands to remember are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\l
\c database_name
\dn
\dt
\d table_name
\du
\dp
\conninfo
\?
\q
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the authoritative and version-specific list, run &lt;code&gt;\?&lt;/code&gt; inside &lt;code&gt;psql&lt;/code&gt;; available commands can vary slightly between PostgreSQL client versions. &lt;a href="https://www.postgresql.org/docs/current/app-psql.html" rel="noopener noreferrer"&gt;postgresql&lt;/a&gt;&lt;/p&gt;

</description>
      <category>postgres</category>
    </item>
    <item>
      <title>Transfer files between devices with light — zero network, zero pairing, 100% offline.</title>
      <dc:creator>Shahid</dc:creator>
      <pubDate>Sun, 02 Aug 2026 11:04:38 +0000</pubDate>
      <link>https://dev.to/shahidkhans/transfer-files-between-devices-with-light-zero-network-zero-pairing-100-offline-kij</link>
      <guid>https://dev.to/shahidkhans/transfer-files-between-devices-with-light-zero-network-zero-pairing-100-offline-kij</guid>
      <description>&lt;p&gt;Transfer files between devices with light — zero network, zero pairing, 100% offline.&lt;/p&gt;

&lt;p&gt;a Progressive Web App that moves files and text snippets from one screen to another device's camera using fountain-coded animated QR codes.&lt;br&gt;
&lt;strong&gt;Live at &lt;a href="https://decimen-opt.pages.dev/" rel="noopener noreferrer"&gt;App&lt;/a&gt;&lt;/strong&gt; — open it on both devices and&lt;br&gt;
go. Works offline after the first visit.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F24bbdcyikrqco1g42lk9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F24bbdcyikrqco1g42lk9.png" alt="Progressive Web App that moves files and text snippets" width="800" height="683"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Why it's useful:&lt;/p&gt;

&lt;p&gt;Air-gapped &amp;amp; offline: No Wi-Fi, Bluetooth, local LAN path, cloud storage, or account required.&lt;br&gt;
Fountain-coded transmission: Uses Luby transform (soliton) fountain codes so the receiver can scan frames in any order. Dropping a frame never corrupts the transfer.&lt;br&gt;
Any file or text: Automatically compresses compressible data with gzip and restores original filenames and bytes bit-exact (verified via SHA-256).&lt;br&gt;
Zero-install PWA: Runs entirely in the browser. You can install it once and use it offline forever.&lt;br&gt;
Open it on your laptop, point your phone camera at the screen, and transfer files with light. Send a file between two devices using nothing but a screen and a camera. One page displays the file as an endless stream of animated QR codes; another device points its camera at it and reconstructs the file. No network path between the devices, no app, no pairing, no permissions beyond the camera. The payload travels as light.&lt;/p&gt;

&lt;p&gt;Live at App — open it on both devices and go. Works offline after the first visit.&lt;/p&gt;

&lt;p&gt;This is a minimal proof of concept extracted from a larger experiment that reached 128 KB/s phone-to-phone with denser frames, multi-code grids, and an error-corrected color channel. This version accepts arbitrary files up to 64 MB, preserves their filename and media type inside the fountain stream, adaptively uses gzip only when it shrinks the optical payload, and verifies SHA-256 before offering the received file for download. The sender can also stream a pasted text snippet instead of a file; the receiver works out which one is arriving from the container's media type.&lt;/p&gt;

&lt;p&gt;Phone receiving a 2 MB image over light: 129.2 KB/s goodput, decoding the sender's animated QR code&lt;/p&gt;

&lt;p&gt;Mid-transfer: a phone pulling a 2 MB image out of the air at 129 KB/s.&lt;/p&gt;

&lt;p&gt;Try it&lt;br&gt;
&lt;strong&gt;&lt;a href="https://decimen-opt.pages.dev/" rel="noopener noreferrer"&gt;App&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;
The hosted site is live at App; everything below is for running it yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Similar projects
&lt;/h2&gt;

&lt;p&gt;I didn't come up with this on my own. It turns out a few different people have tackled this idea, and their perspectives are worth a look:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/bashalarmistalt/decimen-optical-transfer/" rel="noopener noreferrer"&gt;bashalarmistalt/decimen-optical-transfer&lt;/a&gt;: initial app and idea.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/mohankumarelec/airgapped-qr-code-transfer" rel="noopener noreferrer"&gt;mohankumarelec/airgapped-qr-code-transfer&lt;/a&gt;:
browser-based QR file transfer with compression and sequential chunking.
Discovered after publicly demoing this project; convergent evolution in
action.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/divan/txqr" rel="noopener noreferrer"&gt;divan/txqr&lt;/a&gt; (2018): animated QR plus
fountain codes in Go, with two excellent write-ups on why fountain coding
beats sequential looping.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/sz3/libcimbar" rel="noopener noreferrer"&gt;sz3/libcimbar&lt;/a&gt;: goes past QR entirely
with a custom high-density color code purpose-built for this channel.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Built with &lt;a href="https://github.com/soldair/node-qrcode" rel="noopener noreferrer"&gt;node-qrcode&lt;/a&gt; and&lt;br&gt;
&lt;a href="https://github.com/Sec-ant/zxing-wasm" rel="noopener noreferrer"&gt;zxing-wasm&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>software</category>
      <category>tools</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Managing Git Remotes: Deleting, Updating, and Switching Origins</title>
      <dc:creator>Shahid</dc:creator>
      <pubDate>Sun, 26 Jul 2026 09:04:28 +0000</pubDate>
      <link>https://dev.to/shahidkhans/managing-git-remotes-deleting-updating-and-switching-origins-4d2o</link>
      <guid>https://dev.to/shahidkhans/managing-git-remotes-deleting-updating-and-switching-origins-4d2o</guid>
      <description>&lt;p&gt;Whether you've cloned a repo and need to point it at a different GitHub project, or you just want to clean up stray remote branches, Git gives you a few reliable commands to handle it. This post walks through the concepts and ends with a quick-reference cheat sheet you can bookmark.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why You'd Change a Remote
&lt;/h2&gt;

&lt;p&gt;The most common scenario is forking or migrating: you clone an existing repository, but your actual destination is a different GitHub repo—maybe your own fork, a renamed project, or a new organization. Rather than re-cloning from scratch, Git lets you simply repoint your local copy's &lt;code&gt;origin&lt;/code&gt; remote, preserving all your commit history and local branches. &lt;a href="https://stackoverflow.com/questions/2432764/how-do-i-change-the-uri-url-for-a-remote-git-repository" rel="noopener noreferrer"&gt;stackoverflow&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Checking Your Current Remote
&lt;/h2&gt;

&lt;p&gt;Before changing anything, confirm what's currently set up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This lists the remote name (usually &lt;code&gt;origin&lt;/code&gt;) alongside its fetch and push URLs. It's good practice to run this both before and after any change to confirm the update took effect. &lt;a href="https://docs.gitlab.com/tutorials/update_git_remote_url/" rel="noopener noreferrer"&gt;docs.gitlab&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Updating the Remote URL (Recommended Method)
&lt;/h2&gt;

&lt;p&gt;The cleanest way to switch to a new GitHub repo is &lt;code&gt;git remote set-url&lt;/code&gt;, which updates the existing &lt;code&gt;origin&lt;/code&gt; in place without disturbing branch tracking or history: &lt;a href="https://gist.github.com/spences10/5c492e197e95158809a83650ff97fc3a" rel="noopener noreferrer"&gt;gist.github&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote set-url origin &amp;lt;new-repo-url&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, switching to an HTTPS-based GitHub URL looks like &lt;code&gt;git remote set-url origin https://github.com/OWNER/REPOSITORY.git&lt;/code&gt;, or for SSH, &lt;code&gt;git@github.com:OWNER/REPOSITORY.git&lt;/code&gt;. Afterward, run &lt;code&gt;git remote show origin&lt;/code&gt; to confirm the update and verify your local branches are correctly tracked to the new remote. &lt;a href="https://docs.github.com/ja/get-started/git-basics/managing-remote-repositories?changing-a-remote-repositorys-url=" rel="noopener noreferrer"&gt;docs.github&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Removing and Re-adding the Remote (Alternative Method)
&lt;/h2&gt;

&lt;p&gt;If you'd rather start clean, you can delete the remote entirely and add a new one under the same name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote remove origin
git remote add origin &amp;lt;new-repo-url&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This achieves functionally the same result as &lt;code&gt;set-url&lt;/code&gt;—it's mostly a matter of preference or troubleshooting stale configuration. Some teams prefer this approach when they want an explicit reset rather than an in-place edit. &lt;a href="https://graphite.com/guides/remove-remote-origin-git" rel="noopener noreferrer"&gt;graphite&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling Multiple Remotes
&lt;/h2&gt;

&lt;p&gt;If you're managing more than one remote (e.g., &lt;code&gt;origin&lt;/code&gt; and &lt;code&gt;upstream&lt;/code&gt; for a fork), the same &lt;code&gt;set-url&lt;/code&gt; pattern applies—just swap in the remote's name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote set-url &amp;lt;remote_name&amp;gt; &amp;lt;new_url&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is useful when you fork a repo, clone your fork, and also want an &lt;code&gt;upstream&lt;/code&gt; remote pointing back to the original project you forked from. &lt;a href="https://gitlab.cn/docs/jh/tutorials/update_git_remote_url/_index/" rel="noopener noreferrer"&gt;gitlab&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Pushing After the Switch
&lt;/h2&gt;

&lt;p&gt;Once your remote points to the new repo, push your code over:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the new repo is empty, this works immediately. If it already has unrelated commit history, you may need &lt;code&gt;git push origin --all&lt;/code&gt; or resolve merge conflicts with &lt;code&gt;--allow-unrelated-histories&lt;/code&gt; first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deleting a Remote Branch
&lt;/h2&gt;

&lt;p&gt;Separately, if you just want to remove a specific branch on the remote (not the whole remote itself), use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push origin &lt;span class="nt"&gt;--delete&lt;/span&gt; &amp;lt;branch-name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow up with &lt;code&gt;git fetch --prune&lt;/code&gt; to clean up any stale local references to the deleted branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Git Remote Cheatsheet
&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;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;View current remotes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git remote -v&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Update remote URL (in place)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git remote set-url origin &amp;lt;new-url&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remove a remote&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git remote remove origin&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add a new remote&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git remote add origin &amp;lt;new-url&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rename a remote&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git remote rename &amp;lt;old-name&amp;gt; &amp;lt;new-name&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verify remote + tracking&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git remote show origin&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Update URL for any named remote&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git remote set-url &amp;lt;remote_name&amp;gt; &amp;lt;new_url&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Push local branch to new remote&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git push -u origin main&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delete a remote branch&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git push origin --delete &amp;lt;branch-name&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prune stale remote-tracking refs&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git fetch --prune&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;List all remote branches&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git branch -r&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Keep this table handy—&lt;code&gt;git remote set-url&lt;/code&gt; covers 90% of "I need to point my repo somewhere else" situations, while &lt;code&gt;remove&lt;/code&gt; + &lt;code&gt;add&lt;/code&gt; is your fallback for a full reset.&lt;/p&gt;

</description>
      <category>git</category>
      <category>github</category>
    </item>
    <item>
      <title>PostgreSQL Extensions by Category: Real-World Use Cases for Modern Production Systems</title>
      <dc:creator>Shahid</dc:creator>
      <pubDate>Sun, 12 Jul 2026 06:16:31 +0000</pubDate>
      <link>https://dev.to/shahidkhans/postgresql-extensions-by-category-real-world-use-cases-for-modern-production-systems-4hap</link>
      <guid>https://dev.to/shahidkhans/postgresql-extensions-by-category-real-world-use-cases-for-modern-production-systems-4hap</guid>
      <description>&lt;p&gt;PostgreSQL is no longer just a relational database you spin up and forget. Its extension ecosystem lets teams turn one database into a search engine, geospatial engine, vector store, job scheduler, document database, and workflow runtime without introducing a separate platform too early. That flexibility is one of the main reasons PostgreSQL remains a default choice for modern SaaS, internal platforms, analytics systems, and AI-backed applications.&lt;/p&gt;

&lt;p&gt;For engineering teams, extensions matter because they reduce architectural sprawl. Instead of adding Redis, Elasticsearch, MongoDB, Airflow, or a separate geospatial engine on day one, teams can often cover the first serious version of those workloads inside PostgreSQL and split them out later only when scale or specialization demands it.&lt;/p&gt;

&lt;p&gt;This guide lists PostgreSQL extensions category-wise and pairs each one with a practical production use case. The goal is not just to name extensions, but to show where they fit in real systems and how they help solve actual application problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why extensions matter
&lt;/h2&gt;

&lt;p&gt;Extensions let PostgreSQL gain new data types, operators, functions, indexing methods, and runtime features without changing the core database engine. In practical terms, that means a team can keep transactional data, search features, background jobs, vectors, and even document-style data close together, which simplifies deployment, access control, backups, and operational debugging.&lt;/p&gt;

&lt;p&gt;That does not mean PostgreSQL should replace every specialized system forever. It means PostgreSQL extensions give teams a powerful middle path: start with fewer moving parts, validate the product, and then decide later whether a dedicated system is still necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to enable extensions
&lt;/h2&gt;

&lt;p&gt;Most PostgreSQL extensions are enabled with &lt;code&gt;CREATE EXTENSION&lt;/code&gt;, and administrators can inspect what is available using &lt;code&gt;pg_available_extensions&lt;/code&gt;. Managed platforms usually support only a subset, so the exact list depends on whether the database is self-hosted, running on a cloud-managed service, or offered through a platform with its own extension policy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_available_extensions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;EXTENSION&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;pg_stat_statements&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;EXTENSION&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;pg_trgm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;EXTENSION&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;pgcrypto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_extension&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A good rule is to enable only what the workload needs. Extensions add power, but they also become part of operational policy, version compatibility, backup planning, and schema management.&lt;/p&gt;

&lt;h2&gt;
  
  
  Observability and performance
&lt;/h2&gt;

&lt;h3&gt;
  
  
  pg_stat_statements
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pg_stat_statements&lt;/code&gt; is one of the most widely installed PostgreSQL extensions because it records execution statistics for SQL statements and helps teams identify where time is actually going inside the database. It is especially useful when an application looks slow at the API layer but the real issue is a small set of high-cost SQL queries.&lt;/p&gt;

&lt;p&gt;A real-world use case is an e-commerce checkout service where payment creation, cart refresh, coupon validation, and stock lookup all touch the database. With &lt;code&gt;pg_stat_statements&lt;/code&gt;, the team can rank queries by total time, call count, or average latency and quickly identify whether the problem is a missing index, N+1 query pattern, or poor join path.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;calls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mean_time&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_stat_statements&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;total_time&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  auto_explain
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;auto_explain&lt;/code&gt; is useful when slow queries appear only under real production traffic and are difficult to reproduce in development. It logs execution plans automatically, making it easier to understand why the planner chose a bad path for a query that only becomes problematic with production-sized data.&lt;/p&gt;

&lt;p&gt;A practical use case is a B2B admin dashboard that is fast in staging but slow in production after data volume grows. &lt;code&gt;auto_explain&lt;/code&gt; helps capture the exact execution plan at the moment the query becomes expensive, which is often more useful than manually running &lt;code&gt;EXPLAIN&lt;/code&gt; later on a changed dataset.&lt;/p&gt;

&lt;h3&gt;
  
  
  hypopg
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;hypopg&lt;/code&gt; lets teams create hypothetical indexes to test whether a proposed index would help before paying the cost of building it on a large table. This is valuable when a table is large enough that creating the wrong index wastes both time and storage.&lt;/p&gt;

&lt;p&gt;A good real-world example is an &lt;code&gt;orders&lt;/code&gt; table with hundreds of millions of rows in a marketplace system. Before adding a composite index for merchant, status, and created date, the database team can simulate the index and inspect whether the planner would actually use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Search and text processing
&lt;/h2&gt;

&lt;h3&gt;
  
  
  pg_trgm
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pg_trgm&lt;/code&gt; is one of the most practical extensions for application teams because it enables fuzzy string matching and typo-tolerant search by breaking text into trigrams. It is widely used for autocomplete, approximate matching, and user-facing search where exact text equality is too strict.&lt;/p&gt;

&lt;p&gt;A real-time use case is product search in an online storefront. A customer typing “iphon”, “samsng”, or a slightly misspelled brand name can still get useful results, which improves conversion and reduces search abandonment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="s1"&gt;'iphon'&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;similarity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'iphon'&lt;/span&gt;&lt;span class="p"&gt;)&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;h3&gt;
  
  
  unaccent
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;unaccent&lt;/code&gt; removes accents and diacritics, which makes search more forgiving for multilingual applications and international catalogs. This is a small extension, but it often solves a very visible customer-experience problem.&lt;/p&gt;

&lt;p&gt;A real-world example is a travel, education, or food platform where users search terms such as “Cafe”, “Creme Brulee”, or “Resume” even though the stored content contains accented forms. &lt;code&gt;unaccent&lt;/code&gt; helps normalize the comparison and makes search behavior feel more natural.&lt;/p&gt;

&lt;h3&gt;
  
  
  citext
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;citext&lt;/code&gt; provides case-insensitive text behavior without forcing developers to wrap every comparison in &lt;code&gt;LOWER(...)&lt;/code&gt;. It is particularly useful for fields where humans treat different letter casing as the same value.&lt;/p&gt;

&lt;p&gt;A practical production use case is user identity data. Email addresses, usernames, and tags often need case-insensitive uniqueness and lookups, and &lt;code&gt;citext&lt;/code&gt; avoids subtle bugs where &lt;code&gt;Alice@example.com&lt;/code&gt; and &lt;code&gt;alice@example.com&lt;/code&gt; are treated differently in parts of the application.&lt;/p&gt;

&lt;h3&gt;
  
  
  hstore
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;hstore&lt;/code&gt; stores key-value pairs inside a column and remains useful for lightweight semi-structured attributes. While &lt;code&gt;jsonb&lt;/code&gt; is more common today, &lt;code&gt;hstore&lt;/code&gt; is still attractive when the data is simple, flat, and frequently queried by key.&lt;/p&gt;

&lt;p&gt;A good use case is a product catalog with sparse attributes such as color, material, finish, or voltage that vary by SKU. Instead of creating dozens of mostly empty columns, a team can keep these attributes in &lt;code&gt;hstore&lt;/code&gt; and query them when needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Geospatial and location data
&lt;/h2&gt;

&lt;h3&gt;
  
  
  PostGIS
&lt;/h3&gt;

&lt;p&gt;PostGIS is the standard PostgreSQL extension for spatial data, spatial indexing, and location-aware queries. It adds types such as &lt;code&gt;geometry&lt;/code&gt; and &lt;code&gt;geography&lt;/code&gt; along with a large set of functions for distance, containment, area, routing support patterns, and shape operations.&lt;/p&gt;

&lt;p&gt;Its real-world use cases are broad: store locator apps, delivery radius calculations, route-aware logistics, ride-hailing pickup matching, real estate search by map area, and warehouse service coverage analysis. For example, a food delivery platform can use PostGIS to find all active stores within a delivery radius of the customer and then filter them further by service status and estimated delivery time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;locations&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;ST_DWithin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;geom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;ST_MakePoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;122&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;37&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="n"&gt;geography&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="mi"&gt;5000&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Security, identity, and cryptography
&lt;/h2&gt;

&lt;h3&gt;
  
  
  pgcrypto
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pgcrypto&lt;/code&gt; adds cryptographic functions directly inside PostgreSQL, including hashing, random value generation, and encryption-related helpers. It is commonly used in authentication systems, secure metadata handling, and cases where values must be generated or verified close to the data layer.&lt;/p&gt;

&lt;p&gt;A real-world example is a SaaS application that stores password hashes, API verification tokens, or signed one-time secrets. Instead of sending sensitive values out of the database for all cryptographic operations, a team can perform key operations directly in SQL and reduce unnecessary data movement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;crypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'my_password'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gen_salt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'bf'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  uuid-ossp
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;uuid-ossp&lt;/code&gt; is widely used to generate UUID values inside PostgreSQL, especially for primary keys or externally visible identifiers. UUID-based identifiers are useful when sequential IDs would leak business volume or allow enumeration attacks.&lt;/p&gt;

&lt;p&gt;A good use case is a marketplace API where order IDs, customer-facing shipment IDs, or public resource keys should not reveal insertion order. UUIDs make IDs harder to guess and easier to generate safely across distributed systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI and vector search
&lt;/h2&gt;

&lt;h3&gt;
  
  
  pgvector
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pgvector&lt;/code&gt; adds a vector data type and similarity search support, turning PostgreSQL into a practical vector store for many AI applications. It is commonly used for semantic search, retrieval-augmented generation, recommendation systems, duplicate detection, and embedding-based classification.&lt;/p&gt;

&lt;p&gt;A production use case is a support knowledge assistant that stores article embeddings next to the relational article metadata. When a user asks a question, the system can retrieve semantically similar content from PostgreSQL without maintaining a separate vector database in the first version of the product.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;embedding&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;#&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'[0.1, 0.2, 0.3]'&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;distance&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;items&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;distance&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another strong use case is product recommendation in commerce. Instead of relying only on category filters or co-purchase heuristics, embeddings can capture semantic similarity between products, user intent, and content descriptions, which improves discovery for long-tail inventory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scheduling and maintenance
&lt;/h2&gt;

&lt;h3&gt;
  
  
  pg_cron
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pg_cron&lt;/code&gt; gives PostgreSQL a built-in scheduling mechanism for recurring SQL jobs, which is useful for automation tasks that belong close to the data. It helps teams avoid building an external scheduler for simple but essential database operations.&lt;/p&gt;

&lt;p&gt;Real-world examples include deleting expired cache rows, refreshing materialized views, rotating partitions, generating nightly aggregates, and backfilling reporting tables after business hours. In many systems, &lt;code&gt;pg_cron&lt;/code&gt; is the simplest reliable way to keep regular database maintenance visible and version-controlled.&lt;/p&gt;

&lt;h3&gt;
  
  
  pg_partman
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pg_partman&lt;/code&gt; automates partition management for large time-based or serial-based tables. This becomes important when tables such as event logs, audit trails, financial transactions, or telemetry data grow fast enough that manual partition maintenance becomes error-prone.&lt;/p&gt;

&lt;p&gt;A practical example is an order-event stream or clickstream table that grows by millions of rows per day. &lt;code&gt;pg_partman&lt;/code&gt; can pre-create future partitions and help with retention workflows so that inserts stay predictable and cleanup stays manageable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Time-series and analytics
&lt;/h2&gt;

&lt;h3&gt;
  
  
  TimescaleDB
&lt;/h3&gt;

&lt;p&gt;TimescaleDB extends PostgreSQL for time-series workloads and is commonly used for metrics, telemetry, stock ticks, IoT streams, and event-heavy analytical pipelines. It is attractive because teams can keep SQL, relational joins, and operational familiarity while gaining features designed for time-based data growth.&lt;/p&gt;

&lt;p&gt;A real-world use case is infrastructure monitoring for a SaaS platform. Application latency, queue depth, API errors, and worker CPU usage can be stored as time-series data and queried for dashboards, rollups, and anomaly windows without moving immediately to a separate metrics engine.&lt;/p&gt;

&lt;h3&gt;
  
  
  hll
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;hll&lt;/code&gt; implements HyperLogLog for approximate distinct counts, which is extremely useful in analytics systems where exact uniqueness is expensive but approximate answers are acceptable. It helps reduce compute and storage pressure for cardinality-heavy metrics.&lt;/p&gt;

&lt;p&gt;A common production example is counting unique visitors, unique coupon users, unique sessions, or unique SKUs viewed during a time period. In growth analytics or retail traffic reporting, &lt;code&gt;hll&lt;/code&gt; makes these queries much more efficient at scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cross-database and scale-out access
&lt;/h2&gt;

&lt;h3&gt;
  
  
  postgres_fdw
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;postgres_fdw&lt;/code&gt; lets PostgreSQL query tables from another PostgreSQL database as if they were local, which is valuable for integration-heavy architectures. It offers a practical option when teams need shared access across services without immediately committing to a full ETL pipeline.&lt;/p&gt;

&lt;p&gt;A real-world use case is a commerce platform where operational order data lives in one PostgreSQL cluster and finance reconciliation data lives in another. &lt;code&gt;postgres_fdw&lt;/code&gt; can help build internal reporting or migration bridges while preserving separate ownership boundaries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Citus
&lt;/h3&gt;

&lt;p&gt;Citus extends PostgreSQL for distributed scale-out and is often used for multi-tenant SaaS, large analytical workloads, and systems that need sharding with PostgreSQL compatibility. It helps when a single node is no longer enough for storage, throughput, or parallel processing requirements.&lt;/p&gt;

&lt;p&gt;A practical use case is a SaaS platform serving many tenants with tenant-scoped data and predictable distribution keys. Citus can shard data across nodes while preserving a familiar PostgreSQL interface for most application code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Document database extensions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  pg_documentdb_core and pg_documentdb_api
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pg_documentdb_core&lt;/code&gt; adds BSON datatype support and native BSON operations to PostgreSQL, while &lt;code&gt;pg_documentdb_api&lt;/code&gt; provides CRUD and advanced document APIs on top of that foundation. Together, they allow PostgreSQL to act more like a MongoDB-compatible document database while still benefiting from the PostgreSQL ecosystem.&lt;/p&gt;

&lt;p&gt;The feature set goes beyond simple CRUD. The DocumentDB stack supports advanced queries such as full-text search, geospatial queries, vector search, aggregation pipelines, and multiple index types including TTL, text, geospatial, and vector indexes. That makes it relevant not only for document storage but also for hybrid operational workloads where JSON-like flexibility and rich querying are both necessary.&lt;/p&gt;

&lt;p&gt;A strong real-world example is a product catalog or merchant onboarding system with highly variable nested attributes across categories. Electronics, apparel, furniture, and automotive parts often do not share a stable schema, so a document model helps teams move fast while PostgreSQL still handles surrounding transactional data.&lt;/p&gt;

&lt;p&gt;Another practical use case is event payload storage for AI and fraud analysis. Since the extension stack supports full-text, vector, and geospatial capabilities, it can support workloads such as chatbot context documents, anomaly investigation payloads, and customer activity streams without splitting the data across multiple database engines too early.&lt;/p&gt;

&lt;h2&gt;
  
  
  Durable workflows and orchestration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  pg_durable
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pg_durable&lt;/code&gt; is an open-source PostgreSQL extension that brings durable execution directly into the database. It runs long-lived, fault-tolerant workflows with built-in retries, parallelism, scheduling, and recovery, and it does so using a background worker so the user session is not blocked for the duration of the workflow.&lt;/p&gt;

&lt;p&gt;This matters because many teams eventually need multi-step jobs that are tightly coupled to database state: transformations, aggregations, maintenance workflows, embedding pipelines, approvals, and queue-driven business processes. Without a durable execution model, those teams often end up choosing between one fragile long-running SQL function or a separate orchestration system with queue tables, workers, retry logic, and crash recovery code.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pg_durable&lt;/code&gt; is strongest when the workflow reads and writes rows that already live in PostgreSQL and should inherit PostgreSQL durability, backups, high availability, and recovery behavior. The extension breaks workflows into discrete steps, checkpoints state inside PostgreSQL, and retries failed steps individually instead of rerunning the entire process.&lt;/p&gt;

&lt;p&gt;A real-world e-commerce example is an order orchestration flow: validate order, reserve inventory, charge payment, create fulfillment request, notify the customer, and retry only the failed step if an external dependency times out. Another strong use case is an internal AI pipeline where chunking, embedding, indexing, and downstream refreshes should survive restarts without rebuilding completed 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="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;EXTENSION&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;pg_durable&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;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$$&lt;/span&gt;
  &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="s1"&gt;'Hello, durable world!'&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;
&lt;span class="err"&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 Microsoft example also shows &lt;code&gt;pg_durable&lt;/code&gt; handling ETL pipelines, scheduled sync jobs, and human-in-the-loop approvals, which makes it relevant well beyond simple background tasks. For teams that want orchestration close to the data instead of a separate workflow platform, this extension is one of the most interesting recent additions to the PostgreSQL ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  API and REST access
&lt;/h2&gt;

&lt;h3&gt;
  
  
  PostgREST / pgrest
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pgrest&lt;/code&gt; is best described in practice as the category of tools that expose PostgreSQL tables, views, and stored procedures as HTTP APIs. While the exact packaging depends on the implementation a team adopts, the architectural use case is consistent: turn database objects into REST endpoints quickly for internal tools, dashboards, admin apps, prototypes, and data-centric services.&lt;/p&gt;

&lt;p&gt;A real-world use case is a back-office operations app where catalog data, merchant records, settlements, or support queues need fast API exposure without building a large custom backend first. This approach is especially effective when access rules are already modeled in PostgreSQL and the API mostly reflects relational resources and stored procedures.&lt;/p&gt;

&lt;p&gt;Another good example is a BFF-style internal platform for dashboards. When product, finance, and operations teams need secure read APIs on curated views, a Postgres-to-REST layer can shorten delivery time significantly and keep the data contract close to the schema.&lt;/p&gt;

&lt;h2&gt;
  
  
  Procedural logic and database-native business rules
&lt;/h2&gt;

&lt;h3&gt;
  
  
  plpgsql
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;plpgsql&lt;/code&gt; powers stored procedures, triggers, and custom business logic inside PostgreSQL, and it is installed by default in a very large number of databases. It is essential when teams need transactional business rules to execute close to the data with predictable behavior.&lt;/p&gt;

&lt;p&gt;A practical use case is enforcing inventory consistency or audit logging through triggers. For example, when a stock row changes, a &lt;code&gt;plpgsql&lt;/code&gt; trigger can write an audit event, validate transitions, or derive dependent values before the transaction commits.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to choose the right extension
&lt;/h2&gt;

&lt;p&gt;The best extension depends on the workload, not on popularity alone. Search-heavy products usually benefit first from &lt;code&gt;pg_trgm&lt;/code&gt;, &lt;code&gt;unaccent&lt;/code&gt;, and &lt;code&gt;citext&lt;/code&gt;; operations-heavy systems benefit from &lt;code&gt;pg_stat_statements&lt;/code&gt;, &lt;code&gt;pg_cron&lt;/code&gt;, and &lt;code&gt;pg_partman&lt;/code&gt;; AI-backed products often reach for &lt;code&gt;pgvector&lt;/code&gt;; and location-aware platforms almost always need PostGIS.&lt;/p&gt;

&lt;p&gt;For systems with fast-changing schemas, &lt;code&gt;pg_documentdb_core&lt;/code&gt; and &lt;code&gt;pg_documentdb_api&lt;/code&gt; provide a document-oriented option on top of PostgreSQL. For systems with multi-step jobs tied to database state, &lt;code&gt;pg_durable&lt;/code&gt; can eliminate a surprising amount of application-side orchestration code.&lt;/p&gt;

&lt;p&gt;A practical selection framework looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choose &lt;strong&gt;observability extensions&lt;/strong&gt; when the main pain is slow queries and poor visibility.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;search extensions&lt;/strong&gt; when users search messy, multilingual, or typo-prone text.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;geospatial extensions&lt;/strong&gt; when distance, service areas, or coordinates are part of the business model.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;AI extensions&lt;/strong&gt; when semantic retrieval or recommendations matter.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;scheduling and orchestration extensions&lt;/strong&gt; when recurring jobs or multi-step workflows are becoming application infrastructure.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;document extensions&lt;/strong&gt; when schemas are highly variable and nested documents are central to the product.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;REST exposure tools&lt;/strong&gt; when the fastest path to value is to publish clean APIs directly from data models.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Extension shortlist by scenario
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Recommended extensions&lt;/th&gt;
&lt;th&gt;Why they fit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;E-commerce catalog search&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;pg_trgm&lt;/code&gt;, &lt;code&gt;unaccent&lt;/code&gt;, &lt;code&gt;citext&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Handles fuzzy, multilingual, and case-insensitive product and identity search.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Store locator or delivery zone&lt;/td&gt;
&lt;td&gt;&lt;code&gt;postgis&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Supports location indexing, radius search, and spatial filtering.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI knowledge base or RAG&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;pgvector&lt;/code&gt;, &lt;code&gt;pg_durable&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Stores embeddings and can orchestrate durable embedding pipelines.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operational database tuning&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;pg_stat_statements&lt;/code&gt;, &lt;code&gt;auto_explain&lt;/code&gt;, &lt;code&gt;hypopg&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Improves visibility into query cost and index decisions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High-volume event data&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;pg_partman&lt;/code&gt;, &lt;code&gt;TimescaleDB&lt;/code&gt;, &lt;code&gt;hll&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Helps with partitioning, time-series analysis, and approximate uniqueness metrics.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flexible document-style domain model&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;pg_documentdb_core&lt;/code&gt;, &lt;code&gt;pg_documentdb_api&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Supports BSON, CRUD APIs, advanced queries, and multiple index types.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quick internal API platform&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;pgrest&lt;/code&gt; / PostgREST-style layer&lt;/td&gt;
&lt;td&gt;Exposes tables, views, and functions rapidly as REST endpoints.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Closing perspective
&lt;/h2&gt;

&lt;p&gt;The strongest PostgreSQL architectures usually do not come from using the most extensions. They come from choosing a small, focused set of extensions that match real product needs and keep the system operationally simple for as long as possible.&lt;/p&gt;

&lt;p&gt;That is the real advantage of PostgreSQL’s extension ecosystem. It lets a single platform grow from a transactional database into a broader application data layer, and it gives engineering teams room to delay complexity until there is a proven reason to introduce more infrastructure.&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>postgressql</category>
    </item>
    <item>
      <title>Stop Running 5 Databases: PostgreSQL Does It All in 2026</title>
      <dc:creator>Shahid</dc:creator>
      <pubDate>Mon, 15 Jun 2026 10:37:20 +0000</pubDate>
      <link>https://dev.to/shahidkhans/stop-running-5-databases-postgresql-does-it-all-in-2026-1a2e</link>
      <guid>https://dev.to/shahidkhans/stop-running-5-databases-postgresql-does-it-all-in-2026-1a2e</guid>
      <description>&lt;p&gt;&lt;em&gt;How a 35-year-old open-source database became the default choice for relational storage, full-text search, vector AI workloads, geospatial queries, and event-driven architecture — in a single deployment.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Most production architectures look like a small city: a relational database for core data, a document store for flexible schemas, an Elasticsearch cluster for search, a vector database for AI-powered features, and a message broker stitching it all together. Five services. Five deployment pipelines. Five monitoring dashboards. Five points of failure — all to solve problems that, in most applications, &lt;strong&gt;one database already handles&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That database is PostgreSQL. It started as a research project at UC Berkeley in the 1980s and has quietly evolved into one of the most capable data platforms ever built. In 2026, as teams race to bolt AI onto their stacks without doubling infrastructure costs, Postgres has emerged as the default answer — not because it's new, but because it was built right.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Makes Postgres Different
&lt;/h2&gt;

&lt;p&gt;At its core, Postgres is a relational, ACID-compliant SQL database: tables, rows, foreign keys, joins, everything you'd expect. What separates it architecturally from MySQL or SQLite is that it was &lt;strong&gt;built for extensibility from day one&lt;/strong&gt;. There is a formalized plugin API that lets you add new data types, new index strategies, and entirely new capabilities via a single &lt;code&gt;CREATE EXTENSION&lt;/code&gt; command. This is not a bolt-on feature or a marketing checkbox — it is a deeply deliberate design choice baked into the query engine itself.&lt;/p&gt;

&lt;p&gt;The result: Postgres doesn't just store data. It becomes the entire data layer of your application, without stitching together a fleet of specialized services you need to deploy, monitor, and keep in sync.&lt;/p&gt;




&lt;h2&gt;
  
  
  Replacing the Document Store: JSONB
&lt;/h2&gt;

&lt;p&gt;The standard pitch for MongoDB has always been: &lt;em&gt;relational schemas are too rigid for modern applications.&lt;/em&gt; Postgres answers that directly with &lt;code&gt;JSONB&lt;/code&gt; — a binary-encoded JSON column type that lets you store fully schemaless documents right next to your strict relational tables, in the same database, under the same transaction.&lt;/p&gt;

&lt;p&gt;You can query deep into nested JSON using path expressions, check for key existence, test containment, and — critically — put a &lt;strong&gt;GIN index&lt;/strong&gt; on the entire document so those queries stay fast at scale:&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;TABLE&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt;     &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;email&lt;/span&gt;  &lt;span class="nb"&gt;TEXT&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;data&lt;/span&gt;   &lt;span class="n"&gt;JSONB&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;idx_users_data&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;USING&lt;/span&gt; &lt;span class="n"&gt;GIN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Find all users on the 'pro' plan&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="o"&gt;@&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'{"plan": "pro"}'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your schemaless layer and your relational layer live in the same table, under the same backup, in the same &lt;code&gt;SELECT&lt;/code&gt;. No data synchronization. No eventual consistency headaches. No second server.&lt;/p&gt;




&lt;h2&gt;
  
  
  Replacing Elasticsearch: Built-in Full-Text Search
&lt;/h2&gt;

&lt;p&gt;Elasticsearch is powerful — but it's also one of the heaviest pieces of infrastructure you can operate. It needs its own cluster, its own memory tuning, its own index lifecycle management, and it demands you keep two copies of your data in sync at all times.&lt;/p&gt;

&lt;p&gt;Postgres has a native full-text search engine that handles tokenization, stemming (so "running" matches "run" and "runs"), stop-word filtering, relevance ranking, and indexed retrieval. For the overwhelming majority of product search boxes and content discovery features, it is more than sufficient:&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;-- GIN-indexed full-text search&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;idx_articles_fts&lt;/span&gt;
&lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;articles&lt;/span&gt; &lt;span class="k"&gt;USING&lt;/span&gt; &lt;span class="n"&gt;GIN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to_tsvector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'english'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;-- Ranked search results&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;ts_rank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to_tsvector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'english'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;query&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;rank&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;articles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="n"&gt;to_tsquery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'english'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'distributed &amp;amp; systems'&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;query&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;to_tsvector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'english'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;@@&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only time Elasticsearch genuinely pulls ahead is at massive scale with advanced requirements — complex multi-language synonym pipelines, cross-cluster federation, or deep faceted navigation. For everything else, Postgres saves you an entire infrastructure tier.&lt;/p&gt;




&lt;h2&gt;
  
  
  Replacing Pinecone and Weaviate: AI-Native Vector Search
&lt;/h2&gt;

&lt;p&gt;This is the capability that has become non-negotiable in 2026. Every application now has an AI feature. Every AI feature needs semantic search. The &lt;code&gt;pgvector&lt;/code&gt; extension adds a native vector column type and approximate nearest-neighbor (ANN) search, making Postgres the backbone of &lt;strong&gt;Retrieval-Augmented Generation (RAG) pipelines&lt;/strong&gt; without standing up a dedicated vector database.&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="n"&gt;EXTENSION&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;vector&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;TABLE&lt;/span&gt; &lt;span class="n"&gt;documents&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt;        &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;content&lt;/span&gt;   &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;embedding&lt;/span&gt; &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1536&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- HNSW index for fast approximate nearest-neighbor search&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;documents&lt;/span&gt; &lt;span class="k"&gt;USING&lt;/span&gt; &lt;span class="n"&gt;hnsw&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;embedding&lt;/span&gt; &lt;span class="n"&gt;vector_cosine_ops&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Semantic similarity search&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;embedding&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'[0.12, 0.47, ...]'&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;similarity&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;documents&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;embedding&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'[0.12, 0.47, ...]'&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For workloads under roughly 100 million vectors, Postgres with pgvector eliminates dedicated vector database overhead with no measurable quality trade-off.  The real advantage over standalone vector databases isn't just eliminating a service — it's &lt;strong&gt;composability&lt;/strong&gt;: your vector search can be combined with &lt;code&gt;WHERE&lt;/code&gt; filters, &lt;code&gt;JOIN&lt;/code&gt;s across tables, and Row-Level Security in a single query. Pinecone cannot join against your application data. Postgres can.&lt;/p&gt;




&lt;h2&gt;
  
  
  Replacing Redis and RabbitMQ: Queues and Pub/Sub
&lt;/h2&gt;

&lt;p&gt;Two underused, underappreciated Postgres features handle most messaging needs without introducing a broker.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;LISTEN&lt;/code&gt; / &lt;code&gt;NOTIFY&lt;/code&gt;&lt;/strong&gt; is a lightweight pub/sub mechanism built directly into the wire protocol. One session publishes a text payload to a named channel; every subscribed session receives it in milliseconds. It's not Kafka — but for triggering background workers, pushing cache invalidation events, or wiring up a simple notification system, it's zero-infrastructure pub/sub.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;SELECT FOR UPDATE SKIP LOCKED&lt;/code&gt;&lt;/strong&gt; turns an ordinary table into a reliable, concurrent job queue. Multiple workers pull jobs simultaneously without race conditions, because each &lt;code&gt;SELECT&lt;/code&gt; atomically locks the row it claims and skips all rows already locked by other workers:&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;-- Worker atomically claims the next available job&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;jobs&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'pending'&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;created_at&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="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- ... process the job ...&lt;/span&gt;

&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;jobs&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'done'&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="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;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a worker crashes mid-job, the transaction rolls back and the row becomes claimable again — automatic exactly-once delivery, built on the ACID guarantees you already have.&lt;/p&gt;




&lt;h2&gt;
  
  
  Replacing Geospatial APIs: PostGIS
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;PostGIS&lt;/code&gt; extension is one of the most capable geospatial engines in the entire software ecosystem — commercial or otherwise. It adds geometry and geography column types (points, lines, polygons, multipolygons), spatial indexing via GiST, and a rich library of functions for distance calculations, intersection tests, buffering, and coordinate system transformations:&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;-- Find all stores within 5km of a user's location in Bengaluru&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;ST_Distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ST_MakePoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;77&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5946&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;9716&lt;/span&gt;&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="n"&gt;geography&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;dist_meters&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;stores&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;ST_DWithin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;ST_MakePoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;77&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5946&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;9716&lt;/span&gt;&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="n"&gt;geography&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="mi"&gt;5000&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;dist_meters&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Entire commercial GIS platforms used by governments and logistics companies worldwide are built on PostGIS. It replaces the need for a separate geospatial API service for any proximity or boundary query against your own data.&lt;/p&gt;




&lt;h2&gt;
  
  
  The SQL You're Probably Under-Using
&lt;/h2&gt;

&lt;p&gt;Beyond extensions, most developers use roughly 60% of Postgres's SQL capabilities. The remaining 40% eliminates entire categories of application-layer code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Window Functions&lt;/strong&gt; compute aggregates across rows related to the current row without collapsing them like &lt;code&gt;GROUP BY&lt;/code&gt; does — running totals, moving averages, percentile ranks, all in a single pass:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
  &lt;span class="n"&gt;order_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;OVER&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;order_date&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;running_total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;AVG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;OVER&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;order_date&lt;/span&gt;
    &lt;span class="k"&gt;ROWS&lt;/span&gt; &lt;span class="k"&gt;BETWEEN&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="k"&gt;PRECEDING&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="k"&gt;CURRENT&lt;/span&gt; &lt;span class="k"&gt;ROW&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;rolling_7day_avg&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Recursive CTEs&lt;/strong&gt; walk tree structures — org hierarchies, category trees, threaded comments, dependency graphs — in pure SQL, with no application-side recursion or multiple round trips:&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;WITH&lt;/span&gt; &lt;span class="k"&gt;RECURSIVE&lt;/span&gt; &lt;span class="n"&gt;category_tree&lt;/span&gt; &lt;span class="k"&gt;AS&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;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parent_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;depth&lt;/span&gt;
  &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;categories&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;parent_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;UNION&lt;/span&gt; &lt;span class="k"&gt;ALL&lt;/span&gt;

  &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;c&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;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;depth&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;FROM&lt;/span&gt; &lt;span class="n"&gt;categories&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;
  &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;category_tree&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&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;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;category_tree&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;depth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Atomic Upserts&lt;/strong&gt; handle the classic insert-or-update race condition with a single statement — no optimistic locking, no read-then-write, no race:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;inventory&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stock&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="mi"&gt;42&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="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;product_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;stock&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;stock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;updated_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Indexes: A Write Tax for a Read Benefit
&lt;/h2&gt;

&lt;p&gt;Postgres gives you multiple index types, each precision-engineered for a different access pattern. Picking the right one is one of the highest-leverage optimizations available:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Index Type&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;th&gt;Typical Use Case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;B-tree&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Equality, ranges, ordering (default)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;WHERE created_at &amp;gt; '2025-01-01'&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GIN&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;JSONB keys, full-text search, arrays&lt;/td&gt;
&lt;td&gt;&lt;code&gt;data @&amp;gt; '{"plan": "pro"}'&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GiST&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Geometry, ranges, fuzzy matching&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ST_DWithin(location, point, 500)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;BRIN&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Massive append-only time-series tables&lt;/td&gt;
&lt;td&gt;IoT sensor logs, event streams&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HNSW / IVFFlat&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Vector ANN similarity search&lt;/td&gt;
&lt;td&gt;Embedding-based semantic retrieval&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every index is a &lt;strong&gt;write tax for a read benefit&lt;/strong&gt; — it makes &lt;code&gt;INSERT&lt;/code&gt;, &lt;code&gt;UPDATE&lt;/code&gt;, and &lt;code&gt;DELETE&lt;/code&gt; slightly slower because Postgres maintains the index alongside the table. Add indexes surgically, guided by &lt;code&gt;EXPLAIN ANALYZE&lt;/code&gt; output, not speculatively:&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;EXPLAIN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ANALYZE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BUFFERS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&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;customer_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1234&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'shipped'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The most important thing to look for in the output: &lt;strong&gt;Seq Scan vs Index Scan&lt;/strong&gt;. A sequential scan on a large table is your bottleneck. An appropriately chosen index on the same query is your fix.&lt;/p&gt;




&lt;h2&gt;
  
  
  PostgreSQL 18: Built for the AI Era
&lt;/h2&gt;

&lt;p&gt;PostgreSQL 18, released in 2026, doubles down on AI-era workloads with several meaningful improvements.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Asynchronous I/O&lt;/strong&gt; significantly reduces latency on storage-bound operations, directly benefiting heavy embedding writes and similarity search workloads&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skip-scan on multicolumn indexes&lt;/strong&gt; makes filtering around vector similarity searches dramatically faster&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UUIDv7 index optimization&lt;/strong&gt; improves insert and scan performance for tables that use UUID primary keys — common in distributed and event-driven systems&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic data checksums&lt;/strong&gt; are now enabled by default on new clusters, eliminating a common silent data corruption risk&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OAuth 2.0 authentication&lt;/strong&gt; support out of the box for enterprise identity integration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These aren't cosmetic improvements — they're direct responses to the workload patterns that have emerged as teams integrate LLMs and AI features into their production stacks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Under the Hood: Three Mechanisms That Explain Everything
&lt;/h2&gt;

&lt;p&gt;Three internal systems explain most of Postgres's observable behavior — and knowing them prevents a category of production incidents.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MVCC (Multi-Version Concurrency Control)&lt;/strong&gt; is why readers and writers never block each other. When you update a row, Postgres doesn't overwrite it. It writes a &lt;em&gt;new version&lt;/em&gt; of the row and marks the old one as expired. Every transaction sees the world as it existed when that transaction started, regardless of what other transactions are doing concurrently. This is what makes &lt;code&gt;SERIALIZABLE&lt;/code&gt; isolation achievable without locking tables.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WAL (Write-Ahead Log)&lt;/strong&gt; is why Postgres survives crashes with full consistency. Every change is written to a sequential log &lt;em&gt;before&lt;/em&gt; it's applied to data files on disk. On restart after a crash, Postgres replays the WAL and arrives at exactly the state it would have been in had the crash never happened. The same WAL stream is also shipped to read replicas in real time — replication is essentially a free side effect of crash recovery.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;VACUUM and Dead Tuple Bloat&lt;/strong&gt; is the tax you pay for MVCC. Because old row versions aren't overwritten, they accumulate as "dead tuples" on disk. The background &lt;code&gt;autovacuum&lt;/code&gt; process reclaims this space continuously. In write-heavy workloads, autovacuum can fall behind — leading to table bloat, index bloat, and eventually a transaction ID wraparound emergency. Monitor &lt;code&gt;pg_stat_user_tables&lt;/code&gt; for &lt;code&gt;n_dead_tup&lt;/code&gt; values that keep climbing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Scaling Postgres: What's Real and What's Honest
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Read scaling&lt;/strong&gt; is well-understood: stream the WAL to standby servers and route &lt;code&gt;SELECT&lt;/code&gt; queries across them. Read replicas are typically milliseconds behind the primary.&lt;br&gt;
&lt;strong&gt;Write scaling&lt;/strong&gt; is the honest hard limit. One primary accepts all writes. When you genuinely hit that ceiling, these are your options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Table Partitioning&lt;/strong&gt; — splits large tables (by month, by region, by tenant) into physical partitions; Postgres prunes irrelevant partitions at query time, dramatically reducing scan sizes on time-series or multi-tenant data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Citus&lt;/strong&gt; — distributes both data and queries across a cluster of Postgres nodes, enabling horizontal write scaling while keeping the full Postgres SQL interface&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PgBouncer&lt;/strong&gt; — not a scaling tool but an operational necessity. Each Postgres connection is a full OS process consuming 5–10MB of RAM. Serverless functions and connection-heavy frameworks will exhaust your connection limit quickly. PgBouncer pools thousands of application connections onto a small, stable set of real server connections, and it belongs in every production deployment
***&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to Reach for Something Else
&lt;/h2&gt;

&lt;p&gt;Postgres is honest about its limits. You should be too.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pure hot-path in-memory cache&lt;/strong&gt; at millions of ops/sec → Redis; Postgres is not a memory store&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Horizontal write sharding across 10+ nodes from day one&lt;/strong&gt; → purpose-built distributed systems like Cassandra or CockroachDB&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Petabyte-scale OLAP with complex aggregations&lt;/strong&gt; → columnar engines like ClickHouse, DuckDB, or BigQuery will be orders of magnitude faster&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High-throughput real-time event streaming&lt;/strong&gt; → Kafka or Redpanda own that space; &lt;code&gt;NOTIFY&lt;/code&gt; doesn't match their throughput guarantees&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The engineering discipline is: &lt;strong&gt;start with Postgres, measure your actual bottlenecks, and add specialized tooling only when you've conclusively outgrown what Postgres offers.&lt;/strong&gt; The biggest architectural mistake teams make is adding distributed complexity in anticipation of hypothetical scale that never arrives.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why the License Is a Competitive Moat
&lt;/h2&gt;

&lt;p&gt;Postgres is governed by the PostgreSQL Global Development Group — a community intentionally structured so that no single company can change its terms.  The license is permissive, similar in spirit to BSD/MIT. You own your deployment. You control your upgrade path.&lt;/p&gt;

&lt;p&gt;This is not a footnote. In recent years, MongoDB switched to SSPL and Redis changed to BSL, sending engineering teams scrambling for alternatives. That cannot structurally happen with Postgres. The community governance model is the moat — and in a world where vendor lock-in risk has become a real architecture consideration, that stability has genuine business value.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Single-Database Architecture
&lt;/h2&gt;

&lt;p&gt;One database. One backup strategy. One set of credentials. One monitoring dashboard. One &lt;code&gt;EXPLAIN ANALYZE&lt;/code&gt;. It handles your relational data, your documents, your full-text search, your vector embeddings, your geospatial queries, your job queue, and your pub/sub events — and it has been reliably doing so for production systems at scale for over thirty years.&lt;/p&gt;

&lt;p&gt;In 2026, the question isn't whether Postgres is capable enough. The question is whether your architecture has already added five services it didn't need.&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>ai</category>
      <category>programming</category>
    </item>
    <item>
      <title>Testing MCP Server Tools in AI Agents — A Practical Guide</title>
      <dc:creator>Shahid</dc:creator>
      <pubDate>Sun, 24 May 2026 08:26:10 +0000</pubDate>
      <link>https://dev.to/shahidkhans/testing-mcp-server-tools-in-ai-agents-a-practical-guide-1c9d</link>
      <guid>https://dev.to/shahidkhans/testing-mcp-server-tools-in-ai-agents-a-practical-guide-1c9d</guid>
      <description>&lt;p&gt;&lt;strong&gt;Building an MCP server is only half the job. The other half — testing its tools — is where most developers drop the ball.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're using the &lt;a href="https://ai-sdk.dev/docs/introduction" rel="noopener noreferrer"&gt;Vercel AI SDK&lt;/a&gt; to build AI agents with Model Context Protocol (MCP), you already know how powerful tool-calling can be. But an untested tool is a liability. A hallucinating LLM calling a broken tool can cause cascading failures that are notoriously hard to debug in production. This guide walks you through a layered testing strategy — from fast unit tests to full end-to-end evaluations.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Testing MCP Tools Is Uniquely Hard
&lt;/h2&gt;

&lt;p&gt;MCP tools sit at the intersection of three systems: your &lt;strong&gt;server logic&lt;/strong&gt;, the &lt;strong&gt;LLM's tool selection behavior&lt;/strong&gt;, and the &lt;strong&gt;AI SDK's execution pipeline&lt;/strong&gt;. A bug can live in any one of them. Testing just the server in isolation gives you false confidence — you also need to verify that the LLM actually &lt;em&gt;picks&lt;/em&gt; the right tool for a given prompt, and that the AI SDK correctly routes the call.&lt;/p&gt;




&lt;h2&gt;
  
  
  Layer 1: Unit Test Tool Logic Directly
&lt;/h2&gt;

&lt;p&gt;Before involving any LLM, test your tool's &lt;code&gt;execute()&lt;/code&gt; function in complete isolation. The AI SDK lets you invoke tool execution directly with a typed input:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;search-docs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MCP transport options&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="na"&gt;toolCallId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test-001&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeGreaterThan&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This runs in milliseconds, costs nothing, and catches the most common bugs — wrong output shapes, missing error handling, and schema mismatches.&lt;/p&gt;




&lt;h2&gt;
  
  
  Layer 2: Inspect Schemas with the MCP Inspector
&lt;/h2&gt;

&lt;p&gt;Run the official &lt;code&gt;@modelcontextprotocol/inspector&lt;/code&gt; CLI tool against your server before writing a single test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @modelcontextprotocol/inspector node dist/server.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The browser UI lets you browse all registered tools, manually invoke them with custom inputs, and inspect raw JSON-RPC payloads. This is your &lt;strong&gt;smoke test&lt;/strong&gt; — it confirms your server is reachable and your schemas are well-formed. Do this after every new tool you add.&lt;/p&gt;




&lt;h2&gt;
  
  
  Layer 3: Mock the LLM for Integration Tests
&lt;/h2&gt;

&lt;p&gt;Real LLM API calls are slow, flaky, and expensive in CI pipelines. The AI SDK ships a &lt;code&gt;MockLanguageModelV1&lt;/code&gt; in &lt;code&gt;ai/test&lt;/code&gt; specifically for this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MockLanguageModelV1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ai/test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;generateText&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ai&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mockModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MockLanguageModelV1&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;doGenerate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;finishReason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tool-calls&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;toolCalls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
      &lt;span class="na"&gt;toolCallType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;toolCallId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;call-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;toolName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;get-weather&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bengaluru&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="na"&gt;rawCall&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;rawPrompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;rawSettings&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="na"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;promptTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completionTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;toolResults&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;generateText&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mockModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mcpTools&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;What is the weather in Bengaluru?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tests your entire AI agent pipeline — tool registration, execution, result parsing — without a single API call.&lt;/p&gt;




&lt;h2&gt;
  
  
  Layer 4: Evaluate Tool Selection Accuracy
&lt;/h2&gt;

&lt;p&gt;The hardest problem to test is: &lt;em&gt;will the LLM choose the right tool?&lt;/em&gt; A tool with a vague description might get ignored. A poorly scoped tool might be called when it shouldn't be. Use &lt;code&gt;mcp-evals&lt;/code&gt; for structured grading:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;evalTool&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mcp-evals&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;evalTool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Find all open GitHub issues labeled bug&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;expectedTool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;list-github-issues&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;grader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;openai/gpt-4o&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Score: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, Passed: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run these evals whenever you change a tool's name, description, or input schema — those are the highest-risk moments.&lt;/p&gt;




&lt;h2&gt;
  
  
  The One Rule That Saves Hours of Debugging
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Always call &lt;code&gt;await mcpClient.close()&lt;/code&gt; after every test.&lt;/strong&gt; Leaving MCP connections open causes port conflicts, zombie processes, and flaky tests in CI. Wrap every test suite in a &lt;code&gt;beforeAll&lt;/code&gt;/&lt;code&gt;afterAll&lt;/code&gt; block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;beforeAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mcpClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createMCPClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nf"&gt;afterAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mcpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What to Test at Each Layer
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Speed&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;th&gt;Tests&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;tool.execute()&lt;/code&gt; directly&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Logic, output schema, error handling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP Inspector&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Schema validity, tool discoverability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MockLanguageModelV1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Full agent pipeline, tool routing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;mcp-evals&lt;/code&gt; grading&lt;/td&gt;
&lt;td&gt;Slow&lt;/td&gt;
&lt;td&gt;LLM cost&lt;/td&gt;
&lt;td&gt;Tool selection accuracy by description&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Start with Layer 1 for every tool, use Layer 3 for CI, and run Layer 4 before any deployment that touches tool descriptions or names. Your future self — staring at a 3 AM production incident — will thank you.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Have questions about testing a specific tool type? Drop them in the comments below.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>vercel</category>
      <category>agentskills</category>
    </item>
    <item>
      <title>How do I calculate how many shares to buy based on ATR and risk management?</title>
      <dc:creator>Shahid</dc:creator>
      <pubDate>Sun, 10 May 2026 06:42:51 +0000</pubDate>
      <link>https://dev.to/shahidkhans/how-do-i-calculate-how-many-shares-to-buy-based-on-atr-and-risk-management-agn</link>
      <guid>https://dev.to/shahidkhans/how-do-i-calculate-how-many-shares-to-buy-based-on-atr-and-risk-management-agn</guid>
      <description>&lt;p&gt;One of the most common questions I see from traders is: &lt;em&gt;"I like this setup — but how many shares should I buy?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Most people guess. Or buy a round number. Or deploy whatever cash they have.&lt;/p&gt;

&lt;p&gt;Here's the systematic answer using ATR.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;The Framework&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ATR(14) tells you how much a stock moves on an average day. Using that as your stop foundation means your stop is calibrated to the stock's actual volatility — not an arbitrary percentage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1 — Stop Distance&lt;/strong&gt;&lt;br&gt;
Stop Distance = ATR × Multiplier&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2× ATR → short-term / swing trades&lt;/li&gt;
&lt;li&gt;3× ATR → positional / long-term (recommended)&lt;/li&gt;
&lt;li&gt;4× ATR → very wide, for high-volatility stocks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 2 — Risk Budget&lt;/strong&gt;&lt;br&gt;
Risk Budget = Capital × Risk %&lt;br&gt;
Standard: 1% of capital per trade.&lt;br&gt;
₹1,00,000 capital → ₹1,000 max loss per trade&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3 — Position Size&lt;/strong&gt;&lt;br&gt;
Units = Risk Budget ÷ Stop Distance&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Example (round numbers)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Stock price: ₹500 | ATR(14): ₹5 | Capital: ₹1,00,000&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ATR Mult&lt;/th&gt;
&lt;th&gt;Stop Dist&lt;/th&gt;
&lt;th&gt;Stop Price&lt;/th&gt;
&lt;th&gt;Units&lt;/th&gt;
&lt;th&gt;Deployed&lt;/th&gt;
&lt;th&gt;Max Loss&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2×&lt;/td&gt;
&lt;td&gt;₹10&lt;/td&gt;
&lt;td&gt;₹490&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;₹50,000&lt;/td&gt;
&lt;td&gt;₹1,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3× ★&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;₹15&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;₹485&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;66&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;₹33,000&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;₹990&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4×&lt;/td&gt;
&lt;td&gt;₹20&lt;/td&gt;
&lt;td&gt;₹480&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;₹25,000&lt;/td&gt;
&lt;td&gt;₹1,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Notice the max loss stays ~₹1,000 across all levels. The multiplier controls stop tightness — not your risk amount. Your position size automatically adjusts.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;The YOLO trap&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Buying 200 units (full ₹1L deployed) with a 3× ATR stop risks:&lt;br&gt;
200 × ₹15 = &lt;strong&gt;₹3,000 = 3% of capital&lt;/strong&gt; in one trade.&lt;/p&gt;

&lt;p&gt;Across 4 simultaneous positions that's 12% exposure. One bad week is devastating.&lt;/p&gt;

&lt;p&gt;ATR position sizing keeps each trade capped at 1% regardless of entry price or volatility level.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Free Calculator&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I built a browser-based tool that does all this math instantly — enter your ATR, entry price, capital and risk %, and it simulates across all multiplier levels with a comparison table and charts.&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;&lt;a href="https://trade-atr.sk7.workers.dev/" rel="noopener noreferrer"&gt;https://trade-atr.sk7.workers.dev/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No login, no signup — runs entirely in your browser.&lt;/p&gt;

</description>
      <category>stock</category>
      <category>stockmarket</category>
    </item>
    <item>
      <title>npm vs pnpm: The Ultimate Command Comparison Cheat Sheet</title>
      <dc:creator>Shahid</dc:creator>
      <pubDate>Fri, 22 Aug 2025 13:49:58 +0000</pubDate>
      <link>https://dev.to/shahidkhans/npm-vs-pnpm-the-ultimate-command-comparison-cheat-sheet-pp0</link>
      <guid>https://dev.to/shahidkhans/npm-vs-pnpm-the-ultimate-command-comparison-cheat-sheet-pp0</guid>
      <description>&lt;p&gt;pnpm and npm are both package managers for JavaScript, but they handle dependency installation and management differently. &lt;strong&gt;Direct command translation between npm and pnpm is nearly 1:1&lt;/strong&gt;—most operations you run in npm can be run in pnpm with the same arguments, but under the hood, pnpm is typically faster and far more disk-efficient due to its unique content-addressable storage approach and symlinking strategy.&lt;/p&gt;

&lt;p&gt;Below is a direct, &lt;strong&gt;command-by-command comparison&lt;/strong&gt; between npm and pnpm for common package management tasks. The table uses &lt;code&gt;npm&lt;/code&gt; as the reference, with the equivalent &lt;code&gt;pnpm&lt;/code&gt; command, and notes any important behavioral differences.&lt;/p&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;npm Command&lt;/th&gt;
&lt;th&gt;pnpm Command&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Initialize project&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;npm init&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pnpm init&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Both create &lt;code&gt;package.json&lt;/code&gt;; behavior identical.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Install all dependencies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;npm install&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pnpm install&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;pnpm uses a global store and symlinks for speed/space; npm duplicates packages.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Add dependency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;npm add &amp;lt;package&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pnpm add &amp;lt;package&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Both save to &lt;code&gt;package.json&lt;/code&gt; by default; options like &lt;code&gt;--save-dev&lt;/code&gt; work the same.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Add dev dependency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;npm add -D &amp;lt;package&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pnpm add -D &amp;lt;package&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Both add to &lt;code&gt;devDependencies&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Add optional dependency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;npm add -O &amp;lt;package&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pnpm add -O &amp;lt;package&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Both add to &lt;code&gt;optionalDependencies&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Add global package&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;npm add -g &amp;lt;package&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pnpm add -g &amp;lt;package&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;pnpm's global store is more efficient.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Remove package&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;npm remove &amp;lt;package&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pnpm remove &amp;lt;package&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Both remove from &lt;code&gt;package.json&lt;/code&gt; and &lt;code&gt;node_modules&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Update package&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;npm update &amp;lt;package&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pnpm update &amp;lt;package&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;pnpm updates from its global store, often faster.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Check outdated packages&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;npm outdated&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pnpm outdated&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Both show outdated packages.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Run script&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;npm run &amp;lt;script&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pnpm &amp;lt;script&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;pnpm does not require &lt;code&gt;run&lt;/code&gt; keyword if script exists in &lt;code&gt;package.json&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Run command&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;npx &amp;lt;command&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pnpm dlx &amp;lt;command&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;pnpm uses &lt;code&gt;dlx&lt;/code&gt; to download and run commands like &lt;code&gt;npx&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Prune node_modules&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;npm prune&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pnpm prune&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;pnpm &lt;strong&gt;always&lt;/strong&gt; removes extraneous/orphaned packages, no package args allowed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;List installed packages&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;npm ls&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pnpm ls&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Both list dependency trees.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Audit for vulnerabilities&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;npm audit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pnpm audit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Both check for security issues.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Install pnpm globally&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;npm install -g pnpm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;–&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;pnpm&lt;/code&gt; can be installed via npm or other methods.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Key Differences Under the Hood&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Installation Speed &amp;amp; Disk Space&lt;/strong&gt;: pnpm is typically much faster and uses far less disk space than npm, especially in large projects, because it stores each package version once globally and symlinks into project &lt;code&gt;node_modules&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependency Resolution&lt;/strong&gt;: pnpm enforces &lt;strong&gt;strict&lt;/strong&gt; dependency resolution, which can help avoid "phantom" dependencies (packages not listed in &lt;code&gt;package.json&lt;/code&gt; but still accessible). npm’s flattened &lt;code&gt;node_modules&lt;/code&gt; can sometimes allow this.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monorepo/Workspaces&lt;/strong&gt;: pnpm has built-in, optimized support for monorepos and workspaces; npm requires extra configuration for similar features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ecosystem&lt;/strong&gt;: npm has the largest ecosystem and widest compatibility; pnpm’s is growing but smaller.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Global Store&lt;/strong&gt;: pnpm’s global store is a major architectural difference—reducing duplication across all projects on your system.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;When to Use Which&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use npm&lt;/strong&gt; if you want maximum ecosystem compatibility, are working on small projects, or need the broadest community support.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use pnpm&lt;/strong&gt; if you value disk space, installation speed, strict dependency isolation, or are managing large projects/monorepos.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;For most day-to-day commands, just replace &lt;code&gt;npm&lt;/code&gt; with &lt;code&gt;pnpm&lt;/code&gt;.&lt;/strong&gt; The key differences are internal (speed, disk usage, dependency resolution), not in the command syntax. However, pnpm’s architecture means your projects will install faster, use less disk space, and be more strictly isolated—benefits that grow with project size and complexity.&lt;/p&gt;

&lt;p&gt;If you need a &lt;strong&gt;specific npm command translated to pnpm&lt;/strong&gt; that isn’t listed above, just ask—the mapping is nearly always straightforward!&lt;/p&gt;

</description>
      <category>npm</category>
      <category>pnpm</category>
      <category>node</category>
      <category>programming</category>
    </item>
    <item>
      <title>From Zero to AI-Powered Developer: Your Complete Claude Code CLI Setup Guide</title>
      <dc:creator>Shahid</dc:creator>
      <pubDate>Wed, 06 Aug 2025 06:43:45 +0000</pubDate>
      <link>https://dev.to/shahidkhans/from-zero-to-ai-powered-developer-your-complete-claude-code-cli-setup-guide-4l9i</link>
      <guid>https://dev.to/shahidkhans/from-zero-to-ai-powered-developer-your-complete-claude-code-cli-setup-guide-4l9i</guid>
      <description>&lt;p&gt;&lt;em&gt;Setting up your development environment with AI assistance used to be a pipe dream. Today, it's a 10-minute process that could transform how you write code forever. Here's everything you need to know to get Claude Code running on your system—from installation to your first AI-powered commit.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The landscape of software development is shifting rapidly, and at the center of this transformation is &lt;strong&gt;Claude Code&lt;/strong&gt;—Anthropic's command-line AI assistant that brings enterprise-level coding capabilities directly to your terminal. Whether you're a seasoned developer or just starting your coding journey, this comprehensive guide will get you up and running with one of 2025's most powerful development tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why Claude Code Setup Matters More Than Ever&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Before diving into the technical details, it's worth understanding what makes Claude Code different from other AI coding tools. Unlike browser-based chatbots or IDE plugins that work in isolation, Claude Code operates as a &lt;strong&gt;full-fledged development partner&lt;/strong&gt; that can read your entire codebase, understand your project architecture, and make coordinated changes across multiple files simultaneously.&lt;/p&gt;

&lt;p&gt;The setup process might seem straightforward, but getting it right from the beginning can mean the difference between a seamless development experience and hours of troubleshooting down the line.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Pre-Flight Check: System Requirements That Actually Matter&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Baseline Requirements&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Before you begin, ensure your system meets these essential requirements:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Operating Systems&lt;/strong&gt;: macOS 10.15+, Ubuntu 20.04+/Debian 10+, or Windows 10+ (with WSL 1, WSL 2, or Git for Windows)&lt;br&gt;
&lt;strong&gt;Hardware&lt;/strong&gt;: 4GB+ RAM minimum&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Software&lt;/strong&gt;: Node.js 18+ (LTS version strongly recommended)&lt;br&gt;
&lt;strong&gt;Network&lt;/strong&gt;: Stable internet connection for authentication and AI processing&lt;br&gt;
&lt;strong&gt;Shell Environment&lt;/strong&gt;: Works optimally with Bash, Zsh, or Fish&lt;br&gt;
&lt;strong&gt;Geographic Location&lt;/strong&gt;: Must be in an Anthropic-supported country&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;The Often-Overlooked Details&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;What the documentation doesn't emphasize enough is that &lt;strong&gt;your shell choice can significantly impact your experience&lt;/strong&gt;. While Claude Code works across different shells, Bash and Zsh users report the most stable experience, particularly when integrating with IDE workflows and managing complex project structures.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Installation Methods: Choosing Your Path to Success&lt;/strong&gt;
&lt;/h2&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Method 1: NPM Installation (The Reliable Standard)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For most developers, the NPM route provides the most predictable setup experience:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @anthropic-ai/claude-code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Critical Warning&lt;/strong&gt;: Never use &lt;code&gt;sudo&lt;/code&gt; with this command. The &lt;code&gt;sudo npm install -g&lt;/code&gt; approach can create permission issues and security vulnerabilities that will plague your entire setup. If you encounter permission errors, configure your npm permissions properly or consider the local installation method instead.&lt;/p&gt;

&lt;p&gt;This approach works best when you have a properly configured Node.js environment and npm permissions set up correctly on your system.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Method 2: Native Binary Installation (The Cutting-Edge Choice)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For developers who want access to the latest features or need to avoid npm permission complexities entirely, the native binary installation offers a compelling alternative.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For macOS, Linux, and WSL:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install stable version (recommended for most users)&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://claude.ai/install.sh | bash

&lt;span class="c"&gt;# Install latest version (for early adopters)&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://claude.ai/install.sh | bash &lt;span class="nt"&gt;-s&lt;/span&gt; latest

&lt;span class="c"&gt;# Install specific version (for compatibility requirements)&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://claude.ai/install.sh | bash &lt;span class="nt"&gt;-s&lt;/span&gt; 1.0.58
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;For Windows PowerShell:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install stable version&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;irm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;https://claude.ai/install.ps1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Install latest version&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;scriptblock&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;irm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;https://claude.ai/install.ps1&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The native binary installation often provides better performance and eliminates dependency conflicts, making it particularly attractive for developers working in complex environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Method 3: Local Installation Migration&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If you already have a global npm installation and are experiencing autoupdater permission issues, Claude Code provides a seamless migration path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude migrate-installer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command transitions your installation to a local setup that avoids common permission pitfalls. Some users may be automatically migrated to this method during updates.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Platform-Specific Considerations That Make or Break Your Setup&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Windows: Navigating the Complexity&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Windows users have two primary paths, each with distinct advantages:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 1: WSL Integration (Strongly Recommended)&lt;/strong&gt;&lt;br&gt;
Both WSL 1 and WSL 2 are fully supported, but the experience is significantly smoother within a Linux subsystem. Install Ubuntu 20.04+ or Debian 10+ through WSL, then follow the standard Linux installation process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 2: Native Windows with Git Bash&lt;/strong&gt;&lt;br&gt;
This approach requires Git for Windows and additional configuration. For portable Git installations, you'll need to specify the bash path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$env&lt;/span&gt;:CLAUDE_CODE_GIT_BASH_PATH&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"C:&lt;/span&gt;&lt;span class="se"&gt;\P&lt;/span&gt;&lt;span class="s2"&gt;rogram Files&lt;/span&gt;&lt;span class="se"&gt;\G&lt;/span&gt;&lt;span class="s2"&gt;it&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="s2"&gt;in&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="s2"&gt;ash.exe"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Linux and macOS: The Straightforward Path&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Installation on Unix-based systems is typically seamless using either the npm or native binary methods. The primary consideration is ensuring your Node.js version meets the LTS requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Post-Installation Verification: Ensuring Everything Works&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;After installation, verification is crucial to avoid discovering setup issues during critical development moments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check installation health and configuration&lt;/span&gt;
claude doctor

&lt;span class="c"&gt;# Verify global availability and version&lt;/span&gt;
claude &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you used the native binary installation method, you might need to add Claude to your system PATH:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'export PATH="$HOME/.local/bin:$PATH"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.profile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember to restart your terminal or source your profile for PATH changes to take effect.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Authentication: Your Gateway to AI-Powered Development&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Claude Code offers three distinct authentication approaches, each suited to different use cases:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Option 1: Anthropic Console (Default Path)&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Requires an active billing account at console.anthropic.com&lt;/li&gt;
&lt;li&gt;Uses OAuth for secure authentication&lt;/li&gt;
&lt;li&gt;Navigate to your project directory and run &lt;code&gt;claude&lt;/code&gt; to begin the authentication flow&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Option 2: Claude App Integration (Pro/Max Plans)&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Perfect for developers with existing Claude Pro or Max subscriptions&lt;/li&gt;
&lt;li&gt;Provides unified billing and account management&lt;/li&gt;
&lt;li&gt;Log in with your Claude.ai credentials during the initial launch&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Option 3: Enterprise Platforms&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Designed for organizations using Amazon Bedrock or Google Vertex AI&lt;/li&gt;
&lt;li&gt;Requires additional configuration for cloud infrastructure integration&lt;/li&gt;
&lt;li&gt;Ideal for enterprise environments with existing AI platform investments&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;First Session: Making Contact with Your AI Development Partner&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Your first Claude Code session sets the foundation for all future interactions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Navigate to your project directory:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /path/to/your/project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Launch Claude Code:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Complete the authentication flow following the prompts&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;You'll be greeted with the welcome interface:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✻ Welcome to Claude Code!
...
&amp;gt; Try "create a util logging.py that..."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This welcome prompt isn't just ceremonial—it's your first indication that Claude Code has successfully connected to Anthropic's servers and is ready to assist with your development workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Essential Configuration for Maximum Effectiveness&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Environment Variables for Advanced Users&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;While not required for basic operation, setting up environment variables can enhance your Claude Code experience:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# For direct API access (add to ~/.bashrc, ~/.zshrc, or ~/.profile)&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ANTHROPIC_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your-api-key-here"&lt;/span&gt;

&lt;span class="c"&gt;# For Amazon Bedrock integration&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CLAUDE_CODE_USE_BEDROCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1

&lt;span class="c"&gt;# For Google Vertex AI integration&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CLAUDE_CODE_USE_VERTEX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Project-Level Context: The CLAUDE.md Secret Weapon&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;One of Claude Code's most powerful features is its ability to maintain project context through a &lt;code&gt;CLAUDE.md&lt;/code&gt; file placed in your project root. This file acts as a persistent briefing document that Claude Code references for every interaction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Project: Web Application Backend&lt;/span&gt;

&lt;span class="gu"&gt;## Structure&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`src/`&lt;/span&gt; - Main application code
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`tests/`&lt;/span&gt; - Test suites and fixtures
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`docs/`&lt;/span&gt; - Project documentation
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`config/`&lt;/span&gt; - Configuration files

&lt;span class="gu"&gt;## Conventions&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Use TypeScript for all new files
&lt;span class="p"&gt;-&lt;/span&gt; Follow REST API naming conventions
&lt;span class="p"&gt;-&lt;/span&gt; Implement comprehensive error handling
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This context file dramatically improves Claude Code's understanding of your project, resulting in more accurate suggestions and fewer misaligned implementations.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Command Reference: Your Daily Development Arsenal&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Understanding Claude Code's command structure is essential for effective usage:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Command&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Use Case&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;claude&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start interactive mode&lt;/td&gt;
&lt;td&gt;Beginning a development session&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;claude "task"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Execute one-time task&lt;/td&gt;
&lt;td&gt;Quick fixes or implementations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;claude -p "query"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run query and exit&lt;/td&gt;
&lt;td&gt;Getting explanations or guidance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;claude -c&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Continue recent conversation&lt;/td&gt;
&lt;td&gt;Resuming interrupted work&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;claude -r&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Resume previous conversation&lt;/td&gt;
&lt;td&gt;Returning to earlier discussions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;claude commit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create Git commit&lt;/td&gt;
&lt;td&gt;Automated commit message generation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/clear&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Clear conversation history&lt;/td&gt;
&lt;td&gt;Starting fresh within a session&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/help&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show available commands&lt;/td&gt;
&lt;td&gt;Discovering new capabilities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/config&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Configure settings&lt;/td&gt;
&lt;td&gt;Customizing your experience&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;IDE Integration: Bringing AI Into Your Editor&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;VS Code Integration Made Simple&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Claude Code's VS Code integration transforms your editor into an AI-powered development environment:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start Claude Code from your VS Code terminal:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Enable IDE integration:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /ide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install the extension when prompted&lt;/strong&gt;
Claude Code will automatically detect VS Code and guide you through extension installation. Alternatively, you can manually install the &lt;code&gt;claude-code.vsix&lt;/code&gt; file from your installation directory.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Support for Alternative IDEs&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Claude Code also integrates with Cursor and other modern editors using a similar process—start Claude Code from the editor's terminal and use the &lt;code&gt;/ide&lt;/code&gt; command to enable integration.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Troubleshooting: Solving Common Setup Challenges&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Permission Errors&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use the local installation method: &lt;code&gt;claude migrate-installer&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Never use &lt;code&gt;sudo&lt;/code&gt; with npm installation&lt;/li&gt;
&lt;li&gt;Configure npm permissions properly for your user account&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Windows Compatibility Issues&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Prioritize WSL for the best experience&lt;/li&gt;
&lt;li&gt;Ensure Git for Windows is properly installed for native usage&lt;/li&gt;
&lt;li&gt;Configure the correct Git Bash path for portable installations&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;claude doctor&lt;/code&gt; to diagnose authentication status&lt;/li&gt;
&lt;li&gt;Re-authenticate using &lt;code&gt;claude /login&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Verify you're accessing Claude Code from a supported geographic region&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;PATH Configuration Issues&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Add Claude to your PATH following the post-installation instructions&lt;/li&gt;
&lt;li&gt;Remove outdated aliases or symlinks that might conflict&lt;/li&gt;
&lt;li&gt;Restart your terminal session after PATH modifications&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Beyond Setup: What Comes Next&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;With Claude Code properly installed and configured, you're positioned to leverage one of the most sophisticated AI development tools available today. The setup process we've covered here creates the foundation for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multi-file debugging and refactoring&lt;/strong&gt; across complex codebases&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intelligent code generation&lt;/strong&gt; that understands your project's patterns&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated testing and documentation&lt;/strong&gt; that stays in sync with your code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Architecture-aware suggestions&lt;/strong&gt; that respect your existing design decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Investment in Your Development Future&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Setting up Claude Code properly isn't just about getting a tool running—it's about establishing a development workflow that can adapt and scale with your projects. The time invested in understanding authentication options, configuring environment variables, and creating comprehensive project context pays dividends in every subsequent coding session.&lt;/p&gt;

&lt;p&gt;Whether you're building your next startup, contributing to open source, or tackling enterprise-scale applications, Claude Code's CLI interface provides a consistent, powerful foundation for AI-assisted development.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your development environment is ready. Your AI coding partner is waiting. The only question remaining is: what will you build first?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Ready to take your development workflow to the next level? With Claude Code properly configured, you're just one &lt;code&gt;claude&lt;/code&gt; command away from experiencing the future of software development.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>claudeai</category>
      <category>claudecode</category>
      <category>codingagent</category>
      <category>aicode</category>
    </item>
    <item>
      <title>Generate Full Stack React Native Expo project in Seconds ⌚🚀</title>
      <dc:creator>Shahid</dc:creator>
      <pubDate>Thu, 17 Jul 2025 07:46:32 +0000</pubDate>
      <link>https://dev.to/shahidkhans/generate-full-stack-react-native-expo-project-in-seconds-180n</link>
      <guid>https://dev.to/shahidkhans/generate-full-stack-react-native-expo-project-in-seconds-180n</guid>
      <description>&lt;h2&gt;
  
  
  Generate Full Stack React Native project in Seconds.
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Run the below command and get relax
&lt;code&gt;
npx rn-new@latest rn-nw-rnr2 --react-navigation --nativewind --npm --i18next&amp;nbsp; --firebase --drawer --tabs --import-alias --no-install
&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>reactnative</category>
      <category>expo</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Ready-made React &amp; Next.js blocks, Framer Motion FX</title>
      <dc:creator>Shahid</dc:creator>
      <pubDate>Thu, 17 Jul 2025 07:28:15 +0000</pubDate>
      <link>https://dev.to/shahidkhans/ready-made-react-nextjs-blocks-framer-motion-fx-22ig</link>
      <guid>https://dev.to/shahidkhans/ready-made-react-nextjs-blocks-framer-motion-fx-22ig</guid>
      <description>&lt;p&gt;Elevate your next project with a curated suite of minimalist, production-ready UI components crafted in Tailwind CSS, React, and Next.js. Copy-and-paste landing pages, portfolios, and full-stack templates—complete with seamless Supabase integration—let you launch in minutes. Built-in Framer Motion animations, mobile-first responsiveness, and WCAG-focused accessibility ensure every site looks polished and performs flawlessly. Ship professional, scalable web experiences faster than ever.&lt;br&gt;
Visit &lt;a href="https://skiper-ui.com/" rel="noopener noreferrer"&gt;https://skiper-ui.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tailwindcss</category>
      <category>nextjs</category>
      <category>react</category>
      <category>shadcn</category>
    </item>
  </channel>
</rss>
