<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Portlivo]]></title><description><![CDATA[Portlivo]]></description><link>https://portlivo.hashnode.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/6ad49d2be372d668e9a2c200/380469b2-5b99-4e6a-9a0f-3fd7eb9175ee.png</url><title>Portlivo</title><link>https://portlivo.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Tue, 27 Oct 2026 05:42:39 GMT</lastBuildDate><atom:link href="https://portlivo.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How to kill the process on a port on a Mac (and what to do when it comes back)]]></title><description><![CDATA[One command frees the port. Here's the safe way to run it, and why Postgres is back a second later.]]></description><link>https://portlivo.hashnode.dev/how-to-kill-the-process-on-a-port-on-a-mac-and-what-to-do-when-it-comes-back</link><guid isPermaLink="true">https://portlivo.hashnode.dev/how-to-kill-the-process-on-a-port-on-a-mac-and-what-to-do-when-it-comes-back</guid><category><![CDATA[macOS]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Programming Tips]]></category><category><![CDATA[terminal]]></category><category><![CDATA[Developer Tools]]></category><dc:creator><![CDATA[Anmol Sethi]]></dc:creator><pubDate>Fri, 23 Oct 2026 06:47:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6ad49d2be372d668e9a2c200/4d29ad3f-2778-4c74-92cc-ded5c93523dc.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You kill whatever is on port 5432, run your app, and get the same error. The process is back with a new PID. Most guides stop at <code>kill -9</code>, which is the wrong fix for this. Here's the full routine, in the order I use it.</p>
<h2>The one-liner</h2>
<p>Find the process listening on the port and ask it to quit:</p>
<pre><code class="language-plaintext">lsof -ti tcp:3000 -sTCP:LISTEN | xargs kill
</code></pre>
<p><code>-t</code> prints only PIDs. <code>-sTCP:LISTEN</code> is the part most snippets leave out, and it matters: without it, lsof also returns every client connected to the port. If you have the app open in a browser, that includes the browser, and you quit it instead of the server.</p>
<p>A range of ports works too:</p>
<pre><code class="language-plaintext">lsof -ti tcp:3000-3010 -sTCP:LISTEN | xargs kill
</code></pre>
<h2>The careful version</h2>
<p>When you're not sure what's on the port, take it in four steps:</p>
<ol>
<li>See what's listening: <code>lsof -nP -iTCP:3000 -sTCP:LISTEN</code></li>
<li>Check it's the right thing: <code>ps -p &lt;PID&gt; -o command=</code></li>
<li>Ask it to quit: <code>kill &lt;PID&gt;</code></li>
<li>Check again after a second. Only if it's still there: <code>kill -9 &lt;PID&gt;</code></li>
</ol>
<p>Step 2 is the one people skip. <code>node</code> on port 3000 could be your app, or a different project you forgot was running.</p>
<h2>kill, kill -INT or kill -9?</h2>
<table>
<thead>
<tr>
<th>Command</th>
<th>Signal</th>
<th>When to use it</th>
</tr>
</thead>
<tbody><tr>
<td><code>kill &lt;PID&gt;</code></td>
<td>SIGTERM</td>
<td>First choice. The server closes files and connections, then exits.</td>
</tr>
<tr>
<td><code>kill -INT &lt;PID&gt;</code></td>
<td>SIGINT</td>
<td>What Ctrl-C sends. Some servers only clean up on this one.</td>
</tr>
<tr>
<td><code>kill -9 &lt;PID&gt;</code></td>
<td>SIGKILL</td>
<td>Last resort. It can't be caught, so nothing gets cleaned up.</td>
</tr>
</tbody></table>
<p>A database killed with <code>-9</code> has to recover on its next start, and a dev server may leave a lock or socket file behind. Give SIGTERM a second before reaching for it.</p>
<h2>Make it a command</h2>
<p>If you do this every day, add a function to <code>~/.zshrc</code>, open a new terminal, and run <code>killport 3000</code>:</p>
<pre><code class="language-plaintext">killport() { lsof -ti tcp:"$1" -sTCP:LISTEN | xargs kill; }
</code></pre>
<p>There are npm tools too. <code>npx kill-port 3000</code> sends SIGKILL straight away, with no grace period. <code>npx fkill-cli :3000</code> stops the process on a port, and <code>npx fkill-cli</code> on its own opens an interactive picker.</p>
<p><em>If you do this several times a day: full disclosure, I built</em> <a href="https://portlivo.com/?utm_source=hashnode"><em>Portlivo</em></a><em>, a Mac menu bar app that lists every dev server and port. Select one and press K, and it stops it safely, including Homebrew services and Docker containers. It's $8.99 once (early-bird) after a 7-day free trial.</em></p>
<h2>Stop it by name instead</h2>
<p>When you know what it is but not which port it took:</p>
<pre><code class="language-plaintext">pgrep -lf "vite"    # list matches first
pkill -f "vite"     # then stop them
</code></pre>
<p><code>-f</code> matches anywhere in the command line, so <code>pkill -f node</code> also stops your editor's helpers. Always run <code>pgrep -lf</code> with the same pattern first.</p>
<h2>Check the port is free</h2>
<pre><code class="language-plaintext">nc -z localhost 3000 2&gt;/dev/null &amp;&amp; echo taken || echo free
</code></pre>
<p>If it still says <code>taken</code> a second after you stopped the process, something restarted it.</p>
<h2>When it comes straight back</h2>
<p>That's a supervisor doing its job. Homebrew services run under launchd with KeepAlive, so a killed Postgres is restarted within a second. Killing it harder doesn't help. Stop it where it's managed:</p>
<table>
<thead>
<tr>
<th>What holds the port</th>
<th>Stop it with</th>
</tr>
</thead>
<tbody><tr>
<td>Homebrew service (Postgres, MySQL, Redis)</td>
<td><code>brew services stop &lt;name&gt;</code></td>
</tr>
<tr>
<td>Docker or OrbStack container</td>
<td><code>docker stop &lt;container&gt;</code></td>
</tr>
<tr>
<td>pm2</td>
<td><code>pm2 stop &lt;name&gt;</code></td>
</tr>
<tr>
<td>nodemon or a file watcher</td>
<td>Ctrl-C in the terminal that runs it</td>
</tr>
<tr>
<td>launchd agent</td>
<td><code>launchctl bootout gui/$(id -u)/&lt;label&gt;</code></td>
</tr>
<tr>
<td>Laravel Herd (nginx, PHP, dnsmasq)</td>
<td>Stop it from Herd</td>
</tr>
</tbody></table>
<p>Not sure which one it is? <code>brew services list</code> and <code>docker ps</code> cover most cases. For other launchd agents, look in <code>~/Library/LaunchAgents</code> or run <code>launchctl list | grep &lt;name&gt;</code>.</p>
<h2>"Operation not permitted"</h2>
<p>The process belongs to root or another user. <code>sudo kill &lt;PID&gt;</code> works, but check what it is first. One to leave alone: <code>ControlCe</code> on port 5000 or 7000 is macOS's AirPlay Receiver. Turn it off in System Settings → General → AirDrop &amp; Handoff instead.</p>
<p>That covers every way I free a port. If it saved you a trip to Stack Overflow, follow me for more Mac developer fixes like this one.</p>
]]></content:encoded></item><item><title><![CDATA[How to Find Which Project Is Running on a Port on Mac
]]></title><description><![CDATA[lsof gives you a PID. Two more commands give you the folder, the full command and the git branch behind it.]]></description><link>https://portlivo.hashnode.dev/how-to-find-which-project-is-running-on-a-port-on-mac</link><guid isPermaLink="true">https://portlivo.hashnode.dev/how-to-find-which-project-is-running-on-a-port-on-mac</guid><category><![CDATA[mac]]></category><category><![CDATA[Programming Tips]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[terminal]]></category><category><![CDATA[Developer Tools]]></category><dc:creator><![CDATA[Anmol Sethi]]></dc:creator><pubDate>Thu, 22 Oct 2026 04:47:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6ad49d2be372d668e9a2c200/7e838260-bcb1-4782-86f6-d5df7f326bba.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You open localhost:3000 and it’s the wrong app. Or <code>npm run dev</code> says the port is taken, and <code>lsof</code> tells you it’s <code>node</code>. Every dev server is <code>node</code>.</p>
<p>What you actually need is the folder it was started from. macOS doesn’t have Linux’s <code>pwdx</code>, but lsof can tell you, and it takes about ten seconds.</p>
<h3><strong>The quick answer</strong></h3>
<p>Swap 3000 for your port:</p>
<pre><code class="language-plaintext">lsof -a -p "$(lsof -ti tcp:3000 -sTCP:LISTEN | head -1)" -d cwd -Fn | sed -n 's/^n//p'
</code></pre>
<p>It prints the working directory of whatever is listening on the port, like <code>/Users/you/Code/acme-web</code>. The rest of this post is what each part does, how to get the branch and the command too, and what to do when the answer is just <code>/</code>.</p>
<h3><strong>Step 1: find the PID</strong></h3>
<pre><code class="language-plaintext">lsof -nP -iTCP:3000 -sTCP:LISTEN
</code></pre>
<pre><code class="language-plaintext">COMMAND   PID  USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
node    48211   you   23u  IPv6  0x7e9…      0t0  TCP *:3000 (LISTEN)
</code></pre>
<p><code>-n</code> and <code>-P</code> skip the DNS and port-name lookups, so it answers instantly and shows <code>3000</code> instead of <code>hbci</code>. <code>-sTCP:LISTEN</code> keeps only the server. Without it you also get every client connected to the port, including your browser tab.</p>
<p>Add <code>-t</code> when you only want the number: <code>lsof -ti tcp:3000 -sTCP:LISTEN</code>prints <code>48211</code>.</p>
<h3><strong>Step 2: ask lsof for its working directory</strong></h3>
<p>Every process has a current directory, and lsof lists it as a file descriptor called <code>cwd</code>:</p>
<pre><code class="language-plaintext">lsof -a -p 48211 -d cwd
</code></pre>
<pre><code class="language-plaintext">COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF      NODE NAME
node    48211  you  cwd    DIR   1,18      640 382905693 /Users/you/Code/acme-web
</code></pre>
<p><code>-p</code> picks the process, <code>-d cwd</code> picks the descriptor, and <code>-a</code> means both must match. Leave out <code>-a</code> and lsof ORs them, so you get every process’s cwd on the machine.</p>
<p>For scripts, <code>-Fn</code> prints just the path with an <code>n</code> in front, which <code>sed -n 's/^n//p'</code> strips off. That’s the quick answer above.</p>
<p>For most dev servers this is the project folder, because <code>npm run dev</code>, <code>pnpm dev</code>, <code>rails s</code> and <code>go run .</code> all run where you typed them.</p>
<h3><strong>Step 3: see the full command</strong></h3>
<pre><code class="language-plaintext">ps -o command= -p 48211
</code></pre>
<p>This shows the whole command line, which often holds the path as well: <code>node /Users/you/Code/acme-web/node_modules/.bin/vite</code>. It also tells two servers in the same folder apart, like <code>vite</code> and <code>storybook</code>.</p>
<p>To see when it started, which helps spot the one you left running yesterday:</p>
<pre><code class="language-plaintext">ps -o lstart= -p 48211
</code></pre>
<h3><strong>Step 4: get the git branch</strong></h3>
<pre><code class="language-plaintext">git -C /Users/you/Code/acme-web branch --show-current
</code></pre>
<p><code>-C</code> runs git as if you were in that folder, so you don’t have to <code>cd</code>. This matters more than it used to. If you keep several worktrees of one repo, or a coding agent runs servers in its own worktree, you can have three copies of the same app on three ports. The folder and the branch are the only things that tell them apart.</p>
<p>Two more that help here:</p>
<ul>
<li><p><code>git -C &lt;folder&gt; rev-parse --show-toplevel</code> gives the repo root when the server runs in a subfolder, like <code>packages/web</code> in a monorepo.</p>
</li>
<li><p><code>git -C &lt;folder&gt; worktree list</code> shows every worktree of that repo and its branch.</p>
</li>
</ul>
<h3><strong>Make it one command</strong></h3>
<p>Add this to <code>~/.zshrc</code>, open a new terminal, and run <code>whoport 3000</code>:</p>
<pre><code class="language-plaintext">whoport() {
  local pid dir
  pid=$(lsof -ti tcp:"$1" -sTCP:LISTEN | head -1)
  [[ -z $pid ]] &amp;&amp; { echo "Nothing is listening on :$1"; return 1; }
  dir=$(lsof -a -p "$pid" -d cwd -Fn | sed -n 's/^n//p')
  echo "PID     $pid"
  echo "Command $(ps -o command= -p "$pid")"
  echo "Folder  $dir"
  git -C "$dir" rev-parse --is-inside-work-tree &amp;&gt;/dev/null &amp;&amp;
    echo "Branch  $(git -C "$dir" branch --show-current)"
}
</code></pre>
<pre><code class="language-plaintext">% whoport 3000
PID     48211
Command node /Users/you/Code/acme-web/node_modules/.bin/vite
Folder  /Users/you/Code/acme-web
Branch  feature/search
</code></pre>
<p>To see every listening server with its folder at once:</p>
<pre><code class="language-plaintext">lsof -tiTCP -sTCP:LISTEN | sort -u | while read pid; do
  printf '%-6s %-18.18s %s\n' "$pid" "$(ps -o comm= -p "$pid" | sed 's#.*/##')" \
    "$(lsof -a -p "$pid" -d cwd -Fn | sed -n 's/^n//p')"
done
</code></pre>
<p>You’ll see a few apps of your own in there too, like your editor’s helpers. Their folder is usually <code>/</code>.</p>
<p><em>If you check this more than once a day: full disclosure, I built</em> <a href="https://portlivo.com/?utm_source=hashnode&amp;utm_medium=hashnode&amp;utm_campaign=2026-10-22-find-project-on-port"><em>Portlivo</em></a><em>, a Mac menu bar app that shows every dev server with its project, git branch and port. Press E on one and its folder opens in VS Code, Cursor or Zed. It’s $8.99 once for the first 50 licences, after a 7-day free trial. The commands above are free and enough if you only need this now and then.</em></p>
<h3><strong>Open it in your editor</strong></h3>
<p>Once you have the folder, one command opens it:</p>
<table>
<thead>
<tr>
<th>Editor</th>
<th>Command</th>
<th>Install the command</th>
</tr>
</thead>
<tbody><tr>
<td>VS Code</td>
<td><code>code ~/Code/acme-web</code></td>
<td>Command Palette → Shell Command: Install ‘code’ command in PATH</td>
</tr>
<tr>
<td>Cursor</td>
<td><code>cursor ~/Code/acme-web</code></td>
<td>Command Palette → Shell Command: Install ‘cursor’ command</td>
</tr>
<tr>
<td>Zed</td>
<td><code>zed ~/Code/acme-web</code></td>
<td>Zed menu → Install CLI</td>
</tr>
<tr>
<td>Any app</td>
<td><code>open -a "Visual Studio Code" ~/Code/acme-web</code></td>
<td>Nothing to install</td>
</tr>
</tbody></table>
<p>Put them together and you jump from a port straight to its code: <code>code "$(lsof -a -p "$(lsof -ti tcp:3000 -sTCP:LISTEN | head -1)" -d cwd -Fn | sed -n 's/^n//p')"</code>.</p>
<h3><strong>When the folder is / or makes no sense</strong></h3>
<p>Some servers aren’t started from a project folder. lsof is still right; the folder just isn’t the useful answer.</p>
<table>
<thead>
<tr>
<th>What you see</th>
<th>What it is</th>
<th>Where to look instead</th>
</tr>
</thead>
<tbody><tr>
<td><code>com.docker.backend</code>or OrbStack holds the port</td>
<td>A container</td>
<td><code>docker ps --filter publish=3000</code>, then for Compose projects <code>docker inspect -f '{{ index .Config.Labels "com.docker.compose.project.working_dir" }}' &lt;container&gt;</code></td>
</tr>
<tr>
<td>Folder is <code>/</code>, command is <code>postgres</code>, <code>redis-server</code> or <code>mysqld</code></td>
<td>A Homebrew service, started by launchd</td>
<td><code>brew services list</code>. It isn’t tied to a project.</td>
</tr>
<tr>
<td>Folder is <code>/</code>, command is <code>nginx</code></td>
<td>Laravel Herd or Valet</td>
<td><code>herd links</code> or <code>valet links</code> list the folder behind each <code>.test</code> site</td>
</tr>
<tr>
<td>Folder ends in <code>/public</code></td>
<td><code>php artisan serve</code>, which runs from the public folder</td>
<td><code>git -C &lt;folder&gt; rev-parse --show-toplevel</code> for the project root</td>
</tr>
<tr>
<td>Folder is your home folder or <code>/</code>, process is <code>node</code></td>
<td>Started by pm2 or another process manager</td>
<td><code>pm2 list</code>, then <code>pm2 describe &lt;name&gt;</code> shows its exec cwd</td>
</tr>
<tr>
<td>lsof prints nothing, but the port is taken</td>
<td>A process owned by root or another user</td>
<td>Run the same commands with <code>sudo</code></td>
</tr>
</tbody></table>
<p>If the port is taken and you want it back, I wrote up <a href="https://portlivo.com/guides/kill-process-on-port-mac?utm_source=hashnode&amp;utm_medium=hashnode&amp;utm_campaign=2026-10-22-find-project-on-port">how to stop the process on a port safely</a>, including the ones that come straight back.</p>
<h3><strong>FAQ</strong></h3>
<p><strong>Is there a pwdx command on Mac?</strong><br />No. <code>pwdx</code> and <code>/proc/&lt;PID&gt;/cwd</code> are Linux only. On macOS, <code>lsof -a -p &lt;PID&gt; -d cwd</code> does the same job.</p>
<p><strong>How do I find which port a project is using?</strong><br />Run the loop from “Make it one command”, which lists every listening server with its folder, and look for yours. Or check the project’s config: Vite defaults to 5173, Next.js and Rails to 3000, Laravel to 8000.</p>
<p><strong>Does this work for Python, Ruby, Go and PHP servers?</strong><br />Yes. lsof and ps don’t care what language the process is in. I tested the steps above with <code>python3 -m http.server</code>.</p>
<p><strong>Why does lsof show nothing for a port I know is in use?</strong><br />Usually the process belongs to another user, so try <code>sudo</code>. If it’s a Docker container, lsof shows Docker’s own process, not the app inside it.</p>
<p><strong>Can I see this without the terminal?</strong><br />Activity Monitor shows a process’s open files and ports (double-click it, then Open Files and Ports), and the cwd is in that list. It’s slower for this than lsof, but it works.</p>
<h3><strong>The bottom line</strong></h3>
<p>lsof finds the PID, <code>lsof -d cwd</code> turns it into a folder, and <code>git -C</code> gives you the branch. Put them in a <code>whoport</code> function and “which project is this?” takes one command.</p>
<p>How many dev servers do you usually have running at once?</p>
<p>I’m Anmol. I build Mac apps and write about Mac productivity. Follow me on X at <a href="https://x.com/anmolsethi_dev">@anmolsethi_dev</a>.</p>
]]></content:encoded></item><item><title><![CDATA[What's running on my Mac? How to see every dev server and port]]></title><description><![CDATA[One command lists every port. A few more tell you which project each one belongs to.]]></description><link>https://portlivo.hashnode.dev/what-s-running-on-my-mac-how-to-see-every-dev-server-and-port</link><guid isPermaLink="true">https://portlivo.hashnode.dev/what-s-running-on-my-mac-how-to-see-every-dev-server-and-port</guid><category><![CDATA[macOS]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[terminal]]></category><category><![CDATA[terminal command]]></category><category><![CDATA[Developer Tools]]></category><dc:creator><![CDATA[Anmol Sethi]]></dc:creator><pubDate>Mon, 19 Oct 2026 02:26:19 GMT</pubDate><content:encoded><![CDATA[<p>A Vite app from this morning, an <code>artisan serve</code> from yesterday, Postgres, Redis, and whatever your coding agent started in the background. By the afternoon most of us have no idea what's actually running. Here's how to see all of it from Terminal.</p>
<h2>The one command</h2>
<p>This lists every TCP port something is listening on, with the program and its PID:</p>
<pre><code class="language-plaintext">lsof -nP -iTCP -sTCP:LISTEN
</code></pre>
<p>A typical afternoon looks like this:</p>
<pre><code class="language-plaintext">COMMAND     PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
node      48213 you    23u  IPv6  0x8c2f…      0t0  TCP *:3000 (LISTEN)
node      51877 you    24u  IPv4  0x1d07…      0t0  TCP 127.0.0.1:5173 (LISTEN)
php       52210 you     8u  IPv4  0x6b3a…      0t0  TCP 127.0.0.1:8000 (LISTEN)
postgres    611 you     7u  IPv6  0x4e19…      0t0  TCP [::1]:5432 (LISTEN)
redis-ser   702 you     6u  IPv4  0x93c4…      0t0  TCP 127.0.0.1:6379 (LISTEN)
ControlCe   423 you     9u  IPv4  0x2f88…      0t0  TCP *:7000 (LISTEN)
</code></pre>
<p>Three things worth knowing when you read it:</p>
<ul>
<li><p><code>*:3000</code> accepts connections from other devices on your network. <code>127.0.0.1</code> or <code>[::1]</code> means only this Mac.</p>
</li>
<li><p>Names are cut to nine characters: <code>redis-ser</code> is redis-server, and <code>ControlCe</code> is ControlCenter, which is macOS's AirPlay Receiver (it's why port 5000 is often taken). Add <code>+c 0</code> for full names.</p>
</li>
<li><p>One server can appear twice, once for IPv4 and once for IPv6, with the same PID.</p>
</li>
</ul>
<h2>Which project is it?</h2>
<p>lsof says <code>node</code> or <code>php</code>, not "the shop frontend". To get the full command and the folder a process runs in:</p>
<pre><code class="language-plaintext">ps -p &lt;PID&gt; -o command=
lsof -a -p &lt;PID&gt; -d cwd -Fn | sed -n 's/^n//p'
</code></pre>
<p>Or for every listening process at once, folder first:</p>
<pre><code class="language-plaintext">for pid in $(lsof -ti -iTCP -sTCP:LISTEN | sort -u); do
  printf '%s\t%s\n' "$(lsof -a -p "$pid" -d cwd -Fn | sed -n 's/^n//p')" "$(ps -p "$pid" -o command=)"
done
</code></pre>
<p>A folder of <code>/</code> usually means a system or app process, like an editor helper, rather than one of your projects.</p>
<h2>Which ones can your phone reach?</h2>
<p>Anything not bound to <code>127.0.0.1</code> or <code>[::1]</code> is reachable from your network:</p>
<pre><code class="language-plaintext">lsof -nP -iTCP -sTCP:LISTEN | grep -vE '127\.0\.0\.1|\[::1\]'
</code></pre>
<p>That's what you want when testing on a phone, and worth checking on café Wi-Fi. Most dev servers only listen on localhost unless you pass <code>--host</code> (Vite) or <code>-H 0.0.0.0</code> (Next.js).</p>
<h2>Docker and Homebrew hide behind other names</h2>
<p>Ports published by Docker show up in lsof as <code>com.docker.backend</code> (or OrbStack), not as your app. Homebrew services show as the database itself. List them directly:</p>
<pre><code class="language-plaintext">docker ps --format '{{.Names}}\t{{.Ports}}'
brew services list
</code></pre>
<h2>Why not Activity Monitor?</h2>
<p>Activity Monitor shows processes with CPU and memory, but not their ports. You can double-click a process and open Open Files and Ports, one process at a time. Fine for one server, slow for ten.</p>
<h2>Or keep it in the menu bar</h2>
<p>I ran these commands often enough that I built <a href="https://portlivo.com/?utm_source=devto">Portlivo</a>, a Mac menu bar app that keeps this list live: every server named by its project, with the command, uptime, whether it's answering, CPU and memory, and Docker and Homebrew services alongside. One click opens, restarts, tails or stops any of them. It's a native app with a 7-day free trial.</p>
<h2>Takeaways</h2>
<ul>
<li><p><code>lsof -nP -iTCP -sTCP:LISTEN</code> shows every listening port.</p>
</li>
<li><p><code>ps -p &lt;PID&gt; -o command=</code> and the cwd lookup tell you which project it is.</p>
</li>
<li><p><code>*</code> in the address means your network can reach it; <code>127.0.0.1</code> means only you.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[How to fix "port already in use" on a Mac (and stop it happening)
]]></title><description><![CDATA[The two commands that free a port, why ports get stuck in the first place, and the menu bar app I built so I'd stop typing them.]]></description><link>https://portlivo.hashnode.dev/how-to-fix-port-already-in-use-on-a-mac-and-stop-it-happening</link><guid isPermaLink="true">https://portlivo.hashnode.dev/how-to-fix-port-already-in-use-on-a-mac-and-stop-it-happening</guid><category><![CDATA[macOS]]></category><category><![CDATA[Productivity]]></category><category><![CDATA[productivity tools]]></category><category><![CDATA[Developer Tools]]></category><dc:creator><![CDATA[Anmol Sethi]]></dc:creator><pubDate>Sun, 18 Oct 2026 10:26:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6ad49d2be372d668e9a2c200/55a9c40a-c854-47d1-9eb4-a6bcab1fbcba.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You run <code>npm run dev</code> and get this:</p>
<pre><code class="language-plaintext">Error: listen EADDRINUSE: address already in use :::3000
</code></pre>
<p>Something is already listening on port 3000. Usually it's a dev server you started earlier and forgot about: a terminal tab you closed without stopping it, a project from yesterday, or something a coding agent started in the background.</p>
<h2>Fix it in two commands</h2>
<p>Find what's holding the port:</p>
<pre><code class="language-plaintext">lsof -i :3000
</code></pre>
<p>The output lists the process name and its PID (process ID):</p>
<pre><code class="language-plaintext">COMMAND   PID   USER   FD   TYPE  DEVICE  SIZE/OFF NODE NAME
node    41234  you    23u  IPv6  0x...       0t0  TCP *:hbci (LISTEN)
</code></pre>
<p>Then stop it:</p>
<pre><code class="language-plaintext">kill 41234
</code></pre>
<p>If it won't go, <code>kill -9 41234</code> forces it. Use that as a last resort: the process gets no chance to clean up.</p>
<p>One-liner, if you're sure whatever is on the port can go:</p>
<pre><code class="language-plaintext">lsof -ti :3000 | xargs kill
</code></pre>
<h2>Why it keeps happening</h2>
<p>A modern project rarely runs one server. A frontend on 5173, an API on 8000, Postgres on 5432, Redis on 6379, maybe a worker and a docs site. Multiply that by the three projects you touched this week, and nothing on macOS shows you the full picture. Activity Monitor lists processes, not ports. <code>lsof</code> answers one port at a time, and only when you already know which one to ask about.</p>
<p>So stale servers pile up quietly, and you only notice when one blocks the port you need.</p>
<h2>What I built instead</h2>
<p>I got tired of the <code>lsof</code> ritual, so I built <a href="https://portlivo.com/?utm_source=hashnode">Portlivo</a>, a Mac menu bar app that shows every local dev server and port at once:</p>
<ul>
<li><p>which project each server belongs to, and the command that started it</p>
</li>
<li><p>whether it's actually answering, plus CPU and memory</p>
</li>
<li><p>one click to open it in the browser, restart it, tail its logs or kill it</p>
</li>
<li><p>Homebrew services like Postgres and Redis in the same list</p>
</li>
<li><p>a QR code to open any server on your phone</p>
</li>
</ul>
<p>When a port clash happens, it notifies you with a <strong>Kill holder &amp; retry</strong> button, which is the button I'd wanted for years. There's also a command palette, keyboard shortcuts and a <code>devports</code> command-line tool if you'd rather stay in the terminal.</p>
<p>It's a native SwiftUI app for macOS 14 or later, on Apple silicon and Intel. No account, no subscription: a 7-day free trial, then a one-time licence.</p>
<h2>Takeaways</h2>
<ul>
<li><p><code>lsof -i :&lt;port&gt;</code> shows what's on a port; <code>kill &lt;pid&gt;</code> stops it.</p>
</li>
<li><p>Prefer <code>kill</code> over <code>kill -9</code>.</p>
</li>
<li><p>The port clash is a symptom. The real problem is not being able to see what's running.</p>
</li>
</ul>
<p>If you'd like to see everything at a glance, <a href="https://portlivo.com/?utm_source=medium">Portlivo</a> is free to try for 7 days.</p>
]]></content:encoded></item></channel></rss>