<?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: DeviceShelf</title>
    <description>The latest articles on DEV Community by DeviceShelf (@deviceshelf).</description>
    <link>https://dev.to/deviceshelf</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%2F4022828%2F92dc3100-4e93-49c8-b92e-e8436b77eb76.png</url>
      <title>DEV Community: DeviceShelf</title>
      <link>https://dev.to/deviceshelf</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/deviceshelf"/>
    <language>en</language>
    <item>
      <title>Building a local-first network scanner in Go, Wails and Flutter</title>
      <dc:creator>DeviceShelf</dc:creator>
      <pubDate>Thu, 09 Jul 2026 13:34:48 +0000</pubDate>
      <link>https://dev.to/deviceshelf/building-a-local-first-network-scanner-in-go-wails-and-flutter-4f87</link>
      <guid>https://dev.to/deviceshelf/building-a-local-first-network-scanner-in-go-wails-and-flutter-4f87</guid>
      <description>&lt;p&gt;Most network scanners I tried wanted a cloud account and a subscription just to tell me what was sitting on my own LAN. That bugged me enough to build the opposite: a scanner that runs on your machine, keeps the data there, and still tells you what every device is. It's called DeviceShelf, and this is a short tour of how it's put together.&lt;/p&gt;

&lt;h2&gt;
  
  
  One core, three front-ends
&lt;/h2&gt;

&lt;p&gt;The scanning and analysis live in a Go core: ARP/ping sweep, port checks, service probes, DHCP fingerprinting, SNMP, and the device-identification logic. On the desktop that core is wrapped with &lt;a href="https://wails.io" rel="noopener noreferrer"&gt;Wails&lt;/a&gt; — Go on the backend, a normal web UI on the front — so the same engine ships on macOS, Windows and Linux without three native rewrites. The mobile apps are Flutter, talking to the same concepts (a chunk of the identification logic is mirrored and unit-tested on both sides so behaviour matches). And there's a headless build of the core for a 24/7 server edition with no GUI at all.&lt;/p&gt;

&lt;p&gt;Keeping one engine and swapping the shell is the only reason a solo project can cover desktop, mobile and server without drowning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local-first, and meaning it
&lt;/h2&gt;

&lt;p&gt;"Local-first" is easy to put on a landing page and easy to quietly break. The rule here is simple: nothing about your network leaves the machine unless you switch something on. Device identification runs locally; the online fingerprint lookup is opt-in and off by default. If you want AI to help name a weird device, that's there too — but you bring your own key, so the calls are yours, not routed through a server I run.&lt;/p&gt;

&lt;h2&gt;
  
  
  The parts that were actually hard
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Identification.&lt;/strong&gt; Turning a MAC prefix, open ports, a DHCP fingerprint and an SNMP sysName into "this is a printer" is a pile of heuristics with sharp edges — a Nintendo Switch that looks like a network switch, say. It's ordered rules, not one magic classifier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live bandwidth.&lt;/strong&gt; Per-device throughput means packet capture (Npcap on Windows, BPF on macOS), which is platform- and permission-dependent and needs care to stay light.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The server edition.&lt;/strong&gt; Running unattended on a LAN changes everything: alert routing over ntfy/Gotify/webhook, threshold and dependency checks, and taming alert floods so it doesn't page you at 3am because Wi-Fi hiccuped.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where it is now
&lt;/h2&gt;

&lt;p&gt;Desktop and mobile are shipping; the server edition is an honest public beta. If you want to see what's on your own network without signing up for anything, that's the whole point.&lt;/p&gt;

&lt;p&gt;Full write-ups and release notes: &lt;a href="https://deviceshelf.app/blog" rel="noopener noreferrer"&gt;https://deviceshelf.app/blog&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>flutter</category>
      <category>privacy</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
