<?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: Volatil</title>
    <description>The latest articles on DEV Community by Volatil (@volatill).</description>
    <link>https://dev.to/volatill</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%2F4100309%2F7ca37c0f-b639-47b5-8081-14fcf6b7582d.jpg</url>
      <title>DEV Community: Volatil</title>
      <link>https://dev.to/volatill</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/volatill"/>
    <language>en</language>
    <item>
      <title>Why I Built a Vector Database Around Disk Instead of RAM</title>
      <dc:creator>Volatil</dc:creator>
      <pubDate>Sun, 30 Aug 2026 16:35:40 +0000</pubDate>
      <link>https://dev.to/volatill/why-i-built-a-vector-database-around-disk-instead-of-ram-4248</link>
      <guid>https://dev.to/volatill/why-i-built-a-vector-database-around-disk-instead-of-ram-4248</guid>
      <description>&lt;p&gt;I run my AI stack locally: the LLM, the embedding model, and the vector store behind RAG and the agent's memory. Everything shares one machine's RAM. The vector store's share is the part that grows. An embedded vector store keeps its entire index in memory, its memory usage scales with the number of vectors stored, and that growth competes directly with the model for RAM. &lt;/p&gt;

&lt;p&gt;So I built &lt;a href="https://github.com/NTU-Siqiang-Group/AsterVec" rel="noopener noreferrer"&gt;AsterVec&lt;/a&gt;, a vector database that keeps its index on disk and runs within a configurable memory budget.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two data structures with opposite personalities
&lt;/h2&gt;

&lt;p&gt;HNSW is the standard vector index, and it is built for memory. Embedded vector engines like Chroma keeps the whole index in the process heap. Traditional server-based vector databases like pgvector and Elasticsearch stay fast only while it fits in memory: once the index outgrows RAM, searches and updates alike degrade into random disk access, and both slow down sharply.&lt;/p&gt;

&lt;p&gt;So an on-disk index needs its own layout, and designing one starts&lt;br&gt;
with noticing that an HNSW index is really two data structures with&lt;br&gt;
opposite storage needs:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Vectors&lt;/th&gt;
&lt;th&gt;Graph edges&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Shape&lt;/td&gt;
&lt;td&gt;fixed size, same for every node&lt;/td&gt;
&lt;td&gt;varies from node to node&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Writes&lt;/td&gt;
&lt;td&gt;each embedding written once&lt;/td&gt;
&lt;td&gt;neighbour list keeps updating&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reads&lt;/td&gt;
&lt;td&gt;many per query in bulk&lt;/td&gt;
&lt;td&gt;one small list per hop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wants&lt;/td&gt;
&lt;td&gt;a packed page layout&lt;/td&gt;
&lt;td&gt;a flexible structure&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Most engines interleave the two, storing each vector next to its edge list. A single layout then has to serve both access patterns, and it cannot be good at both. The compromise shows up on writes: recording one new edge can rewrite a large block of vector data that did not change.&lt;/p&gt;

&lt;p&gt;This is the conflict AsterVec is built around removing. The index is split into two stores on disk, each shaped for its own half:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Graph edges&lt;/strong&gt; go to a graph-oriented LSM-tree which turns small scattered writes into sequential writes on disk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vectors&lt;/strong&gt; go to a page-based array with a locality-aware cache, so vectors that are searched together tend to be read together.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RAM&lt;/strong&gt; holds only the upper navigation layers and the caches. That is the entire resident footprint, and it is bounded.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The benchmarks
&lt;/h2&gt;

&lt;p&gt;I compared AsterVec with Chroma and LanceDB, because they are also embedded vector databases. All three ran on the same machine on the&lt;br&gt;
SIFT dataset, with identical HNSW parameters and out-of-box settings. At 100K vectors, the working set is mostly cached, so AsterVec is effectively in memory too:&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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcvnzc2qug2ftn49t5fhp.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcvnzc2qug2ftn49t5fhp.png" alt="AsterVec vs Chroma and LanceDB at 100K vectors" width="800" height="224"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AsterVec serves 5.2x Chroma's queries per second and 7.3x its inserts per second, in half the memory, with recall on par.&lt;/p&gt;

&lt;p&gt;At a million vectors, AsterVec is genuinely serving from disk:&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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0jjx11ea0edeuyck6ohc.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0jjx11ea0edeuyck6ohc.png" alt="AsterVec vs Chroma at 1M vectors" width="800" height="224"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Queries run in roughly 0.3 GB of engine memory against Chroma's 1.2 GB, query speed stays in the same ballpark, and recall is slightly ahead. Comparable speed at a fraction of the memory is exactly the trade-off I wanted: on a machine that also runs an LLM, that memory is needed elsewhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it on your workload
&lt;/h2&gt;

&lt;p&gt;If memory is a constraint for your local agent or desktop RAG, or you simply want your vector store to use less of it, AsterVec is built for that problem: &lt;code&gt;pip install aster-vec&lt;/code&gt;. And if you just want a lightweight embedded vector database, it is a good fit for that too. I would like to know how it behaves on your workload: open an issue if something breaks, and star the repo if you find it useful. It is a young project, and feedback from real workloads helps the most.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/NTU-Siqiang-Group/AsterVec" rel="noopener noreferrer"&gt;github.com/NTU-Siqiang-Group/AsterVec&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>showdev</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
