<?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: mrberrysome</title>
    <description>The latest articles on DEV Community by mrberrysome (@mrberry).</description>
    <link>https://dev.to/mrberry</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3881388%2F88290432-69c2-48ce-95d7-f40bc4ca9b37.png</url>
      <title>DEV Community: mrberrysome</title>
      <link>https://dev.to/mrberry</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mrberry"/>
    <language>en</language>
    <item>
      <title>my first post!</title>
      <dc:creator>mrberrysome</dc:creator>
      <pubDate>Tue, 21 Apr 2026 01:31:51 +0000</pubDate>
      <link>https://dev.to/mrberry/my-first-post-3pj0</link>
      <guid>https://dev.to/mrberry/my-first-post-3pj0</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/dropfile/cloud-sql-iam-auth-on-cloud-run-with-postgresjs-no-connector-package-in-your-app-knl" class="crayons-story__hidden-navigation-link"&gt;Cloud SQL IAM auth on Cloud Run with Postgres.js (no connector package in your app)&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;
          &lt;a class="crayons-logo crayons-logo--l" href="/dropfile"&gt;
            &lt;img alt="DropFile logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F13045%2F9e907bfc-8a4c-4262-af90-f6c2abf64700.png" class="crayons-logo__image" width="512" height="512"&gt;
          &lt;/a&gt;

          &lt;a href="/mrberry" class="crayons-avatar  crayons-avatar--s absolute -right-2 -bottom-2 border-solid border-2 border-base-inverted  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3881388%2F88290432-69c2-48ce-95d7-f40bc4ca9b37.png" alt="mrberry profile" class="crayons-avatar__image" width="800" height="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/mrberry" class="crayons-story__secondary fw-medium m:hidden"&gt;
              mrberrysome
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                mrberrysome
                
              
              &lt;div id="story-author-preview-content-3529167" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/mrberry" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3881388%2F88290432-69c2-48ce-95d7-f40bc4ca9b37.png" class="crayons-avatar__image" alt="" width="800" height="800"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;mrberrysome&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

            &lt;span&gt;
              &lt;span class="crayons-story__tertiary fw-normal"&gt; for &lt;/span&gt;&lt;a href="/dropfile" class="crayons-story__secondary fw-medium"&gt;DropFile&lt;/a&gt;
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;a href="https://dev.to/dropfile/cloud-sql-iam-auth-on-cloud-run-with-postgresjs-no-connector-package-in-your-app-knl" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Apr 21&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/dropfile/cloud-sql-iam-auth-on-cloud-run-with-postgresjs-no-connector-package-in-your-app-knl" id="article-link-3529167"&gt;
          Cloud SQL IAM auth on Cloud Run with Postgres.js (no connector package in your app)
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/node"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;node&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/googlecloud"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;googlecloud&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/postgres"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;postgres&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/dropfile/cloud-sql-iam-auth-on-cloud-run-with-postgresjs-no-connector-package-in-your-app-knl" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt; reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/dropfile/cloud-sql-iam-auth-on-cloud-run-with-postgresjs-no-connector-package-in-your-app-knl#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Cloud SQL IAM auth on Cloud Run with Postgres.js (without the connector package in your app)</title>
      <dc:creator>mrberrysome</dc:creator>
      <pubDate>Tue, 21 Apr 2026 01:26:40 +0000</pubDate>
      <link>https://dev.to/dropfile/cloud-sql-iam-auth-on-cloud-run-with-postgresjs-no-connector-package-in-your-app-knl</link>
      <guid>https://dev.to/dropfile/cloud-sql-iam-auth-on-cloud-run-with-postgresjs-no-connector-package-in-your-app-knl</guid>
      <description>&lt;p&gt;&lt;em&gt;After a week that reminded everyone how much trust sits in every extra layer, here's the production pattern we use to keep Cloud Run + Cloud SQL auth simpler — and the 1-hour IAM token trap most examples miss.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This week was a good reminder that infrastructure is never just infrastructure.&lt;/p&gt;

&lt;p&gt;Vercel disclosed a security incident that it said originated from a compromised third-party AI tool and ultimately exposed access to some internal environments and a limited subset of customer-related data. At the same time, the broader developer tooling world is debating where "public by design" ends and security expectations begin.&lt;/p&gt;

&lt;p&gt;That is exactly why boring decisions matter.&lt;/p&gt;

&lt;p&gt;If you are using Cloud SQL from Cloud Run in Node.js, most examples push you toward adding more app-layer machinery. Sometimes that is the right call. But if you are already on Cloud Run, already mounting the Cloud SQL socket, and already using Postgres.js, you may not need to add the connector package inside your app at all.&lt;/p&gt;

&lt;p&gt;That is the pattern we use in production at Dropfile.&lt;/p&gt;

&lt;p&gt;The important caveat: this is manual IAM database auth, not Google's recommended automatic connector-based flow. That distinction matters because IAM DB auth uses short-lived OAuth2 access tokens as the database password. Those tokens expire after one hour, and that is exactly where many examples quietly break.&lt;/p&gt;

&lt;p&gt;This post shows the leaner pattern, where it fits, and the token-refresh detail you need to get right if you do it manually.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters now
&lt;/h2&gt;

&lt;p&gt;Recent incidents across developer tooling have made one thing clearer: every extra layer in your stack is also an extra trust boundary.&lt;/p&gt;

&lt;p&gt;This article is not arguing that connector packages are bad. It is arguing that if your platform already provides the plumbing you need, adding another dependency to app code should be a deliberate choice — not just something copied from the nearest tutorial.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Cloud Run service with &lt;code&gt;--add-cloudsql-instances&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Postgres.js (&lt;code&gt;postgres&lt;/code&gt;, not &lt;code&gt;pg&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Drizzle ORM on top&lt;/li&gt;
&lt;li&gt;IAM database auth, with the service account as the DB user&lt;/li&gt;
&lt;li&gt;No static password in production&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To be clear: we are not removing Cloud Run's Cloud SQL integration. We are just not duplicating that plumbing inside the Node app when Cloud Run is already doing the job.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gotcha everyone hits
&lt;/h2&gt;

&lt;p&gt;Most examples fetch the OAuth2 access token once at startup and pass it as &lt;code&gt;password: token&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That works fine until your process has been warm for over an hour. The token expires, and every new connection starts failing. Existing connections may survive a bit longer. New ones are where the failures show up first.&lt;/p&gt;

&lt;p&gt;The examples weren't wrong. They were just incomplete for long-lived processes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix: pass a function, not a string
&lt;/h2&gt;

&lt;p&gt;Postgres.js lets &lt;code&gt;password&lt;/code&gt; be an async function. It gets resolved when a new connection is created, not once at boot.&lt;/p&gt;

&lt;p&gt;On Cloud Run, the GCP metadata server is always available, so the token fetch is tiny:&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchIAMToken&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token&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;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Metadata-Flavor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Google&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="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Metadata token fetch failed: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;access_token&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;access_token&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;Then wire up the client:&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="nx"&gt;postgres&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;postgres&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;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;postgres&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`/cloudsql/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;INSTANCE_CONNECTION_NAME&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB_USER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// e.g. my-sa@my-project.iam&lt;/span&gt;
  &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fetchIAMToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// function reference, not fetchIAMToken()&lt;/span&gt;
  &lt;span class="na"&gt;max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;idle_timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;connect_timeout&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;max_lifetime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;45&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;// recycle connections before the 1-hour token expiry&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;password&lt;/code&gt; is the function reference, not &lt;code&gt;fetchIAMToken()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;max_lifetime: 45 * 60&lt;/code&gt; recycles pooled connections before they drift too close to the 1-hour token expiry&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That combination is the whole trick.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local dev fallback
&lt;/h2&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;drizzle&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="s2"&gt;drizzle-orm/postgres-js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;postgres&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;postgres&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="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./schema&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;INSTANCE_CONNECTION_NAME&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;drizzle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;postgres&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`/cloudsql/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;INSTANCE_CONNECTION_NAME&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB_USER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fetchIAMToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;idle_timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;connect_timeout&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;max_lifetime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;45&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&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="nx"&gt;schema&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;drizzle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;postgres&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Production uses IAM plus the mounted socket. Local uses &lt;code&gt;DATABASE_URL&lt;/code&gt;. Nothing fancy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy command
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud run deploy my-service &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--add-cloudsql-instances&lt;/span&gt; &lt;span class="s2"&gt;"my-project:us-central1:my-instance"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--service-account&lt;/span&gt; &lt;span class="s2"&gt;"my-sa@my-project.iam.gserviceaccount.com"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set-env-vars&lt;/span&gt; &lt;span class="s2"&gt;"INSTANCE_CONNECTION_NAME=my-project:us-central1:my-instance,DB_USER=my-sa@my-project.iam,DB_NAME=mydb"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--add-cloudsql-instances&lt;/code&gt; mounts the Unix socket path&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DB_USER&lt;/code&gt; for an IAM service-account user is the service account email without &lt;code&gt;.gserviceaccount.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The Cloud Run service account and the IAM DB user should be the same identity&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What you need in GCP
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Cloud SQL instance with IAM database authentication enabled (&lt;code&gt;cloudsql.iam_authentication&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Service account added as a Cloud SQL IAM service-account user&lt;/li&gt;
&lt;li&gt;Service account has both &lt;code&gt;roles/cloudsql.client&lt;/code&gt; and &lt;code&gt;roles/cloudsql.instanceUser&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Normal PostgreSQL grants for that user, because IAM login and schema access are separate&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why we like this approach
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;No static DB password in production&lt;/li&gt;
&lt;li&gt;No extra package in the app&lt;/li&gt;
&lt;li&gt;Token refresh is tied to connection creation, not process startup&lt;/li&gt;
&lt;li&gt;Works cleanly with Postgres.js and Drizzle&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's not the most abstracted setup.&lt;/p&gt;

&lt;p&gt;That's exactly why we like it.&lt;/p&gt;

&lt;p&gt;The real takeaway is bigger than Cloud SQL.&lt;/p&gt;

&lt;p&gt;In 2026, a lot of teams are rediscovering the cost of hidden trust boundaries. If your platform already gives you the secure transport layer, it is worth asking whether your app really needs another package, another auth path, and another thing to maintain. Sometimes the better production pattern is not more abstraction. It is fewer moving parts, with the sharp edges understood.&lt;/p&gt;




&lt;p&gt;Curious if anyone else is doing Cloud SQL IAM auth this way, or if you stuck with the connector package.&lt;/p&gt;

</description>
      <category>node</category>
      <category>googlecloud</category>
      <category>typescript</category>
      <category>postgres</category>
    </item>
  </channel>
</rss>
