<?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: Andreas Quist Batista</title>
    <description>The latest articles on DEV Community by Andreas Quist Batista (@clownay).</description>
    <link>https://dev.to/clownay</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%2F3982896%2Fdf30fb94-cea2-4344-a20d-5887dce3f026.jpeg</url>
      <title>DEV Community: Andreas Quist Batista</title>
      <link>https://dev.to/clownay</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/clownay"/>
    <language>en</language>
    <item>
      <title>Tired of maintaining a compose file for local and a whole other toolchain for prod? I wrote about composing your environment from a catalog of services and deploying it with one tool, from docker compose up to production.</title>
      <dc:creator>Andreas Quist Batista</dc:creator>
      <pubDate>Thu, 18 Jun 2026 21:10:48 +0000</pubDate>
      <link>https://dev.to/clownay/tired-of-maintaining-a-compose-file-for-local-and-a-whole-other-toolchain-for-prod-i-wrote-about-9l5</link>
      <guid>https://dev.to/clownay/tired-of-maintaining-a-compose-file-for-local-and-a-whole-other-toolchain-for-prod-i-wrote-about-9l5</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/clownay/one-config-from-docker-compose-up-to-production-2lp" class="crayons-story__hidden-navigation-link"&gt;One config from `docker compose up` to production&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 href="/clownay" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F3982896%2Fdf30fb94-cea2-4344-a20d-5887dce3f026.jpeg" alt="clownay profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/clownay" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Andreas Quist Batista
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Andreas Quist Batista
                
              
              &lt;div id="story-author-preview-content-3935284" 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="/clownay" 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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3982896%2Fdf30fb94-cea2-4344-a20d-5887dce3f026.jpeg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Andreas Quist Batista&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;/div&gt;
          &lt;a href="https://dev.to/clownay/one-config-from-docker-compose-up-to-production-2lp" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jun 18&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/clownay/one-config-from-docker-compose-up-to-production-2lp" id="article-link-3935284"&gt;
          One config from `docker compose up` to production
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag crayons-tag--filled  " href="/t/showdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;showdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devops"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devops&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/docker"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;docker&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/kubernetes"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;kubernetes&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/clownay/one-config-from-docker-compose-up-to-production-2lp" 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/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;4&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/clownay/one-config-from-docker-compose-up-to-production-2lp#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;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 crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

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

&lt;/div&gt;


</description>
      <category>automation</category>
      <category>devops</category>
      <category>docker</category>
      <category>tooling</category>
    </item>
    <item>
      <title>One config from `docker compose up` to production</title>
      <dc:creator>Andreas Quist Batista</dc:creator>
      <pubDate>Thu, 18 Jun 2026 21:07:55 +0000</pubDate>
      <link>https://dev.to/clownay/one-config-from-docker-compose-up-to-production-2lp</link>
      <guid>https://dev.to/clownay/one-config-from-docker-compose-up-to-production-2lp</guid>
      <description>&lt;p&gt;Here's a workflow most of us just accept: you spin up your local stack with a &lt;code&gt;docker-compose.yml&lt;/code&gt;, and then, to actually ship it, you reach for a completely different toolchain. Helm charts, raw manifests, a GitOps controller, whatever your platform team standardized on. Two representations of the same application, maintained by hand, drifting apart the moment someone's in a hurry.&lt;/p&gt;

&lt;p&gt;I wanted one tool the whole way. The same definitions that bring up my dev environment should also deploy it to staging and prod. Different target, same config.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compose your environment from a catalog
&lt;/h2&gt;

&lt;p&gt;The piece that makes this pleasant is a &lt;strong&gt;catalog of service presets&lt;/strong&gt;. Instead of copy-pasting a Postgres block between six repos, someone curates it once, and you compose your environment out of building blocks:&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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineEnvironment&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="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="c1"&gt;// from the catalog&lt;/span&gt;
    &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;redis&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dependsOn&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;db&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;cache&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;use("postgres")&lt;/code&gt; pulls a curated preset, and your own services sit right next to it. A platform team maintains the catalog (a file, an HTTP endpoint, or an OCI artifact), and developers assemble environments from it. There's even a small visual builder for this. You drag presets onto a canvas, wire up dependencies, and export the config. But the point is the &lt;em&gt;model&lt;/em&gt;: shared building blocks, composed locally.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbkzcazbdgz70qthdv3m5.gif" 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%2Fbkzcazbdgz70qthdv3m5.gif" alt="Kaupang studio" width="599" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then the same command runs everywhere:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kaupang up market                  &lt;span class="c"&gt;# locally, docker compose&lt;/span&gt;
kaupang up market &lt;span class="nt"&gt;--target&lt;/span&gt; prod    &lt;span class="c"&gt;# prod, swarm or kubernetes, same config&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Locally it's Compose. In prod the target says "Swarm" or "Kubernetes" and the &lt;em&gt;same&lt;/em&gt; environment renders to that backend. You stop maintaining two truths.&lt;/p&gt;

&lt;h2&gt;
  
  
  The reason it can be one tool: it's a push tool, not a reconciler
&lt;/h2&gt;

&lt;p&gt;Every modern deploy tool wants to be a control loop. Argo, Flux, the operator pattern. You install an agent, hand it your desired state, and let it reconcile forever. It's a genuinely great model when you need it. It's also a lot of standing machinery, and we've quietly accepted it as the only serious way to ship.&lt;/p&gt;

&lt;p&gt;But a control loop can't be your &lt;code&gt;docker compose up&lt;/code&gt;. You're not going to run an always-on reconciler to bring up your dev stack. The reason one tool can stretch from your laptop to production is that it &lt;em&gt;doesn't&lt;/em&gt; reconcile:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Run it, it acts once, it exits.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No agent, no drift detection, no control loop. That's what makes it identical on a laptop and on a CI agent. The only thing that changes is the ambient target (context, env, secrets). The same property that makes it a good local dev tool is what makes the prod path trustworthy: it's deterministic, and it's the same code path you've run a hundred times locally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy like you build: resolve once, pin, replay
&lt;/h2&gt;

&lt;p&gt;Because it acts once, a deploy can be treated like a build artifact instead of a living system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Images resolve to digests&lt;/strong&gt; at deploy time, so "latest" can't change under you between staging and prod.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Config pins to a bundle&lt;/strong&gt;, a portable, content-addressed artifact you can carry into an airgap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every run is recorded&lt;/strong&gt; in an append-only ledger, so you can replay a deploy or roll back to a known-good snapshot.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It leans on the tools you already have. It shells out to &lt;code&gt;docker&lt;/code&gt;, &lt;code&gt;kubectl&lt;/code&gt;, and &lt;code&gt;oras&lt;/code&gt; rather than reimplementing a registry client or a compose engine. Less surface area, fewer surprises.&lt;/p&gt;

&lt;h2&gt;
  
  
  When you &lt;em&gt;do&lt;/em&gt; want a reconciler
&lt;/h2&gt;

&lt;p&gt;I'm not claiming push beats GitOps. They solve different problems. If you're running a large multi-team fleet where continuous drift-correction is the whole job, a reconciler earns its keep. But there's a long tail of services where you don't want a standing agent. You want to run a deploy, know exactly what happened, and be able to roll it back. And for those, having the same tool from &lt;code&gt;compose up&lt;/code&gt; to production removes a surprising amount of friction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-g&lt;/span&gt; @kaupang/cli
kaupang studio &lt;span class="nt"&gt;--catalog&lt;/span&gt; ./catalog.json   &lt;span class="c"&gt;# the visual builder, on :8080&lt;/span&gt;
&lt;span class="c"&gt;# then:&lt;/span&gt;
kaupang up market
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's early and mostly a solo project, but every backend path (Compose, Swarm, Kubernetes) is exercised end-to-end against real Docker and a &lt;code&gt;kind&lt;/code&gt; cluster in CI, not mocked. Code and docs: &lt;a href="https://github.com/kaupang-dev/kaupang" rel="noopener noreferrer"&gt;https://github.com/kaupang-dev/kaupang&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'd love to hear where you land on this. Is a curated service catalog plus one deploy tool from dev to prod something you'd actually want, or does the reconciler model already cover it for you?&lt;/p&gt;

</description>
      <category>devops</category>
      <category>docker</category>
      <category>kubernetes</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Kaupang: deploy the same config to Docker Compose, Swarm, or Kubernetes</title>
      <dc:creator>Andreas Quist Batista</dc:creator>
      <pubDate>Sat, 13 Jun 2026 16:04:11 +0000</pubDate>
      <link>https://dev.to/clownay/kaupang-deploy-the-same-config-to-docker-compose-swarm-or-kubernetes-1a08</link>
      <guid>https://dev.to/clownay/kaupang-deploy-the-same-config-to-docker-compose-swarm-or-kubernetes-1a08</guid>
      <description>&lt;p&gt;I just released &lt;strong&gt;kaupang&lt;/strong&gt; — Old Norse for a Viking trading hub, where goods from every craft were gathered, packed, and shipped. It's an imperative, push-based deploy&lt;br&gt;
CLI: you point it at a config, it makes a target match it, records exactly what it did, and lets you replay or roll back. The same command runs on your laptop and in CI.&lt;/p&gt;
&lt;h2&gt;
  
  
  The itch
&lt;/h2&gt;

&lt;p&gt;Every project ended up with its own deploy glue — a compose file here, a &lt;code&gt;kubectl apply&lt;/code&gt; there, a hand-rolled promotion script — and none of it behaved the same locally as it did in the pipeline. I wanted &lt;em&gt;one&lt;/em&gt; definition that could target whatever backend a given environment used, run identically everywhere, and make "what I tested is what I ship" the default instead of a hope.&lt;/p&gt;
&lt;h2&gt;
  
  
  What it looks like
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// kaupang.config.ts&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;defineConfig&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;@kaupang/core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;environments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./environments&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shop&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;dockerRepository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ghcr.io/acme&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// environments/api.ts&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;defineEnvironment&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;@kaupang/core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineEnvironment&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shop-api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;ports&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;8080:3000&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kaupang up api &lt;span class="nt"&gt;--target&lt;/span&gt; staging   &lt;span class="c"&gt;# resolve images → pin digests → deploy → record&lt;/span&gt;
kaupang up api &lt;span class="nt"&gt;--dry-run&lt;/span&gt;          &lt;span class="c"&gt;# show the dependency graph + commands, run nothing&lt;/span&gt;
kaupang rollback api &lt;span class="nt"&gt;--target&lt;/span&gt; prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  What makes it different
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Multi-backend from one config — Compose, Swarm, or Kubernetes, same env definition.&lt;/li&gt;
&lt;li&gt;Immutable &amp;amp; auditable — every deploy resolves tags to a digest, pins it, and records the full artifact in a ledger. Staging validates a digest; prod redeploys that exact digest. rollback replays a known-good snapshot.&lt;/li&gt;
&lt;li&gt;Airgap-friendly — pack a "solution" with pinned digests into a portable OCI bundle, ship it over oras, and deploy it with no registry access on the far side.&lt;/li&gt;
&lt;li&gt;Composes with CI, doesn't compete — it's a push tool, not a reconciler. Your pipeline keeps triggers, approvals, and secrets; kaupang owns the deploy recipe.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Status
&lt;/h2&gt;

&lt;p&gt;v0.1.0, MIT. Every deploy path is exercised end-to-end against real Docker and a kind cluster in CI. The Kubernetes backend is intentionally minimal (Namespace + Deployment + Service) — it's for straightforward services, not a Helm replacement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-g&lt;/span&gt; @kaupang/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repo &amp;amp; docs: &lt;a href="https://github.com/kaupang-dev/kaupang" rel="noopener noreferrer"&gt;https://github.com/kaupang-dev/kaupang&lt;/a&gt; — feedback and issues very welcome.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>kubernetes</category>
      <category>docker</category>
      <category>node</category>
    </item>
  </channel>
</rss>
