<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Thomas Shafer</title>
    <description>The latest articles on DEV Community by Thomas Shafer (@thomas_shafer_783798ba461).</description>
    <link>https://dev.to/thomas_shafer_783798ba461</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4187069%2F401ce5fb-4894-455c-bdc2-fab824447cf1.png</url>
      <title>DEV Community: Thomas Shafer</title>
      <link>https://dev.to/thomas_shafer_783798ba461</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thomas_shafer_783798ba461"/>
    <language>en</language>
    <item>
      <title>How to see which app is using the most memory on a Mac</title>
      <dc:creator>Thomas Shafer</dc:creator>
      <pubDate>Fri, 06 Nov 2026 16:03:41 +0000</pubDate>
      <link>https://dev.to/thomas_shafer_783798ba461/how-to-see-which-app-is-using-the-most-memory-on-a-mac-556m</link>
      <guid>https://dev.to/thomas_shafer_783798ba461/how-to-see-which-app-is-using-the-most-memory-on-a-mac-556m</guid>
      <description>&lt;p&gt;The quickest answer is to sort Activity Monitor by Memory and read the top rows. The catch is that one app often shows up as dozens of rows, so the biggest single row is rarely the biggest app. The fix is to add the rows up per app. Here is how I do it in Terminal, and how to tell whether the number is a problem at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I see memory use per app instead of per process?
&lt;/h2&gt;

&lt;p&gt;Browsers and Electron apps run many helper processes. Activity Monitor shows each helper on its own line, with names like &lt;code&gt;Google Chrome Helper (Renderer)&lt;/code&gt;. This one-liner groups every process by the &lt;code&gt;.app&lt;/code&gt; it lives in and adds up resident memory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ps &lt;span class="nt"&gt;-axo&lt;/span&gt; &lt;span class="nv"&gt;rss&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;,command&lt;span class="o"&gt;=&lt;/span&gt; | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{ if (match($0, /[^\/]+\.app/)) { a=substr($0,RSTART,RLENGTH); m[a]+=$1 } } END { for (k in m) printf "%8.0f MB  %s\n", m[k]/1024, k }'&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-rn&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It prints something like this, with your own apps and numbers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    4210 MB  Google Chrome.app
    1650 MB  Slack.app
     980 MB  Xcode.app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two caveats. &lt;code&gt;rss&lt;/code&gt; is resident memory, and shared pages get counted once per process that maps them, so the totals run a little high. And anything that isn't inside a &lt;code&gt;.app&lt;/code&gt; bundle, like &lt;code&gt;node&lt;/code&gt; or &lt;code&gt;docker&lt;/code&gt;, is skipped by this command. For those, use the next section.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I find the biggest single processes?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;top&lt;/code&gt; can do it without leaving the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;top &lt;span class="nt"&gt;-o&lt;/span&gt; mem &lt;span class="nt"&gt;-l&lt;/span&gt; 1 &lt;span class="nt"&gt;-n&lt;/span&gt; 10 &lt;span class="nt"&gt;-stats&lt;/span&gt; pid,command,mem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-l 1&lt;/code&gt; takes one sample and exits, &lt;code&gt;-o mem&lt;/code&gt; sorts by memory, and &lt;code&gt;-n 10&lt;/code&gt; limits it to ten rows. This is where command-line tools like &lt;code&gt;node&lt;/code&gt;, &lt;code&gt;python&lt;/code&gt; or &lt;code&gt;java&lt;/code&gt; show up, which the &lt;code&gt;.app&lt;/code&gt; grouping above misses.&lt;/p&gt;

&lt;p&gt;If you have a pile of &lt;code&gt;node&lt;/code&gt; processes, add them up by name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ps &lt;span class="nt"&gt;-axo&lt;/span&gt; &lt;span class="nv"&gt;rss&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;,comm&lt;span class="o"&gt;=&lt;/span&gt; | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{ n=$2; sub(/.*\//,"",n); m[n]+=$1 } END { for (k in m) printf "%8.0f MB  %s\n", m[k]/1024, k }'&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-rn&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the command that first showed me how much a few forgotten dev servers were holding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is high memory use actually a problem on a Mac?
&lt;/h2&gt;

&lt;p&gt;Not by itself. macOS uses spare RAM for file caches on purpose, so "almost all of it is used" is normal. What matters is pressure: whether the system is having to compress memory or swap to disk to keep up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;memory_pressure | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last line reports the percentage of memory free, and the output above it says whether the system is under pressure. Activity Monitor's Memory tab shows the same thing as the green, yellow or red Memory Pressure graph. As a rule of thumb:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Green:&lt;/strong&gt; nothing to do, even if the used number looks scary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Yellow:&lt;/strong&gt; the system is compressing memory. Worth finding the biggest app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Red:&lt;/strong&gt; it is swapping heavily. Quit something now.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also look at swap directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sysctl vm.swapusage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Swap that keeps growing while you work is a better sign of a leak than a high used-memory number is.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I tell a leak from normal use?
&lt;/h2&gt;

&lt;p&gt;A single reading can't tell you. A leak is memory that keeps climbing in one app while you do the same thing. Run the per-app command twice, thirty minutes apart, and compare. If one app gained a couple of gigabytes and the rest are flat, that is your culprit.&lt;/p&gt;

&lt;p&gt;On the Mac I work on, that app was usually a long-running dev server or an Electron app I had left open for days. Quitting and reopening it gave the memory back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can I quit the app safely?
&lt;/h2&gt;

&lt;p&gt;Use the normal quit first, with Cmd-Q, and give it a few seconds. Only use force quit if it hangs, because you can lose unsaved work. From the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;osascript &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'quit app "Slack"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That asks the app to quit the same way Cmd-Q does, so it gets a chance to save. &lt;code&gt;kill -9&lt;/code&gt; does not, so keep it for last.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is there a way to not do this by hand?
&lt;/h2&gt;

&lt;p&gt;I got tired of pasting that &lt;code&gt;awk&lt;/code&gt; line, so I built the answer into Binnacle, the Mac menu bar monitor I make. Its Memory page lists memory by app with helpers folded in, so Chrome is one row. It keeps 30 days of per-app history, so you can look back at what grew yesterday. It has an alert that fires when an app's memory has grown by 2 GB in 30 minutes, at most once an hour per app. Quitting asks you to confirm first. It is free for 14 days and $9 once after that, and the menu bar readouts stay free after the trial: &lt;a href="https://binnacle.shafer.llc?utm_source=blog" rel="noopener noreferrer"&gt;https://binnacle.shafer.llc?utm_source=blog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You don't need it for this, though. The three commands above answer the question on any Mac:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;ps&lt;/code&gt; with &lt;code&gt;awk&lt;/code&gt; to total memory per app.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;top -o mem&lt;/code&gt; for the biggest single processes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;memory_pressure&lt;/code&gt; to decide whether any of it matters.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If pressure is green, close the terminal and get on with your day. If it is yellow or red, the first line of the per-app list is where to start.&lt;/p&gt;

</description>
      <category>bash</category>
      <category>performance</category>
      <category>terminal</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Port 3000 is already in use: find and stop what holds it</title>
      <dc:creator>Thomas Shafer</dc:creator>
      <pubDate>Wed, 04 Nov 2026 17:03:50 +0000</pubDate>
      <link>https://dev.to/thomas_shafer_783798ba461/port-3000-is-already-in-use-find-and-stop-what-holds-it-47b5</link>
      <guid>https://dev.to/thomas_shafer_783798ba461/port-3000-is-already-in-use-find-and-stop-what-holds-it-47b5</guid>
      <description>&lt;p&gt;You run &lt;code&gt;npm run dev&lt;/code&gt; and get &lt;code&gt;EADDRINUSE: address already in use :::3000&lt;/code&gt;. Something is holding the port, and it's usually a dev server you forgot about. Maybe it's from a terminal tab you closed yesterday, or a script that spawned a child and then died.&lt;/p&gt;

&lt;p&gt;This is how I find and stop it, first with the tools that ship with the Mac, then with the way I do it now.&lt;/p&gt;

&lt;h2&gt;
  
  
  The terminal way
&lt;/h2&gt;

&lt;p&gt;Ask which process is listening on the port:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lsof &lt;span class="nt"&gt;-nP&lt;/span&gt; &lt;span class="nt"&gt;-iTCP&lt;/span&gt;:3000 &lt;span class="nt"&gt;-sTCP&lt;/span&gt;:LISTEN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The flags matter. &lt;code&gt;-n&lt;/code&gt; and &lt;code&gt;-P&lt;/code&gt; skip DNS and service-name lookups, which makes it fast. &lt;code&gt;-iTCP:3000 -sTCP:LISTEN&lt;/code&gt; keeps only the listening socket, so you don't get every client connected to it.&lt;/p&gt;

&lt;p&gt;You'll get a table. The &lt;code&gt;PID&lt;/code&gt; column is what you want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;COMMAND   PID  USER   FD   TYPE  NODE NAME
node    48213  tom    23u  IPv6  TCP  *:3000 (LISTEN)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then stop 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;kill &lt;/span&gt;48213
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Plain &lt;code&gt;kill&lt;/code&gt; sends SIGTERM, which lets the process clean up. Give it a second and run the &lt;code&gt;lsof&lt;/code&gt; line again. If it's still there, &lt;code&gt;kill -9 48213&lt;/code&gt; ends it without asking, so use it second, not first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this goes wrong
&lt;/h2&gt;

&lt;p&gt;The two-step routine works, but I kept running into the same few problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The PID tells you nothing.&lt;/strong&gt; &lt;code&gt;node&lt;/code&gt; is not an answer. Which project is that? I have several. Killing the wrong one means losing a running server in another window.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A single &lt;code&gt;node&lt;/code&gt; can be a tree.&lt;/strong&gt; Dev tools spawn workers, watchers and helper processes. You kill the parent and a child keeps the port. You kill the child and the parent starts another.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IPv4 and IPv6 are separate listeners.&lt;/strong&gt; &lt;code&gt;localhost:3000&lt;/code&gt; can be bound on &lt;code&gt;::1&lt;/code&gt; and &lt;code&gt;127.0.0.1&lt;/code&gt; by different processes. Checking only one hides the other.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's not always yours.&lt;/strong&gt; On macOS, AirPlay Receiver has used port 5000 and 7000, and I've seen people blame their own code for hours before finding that out. Check the process name before you kill anything.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To get the project, you can look up the process's working directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lsof &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 48213 &lt;span class="nt"&gt;-d&lt;/span&gt; cwd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That prints the folder the process was started from, which is usually enough to recognise the project. It's a third command, and I never remembered the flags.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I do it in Binnacle
&lt;/h2&gt;

&lt;p&gt;I built &lt;a href="https://binnacle.shafer.llc?utm_source=blog" rel="noopener noreferrer"&gt;Binnacle&lt;/a&gt; partly because I was tired of this routine. It's a Mac activity monitor that lives in the menu bar and opens into a full-window console I call the Command Deck. It has two ways to deal with a stuck port.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The ⌘K command line.&lt;/strong&gt; Open the Deck, press ⌘K and type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;port 3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It shows the process holding the port. If that's the one you want gone:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kill port 3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It asks you to confirm before it does anything. That confirmation is deliberate: every quit in Binnacle asks first, because I've closed the wrong thing too many times.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Projects page.&lt;/strong&gt; If you don't know which port you're after, this page lists your dev servers grouped by project folder. Each row shows the ports it's listening on, its memory use and how long it has been idle, with a Stop button. The folder grouping answers the "which project is that?" question without a &lt;code&gt;cwd&lt;/code&gt; lookup. The idle time helps with the forgotten ones. A server that has been idle since yesterday morning is probably not one you need.&lt;/p&gt;

&lt;p&gt;One implementation detail, in case you care: Binnacle reads ports through libproc, a macOS system library, so it doesn't shell out to &lt;code&gt;lsof&lt;/code&gt; and parse the text.&lt;/p&gt;

&lt;h2&gt;
  
  
  A short checklist
&lt;/h2&gt;

&lt;p&gt;Whichever tool you use, this order saves me time:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find the listener on the port, not just any socket that mentions it.&lt;/li&gt;
&lt;li&gt;Work out which project it belongs to before you stop it.&lt;/li&gt;
&lt;li&gt;Try a normal stop (SIGTERM) first. Escalate only if it stays.&lt;/li&gt;
&lt;li&gt;Run the check again to confirm the port is actually free.&lt;/li&gt;
&lt;li&gt;If the same port is busy again a minute later, something is restarting it. Look at the parent process, a file watcher or a process manager, instead of killing it over and over.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Is it worth paying for?
&lt;/h2&gt;

&lt;p&gt;If you hit this once a month, the &lt;code&gt;lsof&lt;/code&gt; and &lt;code&gt;kill&lt;/code&gt; pair is fine, and you shouldn't install anything. Save the one-liner as a shell alias and move on.&lt;/p&gt;

&lt;p&gt;Binnacle makes more sense if you run several dev servers at once, or if the port is only one of the questions you ask. The same Deck covers things like which app is behind a spinning fan, or what's using the memory. It has a 14-day trial with everything unlocked. After that it's $9 once, and the menu bar readouts stay free. The Deck, including the Projects page and ⌘K, needs the license.&lt;/p&gt;

&lt;p&gt;It needs macOS 14 or later. It collects no telemetry, and its only network calls are license activation and update checks.&lt;/p&gt;

&lt;p&gt;If you try the port commands and one of them gets it wrong on your machine, tell me which setup you were running. Those reports are the most useful thing I get.&lt;/p&gt;

</description>
      <category>cli</category>
      <category>debugging</category>
      <category>tools</category>
    </item>
    <item>
      <title>Why is my Mac's fan so loud? How to find the app causing it</title>
      <dc:creator>Thomas Shafer</dc:creator>
      <pubDate>Mon, 02 Nov 2026 17:04:41 +0000</pubDate>
      <link>https://dev.to/thomas_shafer_783798ba461/why-is-my-macs-fan-so-loud-how-to-find-the-app-causing-it-4cl9</link>
      <guid>https://dev.to/thomas_shafer_783798ba461/why-is-my-macs-fan-so-loud-how-to-find-the-app-causing-it-4cl9</guid>
      <description>&lt;p&gt;A loud fan almost always means one thing: some app is keeping the CPU busy, and the chip is getting hot. Open Activity Monitor, click the &lt;strong&gt;% CPU&lt;/strong&gt; column to sort, and watch the top rows for 30 seconds. Whatever stays near the top is your answer, or at least your first suspect.&lt;/p&gt;

&lt;p&gt;That's the short version. The rest of this post covers where it goes wrong, the Terminal version, and what I do now.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I see what is using the CPU?
&lt;/h2&gt;

&lt;p&gt;In Activity Monitor (Applications &amp;gt; Utilities), select the &lt;strong&gt;CPU&lt;/strong&gt; tab and click &lt;strong&gt;% CPU&lt;/strong&gt; until the arrow points down. Don't trust a single glance. CPU use jumps around, so watch for half a minute and note which names keep coming back.&lt;/p&gt;

&lt;p&gt;In Terminal, the same thing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;top &lt;span class="nt"&gt;-o&lt;/span&gt; cpu &lt;span class="nt"&gt;-n&lt;/span&gt; 10 &lt;span class="nt"&gt;-l&lt;/span&gt; 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-o cpu&lt;/code&gt; sorts by CPU, &lt;code&gt;-n 10&lt;/code&gt; shows 10 processes, and &lt;code&gt;-l 2&lt;/code&gt; takes two samples. Read the second one. The first sample reports CPU use since the process started, which is why a one-shot &lt;code&gt;top&lt;/code&gt; often shows nonsense.&lt;/p&gt;

&lt;p&gt;For a quick snapshot without the live display:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ps &lt;span class="nt"&gt;-Ao&lt;/span&gt; pid,pcpu,comm &lt;span class="nt"&gt;-r&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 11
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-r&lt;/code&gt; sorts by CPU on macOS. The first line is the header, so &lt;code&gt;head -n 11&lt;/code&gt; gives you the top 10.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does the list not make sense?
&lt;/h2&gt;

&lt;p&gt;Because modern apps are not one process. Chrome, Slack, VS Code and most Electron apps run a main process plus a pile of helpers, renderers and GPU processes. In Activity Monitor, they show up under names like &lt;code&gt;Google Chrome Helper (Renderer)&lt;/code&gt;, a dozen times each.&lt;/p&gt;

&lt;p&gt;Two things follow from that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No single row looks guilty.&lt;/strong&gt; Ten helpers at 8% each is 80% of a core, but nothing in the list looks alarming.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Some names don't point to an app.&lt;/strong&gt; &lt;code&gt;node&lt;/code&gt;, &lt;code&gt;python3&lt;/code&gt; and &lt;code&gt;WindowServer&lt;/code&gt; tell you what ran, not who asked for it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So after sorting, I add up the rows by app in my head, which is tedious. If you do it by hand, add the &lt;code&gt;%CPU&lt;/code&gt; of every helper whose name starts with the same app and compare the totals.&lt;/p&gt;

&lt;h2&gt;
  
  
  What if the CPU looks fine?
&lt;/h2&gt;

&lt;p&gt;Sometimes the fan is loud and no single app is high. Check these:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Is the Mac thermally constrained?&lt;/strong&gt; Running in a closed clamshell, on a soft surface, or on a charging dock with a hot charger all reduce cooling. Fix the situation first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Is it the GPU or media?&lt;/strong&gt; Video calls, external displays and screen sharing load the GPU and media engines, which don't show up as CPU.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Is it the disk or network?&lt;/strong&gt; A big sync or backup can keep several subsystems busy at once. Check the Disk and Network tabs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Is it a short spike?&lt;/strong&gt; Spotlight indexing after an update, or Photos analysing a library, can run hot for an hour and then stop. If it settles by itself, leave it alone.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To see the thermal state macOS itself reports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pmset &lt;span class="nt"&gt;-g&lt;/span&gt; thermlog
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it prints nothing about CPU limits, the system isn't throttling you.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I stop it?
&lt;/h2&gt;

&lt;p&gt;Once you know the app:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Quit it normally&lt;/strong&gt; (⌘Q). Wait ten seconds.&lt;/li&gt;
&lt;li&gt;If it doesn't quit, select it in Activity Monitor and use &lt;strong&gt;Force Quit&lt;/strong&gt; (the stop button). Save your work first.&lt;/li&gt;
&lt;li&gt;If it comes back on its own, something is relaunching it. Check Login Items in System Settings &amp;gt; General.&lt;/li&gt;
&lt;li&gt;If the same app does it every day, look for an update, or a specific tab, extension or project that triggers it. In a browser, I find the heavy tab by opening the browser's own task manager instead of guessing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Don't force quit a process whose name you don't recognise without searching for it first. Quitting &lt;code&gt;WindowServer&lt;/code&gt; logs you out, and &lt;code&gt;kernel_task&lt;/code&gt; going high is usually the system protecting itself from heat, not the cause of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I do it now
&lt;/h2&gt;

&lt;p&gt;I got tired of adding up helper rows, so I built &lt;a href="https://binnacle.shafer.llc?utm_source=blog" rel="noopener noreferrer"&gt;Binnacle&lt;/a&gt;, a Mac activity monitor for the menu bar. It groups processes by app, so Chrome is one row with its CPU, memory, disk, network, GPU and energy summed. The CPU page shows temperatures, fans and the top apps in one place. In the ⌘K command line, &lt;code&gt;why chrome&lt;/code&gt; explains what that app is doing, and &lt;code&gt;quit chrome&lt;/code&gt; closes it after a confirmation.&lt;/p&gt;

&lt;p&gt;On Apple silicon Macs, Binnacle can also set a fan to a fixed speed, within the fan's own minimum and maximum, and it goes back to automatic when the app quits. I mostly use it to check that a fan is doing its job, not to run it hard.&lt;/p&gt;

&lt;p&gt;It has a 14-day trial with everything unlocked. After that it's $9 once, and the menu bar readouts keep working for free. The Deck, the console where all of this lives, needs the license. It requires macOS 14 or later.&lt;/p&gt;

&lt;p&gt;If Activity Monitor and the Terminal lines above answer your question, you don't need it. They answer it for most people most of the time. I built Binnacle for the days when I'd rather not do arithmetic across 30 helper processes to find out which app is hot.&lt;/p&gt;

</description>
      <category>hardware</category>
      <category>performance</category>
      <category>tools</category>
    </item>
    <item>
      <title>How to ask Claude what's eating your Mac's CPU (MCP setup)</title>
      <dc:creator>Thomas Shafer</dc:creator>
      <pubDate>Sat, 31 Oct 2026 17:04:41 +0000</pubDate>
      <link>https://dev.to/thomas_shafer_783798ba461/how-to-ask-claude-whats-eating-your-macs-cpu-mcp-setup-14en</link>
      <guid>https://dev.to/thomas_shafer_783798ba461/how-to-ask-claude-whats-eating-your-macs-cpu-mcp-setup-14en</guid>
      <description>&lt;p&gt;You can ask Claude, Codex or Cursor what is slowing your Mac down, and get an answer from live data instead of generic advice. You need an MCP server on your Mac that reports what is running. Register it once, and the assistant can call it whenever you ask.&lt;/p&gt;

&lt;p&gt;I built one into Binnacle, my menu bar monitor, called &lt;code&gt;binnacle-mcp&lt;/code&gt;. Here is how the setup works and what it can and can't do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why can't an assistant just answer this itself?
&lt;/h2&gt;

&lt;p&gt;Because it can't see your machine. Ask "why is my fan loud?" in a plain chat and you get a list of guesses: close tabs, check Activity Monitor, reset the SMC. Nothing in that answer comes from your Mac.&lt;/p&gt;

&lt;p&gt;An assistant that can run &lt;code&gt;top&lt;/code&gt; in a terminal gets closer, but &lt;code&gt;top&lt;/code&gt; lists processes. Chrome alone shows up as dozens of helper rows, and Electron apps and &lt;code&gt;node&lt;/code&gt; do the same. In one of my screenshots, &lt;code&gt;node&lt;/code&gt; is 134 processes and 9.06 GB. That's a lot of rows for an assistant to add up itself.&lt;/p&gt;

&lt;p&gt;MCP (Model Context Protocol) fixes this by giving the assistant a few named tools it can call. The tools do the measuring. The assistant only has to ask.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I add it to Claude Code?
&lt;/h2&gt;

&lt;p&gt;In Binnacle, open Settings › Assistants. It shows a ready-made line with the right path for your install. It looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add binnacle &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s2"&gt;"/Applications/Binnacle.app/Contents/MacOS/binnacle-mcp"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The path in your copy depends on where you put the app, so copy the line from Settings rather than typing it. Run it in a terminal, then check that it registered:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server talks to the assistant over stdio, so there is nothing to host and no port to open. Codex and Cursor can use the same binary. They each have their own way of registering an MCP server, so check their docs for the config format.&lt;/p&gt;

&lt;p&gt;The server is off by default. You switch it on in Binnacle first. Until you do, the tools reply that it's disabled.&lt;/p&gt;

&lt;h2&gt;
  
  
  What can the assistant ask for?
&lt;/h2&gt;

&lt;p&gt;There are six tools:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it returns&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;system_status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Whole-Mac snapshot: process count, load, temperatures, fans, GPU, battery, disk space, Bluetooth batteries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;top_apps&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Busiest apps, with helper processes folded into their app. CPU is percent of one core&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;app_details&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;One app by name: CPU, memory, processes, listening ports&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;who_uses_port&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Which process is listening on a TCP port, and the folder it was started in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;dev_servers&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Servers running inside project folders, with their ports and memory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;request_quit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Asks you, in Binnacle's own window, whether to quit an app&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One detail matters for CPU questions: &lt;code&gt;top_apps&lt;/code&gt; reports percent of &lt;em&gt;one core&lt;/em&gt;. On a multi-core Mac, an app at 250% is using two and a half cores, not breaking the scale. If the assistant says "Chrome is at 180%", that is the number it means.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does a real question look like?
&lt;/h2&gt;

&lt;p&gt;Try these in Claude Code once the server is registered:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What's using the most CPU on my Mac right now?
Why is my fan running? Check temperatures and the busiest apps.
What is listening on port 3000, and which project started it?
Which dev servers are running, and how much memory are they using?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fan question is a good example of why tools beat guesses. The assistant can call &lt;code&gt;system_status&lt;/code&gt; for temperatures and fans, then &lt;code&gt;top_apps&lt;/code&gt; for the culprit, and answer in one reply with the app's name attached.&lt;/p&gt;

&lt;p&gt;The port question is the one I use most. &lt;code&gt;who_uses_port&lt;/code&gt; returns the process and the folder it was started in, so the assistant can tell you "that's the Vite server from &lt;code&gt;~/Projects/shop&lt;/code&gt;" rather than a bare PID.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can the assistant kill things on its own?
&lt;/h2&gt;

&lt;p&gt;No, and that was a deliberate limit. Five of the six tools only read. The sixth, &lt;code&gt;request_quit&lt;/code&gt;, doesn't quit anything. It opens a confirmation dialog in Binnacle, and you decide there. If you ignore it, nothing happens.&lt;/p&gt;

&lt;p&gt;I wanted it this way because an assistant that acts on a wrong guess about a process is a bad trade for the convenience. A confirmation dialog costs one click.&lt;/p&gt;

&lt;p&gt;Binnacle has no telemetry. Its only network calls are license activation and update checks.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does it cost?
&lt;/h2&gt;

&lt;p&gt;Binnacle has a 14-day trial with everything unlocked, then it's $9 once. &lt;code&gt;binnacle-mcp&lt;/code&gt; is part of what the license unlocks after the trial. The menu bar readouts stay free after the trial, but the MCP server doesn't.&lt;/p&gt;

&lt;p&gt;If you'd rather not install anything, the same questions work from a terminal with &lt;code&gt;top -o cpu&lt;/code&gt; and &lt;code&gt;lsof -i :3000&lt;/code&gt;. You'll do the adding up yourself, and the assistant won't see any of it.&lt;/p&gt;

&lt;p&gt;If you want the version where the assistant does the adding up, Binnacle is at &lt;a href="https://binnacle.shafer.llc?utm_source=blog" rel="noopener noreferrer"&gt;https://binnacle.shafer.llc?utm_source=blog&lt;/a&gt;. It needs macOS 14 or later.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd check if it doesn't work
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The assistant says the tools are disabled.&lt;/strong&gt; Turn the server on in Settings › Assistants.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;claude mcp list&lt;/code&gt; doesn't show &lt;code&gt;binnacle&lt;/code&gt;.&lt;/strong&gt; Re-run the copied line and check the quotes around the path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It worked, then stopped after a trial ended.&lt;/strong&gt; The MCP server needs a license after the 14 days.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>mcp</category>
      <category>tools</category>
    </item>
    <item>
      <title>EADDRINUSE on macOS: find what holds the port, and stop it safely</title>
      <dc:creator>Thomas Shafer</dc:creator>
      <pubDate>Sun, 18 Oct 2026 17:03:06 +0000</pubDate>
      <link>https://dev.to/thomas_shafer_783798ba461/eaddrinuse-on-macos-find-what-holds-the-port-and-stop-it-safely-n1o</link>
      <guid>https://dev.to/thomas_shafer_783798ba461/eaddrinuse-on-macos-find-what-holds-the-port-and-stop-it-safely-n1o</guid>
      <description>&lt;p&gt;You run &lt;code&gt;npm run dev&lt;/code&gt; and 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;Error: listen EADDRINUSE: address already in use :::3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Something is already listening on port 3000. Usually it's a dev server you forgot about: a terminal tab you closed, an editor task that never exited, or a watcher that outlived its parent. This post covers how to find the owner on macOS, how to stop it without guessing, and a pair of shell functions so you only have to work it out once.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: ask the kernel who is listening
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;lsof&lt;/code&gt; is already on your Mac. This is the form worth memorising:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lsof &lt;span class="nt"&gt;-nP&lt;/span&gt; &lt;span class="nt"&gt;-iTCP&lt;/span&gt;:3000 &lt;span class="nt"&gt;-sTCP&lt;/span&gt;:LISTEN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What each flag does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-n&lt;/code&gt; skips DNS lookups, so it returns instantly.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-P&lt;/code&gt; shows &lt;code&gt;3000&lt;/code&gt; instead of a service name.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-iTCP:3000&lt;/code&gt; limits it to TCP port 3000.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-sTCP:LISTEN&lt;/code&gt; hides client connections, so you only see the process that owns the port.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;COMMAND   PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
node    48213 tom    23u  IPv6  0x1234      0t0  TCP *:3000 (LISTEN)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-sTCP:LISTEN&lt;/code&gt; filter matters more than it looks. Without it, &lt;code&gt;lsof -i :3000&lt;/code&gt; also lists your browser's open connections to the server, and you can end up killing Chrome instead.&lt;/p&gt;

&lt;p&gt;If you only want the PID, &lt;code&gt;-t&lt;/code&gt; prints just that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lsof &lt;span class="nt"&gt;-nP&lt;/span&gt; &lt;span class="nt"&gt;-tiTCP&lt;/span&gt;:3000 &lt;span class="nt"&gt;-sTCP&lt;/span&gt;:LISTEN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: check what it is before you kill it
&lt;/h2&gt;

&lt;p&gt;A PID tells you very little. Before you stop it, look at two things: the full command line and the working directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ps &lt;span class="nt"&gt;-o&lt;/span&gt; pid,etime,command &lt;span class="nt"&gt;-p&lt;/span&gt; 48213
lsof &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 48213 &lt;span class="nt"&gt;-d&lt;/span&gt; cwd &lt;span class="nt"&gt;-Fn&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s1"&gt;'s/^n//p'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;etime&lt;/code&gt; shows how long it has been running, and the &lt;code&gt;cwd&lt;/code&gt; line shows which project folder it was started from. Together they usually settle it. A &lt;code&gt;node&lt;/code&gt; process that has been up for three days, started from &lt;code&gt;~/old-prototype&lt;/code&gt;, is safe to stop. One that started two minutes ago from the project you're working on is probably your own server, running in another tab.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: ask nicely first
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;kill&lt;/code&gt; with no signal sends &lt;code&gt;SIGTERM&lt;/code&gt;, which lets the process close its sockets and clean up. Use &lt;code&gt;kill -9&lt;/code&gt; only if that doesn't work.&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;kill &lt;/span&gt;48213
&lt;span class="nb"&gt;sleep &lt;/span&gt;1
lsof &lt;span class="nt"&gt;-nP&lt;/span&gt; &lt;span class="nt"&gt;-tiTCP&lt;/span&gt;:3000 &lt;span class="nt"&gt;-sTCP&lt;/span&gt;:LISTEN &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"port 3000 is free"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reaching for &lt;code&gt;kill -9&lt;/code&gt; first is a common habit and it costs you something real. A process killed that way can't remove its lock files, flush its logs or shut down its child processes, and you can end up with a half-written database or a leaked worker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: put it in your dotfiles
&lt;/h2&gt;

&lt;p&gt;Here are two functions for &lt;code&gt;~/.zshrc&lt;/code&gt;. &lt;code&gt;port&lt;/code&gt; shows who holds a port. &lt;code&gt;killport&lt;/code&gt; stops it with &lt;code&gt;SIGTERM&lt;/code&gt;, waits, and only then falls back to &lt;code&gt;SIGKILL&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;port&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  lsof &lt;span class="nt"&gt;-nP&lt;/span&gt; &lt;span class="nt"&gt;-iTCP&lt;/span&gt;:&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;:?usage:&lt;span class="p"&gt; port N&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-sTCP&lt;/span&gt;:LISTEN
&lt;span class="o"&gt;}&lt;/span&gt;

killport&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;pids
  &lt;span class="nv"&gt;pids&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;lsof &lt;span class="nt"&gt;-nP&lt;/span&gt; &lt;span class="nt"&gt;-tiTCP&lt;/span&gt;:&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;:?usage:&lt;span class="p"&gt; killport N&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-sTCP&lt;/span&gt;:LISTEN&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$pids&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"nothing is listening on &lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;return &lt;/span&gt;0&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$pids&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | xargs &lt;span class="nb"&gt;kill
  sleep &lt;/span&gt;1
  &lt;span class="nv"&gt;pids&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;lsof &lt;span class="nt"&gt;-nP&lt;/span&gt; &lt;span class="nt"&gt;-tiTCP&lt;/span&gt;:&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-sTCP&lt;/span&gt;:LISTEN&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$pids&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$pids&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | xargs &lt;span class="nb"&gt;kill&lt;/span&gt; &lt;span class="nt"&gt;-9&lt;/span&gt;
  lsof &lt;span class="nt"&gt;-nP&lt;/span&gt; &lt;span class="nt"&gt;-tiTCP&lt;/span&gt;:&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-sTCP&lt;/span&gt;:LISTEN &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"port &lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt; is free"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open a new terminal and run &lt;code&gt;port 3000&lt;/code&gt; or &lt;code&gt;killport 3000&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One limit: this only sees processes you own. If the listener belongs to root or another user, &lt;code&gt;lsof&lt;/code&gt; without &lt;code&gt;sudo&lt;/code&gt; may show nothing at all. In that case you'll get "nothing is listening" even though the port really is taken, so try &lt;code&gt;sudo lsof ...&lt;/code&gt; before concluding it's free.&lt;/p&gt;

&lt;h2&gt;
  
  
  When killing the process isn't the answer
&lt;/h2&gt;

&lt;p&gt;Some holders come back, or aren't what they look like.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Port 5000 or 7000 on a recent Mac.&lt;/strong&gt; macOS's AirPlay Receiver listens on both. The owner shows up as &lt;code&gt;ControlCe&lt;/code&gt; (Control Center). Turn it off in System Settings &amp;gt; General &amp;gt; AirDrop &amp;amp; Handoff &amp;gt; AirPlay Receiver, or move your dev server to another port. Killing it just makes macOS start it again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The owner is Docker.&lt;/strong&gt; If &lt;code&gt;lsof&lt;/code&gt; shows &lt;code&gt;com.docker.backend&lt;/code&gt; or similar, a container has published the port. Use &lt;code&gt;docker ps --format '{{.Names}}\t{{.Ports}}'&lt;/code&gt; to find the container, then &lt;code&gt;docker stop&lt;/code&gt; it. Killing the backend process takes down every container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The process has a parent that restarts it.&lt;/strong&gt; &lt;code&gt;nodemon&lt;/code&gt;, &lt;code&gt;next dev&lt;/code&gt;, a &lt;code&gt;docker compose&lt;/code&gt; restart policy and some editor tasks will respawn what you kill. Check the parent with &lt;code&gt;ps -o ppid= -p PID&lt;/code&gt;, then look at what that parent is.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nothing is listening, but the bind still fails.&lt;/strong&gt; This is rare. It can happen when a server binds the same address and port twice, such as &lt;code&gt;localhost&lt;/code&gt; resolving to both &lt;code&gt;::1&lt;/code&gt; and &lt;code&gt;127.0.0.1&lt;/code&gt;, or two copies of a framework starting in one process. &lt;code&gt;lsof&lt;/code&gt; will show one listener for each address family, so read the NAME column carefully.&lt;/p&gt;

&lt;h2&gt;
  
  
  A small habit that prevents most of this
&lt;/h2&gt;

&lt;p&gt;Most EADDRINUSE errors come from servers that were started and then abandoned. Two habits cut them down:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run dev servers in the foreground in a terminal you can see. Don't background them with &lt;code&gt;&amp;amp;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Let your tooling pick a free port where it supports that. Many frameworks will move to the next port if you tell them to, instead of failing.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Full disclosure: I made a tool for this
&lt;/h2&gt;

&lt;p&gt;I built Binnacle, a native Mac menu bar monitor, partly because I got tired of typing the commands above. In its ⌘K command line, &lt;code&gt;port 3000&lt;/code&gt; shows the process, and &lt;code&gt;kill port 3000&lt;/code&gt; stops it after a confirmation. Its Projects page groups dev servers by project folder and shows their ports, memory and how long they've been idle, with a Stop button. The menu bar readouts are free. The rest of the app is free for 14 days, then $9 once. It needs macOS 14 or later. It's at &lt;a href="https://binnacle.shafer.llc?utm_source=devto" rel="noopener noreferrer"&gt;https://binnacle.shafer.llc?utm_source=devto&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You don't need it for any of the above. The two functions in your &lt;code&gt;.zshrc&lt;/code&gt; will cover most days.&lt;/p&gt;

&lt;p&gt;What's the strangest thing you've found sitting on a port? I'm curious what other surprise listeners are out there.&lt;/p&gt;

</description>
      <category>macos</category>
      <category>node</category>
      <category>shell</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
