<?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>Forem: DiPhyx</title>
    <description>The latest articles on Forem by DiPhyx (@diphyx).</description>
    <link>https://forem.com/diphyx</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%2Forganization%2Fprofile_image%2F12461%2F02c67bbc-f307-4b43-b6b2-ee37ecd0168d.png</url>
      <title>Forem: DiPhyx</title>
      <link>https://forem.com/diphyx</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/diphyx"/>
    <language>en</language>
    <item>
      <title>You Just Want Containers — Why Is Installing Docker &amp; Podman Still This Hard?</title>
      <dc:creator>Amir Reza Dalir</dc:creator>
      <pubDate>Mon, 23 Feb 2026 11:14:47 +0000</pubDate>
      <link>https://forem.com/diphyx/you-just-want-containers-why-is-installing-docker-podman-still-this-hard-25a6</link>
      <guid>https://forem.com/diphyx/you-just-want-containers-why-is-installing-docker-podman-still-this-hard-25a6</guid>
      <description>&lt;p&gt;It's 11 PM. Your deadline is tomorrow. The model is ready, the compose file is written, and all you need is &lt;code&gt;docker compose up&lt;/code&gt;. But you're staring at a fresh Ubuntu VM and Docker isn't installed.&lt;/p&gt;

&lt;p&gt;No problem, right? Just install it.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Except the version in the repo is two years old. The docs say to add Docker's official repository. So you start adding GPG keys, configuring apt sources, updating package lists... fifteen minutes later, Docker is running. You pull your image, start the stack, and finally get to work.&lt;/p&gt;

&lt;p&gt;That was the easy version. 😅&lt;/p&gt;

&lt;p&gt;What if you could just type &lt;strong&gt;dock&lt;/strong&gt;er + &lt;strong&gt;pod&lt;/strong&gt;man and have it work — anywhere?&lt;/p&gt;




&lt;h2&gt;
  
  
  When the easy version doesn't exist
&lt;/h2&gt;

&lt;p&gt;🔬 &lt;strong&gt;The researcher.&lt;/strong&gt; You're on a university HPC cluster with a containerized pipeline — a deep learning training job, a genomics workflow, a physics simulation. You need Docker or Podman. But you don't have &lt;code&gt;sudo&lt;/code&gt;. You can't install packages. The sysadmin takes days to respond to tickets. Your deadline doesn't care.&lt;/p&gt;

&lt;p&gt;🧠 &lt;strong&gt;The ML engineer.&lt;/strong&gt; You're spinning up GPU instances on a cloud provider. The VM comes with a minimal OS — no &lt;code&gt;apt&lt;/code&gt;, no &lt;code&gt;yum&lt;/code&gt;, no package manager at all. Just a kernel and a shell. You need Docker, but the official install script assumes you have a full distro underneath.&lt;/p&gt;

&lt;p&gt;🔒 &lt;strong&gt;The restricted environment.&lt;/strong&gt; You're working in a secure facility. The machines are air-gapped — no internet. You can transfer files in via USB, but every tool you need has to be bundled and self-contained.&lt;/p&gt;

&lt;p&gt;🔀 &lt;strong&gt;The mixed-runtime team.&lt;/strong&gt; Your team standardized on Podman for security reasons, but half your tooling still expects Docker. You need both, and switching between them shouldn't require reconfiguring everything.&lt;/p&gt;

&lt;p&gt;These aren't edge cases. For researchers, data scientists, and engineers working outside the typical cloud-native setup — this is everyday reality.&lt;/p&gt;




&lt;h2&gt;
  
  
  The official path is paved, but narrow
&lt;/h2&gt;

&lt;p&gt;Docker does provide a convenience script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://get.docker.com | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's well-maintained and it works. But it needs &lt;code&gt;sudo&lt;/code&gt;. It needs a package manager. It needs internet access. It only supports &lt;a href="https://docs.docker.com/engine/install/" rel="noopener noreferrer"&gt;specific distributions&lt;/a&gt;. And it only installs Docker — no Podman, no rootless mode out of the box.&lt;/p&gt;

&lt;p&gt;For Podman, the story is worse. There's no &lt;code&gt;get.podman.com&lt;/code&gt;. Your options are distro packages (often outdated, sometimes missing entirely) or building from source. That means cloning seven separate repositories — Podman itself, plus crun, conmon, netavark, aardvark-dns, slirp4netns, and fuse-overlayfs — and compiling Go, Rust, and C code. On a machine where you can't even &lt;code&gt;sudo apt install gcc&lt;/code&gt;, that's a dead end. 🛑&lt;/p&gt;

&lt;p&gt;And Compose? That's another installation step on top of everything else.&lt;/p&gt;

&lt;p&gt;The tools exist. The documentation exists. But the path from "I need containers" to "I have containers" is full of assumptions about your environment that don't always hold.&lt;/p&gt;




&lt;h2&gt;
  
  
  Removing the assumptions
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/diphyx/dockpod" rel="noopener noreferrer"&gt;dockpod&lt;/a&gt; (&lt;strong&gt;dock&lt;/strong&gt;er + &lt;strong&gt;pod&lt;/strong&gt;man, quick setup) was built around a simple idea: installing a container runtime should work the same way everywhere.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; diphyx.github.io/dockpod/setup.sh | bash
dockpod &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh71ulum7rp2ols5qrxi4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh71ulum7rp2ols5qrxi4.png" alt="dockpod setup" width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's the entire setup. An interactive menu asks which runtime you want — Docker, Podman, or both. Compose is included automatically with either choice. No &lt;code&gt;sudo&lt;/code&gt; required. No package manager. No GPG keys. No repository configuration.&lt;/p&gt;

&lt;p&gt;It works on any Linux system with kernel 4.18+ and systemd — which covers essentially every modern distro and cloud image. ✅&lt;/p&gt;




&lt;h2&gt;
  
  
  Under the hood
&lt;/h2&gt;

&lt;p&gt;When you run &lt;code&gt;dockpod install&lt;/code&gt;, it checks your system, detects your architecture, and pulls prebuilt static binaries — the same ones compiled from the official upstream sources. It places them in the right directories, writes configuration files, sets up systemd services, and verifies the installation by actually running a container.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft15f2v1ryc0q5xpnucc7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft15f2v1ryc0q5xpnucc7.png" alt="dockpod install" width="800" height="610"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🛡️ If you have root, binaries go to &lt;code&gt;/usr/local/bin/&lt;/code&gt; and services run system-wide. If you don't, everything goes into &lt;code&gt;~/.local/bin/&lt;/code&gt; and runs as user-scoped systemd services. Docker uses its rootless mode, Podman works rootless natively. Either way, you end up with a fully working runtime without ever typing &lt;code&gt;sudo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;🔌 Compose is included out of the box — installed as both a standalone &lt;code&gt;docker-compose&lt;/code&gt; binary and a Docker CLI plugin (&lt;code&gt;docker compose&lt;/code&gt;). When Podman is installed, dockpod creates a &lt;code&gt;podman-compose&lt;/code&gt; symlink automatically, so your existing compose files work with either runtime:&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 up &lt;span class="nt"&gt;-d&lt;/span&gt;       &lt;span class="c"&gt;# with Docker&lt;/span&gt;
podman-compose up &lt;span class="nt"&gt;-d&lt;/span&gt;       &lt;span class="c"&gt;# with Podman — same file, no changes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔀 Need both Docker and Podman? Install both, then switch between them instantly. Your compose files, your scripts, your muscle memory — everything stays the same. Only the engine underneath changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dockpod switch podman
dockpod switch docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  No internet? No problem
&lt;/h2&gt;

&lt;p&gt;This is the part that matters most for restricted environments.&lt;/p&gt;

&lt;p&gt;dockpod publishes architecture-specific tarballs with every release. Each one is self-contained — Docker, Podman, Compose, and all their dependencies bundled together. Nothing is downloaded during installation.&lt;/p&gt;

&lt;p&gt;Grab the tarball on a connected machine, transfer it however you can — USB, scp, a shared drive — and install on the target without a single network call:&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;tar&lt;/span&gt; &lt;span class="nt"&gt;-xzf&lt;/span&gt; dockpod-v2.0.0-amd64.tar.gz &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;dockpod-v2.0.0-amd64
./dockpod.sh &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--offline&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For labs, secure facilities, and isolated clusters, this is often the only practical way to get containers running without a lengthy approval process.&lt;/p&gt;




&lt;h2&gt;
  
  
  Give it a try
&lt;/h2&gt;

&lt;p&gt;If you've ever spent more time installing a container runtime than actually using it — that's exactly what dockpod is for.&lt;/p&gt;

&lt;p&gt;If it saves you time, share it with your team, your lab, or that colleague who's still struggling to get containers running.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/diphyx/dockpod" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://github.com/diphyx/dockpod/blob/main/LICENSE" rel="noopener noreferrer"&gt;MIT licensed&lt;/a&gt; · Built by &lt;a href="https://github.com/diphyx" rel="noopener noreferrer"&gt;DiPhyx&lt;/a&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>podman</category>
      <category>containers</category>
      <category>linux</category>
    </item>
    <item>
      <title>Eliminate 80% of Nuxt store boilerplate with a single createStore call</title>
      <dc:creator>Amir Reza Dalir</dc:creator>
      <pubDate>Tue, 10 Feb 2026 20:00:29 +0000</pubDate>
      <link>https://forem.com/diphyx/eliminate-80-of-nuxt-store-boilerplate-with-a-single-createstore-call-o42</link>
      <guid>https://forem.com/diphyx/eliminate-80-of-nuxt-store-boilerplate-with-a-single-createstore-call-o42</guid>
      <description>&lt;p&gt;Every Nuxt app has the same problem.&lt;/p&gt;

&lt;p&gt;For every API resource — users, posts, products, orders — the same code gets written:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Define a TypeScript interface&lt;/li&gt;
&lt;li&gt;Create reactive state (&lt;code&gt;ref&lt;/code&gt;, &lt;code&gt;reactive&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Create a loading ref&lt;/li&gt;
&lt;li&gt;Create an error ref&lt;/li&gt;
&lt;li&gt;Write a fetch function with try/catch/finally&lt;/li&gt;
&lt;li&gt;Repeat for create, update, delete&lt;/li&gt;
&lt;li&gt;Repeat for the next resource&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://github.com/diphyx/harlemify" rel="noopener noreferrer"&gt;Harlemify&lt;/a&gt; is an open-source Nuxt module by &lt;a href="https://github.com/diphyx" rel="noopener noreferrer"&gt;Diphyx&lt;/a&gt; that eliminates this repetition. It's built on top of &lt;a href="https://harlemjs.com/" rel="noopener noreferrer"&gt;Harlem&lt;/a&gt;, a powerful and extensible state management library for Vue 3 — so the reactive store layer is solid and battle-tested.&lt;/p&gt;

&lt;h2&gt;
  
  
  Define your data shape once, get everything else for free
&lt;/h2&gt;

&lt;p&gt;Harlemify generates typed stores from Zod schemas. Here's what a full CRUD store looks like:&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;createStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ModelOneMode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ModelManyMode&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;@diphyx/harlemify/runtime&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;userShape&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;factory&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;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;email&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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createStore&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nf"&gt;model&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;many&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="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;current&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userShape&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="na"&gt;list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;many&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userShape&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;view&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="k"&gt;from&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="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="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;current&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;list&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="nf"&gt;action&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;api&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="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/users&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="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;list&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModelManyMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SET&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/users/:id&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="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;current&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModelOneMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SET&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/users&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="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;list&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModelManyMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ADD&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="na"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/users/:id&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="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;list&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModelManyMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REMOVE&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No separate type definitions. No manual loading/error refs. No try/catch boilerplate.&lt;/p&gt;

&lt;h2&gt;
  
  
  What comes out of this single definition
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Typed models&lt;/strong&gt; — &lt;code&gt;current&lt;/code&gt; holds a single user, &lt;code&gt;list&lt;/code&gt; holds a collection. Both are fully typed from the Zod shape.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reactive views&lt;/strong&gt; — &lt;code&gt;user&lt;/code&gt; and &lt;code&gt;users&lt;/code&gt; are computed refs that update whenever the underlying model changes. Powered by Harlem's reactive store engine under the hood.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;API actions with auto-commit&lt;/strong&gt; — Each action knows which model to update and how (SET replaces, ADD appends, REMOVE deletes by identifier).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automatic status tracking&lt;/strong&gt; — Every action exposes &lt;code&gt;loading&lt;/code&gt;, &lt;code&gt;error&lt;/code&gt;, and &lt;code&gt;status&lt;/code&gt; without writing a single ref.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using it in components
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;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;execute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useStoreAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;list&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useStoreView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;v-if=&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;v-else-if=&lt;/span&gt;&lt;span class="s"&gt;"!loading"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;v-for=&lt;/span&gt;&lt;span class="s"&gt;"user in users"&lt;/span&gt; &lt;span class="na"&gt;:key=&lt;/span&gt;&lt;span class="s"&gt;"user.id"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three composables cover everything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;useStoreAction&lt;/code&gt; — execute actions, track loading/error/status&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;useStoreView&lt;/code&gt; — access reactive computed state&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;useStoreModel&lt;/code&gt; — mutate state directly (set, patch, add, remove, reset)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Beyond basic state management
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Concurrency control
&lt;/h3&gt;

&lt;p&gt;Every action can be configured with a concurrency strategy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;BLOCK&lt;/strong&gt; — throw if the action is already running&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SKIP&lt;/strong&gt; — return the existing promise&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CANCEL&lt;/strong&gt; — abort the previous call, start a new one&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ALLOW&lt;/strong&gt; — run both in parallel&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No more debouncing hacks or manual AbortController wiring.&lt;/p&gt;

&lt;h3&gt;
  
  
  Record collections
&lt;/h3&gt;

&lt;p&gt;For grouped data (e.g., users by team), use record mode:&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;model&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;many&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="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;byTeam&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;many&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userShape&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModelManyKind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RECORD&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;This gives you &lt;code&gt;{ teamA: [...users], teamB: [...users] }&lt;/code&gt; with typed CRUD operations per key.&lt;/p&gt;

&lt;h3&gt;
  
  
  Handler actions
&lt;/h3&gt;

&lt;p&gt;Not every action is an API call. Custom logic gets first-class support:&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;action&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;handler&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="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;sortByName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;handler&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="nx"&gt;model&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sorted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;localeCompare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sorted&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;Handlers have full access to models and views, with the same status tracking as API actions.&lt;/p&gt;

&lt;h3&gt;
  
  
  SSR with automatic hydration
&lt;/h3&gt;

&lt;p&gt;Harlemify uses Harlem's SSR plugin (&lt;code&gt;@harlem/plugin-ssr&lt;/code&gt;) under the hood. Server-rendered state is automatically hydrated on the client — no manual transfer or serialization needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it compares
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Manual / Pinia&lt;/th&gt;
&lt;th&gt;Harlemify&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Schema&lt;/td&gt;
&lt;td&gt;Separate TypeScript interfaces&lt;/td&gt;
&lt;td&gt;Zod shape — types + validation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API calls&lt;/td&gt;
&lt;td&gt;Manual fetch + state updates&lt;/td&gt;
&lt;td&gt;Declarative with auto-commit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Loading/error&lt;/td&gt;
&lt;td&gt;Manual refs per action&lt;/td&gt;
&lt;td&gt;Automatic per action&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Concurrency&lt;/td&gt;
&lt;td&gt;Not built-in&lt;/td&gt;
&lt;td&gt;Block, Skip, Cancel, Allow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Collections&lt;/td&gt;
&lt;td&gt;Manual array management&lt;/td&gt;
&lt;td&gt;Built-in modes (SET, ADD, PATCH, REMOVE)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSR&lt;/td&gt;
&lt;td&gt;Plugin required&lt;/td&gt;
&lt;td&gt;Built-in via Harlem SSR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lines per resource&lt;/td&gt;
&lt;td&gt;~50-60&lt;/td&gt;
&lt;td&gt;~15-20&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Harlemify is not a Pinia replacement. Pinia is great for general-purpose client state. Harlemify is built on top of Harlem and optimized for &lt;strong&gt;API-driven data&lt;/strong&gt; — the CRUD resources that make up 80% of most apps.&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 &lt;span class="nb"&gt;install&lt;/span&gt; @diphyx/harlemify
&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;// nuxt.config.ts&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;defineNuxtConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;modules&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;@diphyx/harlemify&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;ul&gt;
&lt;li&gt;&lt;a href="https://diphyx.github.io/harlemify/" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/diphyx/harlemify" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/@diphyx/harlemify" rel="noopener noreferrer"&gt;npm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feedback and contributions are welcome — star the repo if it's useful, or open an issue for anything that's missing.&lt;/p&gt;

</description>
      <category>vue</category>
      <category>nuxt</category>
      <category>typescript</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
