<?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: Finn Liu</title>
    <description>The latest articles on DEV Community by Finn Liu (@_bd31c79786d454464f39ed).</description>
    <link>https://dev.to/_bd31c79786d454464f39ed</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%2F4128233%2Ffc057ebb-5407-4abd-8b4b-2ff03f1b1014.jpg</url>
      <title>DEV Community: Finn Liu</title>
      <link>https://dev.to/_bd31c79786d454464f39ed</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/_bd31c79786d454464f39ed"/>
    <language>en</language>
    <item>
      <title>Two questions before you run a local LLM: does it fit, and how fast is it really?</title>
      <dc:creator>Finn Liu</dc:creator>
      <pubDate>Sat, 17 Oct 2026 01:02:00 +0000</pubDate>
      <link>https://dev.to/_bd31c79786d454464f39ed/two-questions-before-you-run-a-local-llm-does-it-fit-and-how-fast-is-it-really-1fh6</link>
      <guid>https://dev.to/_bd31c79786d454464f39ed/two-questions-before-you-run-a-local-llm-does-it-fit-and-how-fast-is-it-really-1fh6</guid>
      <description>&lt;p&gt;I keep seeing the same two failures when people try to run a model locally. The first is buying or allocating hardware that cannot hold the model plus its context. The second is trusting a single tokens/s number that was measured under completely different conditions.&lt;/p&gt;

&lt;p&gt;This is not a product pitch. It is the checklist I use now, plus a small tool I built because I kept redoing the arithmetic.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Separate memory fit from speed
&lt;/h3&gt;

&lt;p&gt;These are two different questions and they deserve two different kinds of evidence.&lt;/p&gt;

&lt;p&gt;Memory fit is arithmetic you can do yourself. Start with the stored size of the quantized weights, add the KV cache for the context you actually want, then leave headroom for the runtime, the driver and the desktop. A 70B model at Q4 is roughly 40 GB of weights before you add anything else, so "it runs on a 24 GB card" is usually a configuration that offloads to system RAM and then runs slowly.&lt;/p&gt;

&lt;p&gt;Speed is a measurement, and it only means something with its conditions attached: exact hardware, exact checkpoint, quantization, runtime and version, context and prompt length, concurrency, and how the number was produced (prefill / TTFT / decode). A decode number from a single stream is not a throughput number from eight concurrent requests. A vendor claim is not a measurement. If the source does not name all of that, the honest answer is "unknown", not a green check.&lt;/p&gt;

&lt;p&gt;Note especially: prefill time and tokens/s are not interchangeable. If you only have TTFT, you are looking at a derived prefill estimate, and it should be labelled that way.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Pick the runtime before you shop
&lt;/h3&gt;

&lt;p&gt;The runtime decides what is even possible. CUDA, ROCm, Metal, Vulkan, CPU and NPU are separate lanes with separate floors, and a feature that exists on one lane is not proof for another. On Apple silicon, for example, MLX is the native path; on an NVIDIA server, vLLM or SGLang are the throughput paths; on a mixed CPU+GPU box, an offloading runtime for mixture-of-experts models is a different trade again.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Serving Apple silicon as an OpenAI-compatible endpoint
&lt;/h3&gt;

&lt;p&gt;A detail worth knowing if you run MLX: &lt;code&gt;mlx-lm&lt;/code&gt; ships &lt;code&gt;mlx_lm.server&lt;/code&gt;, an OpenAI-compatible HTTP server. It exposes &lt;code&gt;/v1/chat/completions&lt;/code&gt;, &lt;code&gt;/v1/completions&lt;/code&gt; and &lt;code&gt;/v1/models&lt;/code&gt;, defaults to &lt;code&gt;127.0.0.1:8080&lt;/code&gt;, and takes &lt;code&gt;--model&lt;/code&gt; plus &lt;code&gt;--host&lt;/code&gt; / &lt;code&gt;--port&lt;/code&gt;. It is convenient for pointing an existing OpenAI client at your Mac.&lt;/p&gt;

&lt;p&gt;The important caveat is upstream's own: &lt;code&gt;mlx_lm.server&lt;/code&gt; implements only basic security checks and is &lt;strong&gt;not recommended for production&lt;/strong&gt;. Keep it bound to localhost unless you add authentication and network controls in front of it. For a single-user local setup that is fine; for anything exposed, it is not.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Write the conditions down
&lt;/h3&gt;

&lt;p&gt;Whatever you measure, record the conditions next to the number. Six weeks later, "42 tok/s" without "M5 Max, Q4, 8k context, single stream, mlx-lm x.y" is useless to you and misleading to anyone else.&lt;/p&gt;

&lt;p&gt;If you want a starting point, I keep a sourced reference that separates memory fit, practical context, measured speed, vendor claims and unknowns, and links every number to its source: &lt;a href="https://localai.hexmobius.com/en/guides/best-gpu-for-local-llm?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=local_llm_fit_20261016" rel="noopener noreferrer"&gt;LocalForge&lt;/a&gt;. It is a decision guide, not a benchmark lab - it publishes no numbers of its own.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>machinelearning</category>
      <category>hardware</category>
    </item>
    <item>
      <title>Build Notes: A Browser-Local Image Compressor for Everyday Upload Problems</title>
      <dc:creator>Finn Liu</dc:creator>
      <pubDate>Thu, 08 Oct 2026 23:41:28 +0000</pubDate>
      <link>https://dev.to/_bd31c79786d454464f39ed/build-notes-a-browser-local-image-compressor-for-everyday-upload-problems-4b80</link>
      <guid>https://dev.to/_bd31c79786d454464f39ed/build-notes-a-browser-local-image-compressor-for-everyday-upload-problems-4b80</guid>
      <description>&lt;p&gt;I built Quick Image Kit as a small browser-local image toolkit: &lt;a href="https://quickimagekit.com/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=browser_local_build_notes" rel="noopener noreferrer"&gt;quickimagekit.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The product is intentionally practical. Many people do not need a full photo editor. They need to make a phone photo small enough for an upload form, profile page, email attachment, document portal, school system, job application, or favicon package.&lt;/p&gt;

&lt;p&gt;The design constraint is simple: the image should be processed in the browser where possible, so the original file does not need to be uploaded to a processing server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why local processing matters
&lt;/h2&gt;

&lt;p&gt;Image compression sounds low-risk until the files are personal. The same workflow often handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ID photos&lt;/li&gt;
&lt;li&gt;passport-style photos&lt;/li&gt;
&lt;li&gt;document scans&lt;/li&gt;
&lt;li&gt;school records&lt;/li&gt;
&lt;li&gt;legal or medical paperwork&lt;/li&gt;
&lt;li&gt;internal screenshots&lt;/li&gt;
&lt;li&gt;application form attachments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For those files, the safest default is not "upload first, compress later." A browser-local flow lets the user load the image, create a smaller copy, download the result, and then upload only that final copy to the actual destination.&lt;/p&gt;

&lt;p&gt;That is the main positioning behind Quick Image Kit's &lt;a href="https://quickimagekit.com/compress-image?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=browser_local_build_notes" rel="noopener noreferrer"&gt;browser-local image compressor&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The main UX problem is not the codec
&lt;/h2&gt;

&lt;p&gt;For an image compressor, it is tempting to start with codecs, quality settings, or performance. Those matter, but they are not the first user problem.&lt;/p&gt;

&lt;p&gt;The first problem is that users usually do not know what changed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Did the image get smaller?&lt;/li&gt;
&lt;li&gt;Is it now under the upload limit?&lt;/li&gt;
&lt;li&gt;Did the dimensions change?&lt;/li&gt;
&lt;li&gt;Is the face still clear?&lt;/li&gt;
&lt;li&gt;Is document text still readable?&lt;/li&gt;
&lt;li&gt;Is the output format accepted by the form?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the interface has to explain the result in normal upload-language, not just expose a quality slider.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resize before heavy compression
&lt;/h2&gt;

&lt;p&gt;Large phone photos often start at 3000 to 4000 pixels wide. If the target is a small profile photo or form attachment, resizing usually improves the result more than pushing JPEG quality lower and lower.&lt;/p&gt;

&lt;p&gt;The practical order is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Crop away unnecessary background.&lt;/li&gt;
&lt;li&gt;Resize when the source image is far larger than the upload needs.&lt;/li&gt;
&lt;li&gt;Compress toward the target size.&lt;/li&gt;
&lt;li&gt;Check readability before downloading.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That is why a useful image toolkit needs &lt;a href="https://quickimagekit.com/resize-image?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=browser_local_build_notes" rel="noopener noreferrer"&gt;resizing&lt;/a&gt;, &lt;a href="https://quickimagekit.com/crop-image?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=browser_local_build_notes" rel="noopener noreferrer"&gt;cropping&lt;/a&gt;, &lt;a href="https://quickimagekit.com/convert-image?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=browser_local_build_notes" rel="noopener noreferrer"&gt;conversion&lt;/a&gt; and compression together, even if each tool stays simple.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exact KB pages are workflow pages, not just SEO pages
&lt;/h2&gt;

&lt;p&gt;Searches like "compress image to 20KB" or "compress photo under 200KB" look repetitive, but the user intent is real. Someone is blocked by a form that rejects their file.&lt;/p&gt;

&lt;p&gt;The page should not only say "upload your image." It should explain what to try when the target is too small:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;crop first if there is empty background&lt;/li&gt;
&lt;li&gt;resize if the source is a large phone photo&lt;/li&gt;
&lt;li&gt;use JPG for photo-like images when the form accepts it&lt;/li&gt;
&lt;li&gt;avoid shrinking documents so far that text becomes unreadable&lt;/li&gt;
&lt;li&gt;aim slightly below the limit, not dramatically below it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For that reason, Quick Image Kit has a separate &lt;a href="https://quickimagekit.com/compress-image-to-exact-size?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=browser_local_build_notes" rel="noopener noreferrer"&gt;exact-size workflow&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The growth lesson
&lt;/h2&gt;

&lt;p&gt;The technical build was the easy part. The harder part is that a new utility site does not get traffic just because the pages exist.&lt;/p&gt;

&lt;p&gt;The current growth work is deliberately simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ship focused pages for real upload scenarios&lt;/li&gt;
&lt;li&gt;create useful external tutorials&lt;/li&gt;
&lt;li&gt;submit to relevant tool lists&lt;/li&gt;
&lt;li&gt;track whether links become live instead of treating submissions as wins&lt;/li&gt;
&lt;li&gt;look for search impressions and referrals, not just sitemap counts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The useful distinction is this: a submitted link is not a live backlink. A live backlink is only counted after the external page actually links back.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would keep if rebuilding it
&lt;/h2&gt;

&lt;p&gt;If I rebuilt the tool from scratch, I would keep these decisions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;keep the core image work local in the browser&lt;/li&gt;
&lt;li&gt;make the output file size and dimensions visible&lt;/li&gt;
&lt;li&gt;create separate workflows for exact KB, forms, passport-style uploads, and documents&lt;/li&gt;
&lt;li&gt;keep the original file unchanged&lt;/li&gt;
&lt;li&gt;avoid login requirements for the core task&lt;/li&gt;
&lt;li&gt;make each page answer one concrete upload problem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tool is here: &lt;a href="https://quickimagekit.com/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=browser_local_build_notes" rel="noopener noreferrer"&gt;quickimagekit.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the main compression workflow is here: &lt;a href="https://quickimagekit.com/compress-image?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=browser_local_build_notes" rel="noopener noreferrer"&gt;compress an image in the browser&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>showdev</category>
      <category>tools</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
