<?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: Ramananda Panda</title>
    <description>The latest articles on Forem by Ramananda Panda (@rp01).</description>
    <link>https://forem.com/rp01</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%2F2853941%2Fedd9a1f5-d8ee-420a-8278-79fc631f4ad1.jpeg</url>
      <title>Forem: Ramananda Panda</title>
      <link>https://forem.com/rp01</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/rp01"/>
    <language>en</language>
    <item>
      <title>🚀 I Built QNVS — A Node.js Version Manager That Doesn't Need Admin Rights (Yes, Even on Windows)</title>
      <dc:creator>Ramananda Panda</dc:creator>
      <pubDate>Thu, 09 Apr 2026 13:27:13 +0000</pubDate>
      <link>https://forem.com/rp01/i-built-qnvs-a-nodejs-version-manager-that-doesnt-need-admin-rights-yes-even-on-windows-20k1</link>
      <guid>https://forem.com/rp01/i-built-qnvs-a-nodejs-version-manager-that-doesnt-need-admin-rights-yes-even-on-windows-20k1</guid>
      <description>&lt;p&gt;&lt;strong&gt;No sudo. No IT ticket. No drama. Just &lt;code&gt;qnvs&lt;/code&gt; and vibes.&lt;/strong&gt;&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%2Fimages.unsplash.com%2Fphoto-1498050108023-c5249f4df085%3Fw%3D1200" 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%2Fimages.unsplash.com%2Fphoto-1498050108023-c5249f4df085%3Fw%3D1200" alt="Hero image — developer at a clean workstation" width="1200" height="799"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Suggested hero image: &lt;a href="https://unsplash.com/photos/m_HRfLhgABo" rel="noopener noreferrer"&gt;Unsplash — Christopher Gower (Developer workstation)&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  The Problem That Made Me Build This
&lt;/h2&gt;

&lt;p&gt;Picture this: Monday morning. You're a developer at a company where IT guards the admin password like it's nuclear launch codes. You need Node.js 22 for a new project, but your machine has Node 18. The options?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Submit an IT ticket.&lt;/strong&gt; Estimated response: 3-7 business days. Maybe. If Mercury is in retrograde.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use nvm.&lt;/strong&gt; Great on macOS/Linux! On Windows? &lt;em&gt;[laughs in Group Policy]&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use nvm-windows.&lt;/strong&gt; Requires admin privileges to create symlinks. Back to step 1.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Download Node.js manually.&lt;/strong&gt; Sure, if you enjoy living like it's 2009.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of these worked for me. So instead of rage-quitting, I rage-coded.&lt;/p&gt;

&lt;p&gt;Meet &lt;strong&gt;&lt;a href="https://github.com/qnvs/qnvs" rel="noopener noreferrer"&gt;QNVS&lt;/a&gt;&lt;/strong&gt; — Quick Node Version Switcher. A single binary, zero-dependency, cross-platform, no-admin-required Node.js version manager with a gorgeous interactive TUI. Built in Go. Ships in ~10MB. Works everywhere.&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%2Fimages.unsplash.com%2Fphoto-1555066931-4365d14bab8c%3Fw%3D1200" 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%2Fimages.unsplash.com%2Fphoto-1555066931-4365d14bab8c%3Fw%3D1200" alt="Terminal with beautiful UI" width="1200" height="800"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Suggested image: &lt;a href="https://unsplash.com/photos/4hbJ-eymZ1o" rel="noopener noreferrer"&gt;Unsplash — Florian Olivo (Terminal/Code)&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Wait, What Does "No Admin Required" Actually Mean?
&lt;/h2&gt;

&lt;p&gt;Let me be crystal clear because this is the &lt;em&gt;entire reason&lt;/em&gt; QNVS exists:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ No &lt;code&gt;sudo&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;❌ No Administrator PowerShell&lt;/li&gt;
&lt;li&gt;❌ No Developer Mode toggle&lt;/li&gt;
&lt;li&gt;❌ No Group Policy exceptions&lt;/li&gt;
&lt;li&gt;❌ No IT tickets&lt;/li&gt;
&lt;li&gt;❌ No "please sir, may I have write access to Program Files"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;QNVS lives entirely in &lt;strong&gt;user space&lt;/strong&gt;. On macOS/Linux, it chills in &lt;code&gt;~/.qnvs&lt;/code&gt;. On Windows, it sits in &lt;code&gt;%LOCALAPPDATA%\qnvs&lt;/code&gt;. That's it. Your home directory. The one place on the computer that's actually &lt;em&gt;yours&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;You download the binary. You run &lt;code&gt;qnvs setup&lt;/code&gt;. You install Node.js versions. You switch between them. You feel powerful. All without elevating a single privilege.&lt;/p&gt;


&lt;h2&gt;
  
  
  The TUI That Made My Terminal Beautiful ✨
&lt;/h2&gt;

&lt;p&gt;Look, I could've just built a boring CLI. But I had access to the &lt;a href="https://charm.sh/" rel="noopener noreferrer"&gt;Charm&lt;/a&gt; ecosystem — &lt;code&gt;bubbletea&lt;/code&gt;, &lt;code&gt;bubbles&lt;/code&gt;, &lt;code&gt;lipgloss&lt;/code&gt; — and honestly, if you're going to build a terminal tool in 2025, you owe it to yourself to make it &lt;em&gt;pretty&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;qnvs&lt;/code&gt; with no arguments and you get this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; ██████╗ ███╗   ██╗██╗   ██╗███████╗
██╔═══██╗████╗  ██║██║   ██║██╔════╝
██║   ██║██╔██╗ ██║██║   ██║███████╗
██║▄▄ ██║██║╚██╗██║╚██╗ ██╔╝╚════██║
╚██████╔╝██║ ╚████║ ╚████╔╝ ███████║
 ╚══▀▀═╝ ╚═╝  ╚═══╝  ╚═══╝  ╚══════╝
  Quick Node Version Switcher • No admin required

╭──────────────────────────────────────────────╮
│                                              │
│  ▸ 📦  Install Node.js                       │
│        Download and install a new version    │
│                                              │
│    📋  List/Switch                            │
│    🗑️   Uninstall                             │
│    🔧  Setup                                  │
│    🔓  Toggle TLS Skip                        │
│    ❓  Help                                   │
│    👋  Exit                                   │
│                                              │
│   2 installed   Active: v22.22.0             │
╰──────────────────────────────────────────────╯

  ↑↓ navigate │ ⏎ select │ q quit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Arrow keys to navigate. Enter to select. &lt;code&gt;q&lt;/code&gt; to quit. That's the &lt;em&gt;entire&lt;/em&gt; learning curve.&lt;/p&gt;

&lt;p&gt;No flags to memorize. No &lt;code&gt;--help&lt;/code&gt; to desperately consult. Just a menu. With emojis. Like civilized people.&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%2Fimages.unsplash.com%2Fphoto-1595225476474-87563907a212%3Fw%3D1200" 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%2Fimages.unsplash.com%2Fphoto-1595225476474-87563907a212%3Fw%3D1200" alt="Colorful keyboard / aesthetic dev setup" width="1200" height="800"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Suggested image: &lt;a href="https://unsplash.com/photos/hwLAI5lRhdM" rel="noopener noreferrer"&gt;Unsplash — Clay Banks (Colorful keyboard)&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  The Windows Problem (And How I Solved It)
&lt;/h2&gt;

&lt;p&gt;Here's the dirty secret of Node.js version managers on Windows: &lt;strong&gt;they almost all rely on symlinks or junctions&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Symlinks&lt;/strong&gt; need Developer Mode or admin rights&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Directory junctions&lt;/strong&gt; (&lt;code&gt;mklink /J&lt;/code&gt;) &lt;em&gt;usually&lt;/em&gt; work without admin... until your company's Group Policy says "nah"&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cue developer tears&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;QNVS takes a &lt;strong&gt;hybrid approach&lt;/strong&gt; that I'm unreasonably proud of:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; Try to create a directory junction. This works on most Windows machines without admin rights and gives you fast, transparent version switching.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; If junctions fail (thanks, Group Policy), QNVS &lt;em&gt;automatically&lt;/em&gt; falls back to &lt;strong&gt;shim mode&lt;/strong&gt; — it creates tiny &lt;code&gt;.cmd&lt;/code&gt; wrapper scripts in &lt;code&gt;~/.qnvs/bin/&lt;/code&gt; that redirect to the active Node.js version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@echo off
"C:\Users\you\AppData\Local\qnvs\versions\v22.22.0\node.exe" %*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. A &lt;code&gt;.cmd&lt;/code&gt; file. Group Policy can't block &lt;code&gt;.cmd&lt;/code&gt; files because that would break &lt;em&gt;literally everything else on Windows&lt;/em&gt;. It's not a hack — it's a feature.&lt;/p&gt;

&lt;p&gt;The fallback is completely automatic and transparent. You don't configure anything. You don't even know it happened. QNVS just... works.&lt;/p&gt;




&lt;h2&gt;
  
  
  The CLI: For When You Know What You Want
&lt;/h2&gt;

&lt;p&gt;The interactive TUI is great for exploring, but sometimes you just want to get in, switch versions, and get out. The CLI has your back:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Install Node 22 (latest 22.x.x)
qnvs install 22

# Install the latest LTS
qnvs install lts

# Install a specific version
qnvs install 20.10.0

# Switch versions
qnvs use 22

# See what you've got
qnvs list

# What's active?
qnvs current
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Version resolution is smart. Type &lt;code&gt;22&lt;/code&gt; and QNVS fetches the latest &lt;code&gt;22.x.x&lt;/code&gt; from nodejs.org. Type &lt;code&gt;lts&lt;/code&gt; and it finds the latest Long Term Support release. Type &lt;code&gt;latest&lt;/code&gt; and... you get the latest. Revolutionary stuff.&lt;/p&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;What It Does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;qnvs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Launch the interactive TUI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;qnvs install &amp;lt;version&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Download and install a version&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;qnvs use &amp;lt;version&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Switch to an installed version&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;qnvs list&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List installed versions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;qnvs current&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show the active version&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;qnvs uninstall &amp;lt;version&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove a version&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;qnvs setup&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Initialize QNVS + configure PATH&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Corporate VPN? No Problem.
&lt;/h2&gt;

&lt;p&gt;Raise your hand if you've ever seen this error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x509: certificate signed by unknown authority
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're behind a corporate VPN like &lt;strong&gt;Cato&lt;/strong&gt;, &lt;strong&gt;Zscaler&lt;/strong&gt;, or &lt;strong&gt;Palo Alto&lt;/strong&gt;, your company is probably doing TLS inspection — which means your HTTPS requests are getting re-signed by a corporate certificate that your tools don't trust.&lt;/p&gt;

&lt;p&gt;Most tools: "Figure it out yourself. Here's a 47-step Stack Overflow thread."&lt;/p&gt;

&lt;p&gt;QNVS: "Toggle a switch."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CLI:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;qnvs install 22 --insecure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Interactive mode:&lt;/strong&gt; Just select &lt;strong&gt;"🔓 Toggle TLS Skip"&lt;/strong&gt; from the menu before installing.&lt;/p&gt;

&lt;p&gt;Is it ideal? No. TLS verification exists for good reasons. But when you're on a locked-down corporate machine and the VPN is doing inspection, this beats "can't install Node.js at all" every single time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Go? (Again)
&lt;/h2&gt;

&lt;p&gt;I keep building things in Go and people keep asking why. So here's the elevator pitch:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Single binary.&lt;/strong&gt; No runtime. No &lt;code&gt;node_modules&lt;/code&gt;. No Python virtual environment. No Java classpath. Just one file. Copy it. Run it. Done.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cross-compilation is stupid easy.&lt;/strong&gt; One command gives me binaries for Windows/macOS/Linux across amd64 and arm64. Six platforms, zero hassle:&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;GOOS=windows GOARCH=amd64 go build -o qnvs-windows-amd64.exe .
GOOS=darwin  GOARCH=arm64  go build -o qnvs-macos-arm64 .
GOOS=linux   GOARCH=amd64  go build -o qnvs-linux-amd64 .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Charm ecosystem.&lt;/strong&gt; Bubbletea + Bubbles + Lipgloss = gorgeous terminal UIs with minimal effort. It's like React but for terminals and without the existential crisis of choosing a state management library.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;~10MB binary.&lt;/strong&gt; The entire tool — TUI, version resolution, download with progress bars, archive extraction, platform detection — fits in the space of about 3 JPEG photos from your phone.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&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%2Fimages.unsplash.com%2Fphoto-1611532736597-de2d4265fba3%3Fw%3D1200" 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%2Fimages.unsplash.com%2Fphoto-1611532736597-de2d4265fba3%3Fw%3D1200" alt="Gopher / Go mascot" width="1200" height="1800"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Suggested image: &lt;a href="https://gopherize.me" rel="noopener noreferrer"&gt;Gopherize.me&lt;/a&gt; for a custom gopher, or &lt;a href="https://unsplash.com/s/photos/golang" rel="noopener noreferrer"&gt;Unsplash — Go-related imagery&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  How It Actually Works Under The Hood
&lt;/h2&gt;

&lt;p&gt;For the curious (and the people who read source code for fun — I see you), here's the architecture:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The whole project is two files:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;main.go&lt;/code&gt; — The core: version resolution, downloading, extraction, symlink/junction/shim management, CLI handling&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;interactive.go&lt;/code&gt; — The entire TUI, built on Bubbletea's Elm architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Version resolution&lt;/strong&gt; hits &lt;code&gt;https://nodejs.org/dist/index.json&lt;/code&gt;, parses the JSON, and fuzzy-matches your input. &lt;code&gt;22&lt;/code&gt; → latest &lt;code&gt;v22.x.x&lt;/code&gt;. &lt;code&gt;lts&lt;/code&gt; → latest release where the &lt;code&gt;lts&lt;/code&gt; field is a string (Node.js marks LTS versions with a codename like &lt;code&gt;"Jod"&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Downloading&lt;/strong&gt; uses a custom progress bar (Charm's &lt;code&gt;progress&lt;/code&gt; component) that shows real-time MB progress. It does a &lt;code&gt;HEAD&lt;/code&gt; request first to get the content length, then streams the download with a 32KB buffer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Extraction&lt;/strong&gt; handles both &lt;code&gt;.tar.gz&lt;/code&gt; (macOS/Linux) and &lt;code&gt;.zip&lt;/code&gt; (Windows) natively — no &lt;code&gt;tar&lt;/code&gt; or &lt;code&gt;unzip&lt;/code&gt; binary needed. Pure Go. It even handles symlinks in tar archives (npm/npx are symlinks in the Node.js distribution).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Switching&lt;/strong&gt; is where it gets spicy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unix:&lt;/strong&gt; Swap a symlink. &lt;code&gt;~/.qnvs/current&lt;/code&gt; → &lt;code&gt;~/.qnvs/versions/v22.22.0&lt;/code&gt;. Done.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Windows (happy path):&lt;/strong&gt; Create a directory junction. Same concept, Windows flavor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Windows (corporate dystopia):&lt;/strong&gt; Generate &lt;code&gt;.cmd&lt;/code&gt; shims. Same result, different mechanism.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Installation: Pick Your Poison
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;macOS / Linux:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -L https://github.com/qnvs/qnvs/releases/latest/download/qnvs-linux-amd64 -o qnvs
chmod +x qnvs
./qnvs setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Windows (PowerShell):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Invoke-WebRequest -Uri "https://github.com/qnvs/qnvs/releases/latest/download/qnvs-windows-amd64.exe" -OutFile "qnvs.exe"
.\qnvs.exe setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Build from source:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/qnvs/qnvs.git
cd qnvs
go build -o qnvs .
./qnvs setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;setup&lt;/code&gt; creates the directory structure, copies the binary to &lt;code&gt;~/.qnvs/bin/&lt;/code&gt;, and even tries to auto-append the PATH export to your &lt;code&gt;.bashrc&lt;/code&gt; or &lt;code&gt;.zshrc&lt;/code&gt;. On Windows, it tells you exactly what to add to your PATH. No guessing.&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%2Fimages.unsplash.com%2Fphoto-1474631245212-32dc3c8310c6%3Fw%3D1200" 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%2Fimages.unsplash.com%2Fphoto-1474631245212-32dc3c8310c6%3Fw%3D1200" alt="Light bulb / idea / inspiration" width="1200" height="962"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Suggested image: &lt;a href="https://unsplash.com/photos/7e2pe9wjL9M" rel="noopener noreferrer"&gt;Unsplash — Riccardo Annandale (Light bulb)&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  QNVS vs. The Competition
&lt;/h2&gt;

&lt;p&gt;Let's be honest — there are other version managers out there. Here's where QNVS stands:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;QNVS&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;nvm&lt;/th&gt;
&lt;th&gt;nvm-windows&lt;/th&gt;
&lt;th&gt;fnm&lt;/th&gt;
&lt;th&gt;Volta&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;No admin required&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;⚠️&lt;/td&gt;
&lt;td&gt;⚠️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows support&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Works behind corporate VPN&lt;/td&gt;
&lt;td&gt;✅ (built-in)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interactive TUI&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Single binary&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Corporate Windows (no junctions)&lt;/td&gt;
&lt;td&gt;✅ (auto shim)&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zero dependencies&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌ (bash)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;strong&gt;corporate Windows&lt;/strong&gt; row is the killer feature. If you've ever been stuck on a locked-down Windows machine where &lt;code&gt;mklink&lt;/code&gt; is blocked and Developer Mode is disabled, you know the pain. QNVS is the first version manager I know of that handles this gracefully with its automatic shim fallback.&lt;/p&gt;




&lt;h2&gt;
  
  
  Who Is This For?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🏢 &lt;strong&gt;Corporate developers&lt;/strong&gt; trapped behind Group Policy and VPN inspection&lt;/li&gt;
&lt;li&gt;💻 &lt;strong&gt;Windows users&lt;/strong&gt; who are tired of "requires admin" being the answer to everything&lt;/li&gt;
&lt;li&gt;🎨 &lt;strong&gt;TUI enthusiasts&lt;/strong&gt; who believe CLI tools should be beautiful&lt;/li&gt;
&lt;li&gt;🏃 &lt;strong&gt;Developers who hate bloat&lt;/strong&gt; — one binary, no runtime, no install scripts&lt;/li&gt;
&lt;li&gt;🔄 &lt;strong&gt;Anyone juggling multiple Node.js projects&lt;/strong&gt; with different version requirements&lt;/li&gt;
&lt;li&gt;🆕 &lt;strong&gt;Beginners&lt;/strong&gt; who find &lt;code&gt;nvm&lt;/code&gt; confusing — just run &lt;code&gt;qnvs&lt;/code&gt; and use the arrow keys&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've ever Googled "how to install Node.js without admin rights" at 11 PM on a work laptop... I built this for you.&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%2Fimages.unsplash.com%2Fphoto-1513151233558-d860c5398176%3Fw%3D1200" 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%2Fimages.unsplash.com%2Fphoto-1513151233558-d860c5398176%3Fw%3D1200" alt="Celebration / confetti" width="1200" height="800"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Suggested image: &lt;a href="https://unsplash.com/photos/Xaanw0s0pMk" rel="noopener noreferrer"&gt;Unsplash — Jason Leung (Confetti)&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;QNVS is at &lt;strong&gt;v1.1.3&lt;/strong&gt; and I'm actively working on it. Things rattling around in my brain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📌 &lt;strong&gt;Auto-detect &lt;code&gt;.nvmrc&lt;/code&gt; / &lt;code&gt;.node-version&lt;/code&gt;&lt;/strong&gt; — walk into a project directory and QNVS switches automatically&lt;/li&gt;
&lt;li&gt;🔄 &lt;strong&gt;Self-update&lt;/strong&gt; — &lt;code&gt;qnvs update&lt;/code&gt; to grab the latest QNVS binary&lt;/li&gt;
&lt;li&gt;📦 &lt;strong&gt;Package manager support&lt;/strong&gt; — install and manage &lt;code&gt;pnpm&lt;/code&gt;/&lt;code&gt;yarn&lt;/code&gt; alongside Node&lt;/li&gt;
&lt;li&gt;🪟 &lt;strong&gt;Windows code signing&lt;/strong&gt; — so you stop getting the "Unknown Publisher" warning&lt;/li&gt;
&lt;li&gt;🌐 &lt;strong&gt;Mirror support&lt;/strong&gt; — for environments that can't reach nodejs.org directly&lt;/li&gt;
&lt;li&gt;📊 &lt;strong&gt;Disk usage display&lt;/strong&gt; — see how much space each version is eating&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Give It a Spin ⭐
&lt;/h2&gt;

&lt;p&gt;QNVS is &lt;strong&gt;open-source&lt;/strong&gt; (MIT licensed) and lives at &lt;strong&gt;&lt;a href="https://github.com/qnvs/qnvs" rel="noopener noreferrer"&gt;github.com/qnvs/qnvs&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Three steps to happiness:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download the binary for your platform from &lt;a href="https://github.com/qnvs/qnvs/releases" rel="noopener noreferrer"&gt;Releases&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;qnvs setup&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;qnvs&lt;/code&gt; and bask in the TUI glow&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Star the repo if it saved you from filing an IT ticket. Open an issue if something's broken. Submit a PR if you want to make it better. Or just enjoy switching Node versions without asking anyone's permission for once in your corporate life.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with 🐹 Go, the ✨ Charm ecosystem, and a deep resentment for "Please contact your system administrator."&lt;/em&gt;&lt;/p&gt;




</description>
      <category>cli</category>
      <category>node</category>
      <category>showdev</category>
      <category>tooling</category>
    </item>
    <item>
      <title>🚀 I Built PQPM — A Process Manager That Doesn't Care What Language You Speak</title>
      <dc:creator>Ramananda Panda</dc:creator>
      <pubDate>Thu, 09 Apr 2026 06:13:49 +0000</pubDate>
      <link>https://forem.com/rp01/i-built-pqpm-a-process-manager-that-doesnt-care-what-language-you-speak-npp</link>
      <guid>https://forem.com/rp01/i-built-pqpm-a-process-manager-that-doesnt-care-what-language-you-speak-npp</guid>
      <description>&lt;p&gt;And yes, your PHP queue workers, Go binaries, and Python bots can finally coexist in peace.**&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%2Fimages.unsplash.com%2Fphoto-1558494949-ef010cbdcc31%3Fw%3D1200" 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%2Fimages.unsplash.com%2Fphoto-1558494949-ef010cbdcc31%3Fw%3D1200" alt="Hero image — servers in a data center" width="1200" height="673"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Suggested hero image: &lt;a href="https://unsplash.com/photos/M5tzZtFCOfs" rel="noopener noreferrer"&gt;Unsplash — Taylor Vick (Server Room)&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  The Itch I Couldn't Stop Scratching
&lt;/h2&gt;

&lt;p&gt;If you've ever managed a VPS — especially with something like Virtualmin — you &lt;em&gt;know&lt;/em&gt; the pain. You've got 14 users on a shared server. Dave is running a Laravel queue worker. Sarah has a Go API. And someone named &lt;code&gt;admin3&lt;/code&gt; (who no one remembers creating) is running a rogue Python Discord bot eating 90% of the RAM.&lt;/p&gt;

&lt;p&gt;You SSH in. You &lt;code&gt;nohup&lt;/code&gt;. You &lt;code&gt;screen&lt;/code&gt;. You pray.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PM2?&lt;/strong&gt; Great tool! ...if your entire universe is Node.js. But the moment you need to babysit a PHP artisan command or a compiled Go binary, PM2 looks at you like you just spoke Klingon.&lt;/p&gt;

&lt;p&gt;I needed something that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let &lt;strong&gt;non-root users&lt;/strong&gt; manage their own processes (without calling me at 2 AM)&lt;/li&gt;
&lt;li&gt;Was &lt;strong&gt;language-agnostic&lt;/strong&gt; — Go, PHP, Python, Rust, a bash script that plays elevator music — I don't judge&lt;/li&gt;
&lt;li&gt;Had real &lt;strong&gt;resource limits&lt;/strong&gt; so one bad actor doesn't nuke the whole server&lt;/li&gt;
&lt;li&gt;Was &lt;strong&gt;dead simple&lt;/strong&gt; to configure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I built it. Meet &lt;strong&gt;&lt;a href="https://github.com/pqpm/pqpm" rel="noopener noreferrer"&gt;PQPM&lt;/a&gt;&lt;/strong&gt; — the Process Queue Process Manager.&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%2Fimages.unsplash.com%2Fphoto-1629654297299-c8506221ca97%3Fw%3D1200" 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%2Fimages.unsplash.com%2Fphoto-1629654297299-c8506221ca97%3Fw%3D1200" alt="Code on a terminal screen" width="1200" height="900"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Suggested image: &lt;a href="https://unsplash.com/photos/g5jpH62pwes" rel="noopener noreferrer"&gt;Unsplash — Gabriel Heinzer (Terminal/Code)&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  What Even Is PQPM?
&lt;/h2&gt;

&lt;p&gt;PQPM is a &lt;strong&gt;lightweight, system-level process manager&lt;/strong&gt; written in Go. It runs as a daemon (&lt;code&gt;pqpmd&lt;/code&gt;) on your Linux server and lets any user on the system manage their own long-running processes through a simple CLI (&lt;code&gt;pqpm&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Think of it as a bouncer at a nightclub: the daemon has the master key (runs as root), but it &lt;em&gt;immediately&lt;/em&gt; drops privileges to match the user who's requesting the action. User A can't touch User B's stuff. Period.&lt;/p&gt;

&lt;p&gt;Here's the whole mental model:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Daemon&lt;/strong&gt; (&lt;code&gt;pqpmd&lt;/code&gt;) — runs as root, listens on a Unix socket&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Config&lt;/strong&gt; (&lt;code&gt;~/.pqpm.toml&lt;/code&gt;) — each user defines their services in a dead-simple TOML file&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The CLI&lt;/strong&gt; (&lt;code&gt;pqpm&lt;/code&gt;) — users run commands like &lt;code&gt;pqpm start my-worker&lt;/code&gt; with zero sudo required&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Magic&lt;/strong&gt; — the daemon verifies the caller's identity using kernel-level socket credentials (&lt;code&gt;SO_PEERCRED&lt;/code&gt;), then spawns the process under that user's UID/GID&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No &lt;code&gt;sudo&lt;/code&gt;. No &lt;code&gt;chmod 777&lt;/code&gt; hacks. No "just run everything as root and hope for the best."&lt;/p&gt;


&lt;h2&gt;
  
  
  The Config File is &lt;em&gt;Chef's Kiss&lt;/em&gt; 🤌
&lt;/h2&gt;

&lt;p&gt;I'm a sucker for simple config files. XML can leave. YAML can take its "is this a string or a boolean" energy elsewhere. TOML just... makes sense.&lt;/p&gt;

&lt;p&gt;Here's what a user's &lt;code&gt;~/.pqpm.toml&lt;/code&gt; looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[service.my-worker]
command = "/usr/bin/php /home/user/public_html/artisan queue:work"
restart = "always"
max_memory = "512MB"
cpu_limit = "20%"

[service.api-server]
command = "/home/user/bin/api-server --port 8080"
restart = "on-failure"
max_memory = "1GB"
cpu_limit = "50%"
working_dir = "/home/user/api"
env = { NODE_ENV = "production", PORT = "8080" }

[service.python-bot]
command = "/usr/bin/python3 /home/user/bots/discord_bot.py"
restart = "always"
max_memory = "256MB"
cpu_limit = "10%"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three services. Three languages. One config file. Zero drama.&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%2Fimages.unsplash.com%2Fphoto-1611532736597-de2d4265fba3%3Fw%3D1200" 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%2Fimages.unsplash.com%2Fphoto-1611532736597-de2d4265fba3%3Fw%3D1200" alt="Gopher plush or Go mascot" width="1200" height="1800"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Suggested image: &lt;a href="https://unsplash.com/photos/a-small-figurine-sitting-on-top-of-a-laptop-computer-a0mHbB970Aw" rel="noopener noreferrer"&gt;Unsplash — Chinmay B (Gopher)&lt;/a&gt; or any Go mascot image from &lt;a href="https://gopherize.me" rel="noopener noreferrer"&gt;Gopherize.me&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Why Go? Because Speed is Non-Negotiable
&lt;/h2&gt;

&lt;p&gt;When your process manager is responsible for keeping other people's services alive, it better not be the thing that dies first.&lt;/p&gt;

&lt;p&gt;Go gave me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Goroutines &amp;amp; channels&lt;/strong&gt; for async, non-blocking process monitoring (each managed process gets its own goroutine — beautiful)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Static binaries&lt;/strong&gt; — &lt;code&gt;pqpmd&lt;/code&gt; and &lt;code&gt;pqpm&lt;/code&gt; are single-file executables. No runtime. No dependencies. Just &lt;code&gt;curl&lt;/code&gt;, extract, and go&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;First-class syscall support&lt;/strong&gt; — spawning processes, dropping privileges with &lt;code&gt;setuid&lt;/code&gt;/&lt;code&gt;setgid&lt;/code&gt;, reading &lt;code&gt;SO_PEERCRED&lt;/code&gt; from Unix sockets — Go's &lt;code&gt;golang.org/x/sys&lt;/code&gt; package is a dream&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-compilation&lt;/strong&gt; — building for &lt;code&gt;amd64&lt;/code&gt; and &lt;code&gt;arm64&lt;/code&gt; in one &lt;code&gt;make&lt;/code&gt; command&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The entire dependency tree is laughably small: &lt;code&gt;BurntSushi/toml&lt;/code&gt; for config parsing, &lt;code&gt;spf13/cobra&lt;/code&gt; for the CLI, and &lt;code&gt;golang.org/x/sys&lt;/code&gt; for syscalls. That's it. Three dependencies. In 2025. I'll wait while you pick your jaw up off the floor.&lt;/p&gt;


&lt;h2&gt;
  
  
  Security: The Part I Lost Sleep Over (So You Don't Have To)
&lt;/h2&gt;

&lt;p&gt;This is a process manager that runs as root. Let me say that louder for the people in the back: &lt;strong&gt;it runs as root&lt;/strong&gt;. If the security isn't airtight, you might as well email your SSH keys to a stranger.&lt;/p&gt;

&lt;p&gt;Here's how PQPM stays paranoid (in a healthy way):&lt;/p&gt;
&lt;h3&gt;
  
  
  🔐 Identity via &lt;code&gt;SO_PEERCRED&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;When the CLI connects to the daemon over a Unix Domain Socket, the daemon asks the &lt;em&gt;kernel&lt;/em&gt; — not the user — "who is this?" The kernel responds with the UID, GID, and PID. No tokens. No passwords. No trust-me-bro headers. The kernel doesn't lie.&lt;/p&gt;
&lt;h3&gt;
  
  
  🪂 Immediate Privilege Drop
&lt;/h3&gt;

&lt;p&gt;The daemon spawns the process as root but &lt;em&gt;instantly&lt;/em&gt; drops to the target user's UID/GID. The spawned process never runs with elevated privileges. Not even for a millisecond... well, maybe a couple of nanoseconds. Go is fast.&lt;/p&gt;
&lt;h3&gt;
  
  
  🧱 Resource Limits via cgroups
&lt;/h3&gt;

&lt;p&gt;Each process can have hard limits on memory and CPU using Linux cgroups (v2). If Dave's queue worker decides to allocate 16 GB of RAM, cgroups will politely (and firmly) say no.&lt;/p&gt;
&lt;h3&gt;
  
  
  📂 Path Restrictions
&lt;/h3&gt;

&lt;p&gt;Processes are locked to running within the user's authorized directories. No sneaky &lt;code&gt;../../etc/shadow&lt;/code&gt; business.&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%2Fimages.unsplash.com%2Fphoto-1555949963-ff9fe0c870eb%3Fw%3D1200" 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%2Fimages.unsplash.com%2Fphoto-1555949963-ff9fe0c870eb%3Fw%3D1200" alt="Lock and shield / cybersecurity" width="1200" height="800"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Suggested image: &lt;a href="https://unsplash.com/photos/mT7lXZPjk7U" rel="noopener noreferrer"&gt;Unsplash — FlyD (Neon Lock)&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  The CLI: Boring On Purpose
&lt;/h2&gt;

&lt;p&gt;I didn't want a CLI that requires a PhD to operate. Six commands. That's your entire vocabulary:&lt;/p&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;What It Does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pqpm start &amp;lt;name&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fire up a service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pqpm stop &amp;lt;name&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Gracefully stop it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pqpm restart &amp;lt;name&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stop + start (shocking, I know)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pqpm status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;See what's running&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pqpm log &amp;lt;name&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tail logs for a service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pqpm version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print the version&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That's it. No &lt;code&gt;pqpm init --template advanced --with-monitoring --enable-clustering --sacrifice-goat&lt;/code&gt;. Just start, stop, restart, status, log, version. Done.&lt;/p&gt;


&lt;h2&gt;
  
  
  Installation: The One-Liner™
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -sSL https://raw.githubusercontent.com/pqpm/pqpm/main/install.sh | sudo bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This detects your architecture, pulls the latest release from GitHub, drops the binaries into &lt;code&gt;/usr/local/bin&lt;/code&gt;, creates runtime directories, and sets up the systemd service. The whole thing takes about 5 seconds.&lt;/p&gt;

&lt;p&gt;Want to build from source? Also easy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/pqpm/pqpm.git
cd pqpm
make build &amp;amp;&amp;amp; sudo make install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Updating? Run the one-liner again. Your managed processes keep running and get "re-adopted" by the daemon once it restarts. Like a responsible parent coming home from the grocery store.&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%2Fimages.unsplash.com%2Fphoto-1516849841032-87cbac4d88f7%3Fw%3D1200" 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%2Fimages.unsplash.com%2Fphoto-1516849841032-87cbac4d88f7%3Fw%3D1200" alt="Rocket launch" width="1200" height="800"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Suggested image: &lt;a href="https://unsplash.com/photos/OHOU-5UVIYQ" rel="noopener noreferrer"&gt;Unsplash — SpaceX (Rocket Launch)&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Who Is This For?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;VPS admins&lt;/strong&gt; running shared hosting environments (especially Virtualmin/Webmin setups)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Small teams&lt;/strong&gt; where multiple developers deploy services on the same box&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anyone tired of PM2&lt;/strong&gt; who runs more than just Node.js&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The sysadmin&lt;/strong&gt; who wants their users to stop asking for root access to run a queue worker&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solo devs&lt;/strong&gt; running a $5 VPS with a Go API, a PHP backend, and a Python cron job — all at once&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've ever typed &lt;code&gt;nohup something &amp;amp;&lt;/code&gt; and then immediately regretted your life choices, PQPM is for you.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;PQPM is at &lt;strong&gt;v0.2.3&lt;/strong&gt; and actively being developed. Here's what's on the roadmap (or at least, living rent-free in my head):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📊 &lt;strong&gt;Web dashboard&lt;/strong&gt; — because sometimes you want to click buttons instead of typing commands&lt;/li&gt;
&lt;li&gt;🔔 &lt;strong&gt;Notifications&lt;/strong&gt; — get pinged when a process dies (and auto-restarts)&lt;/li&gt;
&lt;li&gt;📈 &lt;strong&gt;Metrics export&lt;/strong&gt; — Prometheus-compatible resource usage stats&lt;/li&gt;
&lt;li&gt;🐳 &lt;strong&gt;Container-aware mode&lt;/strong&gt; — playing nice with Docker environments&lt;/li&gt;
&lt;li&gt;🧪 &lt;strong&gt;More tests&lt;/strong&gt; — always more tests&lt;/li&gt;
&lt;/ul&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%2Fimages.unsplash.com%2Fphoto-1522071820081-009f0129c71c%3Fw%3D1200" 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%2Fimages.unsplash.com%2Fphoto-1522071820081-009f0129c71c%3Fw%3D1200" alt="Open source community / collaboration" width="1200" height="800"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Suggested image: &lt;a href="https://unsplash.com/photos/QckxruozjRg" rel="noopener noreferrer"&gt;Unsplash — Annie Spratt (Team collaboration)&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Give It a Spin ⭐
&lt;/h2&gt;

&lt;p&gt;PQPM is &lt;strong&gt;open-source&lt;/strong&gt; (MIT licensed) and lives at &lt;strong&gt;&lt;a href="https://github.com/pqpm/pqpm" rel="noopener noreferrer"&gt;github.com/pqpm/pqpm&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If it saves you even one &lt;code&gt;sudo&lt;/code&gt; argument with a client, one 2 AM SSH session, or one "why is the server at 100% CPU" panic — I'll consider it a win.&lt;/p&gt;

&lt;p&gt;Star the repo if you dig it. Open an issue if you find a bug. Submit a PR if you're feeling generous. Or just silently use it and never tell me — that's cool too. I'll never know. But my download counter will. 👀&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with 🐹 Go, ☕ too much coffee, and a burning hatred for &lt;code&gt;nohup&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Image Source Summary
&lt;/h2&gt;

&lt;p&gt;Here's a quick reference for all the suggested images (all free to use via Unsplash):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Section&lt;/th&gt;
&lt;th&gt;Image&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hero / Banner&lt;/td&gt;
&lt;td&gt;Server room / data center&lt;/td&gt;
&lt;td&gt;&lt;a href="https://unsplash.com/photos/M5tzZtFCOfs" rel="noopener noreferrer"&gt;Unsplash — Taylor Vick&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"What Is PQPM"&lt;/td&gt;
&lt;td&gt;Terminal with code&lt;/td&gt;
&lt;td&gt;&lt;a href="https://unsplash.com/photos/g5jpH62pwes" rel="noopener noreferrer"&gt;Unsplash — Gabriel Heinzer&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Why Go?"&lt;/td&gt;
&lt;td&gt;Go gopher / mascot&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://gopherize.me" rel="noopener noreferrer"&gt;Gopherize.me&lt;/a&gt; or &lt;a href="https://unsplash.com/s/photos/golang" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security section&lt;/td&gt;
&lt;td&gt;Neon lock / cybersecurity&lt;/td&gt;
&lt;td&gt;&lt;a href="https://unsplash.com/photos/mT7lXZPjk7U" rel="noopener noreferrer"&gt;Unsplash — FlyD&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Installation&lt;/td&gt;
&lt;td&gt;Rocket launch&lt;/td&gt;
&lt;td&gt;&lt;a href="https://unsplash.com/photos/OHOU-5UVIYQ" rel="noopener noreferrer"&gt;Unsplash — SpaceX&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Community / CTA&lt;/td&gt;
&lt;td&gt;Team collaboration&lt;/td&gt;
&lt;td&gt;&lt;a href="https://unsplash.com/photos/QckxruozjRg" rel="noopener noreferrer"&gt;Unsplash — Annie Spratt&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>devops</category>
      <category>linux</category>
      <category>showdev</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Fixing "No valid 'aps-environment' entitlement string found for application" in Flutter App</title>
      <dc:creator>Ramananda Panda</dc:creator>
      <pubDate>Wed, 12 Feb 2025 16:56:53 +0000</pubDate>
      <link>https://forem.com/rp01/fixing-no-valid-aps-environment-entitlement-string-found-for-application-in-flutter-app-3o8l</link>
      <guid>https://forem.com/rp01/fixing-no-valid-aps-environment-entitlement-string-found-for-application-in-flutter-app-3o8l</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;If you're developing a Flutter app with push notifications on iOS, you might encounter this frustrating error:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"No valid 'aps-environment' entitlement string found for application"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This issue prevents push notifications from working correctly and often appears when configuring Firebase Cloud Messaging (FCM) or APNs (Apple Push Notification Service). But don’t worry! In this blog, we’ll walk you through the exact steps to fix it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does This Happen?
&lt;/h2&gt;

&lt;p&gt;The error occurs because iOS requires a valid `&lt;code&gt;entitlement in your app’s provisioning profile. This entitlement determines whether your app supports push notifications in development (&lt;/code&gt;development&lt;code&gt;) or production (&lt;/code&gt;production`). If it’s missing, iOS refuses to deliver push notifications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step-by-Step Fix
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Enable Push Notifications in Xcode
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open your Flutter project’s &lt;strong&gt;iOS folder&lt;/strong&gt; in Xcode.&lt;/li&gt;
&lt;li&gt;Select your &lt;strong&gt;Runner&lt;/strong&gt; project from the left panel.&lt;/li&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Signing &amp;amp; Capabilities&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;+ Capability&lt;/strong&gt; button and add &lt;strong&gt;Push Notifications&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Also, add &lt;strong&gt;Background Modes&lt;/strong&gt; and check &lt;strong&gt;Remote notifications&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  2. Ensure Your Provisioning Profile Supports Push Notifications
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://developer.apple.com/" rel="noopener noreferrer"&gt;Apple Developer Account&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Certificates, Identifiers &amp;amp; Profiles&lt;/strong&gt; &amp;gt; &lt;strong&gt;App IDs&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Find your app’s bundle ID and make sure &lt;strong&gt;Push Notifications&lt;/strong&gt; is enabled.&lt;/li&gt;
&lt;li&gt;If it's not enabled, edit the App ID and enable Push Notifications.&lt;/li&gt;
&lt;li&gt;Now, head to &lt;strong&gt;Profiles&lt;/strong&gt; and regenerate your &lt;strong&gt;Provisioning Profile&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Download and install the new profile in Xcode (&lt;strong&gt;Preferences &amp;gt; Accounts &amp;gt; Manage Certificates&lt;/strong&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  3. Check the &lt;code&gt;Entitlements.plist&lt;/code&gt; File
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;strong&gt;Runner/Runner.entitlements&lt;/strong&gt; in Xcode.&lt;/li&gt;
&lt;li&gt;Ensure it contains the following key:
&lt;code&gt;`xml
&amp;lt;key&amp;gt;aps-environment&amp;lt;/key&amp;gt;
&amp;lt;string&amp;gt;development&amp;lt;/string&amp;gt;  &amp;lt;!-- or "production" if releasing --&amp;gt;
`&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If the file doesn’t exist, create a new one named &lt;strong&gt;Runner.entitlements&lt;/strong&gt; and add the above content.&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;Build Settings&lt;/strong&gt; in Xcode, search for &lt;strong&gt;Code Signing Entitlements&lt;/strong&gt;, and make sure it includes &lt;code&gt;Runner.entitlements&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  4. Make &lt;code&gt;Runner.entitlements&lt;/code&gt; Available for Debug Mode
&lt;/h3&gt;

&lt;p&gt;When a user enables push notifications, Xcode adds a &lt;strong&gt;RunnerProfile.entitlements&lt;/strong&gt; file:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;br&gt;
&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br&gt;
&amp;lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&amp;gt;&lt;br&gt;
&amp;lt;plist version="1.0"&amp;gt;&lt;br&gt;
&amp;lt;dict&amp;gt;&lt;br&gt;
    &amp;lt;key&amp;gt;aps-environment&amp;lt;/key&amp;gt;&lt;br&gt;
    &amp;lt;string&amp;gt;development&amp;lt;/string&amp;gt;&lt;br&gt;
&amp;lt;/dict&amp;gt;&lt;br&gt;
&amp;lt;/plist&amp;gt;&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;However, this file may not be available when you try to build and run the app on a simulator or device. To resolve this, you need to explicitly specify the entitlement file for &lt;strong&gt;debug mode&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;Build Settings&lt;/strong&gt; in Xcode.&lt;/li&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Signing &amp;gt; Code Signing Entitlements&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Set the entitlement file path (&lt;code&gt;Runner.entitlements&lt;/code&gt;) for each build mode.&lt;/li&gt;
&lt;li&gt;Users can set multiple entitlement files for &lt;strong&gt;debug&lt;/strong&gt; and &lt;strong&gt;release&lt;/strong&gt; modes.

&lt;ul&gt;
&lt;li&gt;For &lt;strong&gt;debug&lt;/strong&gt;, set &lt;code&gt;aps-environment&lt;/code&gt; to &lt;code&gt;development&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;release&lt;/strong&gt;, set &lt;code&gt;aps-environment&lt;/code&gt; to &lt;code&gt;production&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&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%2Fgzqa6kv9srygp454lt6o.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%2Fgzqa6kv9srygp454lt6o.png" alt="Image description" width="680" height="122"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Rebuild and Deploy
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Clean the project:
&lt;code&gt;sh
flutter clean
&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Reinstall dependencies:
&lt;code&gt;sh
flutter pub get
&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run your app again:
&lt;code&gt;sh
flutter run
&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If you are building for release, ensure you archive and upload the build to TestFlight or App Store.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This error can be annoying, but following these steps should resolve it quickly. If you still face issues, double-check your Apple Developer settings and Xcode configurations.&lt;/p&gt;

&lt;p&gt;Now, go ahead and test your push notifications! 🚀&lt;/p&gt;

&lt;p&gt;Have you faced this issue? Let me know in the comments how you fixed it or if you need any help! 🙌&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>ios</category>
      <category>pushnotification</category>
      <category>fcm</category>
    </item>
  </channel>
</rss>
