<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <!-- Source: https://www.dolthub.com/blog/rss.xml -->
  <channel>
    <title>DoltHub Blog - Latest Posts</title>
    <description>Blog for DoltHub, a website hosting databases made with Dolt, an open-source version-controlled SQL database with Git-like semantics.</description>
    <link>https://siftrss.com/f/Kkmm5PG8lw</link>
    <language>en-us</language>
    <lastBuildDate>Fri, 26 Jun 2026 17:36:15 GMT</lastBuildDate>
    <atom:link href="https://siftrss.com/f/Kkmm5PG8lw" rel="self" type="application/rss+xml"/>
    <item>
      <title>Doltgres 1.0 Coming August 6th</title>
      <link>https://dolthub.com/blog/2026-06-26-doltgres-1-0-coming-this-fall/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-06-26-doltgres-1-0-coming-this-fall/</guid>
      <description>Doltgres 1.0 is coming August 6th. Here's what we've been working on and what we're focused on to get there.</description>
      <pubDate>Fri, 26 Jun 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;&lt;a href="https://www.doltgres.com/"&gt;Doltgres&lt;/a&gt; is a PostgreSQL-compatible database with Git-style version control built in. It gives you all the power of SQL with the ability to branch, merge, diff, clone, and push your data, using the same model you already know from managing your source code with Git. Doltgres implements the PostgreSQL wire protocol, syntax, and type system so that you can use it just like you use PostgreSQL.&lt;/p&gt;
&lt;p&gt;We first &lt;a href="https://www.dolthub.com/blog/2023-11-01-announcing-doltgresql/"&gt;announced Doltgres in November 2023&lt;/a&gt; as an Alpha, then &lt;a href="https://www.dolthub.com/blog/2025-04-16-doltgres-goes-beta/"&gt;launched the Beta in April 2025&lt;/a&gt;, and now we’re announcing our next major milestone: &lt;strong&gt;Doltgres 1.0, coming August 6th&lt;/strong&gt;. This date is pretty special for us here… it’s the eight-year anniversary of DoltHub! Eight years of hard work leading up to a production-ready, PostgreSQL-compatible versioned database! Not too shabby.&lt;/p&gt;
&lt;p&gt;In this post, we’ll explain what 1.0 means for Doltgres, share what we’re focused on in the next few months, and let you know how you can help.&lt;/p&gt;
&lt;h2 id="what-does-10-mean"&gt;What Does 1.0 Mean?&lt;a class="anchor-link" aria-label="Link to heading" href="#what-does-10-mean"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Doltgres reaching 1.0 is our signal that Doltgres is ready for production use. That means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Correctness&lt;/strong&gt; Your queries reliably return the correct results, matching what PostgreSQL returns.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Storage Stability&lt;/strong&gt; The storage format is locked in, and we won’t make breaking storage serialization changes in the 1.x releases that require migrating your data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance&lt;/strong&gt; Query latency is within an acceptable range of PostgreSQL’s performance. We’re shooting to be within 3x PostgreSQL’s latency for key sysbench measurements.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compatibility&lt;/strong&gt; The tools, libraries, ORMs, and frameworks your team already uses work correctly with Doltgres, too.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Six months ago, we gave an update on Doltgres’ progress in the &lt;a href="https://www.dolthub.com/blog/2025-10-16-state-of-doltgres/"&gt;State of Doltgres&lt;/a&gt;. Since then, we’ve made significant progress towards a 1.0 milestone. Here’s what we’re focused on in the home stretch towards 1.0.&lt;/p&gt;
&lt;h2 id="correctness"&gt;Correctness&lt;a class="anchor-link" aria-label="Link to heading" href="#correctness"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of our key tools for testing SQL correctness is the &lt;a href="https://sqlite.org/sqllogictest/doc/trunk/about.wiki"&gt;SQLite SQL Logic Test suite&lt;/a&gt;. This is a large, open-source test suite originally developed by SQLite containing over seven million test queries covering a wide range of SQL expressions and statements. We’ve forked this module and added many more tests, and we run these against Dolt and Doltgres to measure compatibility and ensure that we’re returning correct results.&lt;/p&gt;
&lt;p&gt;We’ve been tracking our progress on this suite &lt;a href="https://www.dolthub.com/blog/2023-11-27-doltgres-sqllogic-test/"&gt;since the early days of the project&lt;/a&gt; when we were only able to execute 70% of the statements correctly. Today, we’re passing a little over 96% of the tests correctly, and we’re digging into the failing tests to categorize them and tackle the discrepancies.&lt;/p&gt;
&lt;p&gt;Our goal for 1.0 is to reach &lt;strong&gt;99% SQL Logic Test compliance&lt;/strong&gt;. Every percentage point matters here. At this scale of testing, 99% represents millions of individual queries and results that must match PostgreSQL exactly.&lt;/p&gt;
&lt;h2 id="storage-stability"&gt;Storage Stability&lt;a class="anchor-link" aria-label="Link to heading" href="#storage-stability"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One thing that makes our major version releases meaningful is the storage format guarantee they carry. For Doltgres 1.0, we’re committing to a stable on-disk serialization format, just like we did for the Dolt 1.0 launch back in 2023. This means &lt;strong&gt;no data migrations will be required&lt;/strong&gt; for any new features we add in the 1.x line of releases. Changing the storage serialization format requires data to be migrated from the old format to the new format, which is disruptive and inconvenient to customers, so we give this guarantee that the storage serialization format won’t change in the 1.x line. When we start to think about a 2.0 release for Doltgres, there may be compelling features or optimizations that require a serialization format change, but we don’t make those changes lightly. There’s a very high bar for backwards incompatible storage serialization changes once we’ve given our customers the green light to use a storage format in production.&lt;/p&gt;
&lt;h2 id="performance"&gt;Performance&lt;a class="anchor-link" aria-label="Link to heading" href="#performance"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We’ve been benchmarking Doltgres performance from &lt;a href="https://www.dolthub.com/blog/2023-12-15-benchmarking-postgres-mysql-dolt/"&gt;the beginning&lt;/a&gt;, and we continue to chase down performance bottlenecks as we find them. Because Doltgres uses the same query engine as Dolt (our MySQL-compatible database product), it has access to all the performance improvements we’ve done for Dolt. However, PostgreSQL raises the performance bar from where MySQL set it. In our testing, &lt;a href="https://www.dolthub.com/blog/2024-07-16-mysql-postgres-sysbench-latency/"&gt;we found that PostgreSQL is more than twice as fast as MySQL&lt;/a&gt;, so we’ve been working hard to find more optimizations, do more performance testing, and keep inching closer to PostgreSQL’s performance.&lt;/p&gt;
&lt;p&gt;Our performance goal for 1.0 is to get &lt;a href="https://github.com/akopytov/sysbench"&gt;sysbench&lt;/a&gt; results for Doltgres to within &lt;strong&gt;3x of PostgreSQL&lt;/strong&gt;. We’re currently right on the cusp of achieving this, with a current performance multiplier of 3.3x.&lt;/p&gt;
&lt;p&gt;We continue to find and fix performance issues as they come up. If you encounter a query that is unexpectedly slow, please &lt;a href="https://github.com/dolthub/doltgresql/issues/new"&gt;file an issue&lt;/a&gt; and we’ll dig in and find a way to make it fast for you.&lt;/p&gt;
&lt;h2 id="compatibility"&gt;Compatibility&lt;a class="anchor-link" aria-label="Link to heading" href="#compatibility"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;PostgreSQL’s ecosystem is vast. Different clients, libraries, ORMs, and tools all speak the PostgreSQL wire protocol in subtly different ways. They use different combinations of the simple and extended query protocols, rely on different parts of &lt;code&gt;pg_catalog&lt;/code&gt;, and have different expectations about types, encodings, and error messages.&lt;/p&gt;
&lt;p&gt;For 1.0, we want to ensure broad compatibility across the PostgreSQL tools most teams are using. This means testing and fixing issues with popular clients and libraries including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Client libraries&lt;/strong&gt;: psycopg2, asyncpg, pgx, pg (node-postgres), and more&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ORMs&lt;/strong&gt;: Prisma, SQLAlchemy, ActiveRecord, Django ORM, Hibernate, and more&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tools&lt;/strong&gt;: psql, TablePlus, pgAdmin, Dolt Workbench, and more&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Many of these tools, especially the ORMs and higher-level tools make extensive use of the system information tables in &lt;code&gt;pg_catalog&lt;/code&gt; to introspect your schema and display it in a UI, generate migrations, or validate configurations, so this work also includes filling in gaps and fixing incorrect data in those tables so that tools can access the information they need to work correctly with Doltgres.&lt;/p&gt;
&lt;p&gt;We’ve already done a lot of work in this area. We’ve previously written about supporting &lt;a href="https://www.dolthub.com/blog/2026-04-06-doltgresql-prisma/"&gt;Prisma&lt;/a&gt;, &lt;a href="https://www.dolthub.com/blog/2025-06-03-doltgres-laravel/"&gt;Laravel&lt;/a&gt;, &lt;a href="https://www.dolthub.com/blog/2025-04-24-doltgres-django/"&gt;Django&lt;/a&gt;, &lt;a href="https://www.dolthub.com/blog/2025-07-18-sql-alchemy-getting-started-doltgres/"&gt;SQLAlchemy&lt;/a&gt;, and &lt;a href="https://www.dolthub.com/blog/2025-04-21-doltgres-and-knexjs/"&gt;KnexJS&lt;/a&gt;, but there’s more to do. We want to find the issues with popular tools before our customers do. This is another place where your real-world usage can help us find gaps. If you hit any issues with Doltgres and a SQL client library, ORM, or other SQL tool, please &lt;a href="https://github.com/dolthub/doltgresql/issues/new"&gt;report it to us&lt;/a&gt; so we can dig in and fix it.&lt;/p&gt;
&lt;h2 id="other-features"&gt;Other Features&lt;a class="anchor-link" aria-label="Link to heading" href="#other-features"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Beyond the core themes of correctness, storage stability, performance, and compatibility, there are several features we’re actively developing and vetting for Doltgres’ 1.0 launch:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Remotes and Push/Pull&lt;/strong&gt; &lt;a href="https://www.doltgres.com/docs/concepts/git/remotes/"&gt;Remotes&lt;/a&gt; are a powerful feature that allow you to work in a distributed mode, by pushing data to remotes and pulling data from remotes, just like Git remotes. We’re working to ensure these features are fully supported in Doltgres, enabling the same kinds of remote collaboration and decentralized workflows that Dolt and Git users are familiar with.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dolt Replication Protocol&lt;/strong&gt; &lt;a href="https://www.doltgres.com/docs/concepts/rdbms/replication/"&gt;Doltgres supports two types of replication&lt;/a&gt;: the PostgreSQL replication protocol and a Dolt-specific replication protocol. The PostgreSQl replication protocol allows you to run DoltgreSQL as a replica of a PostgreSQL server. The Dolt-specific replication protocol allows you to set up more advanced primary/replica configurations and includes features for high-availability and hot-swappable replicas. We’re working to finish testing this support and make sure it’s ready for production.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Garbage Collection Improvements&lt;/strong&gt; As databases accumulate history, they can grow large. Garbage collection helps keeps that growth manageable by cleaning up unreachable data that is no longer needed. Doltgres already supports the standard manually invoking garbage collection with the &lt;code&gt;dolt_gc()&lt;/code&gt; stored procedure, but we don’t want to launch 1.0 without the latest garbage collection improvements: &lt;a href="https://www.dolthub.com/blog/2026-04-28-introducing-incremental-garbage-collection/"&gt;incremental garbage collection&lt;/a&gt; and &lt;a href="https://www.dolthub.com/blog/2025-02-28-announcing-automatic-gc-in-sql-server/"&gt;automatic garbage collection&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id="try-doltgres-and-send-us-issues"&gt;Try Doltgres and Send Us Issues&lt;a class="anchor-link" aria-label="Link to heading" href="#try-doltgres-and-send-us-issues"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The best way you can help us get to 1.0 is to &lt;strong&gt;use Doltgres on real workloads and tell us what breaks&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Install Doltgres and try it with your existing PostgreSQL application. Point your ORM at it. Run your migrations. See what works and what doesn’t. Every issue you report makes the product better, and we love to move fast on customer-reported issues.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Install&lt;/strong&gt;: &lt;code&gt;brew install doltgres&lt;/code&gt; or download from our &lt;a href="https://github.com/dolthub/doltgresql/releases"&gt;GitHub releases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Report issues&lt;/strong&gt;: &lt;a href="https://github.com/dolthub/doltgresql/issues/new"&gt;Create an issue in the Doltgres repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We’re very excited to get Doltgres to 1.0 and announce that it’s ready for production workloads. If you want to be part of getting us there, now is a great time to try out Doltgres! Come by &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;our Discord&lt;/a&gt; and let us know how your experience goes.&lt;/p&gt;</content:encoded>
      <dc:creator>Jason Fulghum</dc:creator>
      <category>doltgres</category>
    </item>
    <item>
      <title>What People Are Saying: LWN Edition</title>
      <link>https://dolthub.com/blog/2026-06-17-what-people-are-saying-lwn/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-06-17-what-people-are-saying-lwn/</guid>
      <description>More and more people are talking about us. Here's what LWN is saying.</description>
      <pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;In 2019, we released &lt;a href="https://www.github.com/dolthub/dolt"&gt;Dolt, the world’s first version-controlled SQL database.&lt;/a&gt; In the seven years since, we’ve seen a gradual but steady influx of attention as people become aware we exist.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/dolt-stars.png/7e357eabb65fb93bd1e2a00b575811b3b6d0a30eaf912545097b99d318ffbd8d.webp" alt="Dolt&amp;#x27;s stars on GitHub"&gt;&lt;/p&gt;
&lt;p&gt;You can clearly see the first time we got mentioned on HackerNews in 2021.&lt;/p&gt;
&lt;p&gt;More and more, this attention is taking the form of people not just noticing us, but talking about us to others. We love that. We think that word-of-mouth buzz is a strong signal for the genuine usefulness of a tool.&lt;/p&gt;
&lt;p&gt;Last month, &lt;a href="https://lwn.net/Articles/1068864/"&gt;Daroc Alden over at LWN wrote about us.&lt;/a&gt;&lt;sup&gt;&lt;a href="#user-content-fn-1" id="user-content-fnref-1" data-footnote-ref="" aria-describedby="footnote-label"&gt;1&lt;/a&gt;&lt;/sup&gt; It was really cool to see an outside perspective. I think they did a great job of explaining what Dolt is and how it can be used. They also have a great explanation of Prolly Trees, the B-tree inspired data structure that makes Dolt possible. &lt;a href="https://www.dolthub.com/blog/2024-03-03-prolly-trees/"&gt;We’re kind of obsessed with Prolly Trees&lt;/a&gt;, so it’s cool to see someone else understand them and even see them talk about some of the improvements that we made to Prolly Trees to improve node size distribution.&lt;/p&gt;
&lt;p&gt;Overall, I think the LWN article did a great job introducing Dolt to a new audience and I’m happy to see it. But there were a couple of misconceptions in the article, so for the sake of completeness I wanted to clear them up.&lt;/p&gt;
&lt;h2 id="project-architecture"&gt;Project Architecture&lt;a class="anchor-link" aria-label="Link to heading" href="#project-architecture"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Two related misconceptions we see pop up on occasion is the claim that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dolt and its siblings (Doltgres and DoltLite) are plugins/forks of common SQL engines.&lt;/li&gt;
&lt;li&gt;Each project is a different wrapper around an otherwise identical storage layer.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Combined, these two ideas paint the picture that Dolt / Doltgres / DoltLite each take the same underlying storage format and bridge it to MySQL / PostgreSQL / SQLite, respectively.&lt;/p&gt;
&lt;p&gt;LWN repeats both of these ideas in their article. To quote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[Dolt, Doltgres, and Doltlite] have separate frontends for the different SQL dialects, but the projects share a common storage backend that supports version-control operations.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;That competitive performance is possible because Dolt only changes the storage layer of the database. The query planner, index maintenance, and so on all reuse MySQL, PostgreSQL, or SQLite’s existing implementations.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The reality is slightly more nuanced. We maintain our own SQL engine, &lt;a href="https://github.com/dolthub/go-mysql-server/"&gt;go-mysql-server&lt;/a&gt;. Like the name suggests, it was originally made for the MySQL dialect, but recently we’ve also been adding support for Postgres.&lt;/p&gt;
&lt;p&gt;We also have a common storage backend, designed for use with &lt;code&gt;go-mysql-server&lt;/code&gt;. Both Dolt and Doltgres use this backend. They aren’t plugins, and they don’t depend on the MySQL or Postgres code bases at all.&lt;/p&gt;
&lt;p&gt;On the other hand, DoltLite &lt;em&gt;is&lt;/em&gt; a custom storage backend for SQLite, and as such, it doesn’t use the common storage backend, but rather its own format and implementation. It’s based on the same design as the original, but the formats are not compatible.&lt;/p&gt;
&lt;h2 id="the-power-of-git"&gt;The Power of Git&lt;a class="anchor-link" aria-label="Link to heading" href="#the-power-of-git"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There’s a lot of reasons why applying the Git model to databases makes sense. The LWN article points out the biggest one:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The real utility of Dolt comes from the ability to restore old commits, fork historical states of the database, and merge in changes after review.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is 100% true, and it’s the most common way we see users take advantage of Git-style version control. But there’s another big benefit to Git-style version control too: remotes.&lt;/p&gt;
&lt;p&gt;Just like Git, Dolt allows you to clone a database from a remote and then sync incrementally. When you &lt;code&gt;dolt pull&lt;/code&gt; or &lt;code&gt;dolt push&lt;/code&gt;, only the new changes get sent. This lets you get a local, up-to-date copy by only downloading the parts that actually changed. That turns out to be a pretty powerful feature for replicas.&lt;/p&gt;
&lt;h2 id="how-git-and-dolt-store-snapshots"&gt;How Git and Dolt Store Snapshots&lt;a class="anchor-link" aria-label="Link to heading" href="#how-git-and-dolt-store-snapshots"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Git and Dolt take a “snapshot” approach to version control, where each commit represents is an independent snapshot of the data at a specific point in time.&lt;sup&gt;&lt;a href="#user-content-fn-2" id="user-content-fnref-2" data-footnote-ref="" aria-describedby="footnote-label"&gt;2&lt;/a&gt;&lt;/sup&gt; But in the event that not much has changed between commits, what stops all the different snapshots from taking up lots of extra storage space?&lt;/p&gt;
&lt;p&gt;A common Git misconception is that Git reduces storage by storing commits internally as deltas. The article repeats that misconception and suggests that this is the main reason why Git (and by extension Dolt) require data structures that can be diffed efficiently. To quote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Each commit is logically independent, and could in theory just be stored as-is. In practice, most Git repositories do not completely change between commits, and it’s more efficient to store the differences between subsequent snapshots, rather than the snapshots themselves.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Git, which works with entire directory trees, relies on being able to quickly check whether a particular sub-tree has changed in order to produce compact diffs that include only the actual changes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There’s some truth to this: Git does have the ability to produce compact diffs (such as with the &lt;code&gt;git diff&lt;/code&gt; command). And Git’s storage format does have the ability to store deltas on individual files. But it doesn’t store the whole commit as a delta, and deltas aren’t the primary method for achieving efficient storage.&lt;/p&gt;
&lt;p&gt;The actual method by which Git and Dolt achieve compact storage is much simpler: when two commits trees contain identical sub-trees, Git and Dolt simply only store that identical tree once. And indeed further down, the LWN article explains exactly that:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Content-addressed storage is a scheme that many version-control systems use to deduplicate data: a particular diff or other object is stored in a location based on the hash of its contents. This ensures that duplicate items will reuse the same storage space.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This trick of reusing the unchanged parts of the tree is called &lt;strong&gt;structural sharing.&lt;/strong&gt; In order to make this possible, the data being stored requires that two trees containing the same items are exactly identical, regardless of how those items were inserted. This property is called &lt;strong&gt;history independence&lt;/strong&gt;, and its the property that Prolly Trees provide that B-trees don’t. History independence is also how both Git and Dolt can produce efficient diffs.&lt;/p&gt;
&lt;p&gt;So Git and Dolt’s efficient storage isn’t because of their diffing capabilities, but rather the same property (history independence) allows for both fast diffs &lt;em&gt;and&lt;/em&gt; compact storage.&lt;/p&gt;
&lt;h2 id="dolts-dynamic-node-size-thresholds"&gt;Dolt’s Dynamic Node Size Thresholds&lt;a class="anchor-link" aria-label="Link to heading" href="#dolts-dynamic-node-size-thresholds"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It was really cool to see this get a shout-out.&lt;/p&gt;
&lt;p&gt;A known shortcoming of the original prolly tree design is that it produces trees where the number of elements per node follows a &lt;a href="https://en.wikipedia.org/wiki/Geometric_distribution"&gt;geometric distribution&lt;/a&gt;. This is a pretty big problem, because it both means that there’s no theoretical upper bound on node sizes, and it leads to imbalanced trees with worse performance.&lt;/p&gt;
&lt;p&gt;Think about it this way: if a small number of nodes in your tree are much larger than others, then those nodes are not only going to take longer to process, but they’re also going to get visited more frequently because they have more children. This makes tree operations more likely to hit slow paths.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.dolthub.com/blog/2022-06-27-prolly-chunker/#chunk-size-variance"&gt;Dolt has a pretty clever solution to this problem,&lt;/a&gt; and not only did the article talk about it, it spawned some good discussion in the comments. Basically, Dolt uses a dynamic threshold to decide how to draw boundaries between tree nodes: as a tree node fills up, the probability of the next element causing a split increases.&lt;/p&gt;
&lt;p&gt;One small correction though: the dynamic threshold isn’t based on the number of node elements like the example suggests, but rather the number of bytes written. This matters when the elements are variable-length, and gives us better control over the exact distribution of node sizes.&lt;/p&gt;
&lt;h1 id="thats-all-folks"&gt;That’s All, Folks&lt;a class="anchor-link" aria-label="Link to heading" href="#thats-all-folks"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This was a great read. It was really cool to see an outsider’s perspective on Dolt. The readers of LWT are lively and did a lot of engaging in the comments of the original article.&lt;/p&gt;
&lt;p&gt;If you’d like to engage with us more, consider joining our &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;Discord&lt;/a&gt;. We’re always down to chat and answer questions.&lt;/p&gt;
&lt;section data-footnotes="" class="footnotes"&gt;&lt;h2 class="sr-only" id="footnote-label"&gt;Footnotes&lt;a class="anchor-link" aria-label="Link to heading" href="#footnote-label"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id="user-content-fn-1"&gt;
&lt;p&gt;What does LWN stand for? &lt;a href="https://lwn.net/op/FAQ.lwn#:~:text=%5BWhat%20does%20LWN%20stand%20for%5D"&gt;Apparently nothing anymore, but it used to stand for Linux Weekly News.&lt;/a&gt; &lt;a href="#user-content-fnref-1" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="user-content-fn-2"&gt;
&lt;p&gt;This is in comparison to delta-based version control systems, where each commit represents a diff on the previous commit. &lt;a href="https://www.dolthub.com/blog/2026-01-07-how-to-version-control-a-database/#version-control-approaches"&gt;We’ve written in the past about the different types of version control schemes.&lt;/a&gt; &lt;a href="#user-content-fnref-2" data-footnote-backref="" aria-label="Back to reference 2" class="data-footnote-backref"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded>
      <dc:creator>Nick Tobey</dc:creator>
      <category>dolt</category>
    </item>
    <item>
      <title>Git For Context</title>
      <link>https://dolthub.com/blog/2026-06-15-git-for-context/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-06-15-git-for-context/</guid>
      <description>We built a version of Open Code with version-controlled context. Check it out.</description>
      <pubDate>Mon, 15 Jun 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;Here at DoltHub we tend to view everything through the lens of version control. We built &lt;a href="https://www.doltdb.com"&gt;Dolt&lt;/a&gt;, the world’s first version-controlled SQL database after all. Would this new tool be better with branches? Diffs? Merges? Clones? Inevitably, we see some opportunities.&lt;/p&gt;
&lt;p&gt;Databases? Check.&lt;br&gt;
Spreadsheets? Eventually.&lt;br&gt;
Coding agents? Hmmm. I wonder…&lt;/p&gt;
&lt;p&gt;With the rise of &lt;a href="https://www.dolthub.com/blog/2026-03-26-vibe-code-vs-trad-code/"&gt;vibe coding&lt;/a&gt; and agents in general, we’re &lt;a href="https://www.dolthub.com/blog/2026-01-22-agentic-memory/"&gt;looking at context&lt;/a&gt; with a lustful, content-addressed eye. What if there was “Git for Context”? What would it look like? What features would developers love? This article won’t just answer those questions — it will answer them with a demo.&lt;/p&gt;
&lt;h1 id="context"&gt;Context&lt;a class="anchor-link" aria-label="Link to heading" href="#context"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I’m sure most people already know this but let’s start with a quick definition of context. Context is the prompt and additional metadata that is sent to a large language model to produce a response. One of the key innovations with agents was the ability to iterate on a context/response action loop, combined with tool use to allow agents to do useful work like writing code. Agents generally have an append-only context with a compaction step when it gets too big.&lt;/p&gt;
&lt;p&gt;For most agents, full context is hidden from the user, but you can dig into files in your &lt;code&gt;.claude&lt;/code&gt; or &lt;code&gt;.codex&lt;/code&gt;. It started as raw text files, but recently, most agents are discovering the need for &lt;a href="https://www.dolthub.com/blog/2026-03-13-multi-agent-persistence/"&gt;structured data in context&lt;/a&gt; for more targeted retrieval, quality control, and concurrency management. So now you’ll see a lot of JSON format files and even, for the more cutting edge agents, SQLite files.&lt;/p&gt;
&lt;h1 id="open-code"&gt;Open Code&lt;a class="anchor-link" aria-label="Link to heading" href="#open-code"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Enter &lt;a href="https://github.com/anomalyco/opencode"&gt;Open Code&lt;/a&gt;, the most popular open source coding agent. An open source coding harness? Yes please.&lt;/p&gt;
&lt;p&gt;Obviously, as an open source company ourselves, we love and support open source. One of the benefits of open source is that you can show, not tell. We saw Open Code &lt;a href="https://github.com/anomalyco/opencode/issues/7840"&gt;migrated their persistence to SQLite&lt;/a&gt; and thought “How hard would it be to add version control for context using Dolt or DoltLite? It’s already SQL.”&lt;/p&gt;
&lt;p&gt;Even the maintainers were goading us into it. This quote is ripped from one of their issues.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is not very big or complex data.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sounds like a perfect place to add version control.&lt;/p&gt;
&lt;h1 id="why-version-control-context"&gt;Why Version Control Context?&lt;a class="anchor-link" aria-label="Link to heading" href="#why-version-control-context"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I wrote a whole article about &lt;a href="https://www.dolthub.com/blog/2026-03-13-multi-agent-persistence/"&gt;agentic memory&lt;/a&gt; that makes a deeper case for version-controlled context: Git for Context.&lt;/p&gt;
&lt;p&gt;But for Open Code in particular, we think Git for Context starts first and foremost as a development tool for Open Code contributors. What specifically happens to context after compaction? What if I compact 10 times on 10 different branches? How consistent is compaction? What if I manually &lt;a href="https://www.dolthub.com/blog/2026-05-13-delete-comments/"&gt;strip out code comments&lt;/a&gt; from context on one branch and leave them on another? I’ll compare the context and code after 5 turns. Branches and diffs are powerful development tools for testing and comparing different strategies in the probabilistic environment agents live in. Could Git for Context make Open Code better, faster?&lt;/p&gt;
&lt;p&gt;If Open Code contributors find Git for Context useful, maybe the most useful features could become user facing features? Having ten sub-agents work from the same context base on branches, comparing outputs, and merging good outcomes seems like a workflow that could work for some tasks. My only hesitation is the user experience. Adding version control to anything is a UX challenge.&lt;/p&gt;
&lt;p&gt;But I think the most important user-facing feature would probably be context preservation. It seems weird to me already that we don’t push the context of our coding agents up to an immutable repository and link to it in our pull requests. Stored context is the agent stack trace. When something goes wrong, surely we will want humans or even other agents to dig through the context to figure out what happened. This can be closely linked to multiplayer mode. Pull an agent’s context locally and have an agentic engineering expert resume the session where it went off the rails as a teaching moment for other engineers. This is more GitHub for Context than Git for Context, but you can’t have one without the other.&lt;/p&gt;
&lt;h1 id="why-talk-when-you-can-show"&gt;Why Talk When You Can Show?&lt;a class="anchor-link" aria-label="Link to heading" href="#why-talk-when-you-can-show"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We built it! You can check out &lt;a href="https://github.com/dolthub/opencode"&gt;version-controlled Open Code on GitHub&lt;/a&gt;, also free and open source.&lt;/p&gt;
&lt;h2 id="clone-and-build-our-open-code-fork"&gt;Clone and Build our Open Code Fork&lt;a class="anchor-link" aria-label="Link to heading" href="#clone-and-build-our-open-code-fork"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First, you need to clone and build &lt;a href="https://github.com/dolthub/opencode"&gt;our Open Code fork&lt;/a&gt;. Before you get started, make sure you have &lt;code&gt;bun&lt;/code&gt; installed. The example assumes you are running OSX with an ARM64 chip. If your architecture is different, the commands below will be similar but for your architecture.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sh"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; ~/opencode-demo&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;git&lt;/span&gt;&lt;span&gt; clone&lt;/span&gt;&lt;span&gt; git@github.com:dolthub/opencode.git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; opencode&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;bun&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; opencode/packages/opencode&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;bun&lt;/span&gt;&lt;span&gt; run&lt;/span&gt;&lt;span&gt; build&lt;/span&gt;&lt;span&gt; --single&lt;/span&gt;&lt;span&gt; --skip-install&lt;/span&gt;&lt;span&gt; --skip-embed-web-ui&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mv&lt;/span&gt;&lt;span&gt; dist/opencode-darwin-arm64/bin/opencode&lt;/span&gt;&lt;span&gt; ~/bin/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, you have an &lt;code&gt;opencode&lt;/code&gt; binary in &lt;code&gt;~/bin&lt;/code&gt;. If &lt;code&gt;~/bin&lt;/code&gt; is at the front f your &lt;code&gt;PATH&lt;/code&gt; your &lt;code&gt;PATH&lt;/code&gt;, you can just run &lt;code&gt;opencode&lt;/code&gt; or you can run it directly with a full path.&lt;/p&gt;
&lt;p&gt;But first, let’s create and start a Dolt server to house your version-controlled context. I would do this in a new shell so you can watch the query logs.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sh"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; ~/opencode-demo&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mkdir&lt;/span&gt;&lt;span&gt; db&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; db&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;dolt&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;dolt&lt;/span&gt;&lt;span&gt; sql&lt;/span&gt;&lt;span&gt; -q&lt;/span&gt;&lt;span&gt; "CREATE USER 'dolt'@'%' IDENTIFIED BY 'pass1234';"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;dolt&lt;/span&gt;&lt;span&gt; sql&lt;/span&gt;&lt;span&gt; -q&lt;/span&gt;&lt;span&gt; "GRANT ALL PRIVILEGES ON *.* TO 'dolt'@'%';'"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;dolt&lt;/span&gt;&lt;span&gt; sql&lt;/span&gt;&lt;span&gt; -q&lt;/span&gt;&lt;span&gt; "CREATE DATABASE opencode;"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;dolt&lt;/span&gt;&lt;span&gt; sql-server&lt;/span&gt;&lt;span&gt; -H127.0.0.1&lt;/span&gt;&lt;span&gt; --loglevel&lt;/span&gt;&lt;span&gt; DEBUG&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="try-it"&gt;Try It&lt;a class="anchor-link" aria-label="Link to heading" href="#try-it"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now, you’re ready to try &lt;a href="https://github.com/dolthub/opencode"&gt;version-controlled OpenCode&lt;/a&gt;.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sh"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;OPENCODE_MYSQL_URL&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;mysql://dolt:pass1234@127.0.0.1:3306/opencode&lt;/span&gt;&lt;span&gt; ~/bin/opencode&lt;/span&gt;&lt;span&gt; ~/myproject/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Version-controlled Open Code exposes the following new version control commands. If you’re familiar with Git, these will look familiar.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="plaintext"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;/commit &amp;#x3C;message&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/log&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/branch [-v]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/branch &amp;#x3C;name&gt; &amp;#x3C;ref&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/branch &amp;#x3C;name&gt; &amp;#x3C;[prompt_index]&gt; -m &amp;#x3C;message&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/checkout &amp;#x3C;branch_name&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/checkout -b &amp;#x3C;branch_name&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/reset&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/reset &amp;#x3C;ref&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/reset &amp;#x3C;[prompt_index]&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/context [--show]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/context &amp;#x3C;ref&gt; [--show]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/diff-stat&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/diff-stat &amp;#x3C;ref&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/diff-stat &amp;#x3C;ref1&gt; &amp;#x3C;ref2&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/diff-context&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/diff-context &amp;#x3C;ref&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/diff-context &amp;#x3C;ref1&gt; &amp;#x3C;ref2&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/history [-v]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/history &amp;#x3C;ref&gt; [-v]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/sql &amp;#x3C;SQL STATEMENT&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="demo"&gt;Demo&lt;a class="anchor-link" aria-label="Link to heading" href="#demo"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As many of you know, my pet project is &lt;a href="https://github.com/dolthub/doltlite"&gt;DoltLite&lt;/a&gt;, a fork of SQLite with Dolt-inspired version control. I asked Open Code to clone a copy and give it a code review, making commits along the way. I’m just going to show the &lt;code&gt;diff&lt;/code&gt; functionality today and come up with a more complex demo for another blog article.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="plaintext"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;ok. we're going to be working on doltlite. can you give it a code review for duplicate code?&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There was a lot of output. But how did the context change? I can use &lt;code&gt;/diff-stat&lt;/code&gt; for a raw view of what’s changed in my context.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="plaintext"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;[/diff-stat]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Diff stat HEAD → WORKING&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;message:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  rows:   3 → 35 (+32)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  added:    +32 rows, +160 cells&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  deleted:  -0 rows, -0 cells&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  modified: ~0 rows, ~0 cells&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  data:   0 B → 13.5 KB (+13.5 KB)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    added rows:    +13.5 KB&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    deleted rows:  -0 B&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    modified rows: 0 B&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;part:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  rows:   9 → 142 (+133)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  added:    +133 rows, +798 cells&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  deleted:  -0 rows, -0 cells&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  modified: ~0 rows, ~0 cells&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  data:   0 B → 248.5 KB (+248.5 KB)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    added rows:    +248.5 KB&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    deleted rows:  -0 B&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    modified rows: 0 B&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;todo:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  rows:   0 → 5 (+5)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  added:    +5 rows, +35 cells&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  deleted:  -0 rows, -0 cells&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  modified: ~0 rows, ~0 cells&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, I’ll make another &lt;code&gt;/commit&lt;/code&gt; and ask Open Code to fix the first item in the review.&lt;/p&gt;
&lt;p&gt;After a few minutes, I’ll use &lt;code&gt;/diff-context&lt;/code&gt; this time to see a more human readable diff.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="plaintext"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;[/diff-context]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Context diff HEAD → WORKING&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Model:           opencode/big-pickle (unchanged)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Messages:        64 → 124 (+60)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  assistant    32 → 62 (+30)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  tool         29 → 58 (+29)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  user         3 → 4 (+1)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Tool calls:      41 → 75 (+34)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total chars:     168023 → 275974 (+107951)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Approx tokens:   42006 → 68994 (+26988)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Changes by position:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [0..63]  identical (64 msgs)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [64]      added    user (+57 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [65]      added    assistant (+20832 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [66]      added    tool (+803 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [67]      added    assistant (+919 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [68]      added    tool (+3971 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [69]      added    assistant (+710 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [70]      added    tool (+1663 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [71]      added    assistant (+8361 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [72]      added    tool (+790 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [73]      added    assistant (+625 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [74]      added    tool (+4655 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [75]      added    assistant (+391 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [76]      added    tool (+1364 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [77]      added    assistant (+4381 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [78]      added    tool (+149 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [79]      added    assistant (+953 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [80]      added    tool (+805 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [81]      added    assistant (+306 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [82]      added    tool (+9912 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [83]      added    assistant (+8428 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [84]      added    tool (+149 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [85]      added    assistant (+3446 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [86]      added    tool (+150 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [87]      added    assistant (+715 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [88]      added    tool (+150 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [89]      added    assistant (+681 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [90]      added    tool (+807 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [91]      added    assistant (+662 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [92]      added    tool (+17608 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [93]      added    assistant (+18140 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [94]      added    tool (+149 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [95]      added    assistant (+720 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [96]      added    tool (+809 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [97]      added    assistant (+298 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [98]      added    tool (+141 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [99]      added    assistant (+294 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [100]      added    tool (+1141 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [101]      added    assistant (+1398 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [102]      added    tool (+135 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [103]      added    assistant (+1117 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [104]      added    tool (+135 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [105]      added    assistant (+506 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [106]      added    tool (+8433 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [107]      added    assistant (+421 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [108]      added    tool (+4157 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [109]      added    assistant (+1946 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [110]      added    tool (+542 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [111]      added    assistant (+525 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [112]      added    tool (+624 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [113]      added    assistant (+1340 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [114]      added    tool (+274 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [115]      added    assistant (+811 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [116]      added    tool (+263 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [117]      added    assistant (+507 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [118]      added    tool (+417 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [119]      added    assistant (+2730 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [120]      added    tool (+291 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [121]      added    assistant (+847 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [122]      added    tool (+809 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [123]      added    assistant (+1562 chars)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Compare this to my next &lt;code&gt;make a pr&lt;/code&gt; prompt. Much lighter weight.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="plaintext"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;  [/diff-context]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Context diff HEAD → WORKING&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Model:           opencode/big-pickle (unchanged)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Messages:        124 → 136 (+12)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  assistant    62 → 68 (+6)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  tool         58 → 63 (+5)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  user         4 → 5 (+1)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Tool calls:      75 → 82 (+7)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total chars:     275974 → 298799 (+22825)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Approx tokens:   68994 → 74700 (+5706)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Changes by position:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [0..123]  identical (124 msgs)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [124]      added    user (+34 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [125]      added    assistant (+971 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [126]      added    tool (+20477 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [127]      added    assistant (+449 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [128]      added    tool (+418 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [129]      added    assistant (+1098 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [130]      added    tool (+382 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [131]      added    assistant (+342 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [132]      added    tool (+327 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [133]      added    assistant (+1061 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [134]      added    tool (+174 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [135]      added    assistant (+215 chars)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The agent created &lt;a href="https://github.com/dolthub/doltlite/pull/1426"&gt;this PR&lt;/a&gt; which failed CI with a build error on the &lt;code&gt;sqllogictest&lt;/code&gt; job. I made another commit and then asked the agent to fix its build. At this point, the agent was ready for compaction and I hit a bug in our prototype. I have it trying to fix itself now.&lt;/p&gt;
&lt;p&gt;As you can see, this &lt;code&gt;diff&lt;/code&gt; functionality would be very useful for Open Code developers to track the evolution of context, especially under code changes to Open Code.&lt;/p&gt;
&lt;h1 id="conclusion"&gt;Conclusion&lt;a class="anchor-link" aria-label="Link to heading" href="#conclusion"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We’re definitely looking for feedback here. Please try out this harness and tell us what you think. Were the Git features useful? Do you want to see others? As always, you can come chat with us on &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;our Discord&lt;/a&gt; or &lt;a href="https://github.com/dolthub/opencode/issues"&gt;create a GitHub issue&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <dc:creator>Tim Sehn</dc:creator>
      <category>dolt</category>
      <category>ai</category>
    </item>
    <item>
      <title>How Fast Is DoltLite?</title>
      <link>https://dolthub.com/blog/2026-06-08-how-fast-is-doltlite/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-06-08-how-fast-is-doltlite/</guid>
      <description>DoltLite replaces SQLite's B-tree interface with a Prolly tree, so we can finally have a fair B-tree vs Prolly Tree race. How do the two data structures compare on sysbench using SQLite's SQL engine?</description>
      <pubDate>Mon, 08 Jun 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;A couple months ago, we released &lt;a href="https://github.com/dolthub/doltlite"&gt;DoltLite&lt;/a&gt;, a free open-source drop-in replacement for &lt;a href="https://sqlite.org"&gt;SQLite&lt;/a&gt; with &lt;a href="https://github.com/dolthub/dolt"&gt;Dolt&lt;/a&gt;-style version control features. DoltLite works by ripping out SQLite’s B-Tree storage engine and replacing it with a content-addressed &lt;a href="https://docs.dolthub.com/architecture/storage-engine/prolly-tree"&gt;Prolly Tree&lt;/a&gt;, the same data structure that powers Dolt.&lt;/p&gt;
&lt;p&gt;We’ve been benchmarking Dolt against MySQL &lt;a href="https://www.dolthub.com/blog/2020-10-11-benchmarking-dolt-with-sysbench/"&gt;for years using &lt;code&gt;sysbench&lt;/code&gt;&lt;/a&gt;. Recently, &lt;a href="https://www.dolthub.com/blog/2026-01-06-more-read-performance-wins/"&gt;Dolt got faster than MySQL&lt;/a&gt; on &lt;code&gt;sysbench&lt;/code&gt;. But, Dolt and MySQL are completely separate SQL engines. Most of the performance difference comes from the SQL engine, not the B-tree vs Prolly Tree difference. “How much?”, you ask. It was hard to tell.&lt;/p&gt;
&lt;p&gt;Until now. DoltLite is SQLite from the B-tree interface up, in other words, the same SQL engine. The only difference between DoltLite and SQLite is B-tree versus Prolly Tree, a true performance bake off. We can finally answer the question “What’s the Prolly Tree performance tax?” This article does just that.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/dolthub/doltlite"&gt;&lt;img src="https://static.dolthub.com/blogimages/doltlite-logo.png/187cf16f99ea27a3199258d56892a3869221f9c9af529beeaffba3990bfc3f47.webp" alt="DoltLite Logo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id="the-prolly-tree-tax"&gt;The Prolly Tree Tax&lt;a class="anchor-link" aria-label="Link to heading" href="#the-prolly-tree-tax"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Here’s the whole article in one table. Same SQL engine on both sides, so every number below is purely the Prolly Tree versus SQLite’s B-tree, nothing else. We run in memory to keep it a clean race, with no disk or page cache to muddy the result. The one exception is autocommit writes, which only mean anything on disk, since committing is a durability cost. Lower is better for DoltLite:&lt;/p&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Workload&lt;/th&gt;&lt;th&gt;Prolly Tree tax&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Reads&lt;/td&gt;&lt;td&gt;1.20x — a 20% tax&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Batched writes&lt;/td&gt;&lt;td&gt;1.67x — a 67% tax&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Autocommit writes&lt;/td&gt;&lt;td&gt;4.00x — the real tax lives here&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The Prolly Tree tax is modest on reads, noticeable on batched writes, and only really bites when you commit every single write. And on that last one you usually have an out: batch your writes in a transaction.&lt;/p&gt;
&lt;h1 id="a-true-bake-off"&gt;A True Bake-Off&lt;a class="anchor-link" aria-label="Link to heading" href="#a-true-bake-off"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;DoltLite is a drop-in replacement for SQLite, and that’s exactly what makes this measurement clean. Everything from the B-tree interface up — the parser, the planner, the whole SQL engine — is line-for-line SQLite. The only thing we
changed is the storage engine underneath. So when we run the identical SQL through both and compare, the difference is the Prolly Tree tax, isolated. No SQL-engine variable muddying the result the way there is when we benchmark Dolt against MySQL.&lt;/p&gt;
&lt;p&gt;To isolate the data structure even further, the numbers in this article are from in-memory databases. That strips out the disk and the page cache, leaving the raw cost of walking and updating a Prolly Tree instead of a B-tree.&lt;/p&gt;
&lt;p&gt;We build stock SQLite straight out of the same source tree (&lt;code&gt;make DOLTLITE_PROLLY=0 sqlite3&lt;/code&gt;) and run a &lt;a href="https://github.com/dolthub/doltlite/blob/main/test/sysbench_compare.sh"&gt;sysbench-style OLTP suite&lt;/a&gt; against both on every PR: 100,000-row tables, the median of 5 invocations per test (9 for autocommit writes), workload-only timing off a monotonic clock. CI enforces a hard ceiling: 2.5x on any individual test, 2x on a section average. The build goes red if we regress performance. We run the whole thing four times with different key types: integer, text, blob, and composite.&lt;/p&gt;
&lt;p&gt;The full table gets posted as a comment on &lt;a href="https://github.com/dolthub/doltlite/pull/1270"&gt;every PR&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id="reads"&gt;Reads&lt;a class="anchor-link" aria-label="Link to heading" href="#reads"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;In memory, reads cost about 20% more than SQLite:&lt;/p&gt;











































































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Test&lt;/th&gt;&lt;th align="right"&gt;SQLite (us)&lt;/th&gt;&lt;th align="right"&gt;DoltLite (us)&lt;/th&gt;&lt;th align="right"&gt;Multiplier&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;oltp_point_select&lt;/td&gt;&lt;td align="right"&gt;23,710&lt;/td&gt;&lt;td align="right"&gt;29,457&lt;/td&gt;&lt;td align="right"&gt;1.24&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_range_select&lt;/td&gt;&lt;td align="right"&gt;10,124&lt;/td&gt;&lt;td align="right"&gt;11,930&lt;/td&gt;&lt;td align="right"&gt;1.18&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_sum_range&lt;/td&gt;&lt;td align="right"&gt;9,490&lt;/td&gt;&lt;td align="right"&gt;11,938&lt;/td&gt;&lt;td align="right"&gt;1.26&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_order_range&lt;/td&gt;&lt;td align="right"&gt;2,572&lt;/td&gt;&lt;td align="right"&gt;2,953&lt;/td&gt;&lt;td align="right"&gt;1.15&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_distinct_range&lt;/td&gt;&lt;td align="right"&gt;3,628&lt;/td&gt;&lt;td align="right"&gt;4,013&lt;/td&gt;&lt;td align="right"&gt;1.11&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_index_scan&lt;/td&gt;&lt;td align="right"&gt;3,951&lt;/td&gt;&lt;td align="right"&gt;5,275&lt;/td&gt;&lt;td align="right"&gt;1.34&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;select_random_points&lt;/td&gt;&lt;td align="right"&gt;10,245&lt;/td&gt;&lt;td align="right"&gt;11,268&lt;/td&gt;&lt;td align="right"&gt;1.10&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;select_random_ranges&lt;/td&gt;&lt;td align="right"&gt;2,979&lt;/td&gt;&lt;td align="right"&gt;4,117&lt;/td&gt;&lt;td align="right"&gt;1.38&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;covering_index_scan&lt;/td&gt;&lt;td align="right"&gt;4,124&lt;/td&gt;&lt;td align="right"&gt;4,380&lt;/td&gt;&lt;td align="right"&gt;1.06&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;groupby_scan&lt;/td&gt;&lt;td align="right"&gt;30,945&lt;/td&gt;&lt;td align="right"&gt;33,884&lt;/td&gt;&lt;td align="right"&gt;1.09&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;index_join&lt;/td&gt;&lt;td align="right"&gt;6,005&lt;/td&gt;&lt;td align="right"&gt;8,159&lt;/td&gt;&lt;td align="right"&gt;1.36&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;index_join_scan&lt;/td&gt;&lt;td align="right"&gt;3,396&lt;/td&gt;&lt;td align="right"&gt;4,597&lt;/td&gt;&lt;td align="right"&gt;1.35&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;types_table_scan&lt;/td&gt;&lt;td align="right"&gt;1,057,625&lt;/td&gt;&lt;td align="right"&gt;1,218,914&lt;/td&gt;&lt;td align="right"&gt;1.15&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;table_scan&lt;/td&gt;&lt;td align="right"&gt;1,233,810&lt;/td&gt;&lt;td align="right"&gt;1,304,540&lt;/td&gt;&lt;td align="right"&gt;1.06&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_read_only&lt;/td&gt;&lt;td align="right"&gt;102,177&lt;/td&gt;&lt;td align="right"&gt;120,120&lt;/td&gt;&lt;td align="right"&gt;1.18&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Average&lt;/td&gt;&lt;td align="right"&gt;&lt;/td&gt;&lt;td align="right"&gt;&lt;/td&gt;&lt;td align="right"&gt;1.20&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Why 20%? A Prolly Tree node is content-addressed, so every step down the tree is a hash lookup in the chunk cache plus a decode of the node’s packed key/value layout, where SQLite’s B-tree just follows a page pointer. That extra indirection is the tax.&lt;/p&gt;
&lt;h1 id="batched-writes"&gt;Batched Writes&lt;a class="anchor-link" aria-label="Link to heading" href="#batched-writes"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Batched into a transaction, writes cost about 67% more in memory:&lt;/p&gt;

































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Test&lt;/th&gt;&lt;th align="right"&gt;SQLite (us)&lt;/th&gt;&lt;th align="right"&gt;DoltLite (us)&lt;/th&gt;&lt;th align="right"&gt;Multiplier&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;oltp_bulk_insert&lt;/td&gt;&lt;td align="right"&gt;181,919&lt;/td&gt;&lt;td align="right"&gt;253,557&lt;/td&gt;&lt;td align="right"&gt;1.39&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_insert&lt;/td&gt;&lt;td align="right"&gt;15,472&lt;/td&gt;&lt;td align="right"&gt;27,785&lt;/td&gt;&lt;td align="right"&gt;1.80&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_update_index&lt;/td&gt;&lt;td align="right"&gt;51,887&lt;/td&gt;&lt;td align="right"&gt;89,758&lt;/td&gt;&lt;td align="right"&gt;1.73&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_update_non_index&lt;/td&gt;&lt;td align="right"&gt;34,388&lt;/td&gt;&lt;td align="right"&gt;59,641&lt;/td&gt;&lt;td align="right"&gt;1.73&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_delete_insert&lt;/td&gt;&lt;td align="right"&gt;46,005&lt;/td&gt;&lt;td align="right"&gt;71,917&lt;/td&gt;&lt;td align="right"&gt;1.56&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_write_only&lt;/td&gt;&lt;td align="right"&gt;22,530&lt;/td&gt;&lt;td align="right"&gt;44,628&lt;/td&gt;&lt;td align="right"&gt;1.98&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;types_delete_insert&lt;/td&gt;&lt;td align="right"&gt;24,611&lt;/td&gt;&lt;td align="right"&gt;40,401&lt;/td&gt;&lt;td align="right"&gt;1.64&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_read_write&lt;/td&gt;&lt;td align="right"&gt;72,397&lt;/td&gt;&lt;td align="right"&gt;108,598&lt;/td&gt;&lt;td align="right"&gt;1.50&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Average&lt;/td&gt;&lt;td align="right"&gt;&lt;/td&gt;&lt;td align="right"&gt;&lt;/td&gt;&lt;td align="right"&gt;1.67&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;A 67% tax to get full history, branching, diff, and merge on your data. Sounds like a good trade to me.&lt;/p&gt;
&lt;p&gt;Writes cost more than reads because a Prolly Tree is immutable. Changing one row can’t overwrite a node in place the way a B-tree does. It re-hashes that node and every node above it up to the root, allocating new content-addressed chunks along the way. That’s more work per write, even inside a single transaction. The flip side is that the very same immutability is what buys you cheap branching and content-addressed diffs.&lt;/p&gt;
&lt;h1 id="autocommit-writes"&gt;Autocommit Writes&lt;a class="anchor-link" aria-label="Link to heading" href="#autocommit-writes"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;It was going so well. Committing every write is where the Prolly Tree performance story gets a little gnarly. This is the one section measured on disk: a commit is a durable write, so it only means anything with a real file behind it.&lt;/p&gt;

































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Test&lt;/th&gt;&lt;th align="right"&gt;SQLite (us)&lt;/th&gt;&lt;th align="right"&gt;DoltLite (us)&lt;/th&gt;&lt;th align="right"&gt;Multiplier&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;oltp_bulk_insert_ac&lt;/td&gt;&lt;td align="right"&gt;20,541&lt;/td&gt;&lt;td align="right"&gt;75,772&lt;/td&gt;&lt;td align="right"&gt;3.69&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_insert_ac&lt;/td&gt;&lt;td align="right"&gt;23,297&lt;/td&gt;&lt;td align="right"&gt;91,726&lt;/td&gt;&lt;td align="right"&gt;3.94&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_update_index_ac&lt;/td&gt;&lt;td align="right"&gt;26,183&lt;/td&gt;&lt;td align="right"&gt;104,527&lt;/td&gt;&lt;td align="right"&gt;3.99&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_update_non_index_ac&lt;/td&gt;&lt;td align="right"&gt;21,466&lt;/td&gt;&lt;td align="right"&gt;86,763&lt;/td&gt;&lt;td align="right"&gt;4.04&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_delete_insert_ac&lt;/td&gt;&lt;td align="right"&gt;22,961&lt;/td&gt;&lt;td align="right"&gt;96,960&lt;/td&gt;&lt;td align="right"&gt;4.22&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_write_only_ac&lt;/td&gt;&lt;td align="right"&gt;23,384&lt;/td&gt;&lt;td align="right"&gt;95,285&lt;/td&gt;&lt;td align="right"&gt;4.07&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;types_delete_insert_ac&lt;/td&gt;&lt;td align="right"&gt;20,889&lt;/td&gt;&lt;td align="right"&gt;93,985&lt;/td&gt;&lt;td align="right"&gt;4.50&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_read_write_ac&lt;/td&gt;&lt;td align="right"&gt;29,065&lt;/td&gt;&lt;td align="right"&gt;103,041&lt;/td&gt;&lt;td align="right"&gt;3.55&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Average&lt;/td&gt;&lt;td align="right"&gt;&lt;/td&gt;&lt;td align="right"&gt;&lt;/td&gt;&lt;td align="right"&gt;4.00&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;About 4x. This is structural, not a bug. Every commit in a Prolly Tree re-hashes the path from the changed leaf up to the root and writes new immutable, content-addressed chunks. That cost is O(log n) in the tree’s depth, but with a bigger constant than SQLite, so it grows as tables get bigger. Back when &lt;a href="https://github.com/dolthub/doltlite/pull/1000"&gt;we ran the suite at 10,000-row tables&lt;/a&gt;, autocommit writes were comfortably under 2x, versus the 4x you see here at 100,000 rows. SQLite just mutates a page in place and shifts the index if necessary.&lt;/p&gt;
&lt;p&gt;Moreover, DoltLite’s content-addressed store must update more physical locations on disk as well as the manifest and the branch HEADs. This just adds to the performance overhead.&lt;/p&gt;
&lt;h1 id="keep-doltlite-fast"&gt;Keep DoltLite Fast&lt;a class="anchor-link" aria-label="Link to heading" href="#keep-doltlite-fast"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The &lt;code&gt;sysbench&lt;/code&gt; metrics suggest two pieces of DoltLite performance advice.&lt;/p&gt;
&lt;h2 id="batch-writes"&gt;Batch Writes&lt;a class="anchor-link" aria-label="Link to heading" href="#batch-writes"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The autocommit write fix is the same advice you’d get for stock SQLite: batch your writes.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;BEGIN&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;-- thousands of inserts here&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;COMMIT&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Those same operations get much cheaper the moment you wrap them. Batching amortizes the per-commit re-hashing across thousands of rows, which is exactly why the batched-writes tax (1.67x) is so much smaller than the autocommit one (4x).&lt;/p&gt;
&lt;p&gt;Let’s keep the 4x in perspective. That autocommit test is 200 separate committed inserts, ~25ms total in SQLite versus ~100ms in DoltLite. Per write, that’s about 0.125ms versus 0.5ms, both faster than a single frame of video. Unless you’re committing one row at a time in a loop, you will never feel it. So go ahead and use &lt;code&gt;autocommit&lt;/code&gt; if it’s easier. For most applications the tax simply won’t matter.&lt;/p&gt;
&lt;h1 id="use-integer-keys"&gt;Use Integer Keys&lt;a class="anchor-link" aria-label="Link to heading" href="#use-integer-keys"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We run everything with a few different primary key types to see what, say, UUID-shaped keys cost. In memory, text keys push reads to about 1.5x and batched writes to about 1.9x, with range scans climbing toward 2.3x. The takeaway: if you care about speed, integer primary keys are the fast path. UUIDs work, they just cost more.&lt;/p&gt;
&lt;h1 id="conclusion"&gt;Conclusion&lt;a class="anchor-link" aria-label="Link to heading" href="#conclusion"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;So what’s the Prolly Tree tax? For years we could only guess. Dolt is faster than MySQL, but they’re different
SQL engines, so the storage layer’s contribution was buried. DoltLite finally lets us measure it in isolation. The Prolly Tree tax is about 20% on reads, 67% on batched writes, and 4x on single-row autocommit writes. Just like my beloved California, the taxes are worth it. In California, you get the weather. With DoltLite, you get the version control.&lt;/p&gt;
&lt;p&gt;Packing your bags and joining the DoltLite gold rush? Come by &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;our Discord&lt;/a&gt;, and we’ll give you a warm welcome in the #doltlite🪶 channel.&lt;/p&gt;</content:encoded>
      <dc:creator>Tim Sehn</dc:creator>
      <category>doltlite</category>
      <category>performance</category>
    </item>
    <item>
      <title>Announcing Dumbo Garbage Collection</title>
      <link>https://dolthub.com/blog/2026-06-02-dumbodb-gc/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-06-02-dumbodb-gc/</guid>
      <description>MongoDB and Git had a baby, and it's named Dumbo. The latest release has garbage collection!</description>
      <pubDate>Tue, 02 Jun 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/dumbo-logo.png/c02da7b39168585c4dc1adf3ebf6ffe77404dd9b8fc5a35f6dc765bb9dea9e16.webp" alt="DumboDB Logo"&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/dolthub/dumbodb"&gt;DumboDB&lt;/a&gt; is a document database inspired by &lt;a href="https://github.com/mongodb/mongo"&gt;MongoDB&lt;/a&gt;, built on top of &lt;a href="https://github.com/dolthub/dolt"&gt;Dolt’s storage&lt;/a&gt;. DumboDB combines the flexibility of a document database with the power of Git-like version control, allowing you to track changes, branch, and merge your data with ease.&lt;/p&gt;
&lt;p&gt;It’s early days for DumboDB, but thanks to leveraging Dolt’s underlying architecture, we’re able to rapidly iterate and add new features. In &lt;a href="https://github.com/dolthub/dumbodb/releases/tag/v0.1.3"&gt;release 0.1.3&lt;/a&gt;, we’re excited to announce the addition of garbage collection (GC) to DumboDB!&lt;/p&gt;
&lt;h2 id="what-is-garbage-collection"&gt;What is Garbage Collection?&lt;a class="anchor-link" aria-label="Link to heading" href="#what-is-garbage-collection"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In many databases, as you update your data on disk, old versions of your data will accumulate over time. Cleaning up this data goes by many names. In PostgreSQL, it’s called &lt;a href="https://www.postgresql.org/docs/current/sql-vacuum.html"&gt;VACUUM&lt;/a&gt;. In MySQL, it’s called &lt;a href="https://dev.mysql.com/doc/refman/9.7/en/innodb-purge-configuration.html"&gt;purging&lt;/a&gt;. In Dolt, it’s called &lt;a href="https://www.dolthub.com/docs/sql-reference/server/garbage-collection/"&gt;garbage collection&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In traditional databases, it makes sense that garbage would exist. When you update a row in a table, the old version of that row is still on disk until the database decides to clean it up.&lt;/p&gt;
&lt;p&gt;Dolt and Dumbo are version-controlled databases, so it’s reasonable to assume we store every version of the data forever. Unfortunately, it’s not that simple. Dolt and Dumbo keep track of all &lt;em&gt;committed&lt;/em&gt; data, specifically data that has been committed to the database and is part of the commit history.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/how-garbage-is-created.png/c719463f830464444cce6a285c5a4125cc88710480ad62d28a3108f60a25739b.webp" alt="how garbage is created"&gt;&lt;/p&gt;
&lt;p&gt;In scenarios where you insert or update many documents, there are intermediate versions of the data that are not committed to the commit history. These intermediate versions take up disk space and may not be necessary to keep around indefinitely. This is where garbage collection comes in.&lt;/p&gt;
&lt;h2 id="how-does-dumbos-garbage-collection-work"&gt;How Does Dumbo’s Garbage Collection Work?&lt;a class="anchor-link" aria-label="Link to heading" href="#how-does-dumbos-garbage-collection-work"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The short answer is that it’s just like &lt;a href="https://www.dolthub.com/blog/2025-03-21-session-aware-gc-technical-details/"&gt;Dolt’s Session Aware GC&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I won’t go into that level of detail here, but at a high level, every chunk of data in a Dolt (and Dumbo) database must be reachable from the commit history of all branches. We build a list of all chunks in the database, then walk the commit history to find all chunks that are reachable from commits. Any chunks that are not reachable from the commit history are considered garbage and can be safely deleted.&lt;/p&gt;
&lt;p&gt;This becomes more complicated when you consider that there may be active sessions in the database that are still using some of the intermediate versions of the data. We don’t want to delete any chunks that are still being used by active sessions, so we need to keep track of those as well.&lt;/p&gt;
&lt;p&gt;Dolt’s GC process takes this into account by keeping track of the active sessions and ensuring that any chunks that are still being used by those sessions are not deleted during the GC process. This allows us to safely clean up any garbage data without affecting any active operations in the database.&lt;/p&gt;
&lt;p&gt;DumboDB uses the same storage engine as Dolt, so we were able to leverage the existing GC implementation in Dolt to add GC support to DumboDB. This means that DumboDB can now automatically clean up any garbage data that may be taking up space on disk, without affecting any active sessions or operations in the database.&lt;/p&gt;
&lt;h2 id="using-garbage-collection-in-dumbodb"&gt;Using Garbage Collection in DumboDB&lt;a class="anchor-link" aria-label="Link to heading" href="#using-garbage-collection-in-dumbodb"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Garbage collection has been added in the &lt;a href="https://github.com/dolthub/dumbodb/releases/tag/v0.1.3"&gt;latest release&lt;/a&gt; of DumboDB.&lt;/p&gt;
&lt;p&gt;Be sure that the &lt;code&gt;mongo&lt;/code&gt; driver is installed for Python:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;pip&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;span&gt; pymongo&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then create a script that creates a bunch of garbage chunks. Put this text in a file called &lt;code&gt;make_garbage.py&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="python"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; random&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; secrets&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; pymongo &lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; MongoClient&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;client &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; MongoClient(&lt;/span&gt;&lt;span&gt;"mongodb://127.0.0.1:27017"&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;db &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; client[&lt;/span&gt;&lt;span&gt;"gcdemo"&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;coll &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; db[&lt;/span&gt;&lt;span&gt;"items"&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; b &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt; range&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;50&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    docs &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; []&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    for&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt; range&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;        docs.append({&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;            "_id"&lt;/span&gt;&lt;span&gt;:   &lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;"b&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;-d&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;secrets.token_hex(&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;            "name"&lt;/span&gt;&lt;span&gt;:  &lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;"user-&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;secrets.token_hex(&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;            "email"&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;secrets.token_hex(&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;@example.com"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;            "age"&lt;/span&gt;&lt;span&gt;:   random.randint(&lt;/span&gt;&lt;span&gt;18&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;80&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;            "score"&lt;/span&gt;&lt;span&gt;: random.random() &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; 100&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;        })&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    coll.insert_many(docs)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    db.command({&lt;/span&gt;&lt;span&gt;"dumboCommit"&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;"message"&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;"batch &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;"author"&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;"gcdemo &amp;#x3C;gcdemo@example.com&gt;"&lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;"batch &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;b &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; 1}&lt;/span&gt;&lt;span&gt;/50 committed"&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;client.close()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This script creates 50 commits, each with 100 new random documents. As a result, it creates a lot of intermediate data versions that are not committed to the commit history and are therefore considered garbage. Run the script:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sh"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; python&lt;/span&gt;&lt;span&gt; make_garbage.py&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;batch&lt;/span&gt;&lt;span&gt; 1/50&lt;/span&gt;&lt;span&gt; committed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;batch&lt;/span&gt;&lt;span&gt; 2/50&lt;/span&gt;&lt;span&gt; committed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;[... snip ...]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;batch&lt;/span&gt;&lt;span&gt; 49/50&lt;/span&gt;&lt;span&gt; committed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;batch&lt;/span&gt;&lt;span&gt; 50/50&lt;/span&gt;&lt;span&gt; committed&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In another file, &lt;code&gt;run_gc.py&lt;/code&gt;, add the following code to trigger the GC process:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="python"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; pprint &lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; pprint&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; pymongo &lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; MongoClient&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;client &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; MongoClient(&lt;/span&gt;&lt;span&gt;"mongodb://127.0.0.1:27017"&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;res &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; client[&lt;/span&gt;&lt;span&gt;"gcdemo"&lt;/span&gt;&lt;span&gt;].command({&lt;/span&gt;&lt;span&gt;"dumboGC"&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;pprint(&lt;/span&gt;&lt;span&gt;dict&lt;/span&gt;&lt;span&gt;(res))&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;client.close()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you run this script, it will trigger the GC process in DumboDB and print out the results:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sh"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; python&lt;/span&gt;&lt;span&gt; run_gc.py&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;'chunksAfter'&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 6608.0,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 'chunksBefore'&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 7119.0,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 'db'&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 'gcdemo',&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 'durationMs'&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 163.0,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 'mode'&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 'default',&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 'ok'&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 1.0,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 'sizeAfter'&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 5929327.0,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 'sizeBefore'&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 7452156.0&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command returns statistics about the number of chunks before and after the GC process, the database size before and after, and how long the GC process took to run.&lt;/p&gt;
&lt;h2 id="comparison-to-dolt"&gt;Comparison to Dolt&lt;a class="anchor-link" aria-label="Link to heading" href="#comparison-to-dolt"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the reasons I wanted to add GC to DumboDB is to see how Dumbo’s storage usage compares to Dolt’s. I added &lt;a href="https://github.com/dolthub/dumbodb-parity-testing/pull/14"&gt;parity tests&lt;/a&gt; to generate equivalent data in both Dolt and Dumbo, then ran GC on both databases to see how much space was used for each.&lt;/p&gt;
&lt;p&gt;The results aren’t fantastic, I’m not gonna lie. There is clearly something amiss. When storing about 1M documents, Dumbo is using about 6x the amount of space after GC compared to Dolt.&lt;/p&gt;
&lt;p&gt;It’s not clear yet if this is the result of a bug in how Dumbo stores data or if we are being too conservative when we garbage collect. As we &lt;a href="https://www.dolthub.com/blog/2026-05-19-dumbodb-01-performance/"&gt;discussed in a previous post&lt;/a&gt;, this kind of side-by-side comparison is one of the main ways we can verify that a vibe-coded product such as Dumbo is working correctly. My gut says that we should have collected more data in our example and we are being too conservative. We will be investigating this issue in the coming weeks and will share our findings in a future blog post.&lt;/p&gt;
&lt;h2 id="whats-next"&gt;What’s Next?&lt;a class="anchor-link" aria-label="Link to heading" href="#whats-next"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Sorting out the storage discrepancy just mentioned is the top priority. After we sort that out, automatic garbage collection is the next step. Similar to Dolt, when the server determines that there is a reasonable amount of garbage data that can be cleaned up, it will automatically trigger the GC process. This will help ensure that your DumboDB instance stays clean and efficient without requiring manual intervention.&lt;/p&gt;
&lt;p&gt;Want to learn more about Dolt and Dumbo? Hop on our &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;Discord&lt;/a&gt; to ask questions and nerd out about version-controlled databases!&lt;/p&gt;</content:encoded>
      <dc:creator>Neil Macneale</dc:creator>
      <category>dumbo</category>
      <category>feature release</category>
    </item>
    <item>
      <title>Evolving with Beads</title>
      <link>https://dolthub.com/blog/2026-05-29-evolving-with-beads/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-05-29-evolving-with-beads/</guid>
      <description>A guide to evolving your Beads setup from classic single-agent mode to server and shared-server modes for multi-agent workflows, with a bonus look at the global Beads database.</description>
      <pubDate>Fri, 29 May 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;&lt;a href="https://github.com/gastownhall/beads"&gt;Beads&lt;/a&gt; is a tool for extending the memory of coding agents, such as &lt;a href="https://claude.com/product/claude-code"&gt;Claude Code&lt;/a&gt;, allowing them to manage tasks (i.e. beads) themselves. It was originally built by &lt;a href="https://steve-yegge.medium.com/introducing-beads-a-coding-agent-memory-system-637d7d92514a"&gt;Steve Yegge&lt;/a&gt; and is now part of &lt;a href="https://gastownhall.ai/"&gt;Gaslandia&lt;/a&gt;, which comprises of Beads, Gastown, Gas City, and Wasteland. Beads is backed by Dolt, and version &lt;a href="https://github.com/gastownhall/beads/releases/tag/v1.0.5"&gt;v1.0.5&lt;/a&gt; is available now.&lt;/p&gt;
&lt;p&gt;In today’s blog, I’ll cover a common question we’ve seen from Beads users about how to evolve with the tool: “I’ve been using Beads classic and want to know how to move to server mode, when should I do that, and how do I do that?” I’ll answer this by migrating from the most simple, “classic”, single-agent mode to the server and shared-server modes that better support multi-agent workflows.&lt;/p&gt;
&lt;h1 id="beads-classic"&gt;Beads Classic&lt;a class="anchor-link" aria-label="Link to heading" href="#beads-classic"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Most Beads users use the “classic” mode of Beads, which provides a coding-agent persistent memory and an interface for self-managing it. In this example, I have the latest Dolt installed, &lt;a href="https://github.com/dolthub/dolt/releases/tag/v2.0.8"&gt;v2.0.8&lt;/a&gt;, and will make a new Git project where my coding agent will work.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  repros&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;dolt&lt;/span&gt;&lt;span&gt; version&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;dolt&lt;/span&gt;&lt;span&gt; version&lt;/span&gt;&lt;span&gt; 2.0.8&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  repros&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; mkdir&lt;/span&gt;&lt;span&gt; evolving_demo&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  repros&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; cd&lt;/span&gt;&lt;span&gt; evolving_demo&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; echo&lt;/span&gt;&lt;span&gt; "# evolving_demo"&lt;/span&gt;&lt;span&gt; &gt;&gt;&lt;/span&gt;&lt;span&gt; README.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Initialized&lt;/span&gt;&lt;span&gt; empty&lt;/span&gt;&lt;span&gt; Git&lt;/span&gt;&lt;span&gt; repository&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/.git/&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;span&gt; add&lt;/span&gt;&lt;span&gt; .&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;span&gt; commit&lt;/span&gt;&lt;span&gt; -m&lt;/span&gt;&lt;span&gt; 'README.md'&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;[main (root&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;commit) 9dffb6e] README.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; file&lt;/span&gt;&lt;span&gt; changed,&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; insertion&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; create&lt;/span&gt;&lt;span&gt; mode&lt;/span&gt;&lt;span&gt; 100644&lt;/span&gt;&lt;span&gt; README.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;git&lt;/span&gt;&lt;span&gt; remote&lt;/span&gt;&lt;span&gt; add&lt;/span&gt;&lt;span&gt; origin&lt;/span&gt;&lt;span&gt; https://github.com/coffeegoddd/evolving_demo.git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;git&lt;/span&gt;&lt;span&gt; push&lt;/span&gt;&lt;span&gt; origin&lt;/span&gt;&lt;span&gt; main&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Enumerating&lt;/span&gt;&lt;span&gt; objects:&lt;/span&gt;&lt;span&gt; 3,&lt;/span&gt;&lt;span&gt; done.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Counting&lt;/span&gt;&lt;span&gt; objects:&lt;/span&gt;&lt;span&gt; 100%&lt;/span&gt;&lt;span&gt; (3/3), done.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Writing&lt;/span&gt;&lt;span&gt; objects:&lt;/span&gt;&lt;span&gt; 100%&lt;/span&gt;&lt;span&gt; (3/3), 250 bytes &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; 250.00&lt;/span&gt;&lt;span&gt; KiB/s,&lt;/span&gt;&lt;span&gt; done.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total&lt;/span&gt;&lt;span&gt; 3&lt;/span&gt;&lt;span&gt; (delta &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;), reused 0 (&lt;/span&gt;&lt;span&gt;delta&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;), pack-reused 0 (&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;To&lt;/span&gt;&lt;span&gt; https://github.com/coffeegoddd/evolving_demo.git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; [new &lt;/span&gt;&lt;span&gt;branch]&lt;/span&gt;&lt;span&gt;      main&lt;/span&gt;&lt;span&gt; -&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; main&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’ve initialized my git project and pushed it to GitHub as well. Next, I also have the latest version of Beads installed, and I can run &lt;code&gt;bd init&lt;/code&gt; to initialize the project with everything my agent will need to use Beads successfully.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; version&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; version&lt;/span&gt;&lt;span&gt; 1.0.5&lt;/span&gt;&lt;span&gt; (dev: &lt;/span&gt;&lt;span&gt;801fb95d1767&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Configured&lt;/span&gt;&lt;span&gt; Dolt&lt;/span&gt;&lt;span&gt; remote:&lt;/span&gt;&lt;span&gt; origin&lt;/span&gt;&lt;span&gt; →&lt;/span&gt;&lt;span&gt; git+https://github.com/coffeegoddd/evolving_demo.git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Repository&lt;/span&gt;&lt;span&gt; ID:&lt;/span&gt;&lt;span&gt; 76062c1e&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Clone&lt;/span&gt;&lt;span&gt; ID:&lt;/span&gt;&lt;span&gt; 642acc6d98a2785e&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;▶&lt;/span&gt;&lt;span&gt; Already&lt;/span&gt;&lt;span&gt; configured&lt;/span&gt;&lt;span&gt; as:&lt;/span&gt;&lt;span&gt; maintainer&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Change&lt;/span&gt;&lt;span&gt; role?&lt;/span&gt;&lt;span&gt; [y/N]: n&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;▶&lt;/span&gt;&lt;span&gt; Auto-export&lt;/span&gt;&lt;span&gt; can&lt;/span&gt;&lt;span&gt; keep&lt;/span&gt;&lt;span&gt; .beads/issues.jsonl&lt;/span&gt;&lt;span&gt; up&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; date&lt;/span&gt;&lt;span&gt; after&lt;/span&gt;&lt;span&gt; write&lt;/span&gt;&lt;span&gt; commands.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  This&lt;/span&gt;&lt;span&gt; optional&lt;/span&gt;&lt;span&gt; JSONL&lt;/span&gt;&lt;span&gt; export&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; useful&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; viewers&lt;/span&gt;&lt;span&gt; (bv), interchange, and issue-level migration.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Dolt&lt;/span&gt;&lt;span&gt; remotes/backups&lt;/span&gt;&lt;span&gt; handle&lt;/span&gt;&lt;span&gt; cross-machine&lt;/span&gt;&lt;span&gt; sync&lt;/span&gt;&lt;span&gt; and&lt;/span&gt;&lt;span&gt; backup.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Enable&lt;/span&gt;&lt;span&gt; auto-export?&lt;/span&gt;&lt;span&gt; [y/N]: n&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Auto-export&lt;/span&gt;&lt;span&gt; disabled&lt;/span&gt;&lt;span&gt; (enable &lt;/span&gt;&lt;span&gt;later&lt;/span&gt;&lt;span&gt; with:&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; config&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; export.auto&lt;/span&gt;&lt;span&gt; true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Hooks&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;span&gt; to:&lt;/span&gt;&lt;span&gt; .beads/hooks/&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Created&lt;/span&gt;&lt;span&gt; AGENTS.md&lt;/span&gt;&lt;span&gt; with&lt;/span&gt;&lt;span&gt; agent&lt;/span&gt;&lt;span&gt; instructions&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; hooks&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; project...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Registered&lt;/span&gt;&lt;span&gt; SessionStart&lt;/span&gt;&lt;span&gt; hook&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; integration...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Created&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; CLAUDE.md&lt;/span&gt;&lt;span&gt; with&lt;/span&gt;&lt;span&gt; beads&lt;/span&gt;&lt;span&gt; integration&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; integration&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  File:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/CLAUDE.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;No&lt;/span&gt;&lt;span&gt; additional&lt;/span&gt;&lt;span&gt; configuration&lt;/span&gt;&lt;span&gt; needed!&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; integration&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Settings:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/.claude/settings.json&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Restart&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; changes&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; take&lt;/span&gt;&lt;span&gt; effect.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Beads&lt;/span&gt;&lt;span&gt; agent&lt;/span&gt;&lt;span&gt; skill...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Beads&lt;/span&gt;&lt;span&gt; agent&lt;/span&gt;&lt;span&gt; skill&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Skill:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/.agents/skills/beads/SKILL.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; native&lt;/span&gt;&lt;span&gt; hooks&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; project...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; native&lt;/span&gt;&lt;span&gt; hooks&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; instructions&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; project...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; instructions&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  File:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/AGENTS.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Restart&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; if&lt;/span&gt;&lt;span&gt; it&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; already&lt;/span&gt;&lt;span&gt; running.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Committed&lt;/span&gt;&lt;span&gt; beads&lt;/span&gt;&lt;span&gt; files&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;⚠&lt;/span&gt;&lt;span&gt; Git&lt;/span&gt;&lt;span&gt; upstream&lt;/span&gt;&lt;span&gt; not&lt;/span&gt;&lt;span&gt; configured&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  For&lt;/span&gt;&lt;span&gt; sync&lt;/span&gt;&lt;span&gt; workflows,&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; your&lt;/span&gt;&lt;span&gt; upstream&lt;/span&gt;&lt;span&gt; with:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  git&lt;/span&gt;&lt;span&gt; remote&lt;/span&gt;&lt;span&gt; add&lt;/span&gt;&lt;span&gt; upstream&lt;/span&gt;&lt;span&gt; &amp;#x3C;&lt;/span&gt;&lt;span&gt;repo-ur&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; initialized&lt;/span&gt;&lt;span&gt; successfully!&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Backend:&lt;/span&gt;&lt;span&gt; dolt&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Mode:&lt;/span&gt;&lt;span&gt; embedded&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Database:&lt;/span&gt;&lt;span&gt; evolving_demo&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Issue&lt;/span&gt;&lt;span&gt; prefix:&lt;/span&gt;&lt;span&gt; evolving_demo&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Issues&lt;/span&gt;&lt;span&gt; will&lt;/span&gt;&lt;span&gt; be&lt;/span&gt;&lt;span&gt; named:&lt;/span&gt;&lt;span&gt; evolving_demo-&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;has&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; (e.g., &lt;/span&gt;&lt;span&gt;evolving_demo-a3f2dd&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Run&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; quickstart&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; get&lt;/span&gt;&lt;span&gt; started.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Importantly, always choose the role ‘maintainer’ and choose ‘no’ for auto-export.&lt;/p&gt;
&lt;p&gt;Contributor mode is outside the scope of this blog, and auto-export is a legacy feature.&lt;/p&gt;
&lt;p&gt;After Beads is initialized in my repo, I can create a sample bead to test it out before my agent takes over.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; create&lt;/span&gt;&lt;span&gt; "my first bead"&lt;/span&gt;&lt;span&gt; -t&lt;/span&gt;&lt;span&gt; task&lt;/span&gt;&lt;span&gt; -p&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Created&lt;/span&gt;&lt;span&gt; issue:&lt;/span&gt;&lt;span&gt; evolving_demo-0v4&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; my&lt;/span&gt;&lt;span&gt; first&lt;/span&gt;&lt;span&gt; bead&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Priority:&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Status:&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;💡&lt;/span&gt;&lt;span&gt; Tip:&lt;/span&gt;&lt;span&gt; Install&lt;/span&gt;&lt;span&gt; the&lt;/span&gt;&lt;span&gt; beads&lt;/span&gt;&lt;span&gt; plugin&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; automatic&lt;/span&gt;&lt;span&gt; workflow&lt;/span&gt;&lt;span&gt; context,&lt;/span&gt;&lt;span&gt; or&lt;/span&gt;&lt;span&gt; run&lt;/span&gt;&lt;span&gt; 'bd setup claude'&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; CLI-only&lt;/span&gt;&lt;span&gt; mode&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; evolving_demo-0v4&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; my&lt;/span&gt;&lt;span&gt; first&lt;/span&gt;&lt;span&gt; bead&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;--------------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total:&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; (1 &lt;/span&gt;&lt;span&gt;open,&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; progress&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Status:&lt;/span&gt;&lt;span&gt; ○&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;span&gt;  ◐&lt;/span&gt;&lt;span&gt; in_progress&lt;/span&gt;&lt;span&gt;  ●&lt;/span&gt;&lt;span&gt; blocked&lt;/span&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; closed&lt;/span&gt;&lt;span&gt;  ❄&lt;/span&gt;&lt;span&gt; deferred&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, I’ll delete this sample issue and turn things over to Claude to start working.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; delete&lt;/span&gt;&lt;span&gt; evolving_demo-0v4&lt;/span&gt;&lt;span&gt; --force&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Deleted&lt;/span&gt;&lt;span&gt; evolving_demo-0v4&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Removed&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; dependency&lt;/span&gt;&lt;span&gt; link&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Updated&lt;/span&gt;&lt;span&gt; text&lt;/span&gt;&lt;span&gt; references&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; issue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Starting my agent in the repo brings it up with all the context it needs to use Beads on its own, so I can just talk to the agent normally, and it will get to work.&lt;/p&gt;
&lt;p&gt;In this example I’ve asked it to write me a news fetching application, and when Claude starts working, I can see what it’s doing in the &lt;code&gt;bd list&lt;/code&gt; output.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; evolving_demo-2wo&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; Unit&lt;/span&gt;&lt;span&gt; test&lt;/span&gt;&lt;span&gt; RSS&lt;/span&gt;&lt;span&gt; client&lt;/span&gt;&lt;span&gt; with&lt;/span&gt;&lt;span&gt; httptest&lt;/span&gt;&lt;span&gt; fixture&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; evolving_demo-gby&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; Implement&lt;/span&gt;&lt;span&gt; output&lt;/span&gt;&lt;span&gt; formatters&lt;/span&gt;&lt;span&gt; (text &lt;/span&gt;&lt;span&gt;and&lt;/span&gt;&lt;span&gt; JSON&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;◐&lt;/span&gt;&lt;span&gt; evolving_demo-mlq&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; Scaffold&lt;/span&gt;&lt;span&gt; Go&lt;/span&gt;&lt;span&gt; module&lt;/span&gt;&lt;span&gt; and&lt;/span&gt;&lt;span&gt; CLI&lt;/span&gt;&lt;span&gt; entry&lt;/span&gt;&lt;span&gt; point&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; evolving_demo-p5d&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; Implement&lt;/span&gt;&lt;span&gt; Google&lt;/span&gt;&lt;span&gt; News&lt;/span&gt;&lt;span&gt; RSS&lt;/span&gt;&lt;span&gt; client&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; evolving_demo-y7r&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; Wire&lt;/span&gt;&lt;span&gt; main.go:&lt;/span&gt;&lt;span&gt; client&lt;/span&gt;&lt;span&gt; +&lt;/span&gt;&lt;span&gt; formatter&lt;/span&gt;&lt;span&gt; +&lt;/span&gt;&lt;span&gt; error&lt;/span&gt;&lt;span&gt; handling&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; evolving_demo-6ed&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P3&lt;/span&gt;&lt;span&gt; Write&lt;/span&gt;&lt;span&gt; README&lt;/span&gt;&lt;span&gt; with&lt;/span&gt;&lt;span&gt; build&lt;/span&gt;&lt;span&gt; and&lt;/span&gt;&lt;span&gt; usage&lt;/span&gt;&lt;span&gt; instructions&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;--------------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total:&lt;/span&gt;&lt;span&gt; 6&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; (5 &lt;/span&gt;&lt;span&gt;open,&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; progress&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Status:&lt;/span&gt;&lt;span&gt; ○&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;span&gt;  ◐&lt;/span&gt;&lt;span&gt; in_progress&lt;/span&gt;&lt;span&gt;  ●&lt;/span&gt;&lt;span&gt; blocked&lt;/span&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; closed&lt;/span&gt;&lt;span&gt;  ❄&lt;/span&gt;&lt;span&gt; deferred&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When Claude is done, it closes the beads it worked on, and my app is ready to use. But Claude did not know that it can push the beads of this repo up to GitHub too, just like it pushes code, so I let Claude know.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;●&lt;/span&gt;&lt;span&gt; Committed&lt;/span&gt;&lt;span&gt; as&lt;/span&gt;&lt;span&gt; 9ed3470.&lt;/span&gt;&lt;span&gt; Working&lt;/span&gt;&lt;span&gt; tree&lt;/span&gt;&lt;span&gt; clean,&lt;/span&gt;&lt;span&gt; only&lt;/span&gt;&lt;span&gt; the&lt;/span&gt;&lt;span&gt; gitignored&lt;/span&gt;&lt;span&gt; usnews&lt;/span&gt;&lt;span&gt; binary&lt;/span&gt;&lt;span&gt; remains&lt;/span&gt;&lt;span&gt; untracked.&lt;/span&gt;&lt;span&gt; All&lt;/span&gt;&lt;span&gt; 6&lt;/span&gt;&lt;span&gt; beads&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; closed.&lt;/span&gt;&lt;span&gt; No&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  remote&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; push&lt;/span&gt;&lt;span&gt; to.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✻&lt;/span&gt;&lt;span&gt; Baked&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; 25s&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;❯&lt;/span&gt;&lt;span&gt; there&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt; remote,&lt;/span&gt;&lt;span&gt; try&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; dolt&lt;/span&gt;&lt;span&gt; push&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;●&lt;/span&gt;&lt;span&gt; Bash&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; dolt&lt;/span&gt;&lt;span&gt; push&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ⎿&lt;/span&gt;&lt;span&gt;  Pushing&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; Dolt&lt;/span&gt;&lt;span&gt; remote...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;     Push&lt;/span&gt;&lt;span&gt; complete.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;●&lt;/span&gt;&lt;span&gt; Beads&lt;/span&gt;&lt;span&gt; pushed.&lt;/span&gt;&lt;span&gt; Now&lt;/span&gt;&lt;span&gt; checking&lt;/span&gt;&lt;span&gt; the&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;span&gt; remote.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It actually used to be the case that there was &lt;a href="https://www.dolthub.com/blog/2026-02-19-supporting-git-remotes-as-dolt-remotes/"&gt;nothing visible on GitHub&lt;/a&gt; when using it as a Dolt remote, but we recently added some visual cues to more easily tell that your Git repo has Dolt data.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/git-dolt-remotes-github-visual-1.png/6e8bb4e95424055d1453ec4afb9ada0430b69f499ee4e77f13756ff3ac47f5d4.webp" alt="GitHub Dolt Remote Visualization 1"&gt;&lt;/p&gt;
&lt;p&gt;Git Dolt remotes now also create and push to a branch &lt;code&gt;__dolt_remote_info__&lt;/code&gt;, and this branch will have a file updated on each &lt;code&gt;dolt push&lt;/code&gt; that tells you the ref Dolt is using and its &lt;code&gt;HEAD&lt;/code&gt; sha.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/git-dolt-remotes-github-visual-2.png/1c3874b2ff3c533caf3b5320ee647cd3a1b638ed0f3e49a382bcfe1d8669a418.webp" alt="GitHub Dolt Remote Visualization 2"&gt;&lt;/p&gt;
&lt;p&gt;This is the standard Beads Classic usage pattern and app development style. And the application Claude wrote works great.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;go&lt;/span&gt;&lt;span&gt; run&lt;/span&gt;&lt;span&gt; .&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 1.&lt;/span&gt;&lt;span&gt; U.S.,&lt;/span&gt;&lt;span&gt; Iran&lt;/span&gt;&lt;span&gt; nearing&lt;/span&gt;&lt;span&gt; deal&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; end&lt;/span&gt;&lt;span&gt; war&lt;/span&gt;&lt;span&gt; and&lt;/span&gt;&lt;span&gt; reopen&lt;/span&gt;&lt;span&gt; Strait&lt;/span&gt;&lt;span&gt; of&lt;/span&gt;&lt;span&gt; Hormuz&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; The&lt;/span&gt;&lt;span&gt; Washington&lt;/span&gt;&lt;span&gt; Post&lt;/span&gt;&lt;span&gt; (1h &lt;/span&gt;&lt;span&gt;ago&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 2.&lt;/span&gt;&lt;span&gt; Judge&lt;/span&gt;&lt;span&gt; halts&lt;/span&gt;&lt;span&gt; Trump&lt;/span&gt;&lt;span&gt; ‘anti-weaponization’&lt;/span&gt;&lt;span&gt; fund&lt;/span&gt;&lt;span&gt; after&lt;/span&gt;&lt;span&gt; Jan.&lt;/span&gt;&lt;span&gt; 6&lt;/span&gt;&lt;span&gt; prosecutor&lt;/span&gt;&lt;span&gt; sues&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; NBC&lt;/span&gt;&lt;span&gt; News&lt;/span&gt;&lt;span&gt; (1h &lt;/span&gt;&lt;span&gt;ago&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 3.&lt;/span&gt;&lt;span&gt; Former&lt;/span&gt;&lt;span&gt; AG&lt;/span&gt;&lt;span&gt; Pam&lt;/span&gt;&lt;span&gt; Bondi&lt;/span&gt;&lt;span&gt; testifies&lt;/span&gt;&lt;span&gt; before&lt;/span&gt;&lt;span&gt; Congress&lt;/span&gt;&lt;span&gt; over&lt;/span&gt;&lt;span&gt; handling&lt;/span&gt;&lt;span&gt; of&lt;/span&gt;&lt;span&gt; the&lt;/span&gt;&lt;span&gt; Epstein&lt;/span&gt;&lt;span&gt; files&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; NPR&lt;/span&gt;&lt;span&gt; (23m &lt;/span&gt;&lt;span&gt;ago&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 4.&lt;/span&gt;&lt;span&gt; Romania&lt;/span&gt;&lt;span&gt; Says&lt;/span&gt;&lt;span&gt; It&lt;/span&gt;&lt;span&gt; Could&lt;/span&gt;&lt;span&gt; Invoke&lt;/span&gt;&lt;span&gt; NATO’s&lt;/span&gt;&lt;span&gt; Article&lt;/span&gt;&lt;span&gt; 4.&lt;/span&gt;&lt;span&gt; What&lt;/span&gt;&lt;span&gt; Would&lt;/span&gt;&lt;span&gt; That&lt;/span&gt;&lt;span&gt; Do?&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; The&lt;/span&gt;&lt;span&gt; New&lt;/span&gt;&lt;span&gt; York&lt;/span&gt;&lt;span&gt; Times&lt;/span&gt;&lt;span&gt; (4h &lt;/span&gt;&lt;span&gt;ago&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 5.&lt;/span&gt;&lt;span&gt; Kenyan&lt;/span&gt;&lt;span&gt; court&lt;/span&gt;&lt;span&gt; halts&lt;/span&gt;&lt;span&gt; US&lt;/span&gt;&lt;span&gt; plans&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; Ebola&lt;/span&gt;&lt;span&gt; quarantine&lt;/span&gt;&lt;span&gt; facility&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; Americans&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; politico.eu&lt;/span&gt;&lt;span&gt; (5h &lt;/span&gt;&lt;span&gt;ago&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 6.&lt;/span&gt;&lt;span&gt; Trump&lt;/span&gt;&lt;span&gt; Loses&lt;/span&gt;&lt;span&gt; It&lt;/span&gt;&lt;span&gt; at&lt;/span&gt;&lt;span&gt; Jill&lt;/span&gt;&lt;span&gt; Biden&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; Morning&lt;/span&gt;&lt;span&gt; Rage&lt;/span&gt;&lt;span&gt; Post&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; The&lt;/span&gt;&lt;span&gt; Daily&lt;/span&gt;&lt;span&gt; Beast&lt;/span&gt;&lt;span&gt; (4h &lt;/span&gt;&lt;span&gt;ago&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 7.&lt;/span&gt;&lt;span&gt; Bus&lt;/span&gt;&lt;span&gt; hits&lt;/span&gt;&lt;span&gt; cars&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; Virginia,&lt;/span&gt;&lt;span&gt; killing&lt;/span&gt;&lt;span&gt; 5&lt;/span&gt;&lt;span&gt; people&lt;/span&gt;&lt;span&gt; and&lt;/span&gt;&lt;span&gt; injuring&lt;/span&gt;&lt;span&gt; 34,&lt;/span&gt;&lt;span&gt; state&lt;/span&gt;&lt;span&gt; police&lt;/span&gt;&lt;span&gt; say&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; AP&lt;/span&gt;&lt;span&gt; News&lt;/span&gt;&lt;span&gt; (3h &lt;/span&gt;&lt;span&gt;ago&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 8.&lt;/span&gt;&lt;span&gt; California&lt;/span&gt;&lt;span&gt; House&lt;/span&gt;&lt;span&gt; Primary&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; Sacramento&lt;/span&gt;&lt;span&gt; Displays&lt;/span&gt;&lt;span&gt; Democrats’&lt;/span&gt;&lt;span&gt; Fierce&lt;/span&gt;&lt;span&gt; Generational&lt;/span&gt;&lt;span&gt; Battle&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; The&lt;/span&gt;&lt;span&gt; New&lt;/span&gt;&lt;span&gt; York&lt;/span&gt;&lt;span&gt; Times&lt;/span&gt;&lt;span&gt; (7h &lt;/span&gt;&lt;span&gt;ago&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 9.&lt;/span&gt;&lt;span&gt; Mullin&lt;/span&gt;&lt;span&gt; plan&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; punish&lt;/span&gt;&lt;span&gt; sanctuary&lt;/span&gt;&lt;span&gt; jurisdictions&lt;/span&gt;&lt;span&gt; by&lt;/span&gt;&lt;span&gt; targeting&lt;/span&gt;&lt;span&gt; their&lt;/span&gt;&lt;span&gt; airports&lt;/span&gt;&lt;span&gt; faces&lt;/span&gt;&lt;span&gt; fierce&lt;/span&gt;&lt;span&gt; headwinds&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; CNN&lt;/span&gt;&lt;span&gt; (7h &lt;/span&gt;&lt;span&gt;ago&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;10.&lt;/span&gt;&lt;span&gt; In&lt;/span&gt;&lt;span&gt; Carroll&lt;/span&gt;&lt;span&gt; Lawsuits&lt;/span&gt;&lt;span&gt; Inquiry,&lt;/span&gt;&lt;span&gt; Scrutiny&lt;/span&gt;&lt;span&gt; Turns&lt;/span&gt;&lt;span&gt; Toward&lt;/span&gt;&lt;span&gt; Private&lt;/span&gt;&lt;span&gt; Citizens&lt;/span&gt;&lt;span&gt; Who&lt;/span&gt;&lt;span&gt; Antagonized&lt;/span&gt;&lt;span&gt; Trump&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; The&lt;/span&gt;&lt;span&gt; New&lt;/span&gt;&lt;span&gt; York&lt;/span&gt;&lt;span&gt; Times&lt;/span&gt;&lt;span&gt; (51m &lt;/span&gt;&lt;span&gt;ago&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id="server-mode"&gt;Server Mode&lt;a class="anchor-link" aria-label="Link to heading" href="#server-mode"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The next phase of evolving with Beads is transitioning from classic to server mode. Server mode here means Beads will run a local Dolt server on your host, instead of using the non-server embedded Dolt mode, which is the default.&lt;/p&gt;
&lt;p&gt;But why use server mode in the first place?&lt;/p&gt;
&lt;p&gt;The reason users may want to consider running Beads in server mode is because it allows you to run many coding agent sessions against the same Git repo, since server mode is designed for multi-process concurrent use. This is a limitation of Beads classic, which is single-writer.&lt;/p&gt;
&lt;p&gt;To migrate from classic mode to server mode, let’s first make a new bead that we can easily track across the migration from classic to server mode.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; create&lt;/span&gt;&lt;span&gt; "from classic to server mode"&lt;/span&gt;&lt;span&gt; -p&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Created&lt;/span&gt;&lt;span&gt; issue:&lt;/span&gt;&lt;span&gt; evolving_demo-w1g&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; classic&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; mode&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Priority:&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Status:&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, to perform the migration we actually want to take a backup of our Beads database in classic mode, then after we initialize Beads in server mode, we’ll restore from the backup, which will give us our database back.&lt;/p&gt;
&lt;p&gt;To do this I first make a new directory to use as my database backup, then initialize it with the &lt;code&gt;bd backup init&lt;/code&gt; command. After initialization I can run &lt;code&gt;bd backup sync&lt;/code&gt; to sync my database to the backup destination.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; mkdir&lt;/span&gt;&lt;span&gt; ../ed_backup_1&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; backup&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;span&gt; ../ed_backup_1&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Backup&lt;/span&gt;&lt;span&gt; destination&lt;/span&gt;&lt;span&gt; configured:&lt;/span&gt;&lt;span&gt; file:///home/dustin/cursor_src/repros/ed_backup_1&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Run&lt;/span&gt;&lt;span&gt; 'bd backup sync'&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; push&lt;/span&gt;&lt;span&gt; your&lt;/span&gt;&lt;span&gt; data.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; backup&lt;/span&gt;&lt;span&gt; sync&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Backup&lt;/span&gt;&lt;span&gt; synced&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; 20ms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the backup synced, I can then remove the &lt;code&gt;.beads&lt;/code&gt; directory in my Git repo, which will delete the classic mode database (or just &lt;code&gt;mv&lt;/code&gt; it to not be named &lt;code&gt;.beads&lt;/code&gt; just in case), and then re-initialize Beads using the &lt;code&gt;--server&lt;/code&gt; flag.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; rm&lt;/span&gt;&lt;span&gt; -rf&lt;/span&gt;&lt;span&gt; .beads&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;span&gt; --server&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Bootstrapped&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; remote:&lt;/span&gt;&lt;span&gt; git+https://github.com/coffeegoddd/evolving_demo.git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Synced&lt;/span&gt;&lt;span&gt; database&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; git+https://github.com/coffeegoddd/evolving_demo.git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Bootstrapped&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; remote:&lt;/span&gt;&lt;span&gt; git+https://github.com/coffeegoddd/evolving_demo.git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Repository&lt;/span&gt;&lt;span&gt; ID:&lt;/span&gt;&lt;span&gt; 76062c1e&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Clone&lt;/span&gt;&lt;span&gt; ID:&lt;/span&gt;&lt;span&gt; 642acc6d98a2785e&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Adopted&lt;/span&gt;&lt;span&gt; project&lt;/span&gt;&lt;span&gt; identity&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; existing&lt;/span&gt;&lt;span&gt; database&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;▶&lt;/span&gt;&lt;span&gt; Already&lt;/span&gt;&lt;span&gt; configured&lt;/span&gt;&lt;span&gt; as:&lt;/span&gt;&lt;span&gt; maintainer&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Change&lt;/span&gt;&lt;span&gt; role?&lt;/span&gt;&lt;span&gt; [y/N]: n&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;▶&lt;/span&gt;&lt;span&gt; Auto-export&lt;/span&gt;&lt;span&gt; can&lt;/span&gt;&lt;span&gt; keep&lt;/span&gt;&lt;span&gt; .beads/issues.jsonl&lt;/span&gt;&lt;span&gt; up&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; date&lt;/span&gt;&lt;span&gt; after&lt;/span&gt;&lt;span&gt; write&lt;/span&gt;&lt;span&gt; commands.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  This&lt;/span&gt;&lt;span&gt; optional&lt;/span&gt;&lt;span&gt; JSONL&lt;/span&gt;&lt;span&gt; export&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; useful&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; viewers&lt;/span&gt;&lt;span&gt; (bv), interchange, and issue-level migration.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Dolt&lt;/span&gt;&lt;span&gt; remotes/backups&lt;/span&gt;&lt;span&gt; handle&lt;/span&gt;&lt;span&gt; cross-machine&lt;/span&gt;&lt;span&gt; sync&lt;/span&gt;&lt;span&gt; and&lt;/span&gt;&lt;span&gt; backup.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Enable&lt;/span&gt;&lt;span&gt; auto-export?&lt;/span&gt;&lt;span&gt; [y/N]: n&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Auto-export&lt;/span&gt;&lt;span&gt; disabled&lt;/span&gt;&lt;span&gt; (enable &lt;/span&gt;&lt;span&gt;later&lt;/span&gt;&lt;span&gt; with:&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; config&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; export.auto&lt;/span&gt;&lt;span&gt; true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Hooks&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;span&gt; to:&lt;/span&gt;&lt;span&gt; .beads/hooks/&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Updated&lt;/span&gt;&lt;span&gt; beads&lt;/span&gt;&lt;span&gt; section&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; AGENTS.md&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; latest&lt;/span&gt;&lt;span&gt; format&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; hooks&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; project...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Hook&lt;/span&gt;&lt;span&gt; already&lt;/span&gt;&lt;span&gt; registered:&lt;/span&gt;&lt;span&gt; SessionStart&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; integration...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Updated&lt;/span&gt;&lt;span&gt; existing&lt;/span&gt;&lt;span&gt; beads&lt;/span&gt;&lt;span&gt; section&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; CLAUDE.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; integration&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  File:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/CLAUDE.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;No&lt;/span&gt;&lt;span&gt; additional&lt;/span&gt;&lt;span&gt; configuration&lt;/span&gt;&lt;span&gt; needed!&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; integration&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Settings:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/.claude/settings.json&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Restart&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; changes&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; take&lt;/span&gt;&lt;span&gt; effect.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Beads&lt;/span&gt;&lt;span&gt; agent&lt;/span&gt;&lt;span&gt; skill...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Beads&lt;/span&gt;&lt;span&gt; agent&lt;/span&gt;&lt;span&gt; skill&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Skill:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/.agents/skills/beads/SKILL.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; native&lt;/span&gt;&lt;span&gt; hooks&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; project...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; native&lt;/span&gt;&lt;span&gt; hooks&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; instructions&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; project...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; instructions&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  File:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/AGENTS.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Restart&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; if&lt;/span&gt;&lt;span&gt; it&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; already&lt;/span&gt;&lt;span&gt; running.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Committed&lt;/span&gt;&lt;span&gt; beads&lt;/span&gt;&lt;span&gt; files&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; initialized&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;span&gt; remote!&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Backend:&lt;/span&gt;&lt;span&gt; dolt&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Mode:&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Server:&lt;/span&gt;&lt;span&gt; root@127.0.0.1:46091&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ⚠&lt;/span&gt;&lt;span&gt; Server&lt;/span&gt;&lt;span&gt; host&lt;/span&gt;&lt;span&gt; defaulted&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; 127.0.0.1.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    If&lt;/span&gt;&lt;span&gt; your&lt;/span&gt;&lt;span&gt; Dolt&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; remote,&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; BEADS_DOLT_SERVER_HOST&lt;/span&gt;&lt;span&gt; or&lt;/span&gt;&lt;span&gt; pass&lt;/span&gt;&lt;span&gt; --server-host.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Database:&lt;/span&gt;&lt;span&gt; evolving_demo&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Issue&lt;/span&gt;&lt;span&gt; prefix:&lt;/span&gt;&lt;span&gt; evolving_demo&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Issues&lt;/span&gt;&lt;span&gt; will&lt;/span&gt;&lt;span&gt; be&lt;/span&gt;&lt;span&gt; named:&lt;/span&gt;&lt;span&gt; evolving_demo-&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;has&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; (e.g., &lt;/span&gt;&lt;span&gt;evolving_demo-a3f2dd&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Run&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; quickstart&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; get&lt;/span&gt;&lt;span&gt; started.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As before, I keep my role as ‘maintainer’ and decline auto-export. This time though Beads is using a local server running on port &lt;code&gt;46091&lt;/code&gt;, as shown in the output above.&lt;/p&gt;
&lt;p&gt;Now I can restore from the backup I made earlier to get all my beads back.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; backup&lt;/span&gt;&lt;span&gt; restore&lt;/span&gt;&lt;span&gt; ../ed_backup_1&lt;/span&gt;&lt;span&gt; --force&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Restore&lt;/span&gt;&lt;span&gt; complete&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; evolving_demo-w1g&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; classic&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; mode&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;--------------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total:&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; (1 &lt;/span&gt;&lt;span&gt;open,&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; progress&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Status:&lt;/span&gt;&lt;span&gt; ○&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;span&gt;  ◐&lt;/span&gt;&lt;span&gt; in_progress&lt;/span&gt;&lt;span&gt;  ●&lt;/span&gt;&lt;span&gt; blocked&lt;/span&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; closed&lt;/span&gt;&lt;span&gt;  ❄&lt;/span&gt;&lt;span&gt; deferred&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And you can see that the bead I made is available and ready. I can also see the “status” of my Beads server by running &lt;code&gt;bd dolt status&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; dolt&lt;/span&gt;&lt;span&gt; status&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Dolt&lt;/span&gt;&lt;span&gt; server:&lt;/span&gt;&lt;span&gt; running&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  PID:&lt;/span&gt;&lt;span&gt;  778645&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Port:&lt;/span&gt;&lt;span&gt; 46091&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Data:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/.beads/dolt&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Logs:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/.beads/dolt-server.log&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If I wanted to actually poke around in the state of my Beads database, I could do so with a standard MySQL client. As of this blog, Beads servers always run with &lt;code&gt;root&lt;/code&gt; and no password.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; docker&lt;/span&gt;&lt;span&gt; run&lt;/span&gt;&lt;span&gt; --rm&lt;/span&gt;&lt;span&gt; -it&lt;/span&gt;&lt;span&gt; --network&lt;/span&gt;&lt;span&gt; host&lt;/span&gt;&lt;span&gt; mysql:8&lt;/span&gt;&lt;span&gt; mysql&lt;/span&gt;&lt;span&gt; -h&lt;/span&gt;&lt;span&gt; 127.0.0.1&lt;/span&gt;&lt;span&gt; -P&lt;/span&gt;&lt;span&gt; 46091&lt;/span&gt;&lt;span&gt; -u&lt;/span&gt;&lt;span&gt; root&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Welcome&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; the&lt;/span&gt;&lt;span&gt; MySQL&lt;/span&gt;&lt;span&gt; monitor.&lt;/span&gt;&lt;span&gt;  Commands&lt;/span&gt;&lt;span&gt; end&lt;/span&gt;&lt;span&gt; with&lt;/span&gt;&lt;span&gt; ; &lt;/span&gt;&lt;span&gt;or&lt;/span&gt;&lt;span&gt; \g&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Your&lt;/span&gt;&lt;span&gt; MySQL&lt;/span&gt;&lt;span&gt; connection&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; 27&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Server&lt;/span&gt;&lt;span&gt; version:&lt;/span&gt;&lt;span&gt; 8.0.33&lt;/span&gt;&lt;span&gt; Dolt&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Copyright&lt;/span&gt;&lt;span&gt; (c) 2000, 2026, Oracle and/or its affiliates.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Oracle&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt; registered&lt;/span&gt;&lt;span&gt; trademark&lt;/span&gt;&lt;span&gt; of&lt;/span&gt;&lt;span&gt; Oracle&lt;/span&gt;&lt;span&gt; Corporation&lt;/span&gt;&lt;span&gt; and/or&lt;/span&gt;&lt;span&gt; its&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;affiliates.&lt;/span&gt;&lt;span&gt; Other&lt;/span&gt;&lt;span&gt; names&lt;/span&gt;&lt;span&gt; may&lt;/span&gt;&lt;span&gt; be&lt;/span&gt;&lt;span&gt; trademarks&lt;/span&gt;&lt;span&gt; of&lt;/span&gt;&lt;span&gt; their&lt;/span&gt;&lt;span&gt; respective&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;owners.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Type&lt;/span&gt;&lt;span&gt; 'help;'&lt;/span&gt;&lt;span&gt; or&lt;/span&gt;&lt;span&gt; '\h'&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; help.&lt;/span&gt;&lt;span&gt; Type&lt;/span&gt;&lt;span&gt; '\c'&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; clear&lt;/span&gt;&lt;span&gt; the&lt;/span&gt;&lt;span&gt; current&lt;/span&gt;&lt;span&gt; input&lt;/span&gt;&lt;span&gt; statement.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mysql&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;show&lt;/span&gt;&lt;span&gt; databases&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+--------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; Database&lt;/span&gt;&lt;span&gt;           |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+--------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; dolt&lt;/span&gt;&lt;span&gt;               |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; evolving_demo&lt;/span&gt;&lt;span&gt;      |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; information_schema&lt;/span&gt;&lt;span&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; mysql&lt;/span&gt;&lt;span&gt;              |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+--------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt; rows&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; (0.00 &lt;/span&gt;&lt;span&gt;sec&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mysql&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; evolving_demo&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Reading&lt;/span&gt;&lt;span&gt; table&lt;/span&gt;&lt;span&gt; information&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; completion&lt;/span&gt;&lt;span&gt; of&lt;/span&gt;&lt;span&gt; table&lt;/span&gt;&lt;span&gt; and&lt;/span&gt;&lt;span&gt; column&lt;/span&gt;&lt;span&gt; names&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;You&lt;/span&gt;&lt;span&gt; can&lt;/span&gt;&lt;span&gt; turn&lt;/span&gt;&lt;span&gt; off&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; feature&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; get&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt; quicker&lt;/span&gt;&lt;span&gt; startup&lt;/span&gt;&lt;span&gt; with&lt;/span&gt;&lt;span&gt; -A&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Database&lt;/span&gt;&lt;span&gt; changed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mysql&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;select&lt;/span&gt;&lt;span&gt; count&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+----------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; count(*&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+----------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt;        7&lt;/span&gt;&lt;span&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+----------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt; row&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; (0.00 &lt;/span&gt;&lt;span&gt;sec&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mysql&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;exit&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Bye&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our issue count in our restored database has our bead that we tracked across the classic to server migration and the six now closed issues used to build the news application.&lt;/p&gt;
&lt;p&gt;From this point forward, we could continue to use Beads in single-player mode as we did with classic mode, or we could open multiple terminal sessions against this repo and dispatch agents in each in parallel (non-overlapping) feature work.&lt;/p&gt;
&lt;h1 id="shared-server-mode"&gt;Shared-server Mode&lt;a class="anchor-link" aria-label="Link to heading" href="#shared-server-mode"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Lastly, let’s say I’ve been enjoying using Beads on many projects on my host, both in classic mode and server mode, but have noticed that each server mode project spins up a new Dolt sql-server process. Instead of doing this, can Beads run just a single Dolt sql-server for all my projects?&lt;/p&gt;
&lt;p&gt;Why yes it can, and this is the motivation behind shared-server mode. In this mode, Beads will manage a single global Dolt server that can house all Beads for your Git projects on the host, and these Beads will be isolated, so Beads will not leak between projects.&lt;/p&gt;
&lt;p&gt;To migrate from normal &lt;code&gt;--server&lt;/code&gt; mode to &lt;code&gt;--shared-server&lt;/code&gt; mode, we simply need to go through our backup and restore flow we did above, making sure to stop the running &lt;code&gt;--server&lt;/code&gt; mode process before starting the new &lt;code&gt;--shared-server&lt;/code&gt; process. If you have many &lt;code&gt;--server&lt;/code&gt; mode Beads projects on your host, you’ll want to do this for each one.&lt;/p&gt;
&lt;p&gt;To start, let’s remove the old bead we made and make a new one to watch across the migration.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; evolving_demo-w1g&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; classic&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; mode&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;--------------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total:&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; (1 &lt;/span&gt;&lt;span&gt;open,&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; progress&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Status:&lt;/span&gt;&lt;span&gt; ○&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;span&gt;  ◐&lt;/span&gt;&lt;span&gt; in_progress&lt;/span&gt;&lt;span&gt;  ●&lt;/span&gt;&lt;span&gt; blocked&lt;/span&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; closed&lt;/span&gt;&lt;span&gt;  ❄&lt;/span&gt;&lt;span&gt; deferred&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; delete&lt;/span&gt;&lt;span&gt; evolving_demo-w1g&lt;/span&gt;&lt;span&gt; --force&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Deleted&lt;/span&gt;&lt;span&gt; evolving_demo-w1g&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Removed&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; dependency&lt;/span&gt;&lt;span&gt; link&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Updated&lt;/span&gt;&lt;span&gt; text&lt;/span&gt;&lt;span&gt; references&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; issue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;No&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; found.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; create&lt;/span&gt;&lt;span&gt; "from server to shared-server"&lt;/span&gt;&lt;span&gt; -p&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Created&lt;/span&gt;&lt;span&gt; issue:&lt;/span&gt;&lt;span&gt; evolving_demo-pz8&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; shared-server&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Priority:&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Status:&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; evolving_demo-pz8&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; shared-server&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;--------------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total:&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; (1 &lt;/span&gt;&lt;span&gt;open,&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; progress&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Status:&lt;/span&gt;&lt;span&gt; ○&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;span&gt;  ◐&lt;/span&gt;&lt;span&gt; in_progress&lt;/span&gt;&lt;span&gt;  ●&lt;/span&gt;&lt;span&gt; blocked&lt;/span&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; closed&lt;/span&gt;&lt;span&gt;  ❄&lt;/span&gt;&lt;span&gt; deferred&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we will need a new backup directory for our existing &lt;code&gt;--server&lt;/code&gt; mode Beads database.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;mkdir&lt;/span&gt;&lt;span&gt; ../ed_backup_2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; backup&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;span&gt; ../ed_backup_2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Backup&lt;/span&gt;&lt;span&gt; destination&lt;/span&gt;&lt;span&gt; configured:&lt;/span&gt;&lt;span&gt; file:///home/dustin/cursor_src/repros/ed_backup_2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Run&lt;/span&gt;&lt;span&gt; 'bd backup sync'&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; push&lt;/span&gt;&lt;span&gt; your&lt;/span&gt;&lt;span&gt; data.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; backup&lt;/span&gt;&lt;span&gt; sync&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Backup&lt;/span&gt;&lt;span&gt; synced&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; 50ms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the backup is synced I can stop the &lt;code&gt;--server&lt;/code&gt; mode server with &lt;code&gt;bd dolt stop&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; dolt&lt;/span&gt;&lt;span&gt; stop&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Flushed&lt;/span&gt;&lt;span&gt; working&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; database&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;before&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; stop&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Dolt&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; stopped.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, like before, I can remove the existing &lt;code&gt;.beads&lt;/code&gt; directory in my Git project and reinitialize Beads with the &lt;code&gt;--shared-server&lt;/code&gt; flag.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; rm&lt;/span&gt;&lt;span&gt; -rf&lt;/span&gt;&lt;span&gt; .beads&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;span&gt; --shared-server&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Bootstrapped&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; remote:&lt;/span&gt;&lt;span&gt; git+https://github.com/coffeegoddd/evolving_demo.git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Shared&lt;/span&gt;&lt;span&gt; Dolt&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; started&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Global&lt;/span&gt;&lt;span&gt; database&lt;/span&gt;&lt;span&gt; beads_global&lt;/span&gt;&lt;span&gt; available&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Global&lt;/span&gt;&lt;span&gt; database&lt;/span&gt;&lt;span&gt; schema&lt;/span&gt;&lt;span&gt; initialized&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Configured&lt;/span&gt;&lt;span&gt; Dolt&lt;/span&gt;&lt;span&gt; remote:&lt;/span&gt;&lt;span&gt; origin&lt;/span&gt;&lt;span&gt; →&lt;/span&gt;&lt;span&gt; git+https://github.com/coffeegoddd/evolving_demo.git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Repository&lt;/span&gt;&lt;span&gt; ID:&lt;/span&gt;&lt;span&gt; 76062c1e&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Clone&lt;/span&gt;&lt;span&gt; ID:&lt;/span&gt;&lt;span&gt; 642acc6d98a2785e&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Shared&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; mode&lt;/span&gt;&lt;span&gt; enabled&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;▶&lt;/span&gt;&lt;span&gt; Already&lt;/span&gt;&lt;span&gt; configured&lt;/span&gt;&lt;span&gt; as:&lt;/span&gt;&lt;span&gt; maintainer&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Change&lt;/span&gt;&lt;span&gt; role?&lt;/span&gt;&lt;span&gt; [y/N]: n&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;▶&lt;/span&gt;&lt;span&gt; Auto-export&lt;/span&gt;&lt;span&gt; can&lt;/span&gt;&lt;span&gt; keep&lt;/span&gt;&lt;span&gt; .beads/issues.jsonl&lt;/span&gt;&lt;span&gt; up&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; date&lt;/span&gt;&lt;span&gt; after&lt;/span&gt;&lt;span&gt; write&lt;/span&gt;&lt;span&gt; commands.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  This&lt;/span&gt;&lt;span&gt; optional&lt;/span&gt;&lt;span&gt; JSONL&lt;/span&gt;&lt;span&gt; export&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; useful&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; viewers&lt;/span&gt;&lt;span&gt; (bv), interchange, and issue-level migration.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Dolt&lt;/span&gt;&lt;span&gt; remotes/backups&lt;/span&gt;&lt;span&gt; handle&lt;/span&gt;&lt;span&gt; cross-machine&lt;/span&gt;&lt;span&gt; sync&lt;/span&gt;&lt;span&gt; and&lt;/span&gt;&lt;span&gt; backup.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Enable&lt;/span&gt;&lt;span&gt; auto-export?&lt;/span&gt;&lt;span&gt; [y/N]: n&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Auto-export&lt;/span&gt;&lt;span&gt; disabled&lt;/span&gt;&lt;span&gt; (enable &lt;/span&gt;&lt;span&gt;later&lt;/span&gt;&lt;span&gt; with:&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; config&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; export.auto&lt;/span&gt;&lt;span&gt; true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Hooks&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;span&gt; to:&lt;/span&gt;&lt;span&gt; .beads/hooks/&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  AGENTS.md&lt;/span&gt;&lt;span&gt; already&lt;/span&gt;&lt;span&gt; has&lt;/span&gt;&lt;span&gt; current&lt;/span&gt;&lt;span&gt; agent&lt;/span&gt;&lt;span&gt; instructions&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; hooks&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; project...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Hook&lt;/span&gt;&lt;span&gt; already&lt;/span&gt;&lt;span&gt; registered:&lt;/span&gt;&lt;span&gt; SessionStart&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; integration...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Updated&lt;/span&gt;&lt;span&gt; existing&lt;/span&gt;&lt;span&gt; beads&lt;/span&gt;&lt;span&gt; section&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; CLAUDE.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; integration&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  File:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/CLAUDE.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;No&lt;/span&gt;&lt;span&gt; additional&lt;/span&gt;&lt;span&gt; configuration&lt;/span&gt;&lt;span&gt; needed!&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; integration&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Settings:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/.claude/settings.json&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Restart&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; changes&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; take&lt;/span&gt;&lt;span&gt; effect.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Beads&lt;/span&gt;&lt;span&gt; agent&lt;/span&gt;&lt;span&gt; skill...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Beads&lt;/span&gt;&lt;span&gt; agent&lt;/span&gt;&lt;span&gt; skill&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Skill:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/.agents/skills/beads/SKILL.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; native&lt;/span&gt;&lt;span&gt; hooks&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; project...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; native&lt;/span&gt;&lt;span&gt; hooks&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; instructions&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; project...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; instructions&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  File:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/AGENTS.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Restart&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; if&lt;/span&gt;&lt;span&gt; it&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; already&lt;/span&gt;&lt;span&gt; running.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Committed&lt;/span&gt;&lt;span&gt; beads&lt;/span&gt;&lt;span&gt; files&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; initialized&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;span&gt; remote!&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Backend:&lt;/span&gt;&lt;span&gt; dolt&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Mode:&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Server:&lt;/span&gt;&lt;span&gt; root@127.0.0.1:3308&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ⚠&lt;/span&gt;&lt;span&gt; Server&lt;/span&gt;&lt;span&gt; host&lt;/span&gt;&lt;span&gt; defaulted&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; 127.0.0.1.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    If&lt;/span&gt;&lt;span&gt; your&lt;/span&gt;&lt;span&gt; Dolt&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; remote,&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; BEADS_DOLT_SERVER_HOST&lt;/span&gt;&lt;span&gt; or&lt;/span&gt;&lt;span&gt; pass&lt;/span&gt;&lt;span&gt; --server-host.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Database:&lt;/span&gt;&lt;span&gt; evolving_demo&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Issue&lt;/span&gt;&lt;span&gt; prefix:&lt;/span&gt;&lt;span&gt; evolving_demo&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Issues&lt;/span&gt;&lt;span&gt; will&lt;/span&gt;&lt;span&gt; be&lt;/span&gt;&lt;span&gt; named:&lt;/span&gt;&lt;span&gt; evolving_demo-&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;has&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; (e.g., &lt;/span&gt;&lt;span&gt;evolving_demo-a3f2dd&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Run&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; quickstart&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; get&lt;/span&gt;&lt;span&gt; started.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, the role is ‘maintainer’ and ‘auto-export’ is disabled.&lt;/p&gt;
&lt;p&gt;Now I can restore from my &lt;code&gt;--server&lt;/code&gt; backup.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; backup&lt;/span&gt;&lt;span&gt; restore&lt;/span&gt;&lt;span&gt; ../ed_backup_2&lt;/span&gt;&lt;span&gt; --force&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Restore&lt;/span&gt;&lt;span&gt; complete&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; evolving_demo-pz8&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; shared-server&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;--------------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total:&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; (1 &lt;/span&gt;&lt;span&gt;open,&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; progress&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Status:&lt;/span&gt;&lt;span&gt; ○&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;span&gt;  ◐&lt;/span&gt;&lt;span&gt; in_progress&lt;/span&gt;&lt;span&gt;  ●&lt;/span&gt;&lt;span&gt; blocked&lt;/span&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; closed&lt;/span&gt;&lt;span&gt;  ❄&lt;/span&gt;&lt;span&gt; deferred&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And once I do that, I’m successfully running in Shared-server mode!&lt;/p&gt;
&lt;h1 id="bonus"&gt;Bonus&lt;a class="anchor-link" aria-label="Link to heading" href="#bonus"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;As I mentioned earlier, Beads are scoped to a single Git repository and single Dolt database, so there is currently no way to share beads across projects.&lt;/p&gt;
&lt;p&gt;Except actually, there &lt;em&gt;kinda&lt;/em&gt; is… As a maintainer of Beads I snuck in a unique feature to Beads Shared-server mode which seemed like it needed, but didn’t have a way to share beads across projects.&lt;/p&gt;
&lt;p&gt;In Shared-server mode there is a unique &lt;code&gt;global&lt;/code&gt; beads database that works like a normal Beads database, except it is readable and writeable by all clients of the Shared server. This database is not tied to any specific Git project, so it does not have the same restrictions as ones that are tied to a specific Git project.&lt;/p&gt;
&lt;p&gt;For this reason, if you did need to share beads between projects, you can do so by reading and writing beads with the &lt;code&gt;--global&lt;/code&gt; flag, which will route the &lt;code&gt;bd&lt;/code&gt; command to the global database instead of the project scoped one.&lt;/p&gt;
&lt;p&gt;Here’s an example. First let’s delete the old migration bead we made.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; delete&lt;/span&gt;&lt;span&gt; evolving_demo-pz8&lt;/span&gt;&lt;span&gt; --force&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Deleted&lt;/span&gt;&lt;span&gt; evolving_demo-pz8&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Removed&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; dependency&lt;/span&gt;&lt;span&gt; link&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Updated&lt;/span&gt;&lt;span&gt; text&lt;/span&gt;&lt;span&gt; references&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; issue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we’ll make another Beads project on our host and register it on the shared server by initializing Beads with &lt;code&gt;--shared-server&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;No&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; found.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; ..&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  repros&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; mkdir&lt;/span&gt;&lt;span&gt; different_project&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  repros&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; cd&lt;/span&gt;&lt;span&gt; different_project&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Initialized&lt;/span&gt;&lt;span&gt; empty&lt;/span&gt;&lt;span&gt; Git&lt;/span&gt;&lt;span&gt; repository&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/different_project/.git/&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;echo&lt;/span&gt;&lt;span&gt; "# different project"&lt;/span&gt;&lt;span&gt; &gt;&gt;&lt;/span&gt;&lt;span&gt; README.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;span&gt; add&lt;/span&gt;&lt;span&gt; .&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;span&gt; commit&lt;/span&gt;&lt;span&gt; -m&lt;/span&gt;&lt;span&gt; 'README.md'&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;[main (root&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;commit) a11c0f1] README.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; file&lt;/span&gt;&lt;span&gt; changed,&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; insertion&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; create&lt;/span&gt;&lt;span&gt; mode&lt;/span&gt;&lt;span&gt; 100644&lt;/span&gt;&lt;span&gt; README.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;span&gt; --shared-server&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Global&lt;/span&gt;&lt;span&gt; database&lt;/span&gt;&lt;span&gt; beads_global&lt;/span&gt;&lt;span&gt; available&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Global&lt;/span&gt;&lt;span&gt; database&lt;/span&gt;&lt;span&gt; schema&lt;/span&gt;&lt;span&gt; initialized&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Repository&lt;/span&gt;&lt;span&gt; ID:&lt;/span&gt;&lt;span&gt; ad3c7c9e&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Clone&lt;/span&gt;&lt;span&gt; ID:&lt;/span&gt;&lt;span&gt; d9436fdceeb5a843&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Shared&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; mode&lt;/span&gt;&lt;span&gt; enabled&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;▶&lt;/span&gt;&lt;span&gt; Already&lt;/span&gt;&lt;span&gt; configured&lt;/span&gt;&lt;span&gt; as:&lt;/span&gt;&lt;span&gt; maintainer&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Change&lt;/span&gt;&lt;span&gt; role?&lt;/span&gt;&lt;span&gt; [y/N]: n&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;▶&lt;/span&gt;&lt;span&gt; Auto-export&lt;/span&gt;&lt;span&gt; can&lt;/span&gt;&lt;span&gt; keep&lt;/span&gt;&lt;span&gt; .beads/issues.jsonl&lt;/span&gt;&lt;span&gt; up&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; date&lt;/span&gt;&lt;span&gt; after&lt;/span&gt;&lt;span&gt; write&lt;/span&gt;&lt;span&gt; commands.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  This&lt;/span&gt;&lt;span&gt; optional&lt;/span&gt;&lt;span&gt; JSONL&lt;/span&gt;&lt;span&gt; export&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; useful&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; viewers&lt;/span&gt;&lt;span&gt; (bv), interchange, and issue-level migration.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Dolt&lt;/span&gt;&lt;span&gt; remotes/backups&lt;/span&gt;&lt;span&gt; handle&lt;/span&gt;&lt;span&gt; cross-machine&lt;/span&gt;&lt;span&gt; sync&lt;/span&gt;&lt;span&gt; and&lt;/span&gt;&lt;span&gt; backup.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Enable&lt;/span&gt;&lt;span&gt; auto-export?&lt;/span&gt;&lt;span&gt; [y/N]: n&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Auto-export&lt;/span&gt;&lt;span&gt; disabled&lt;/span&gt;&lt;span&gt; (enable &lt;/span&gt;&lt;span&gt;later&lt;/span&gt;&lt;span&gt; with:&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; config&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; export.auto&lt;/span&gt;&lt;span&gt; true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Hooks&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;span&gt; to:&lt;/span&gt;&lt;span&gt; .beads/hooks/&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Created&lt;/span&gt;&lt;span&gt; AGENTS.md&lt;/span&gt;&lt;span&gt; with&lt;/span&gt;&lt;span&gt; agent&lt;/span&gt;&lt;span&gt; instructions&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; hooks&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; project...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Registered&lt;/span&gt;&lt;span&gt; SessionStart&lt;/span&gt;&lt;span&gt; hook&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; integration...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Created&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; CLAUDE.md&lt;/span&gt;&lt;span&gt; with&lt;/span&gt;&lt;span&gt; beads&lt;/span&gt;&lt;span&gt; integration&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; integration&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  File:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/different_project/CLAUDE.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;No&lt;/span&gt;&lt;span&gt; additional&lt;/span&gt;&lt;span&gt; configuration&lt;/span&gt;&lt;span&gt; needed!&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; integration&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Settings:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/different_project/.claude/settings.json&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Restart&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; changes&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; take&lt;/span&gt;&lt;span&gt; effect.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Beads&lt;/span&gt;&lt;span&gt; agent&lt;/span&gt;&lt;span&gt; skill...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Beads&lt;/span&gt;&lt;span&gt; agent&lt;/span&gt;&lt;span&gt; skill&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Skill:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/different_project/.agents/skills/beads/SKILL.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; native&lt;/span&gt;&lt;span&gt; hooks&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; project...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; native&lt;/span&gt;&lt;span&gt; hooks&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; instructions&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; project...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; instructions&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  File:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/different_project/AGENTS.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Restart&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; if&lt;/span&gt;&lt;span&gt; it&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; already&lt;/span&gt;&lt;span&gt; running.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Committed&lt;/span&gt;&lt;span&gt; beads&lt;/span&gt;&lt;span&gt; files&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;⚠&lt;/span&gt;&lt;span&gt; No&lt;/span&gt;&lt;span&gt; Dolt&lt;/span&gt;&lt;span&gt; remote&lt;/span&gt;&lt;span&gt; configured&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Issues&lt;/span&gt;&lt;span&gt; are&lt;/span&gt;&lt;span&gt; stored&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; local&lt;/span&gt;&lt;span&gt; Dolt.&lt;/span&gt;&lt;span&gt; .beads/issues.jsonl&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; an&lt;/span&gt;&lt;span&gt; export,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  not&lt;/span&gt;&lt;span&gt; cross-machine&lt;/span&gt;&lt;span&gt; sync&lt;/span&gt;&lt;span&gt; or&lt;/span&gt;&lt;span&gt; the&lt;/span&gt;&lt;span&gt; source&lt;/span&gt;&lt;span&gt; of&lt;/span&gt;&lt;span&gt; truth.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  To&lt;/span&gt;&lt;span&gt; enable&lt;/span&gt;&lt;span&gt; durable&lt;/span&gt;&lt;span&gt; sync,&lt;/span&gt;&lt;span&gt; add&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;span&gt; origin&lt;/span&gt;&lt;span&gt; and&lt;/span&gt;&lt;span&gt; then&lt;/span&gt;&lt;span&gt; run:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    bd&lt;/span&gt;&lt;span&gt; dolt&lt;/span&gt;&lt;span&gt; push&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; initialized&lt;/span&gt;&lt;span&gt; successfully!&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Backend:&lt;/span&gt;&lt;span&gt; dolt&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Mode:&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Server:&lt;/span&gt;&lt;span&gt; root@127.0.0.1:3308&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ⚠&lt;/span&gt;&lt;span&gt; Server&lt;/span&gt;&lt;span&gt; host&lt;/span&gt;&lt;span&gt; defaulted&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; 127.0.0.1.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    If&lt;/span&gt;&lt;span&gt; your&lt;/span&gt;&lt;span&gt; Dolt&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; remote,&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; BEADS_DOLT_SERVER_HOST&lt;/span&gt;&lt;span&gt; or&lt;/span&gt;&lt;span&gt; pass&lt;/span&gt;&lt;span&gt; --server-host.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Database:&lt;/span&gt;&lt;span&gt; different_project&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Issue&lt;/span&gt;&lt;span&gt; prefix:&lt;/span&gt;&lt;span&gt; different_project&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Issues&lt;/span&gt;&lt;span&gt; will&lt;/span&gt;&lt;span&gt; be&lt;/span&gt;&lt;span&gt; named:&lt;/span&gt;&lt;span&gt; different_project-&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;has&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; (e.g., &lt;/span&gt;&lt;span&gt;different_project-a3f2dd&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Run&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; quickstart&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; get&lt;/span&gt;&lt;span&gt; started.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we can use the project as normal, and beads will route to their project scoped database.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;No&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; found.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; create&lt;/span&gt;&lt;span&gt; "my first different project bead"&lt;/span&gt;&lt;span&gt; -p&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Created&lt;/span&gt;&lt;span&gt; issue:&lt;/span&gt;&lt;span&gt; different_project-s9i&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; my&lt;/span&gt;&lt;span&gt; first&lt;/span&gt;&lt;span&gt; different&lt;/span&gt;&lt;span&gt; project&lt;/span&gt;&lt;span&gt; bead&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Priority:&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Status:&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;💡&lt;/span&gt;&lt;span&gt; Tip:&lt;/span&gt;&lt;span&gt; Install&lt;/span&gt;&lt;span&gt; the&lt;/span&gt;&lt;span&gt; beads&lt;/span&gt;&lt;span&gt; plugin&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; automatic&lt;/span&gt;&lt;span&gt; workflow&lt;/span&gt;&lt;span&gt; context,&lt;/span&gt;&lt;span&gt; or&lt;/span&gt;&lt;span&gt; run&lt;/span&gt;&lt;span&gt; 'bd setup claude'&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; CLI-only&lt;/span&gt;&lt;span&gt; mode&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; different_project-s9i&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; my&lt;/span&gt;&lt;span&gt; first&lt;/span&gt;&lt;span&gt; different&lt;/span&gt;&lt;span&gt; project&lt;/span&gt;&lt;span&gt; bead&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;--------------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total:&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; (1 &lt;/span&gt;&lt;span&gt;open,&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; progress&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Status:&lt;/span&gt;&lt;span&gt; ○&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;span&gt;  ◐&lt;/span&gt;&lt;span&gt; in_progress&lt;/span&gt;&lt;span&gt;  ●&lt;/span&gt;&lt;span&gt; blocked&lt;/span&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; closed&lt;/span&gt;&lt;span&gt;  ❄&lt;/span&gt;&lt;span&gt; deferred&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we return to our earlier project which also uses this shared-server, you’ll see that it won’t be able to see the bead created and scoped to &lt;code&gt;different_project&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; ../evolving_demo&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;No&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; found.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Buuuuuuuut, if we go back to &lt;code&gt;different_project&lt;/code&gt; and create a bead using &lt;code&gt;--global&lt;/code&gt;, we’ll create a global bead that all shared-server projects can access.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; ../different_project&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; create&lt;/span&gt;&lt;span&gt; --global&lt;/span&gt;&lt;span&gt; "my first global bead"&lt;/span&gt;&lt;span&gt; -p&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Created&lt;/span&gt;&lt;span&gt; issue:&lt;/span&gt;&lt;span&gt; global-wqk&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; my&lt;/span&gt;&lt;span&gt; first&lt;/span&gt;&lt;span&gt; global&lt;/span&gt;&lt;span&gt; bead&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Priority:&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Status:&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice the different output of &lt;code&gt;bd list&lt;/code&gt; with and without the &lt;code&gt;--global&lt;/code&gt; flag.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; different_project-s9i&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; my&lt;/span&gt;&lt;span&gt; first&lt;/span&gt;&lt;span&gt; different&lt;/span&gt;&lt;span&gt; project&lt;/span&gt;&lt;span&gt; bead&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;--------------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total:&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; (1 &lt;/span&gt;&lt;span&gt;open,&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; progress&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Status:&lt;/span&gt;&lt;span&gt; ○&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;span&gt;  ◐&lt;/span&gt;&lt;span&gt; in_progress&lt;/span&gt;&lt;span&gt;  ●&lt;/span&gt;&lt;span&gt; blocked&lt;/span&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; closed&lt;/span&gt;&lt;span&gt;  ❄&lt;/span&gt;&lt;span&gt; deferred&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;span&gt; --global&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; global-wqk&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; my&lt;/span&gt;&lt;span&gt; first&lt;/span&gt;&lt;span&gt; global&lt;/span&gt;&lt;span&gt; bead&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;--------------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total:&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; (1 &lt;/span&gt;&lt;span&gt;open,&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; progress&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Status:&lt;/span&gt;&lt;span&gt; ○&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;span&gt;  ◐&lt;/span&gt;&lt;span&gt; in_progress&lt;/span&gt;&lt;span&gt;  ●&lt;/span&gt;&lt;span&gt; blocked&lt;/span&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; closed&lt;/span&gt;&lt;span&gt;  ❄&lt;/span&gt;&lt;span&gt; deferred&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And similarly, if we return to the previous project we see the scoped beads
versus the global ones, by using the &lt;code&gt;--global&lt;/code&gt; flag.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; ../evolving_demo&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;No&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; found.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;span&gt; --global&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; global-wqk&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; my&lt;/span&gt;&lt;span&gt; first&lt;/span&gt;&lt;span&gt; global&lt;/span&gt;&lt;span&gt; bead&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;--------------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total:&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; (1 &lt;/span&gt;&lt;span&gt;open,&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; progress&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Status:&lt;/span&gt;&lt;span&gt; ○&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;span&gt;  ◐&lt;/span&gt;&lt;span&gt; in_progress&lt;/span&gt;&lt;span&gt;  ●&lt;/span&gt;&lt;span&gt; blocked&lt;/span&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; closed&lt;/span&gt;&lt;span&gt;  ❄&lt;/span&gt;&lt;span&gt; deferred&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id="conclusion"&gt;Conclusion&lt;a class="anchor-link" aria-label="Link to heading" href="#conclusion"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I hope this helps clarify some common usage patterns for Beads, and we encourage you to give it a try if you haven’t already.&lt;/p&gt;
&lt;p&gt;Also, feel free to join both the &lt;a href="https://discord.gg/xHpUGUzZp2"&gt;Gaslandia Discord&lt;/a&gt; and the &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;Dolt Discord&lt;/a&gt; if you haven’t already. We’d love to chat with you and discuss building for the agentic future.&lt;/p&gt;</content:encoded>
      <dc:creator>Dustin Brown</dc:creator>
      <category>ai</category>
    </item>
    <item>
      <title>How TPC-C Works</title>
      <link>https://dolthub.com/blog/2026-05-14-how-tpcc-works/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-05-14-how-tpcc-works/</guid>
      <description>A detailed description of Dolt's TPC-C benchmarking.</description>
      <pubDate>Thu, 14 May 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;Dolt is a version-controlled database that works as a drop-in MySQL replacement.
In addition to correctness parity with MySQL, we are also determined to reach performance parity with MySQL.
For years now, we’ve been improving Dolt performance on both Sysbench and TPC-C benchmarks.
Towards the end of 2025, Dolt reached &lt;a href="https://www.dolthub.com/blog/2025-12-04-dolt-is-as-fast-as-mysql/"&gt;parity with MySQL on Sysbench&lt;/a&gt; when averaging reads and writes.
Shortly after, we managed to reach &lt;a href="https://www.dolthub.com/blog/2026-01-06-more-read-performance-wins/"&gt;MySQL parity on both read and writes&lt;/a&gt;.
Now, we &lt;a href="https://dolthub.com/docs/sql-reference/benchmarks/latency"&gt;surpass MySQL on Sysbench reads and writes&lt;/a&gt; with a &lt;code&gt;0.95&lt;/code&gt; reads mean multiplier and &lt;code&gt;0.87&lt;/code&gt; write mean multiplier.&lt;/p&gt;
&lt;p&gt;While we are proud of our accomplishments on Sysbench, TPC-C Benchmarks are arguably more important to the average user experience.
This blog will go into detail about the TPC-C benchmarks and the kinds of queries run against the database.&lt;/p&gt;
&lt;h1 id="what-is-tpc-c"&gt;What is TPC-C&lt;a class="anchor-link" aria-label="Link to heading" href="#what-is-tpc-c"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://www.tpc.org/tpcc/"&gt;TPC-C&lt;/a&gt; stands for Transaction Processing Performance Council Benchmark C.
It is the industry standard benchmark used for OLTP databases.
TPC-C simulates real-world usage of a database by modeling transactions for a wholesale supplier.
Dolt actually uses a slightly modified version of the official TPC-C benchmarks from &lt;a href="https://github.com/Percona-Lab/sysbench-tpcc"&gt;Percona Labs&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="settings"&gt;Settings&lt;a class="anchor-link" aria-label="Link to heading" href="#settings"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We run TPC-C with these settings:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="shell"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;./tpcc.lua&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  --db-driver=&lt;/span&gt;&lt;span&gt;"mysql"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  --mysql-db=&lt;/span&gt;&lt;span&gt;"sbtest"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  --mysql-host=&lt;/span&gt;&lt;span&gt;"127.0.0.1"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  --mysql-port=&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt;$PORT&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  --mysql-user=&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt;$USER&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  --mysql-password=&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt;$PASS&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  --time=800&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  --report_interval=10&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  --threads=1&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  --tables=1&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  --scale=1&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  --trx_level=&lt;/span&gt;&lt;span&gt;"RR"&lt;/span&gt;&lt;span&gt; run&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The benchmarks are run with a single thread for &lt;code&gt;800&lt;/code&gt; seconds with &lt;code&gt;autocommit&lt;/code&gt; and &lt;code&gt;foreign_key_checks&lt;/code&gt; disabled.
&lt;code&gt;trx_level="RR"&lt;/code&gt; is &lt;code&gt;REPEATABLE_READ&lt;/code&gt; (the MySQL/Innodb default), which means that &lt;code&gt;SELECT&lt;/code&gt; results are isolated within a transaction.
Uncommitted writes to a table from another transaction will not be visible to this transaction.
We compare the 95th percentile latency and number of transactions per second (tps) against MySQL.&lt;/p&gt;
&lt;h2 id="tables"&gt;Tables&lt;a class="anchor-link" aria-label="Link to heading" href="#tables"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here is a brief summary of the tables created.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;warehouse&lt;/code&gt; with &lt;code&gt;1&lt;/code&gt; row&lt;/li&gt;
&lt;li&gt;&lt;code&gt;district&lt;/code&gt; with &lt;code&gt;10&lt;/code&gt; rows&lt;/li&gt;
&lt;li&gt;&lt;code&gt;customer&lt;/code&gt; with &lt;code&gt;30000&lt;/code&gt; rows&lt;/li&gt;
&lt;li&gt;&lt;code&gt;orders&lt;/code&gt; with &lt;code&gt;30000&lt;/code&gt; rows&lt;/li&gt;
&lt;li&gt;&lt;code&gt;new_orders&lt;/code&gt; with &lt;code&gt;9000&lt;/code&gt; rows&lt;/li&gt;
&lt;li&gt;&lt;code&gt;order_line&lt;/code&gt; with &lt;code&gt;299293&lt;/code&gt; rows&lt;/li&gt;
&lt;li&gt;&lt;code&gt;item&lt;/code&gt; with &lt;code&gt;100000&lt;/code&gt; rows&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stock&lt;/code&gt; with &lt;code&gt;100000&lt;/code&gt; rows&lt;/li&gt;
&lt;li&gt;&lt;code&gt;history&lt;/code&gt; with &lt;code&gt;30000&lt;/code&gt; rows&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Many of these tables have primary keys, secondary keys, and foreign keys (even though &lt;code&gt;foreign_key_checks&lt;/code&gt; are disabled).&lt;/p&gt;
&lt;h2 id="transactions"&gt;Transactions&lt;a class="anchor-link" aria-label="Link to heading" href="#transactions"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;TPC-C randomly selects between &lt;code&gt;5&lt;/code&gt; different transaction types with varying odds.
Each transaction starts with a &lt;code&gt;BEGIN&lt;/code&gt; and ends with &lt;code&gt;COMMIT&lt;/code&gt;.
Without spelling out every query run within a transaction, here is a high-level overview of each transaction.&lt;/p&gt;

































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;trx_type&lt;/th&gt;&lt;th&gt;run_percent&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;new_order&lt;/code&gt;&lt;/td&gt;&lt;td&gt;43.48%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;payment&lt;/code&gt;&lt;/td&gt;&lt;td&gt;43.48%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;order_status&lt;/code&gt;&lt;/td&gt;&lt;td&gt;4.35%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;delivery&lt;/code&gt;&lt;/td&gt;&lt;td&gt;4.35%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;payment&lt;/code&gt;&lt;/td&gt;&lt;td&gt;4.35%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;TOTAL&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;≈100.00%&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3 id="1-new_order"&gt;1. &lt;code&gt;new_order&lt;/code&gt;&lt;a class="anchor-link" aria-label="Link to heading" href="#1-new_order"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;:
This transaction simulates a customer order of &lt;code&gt;5&lt;/code&gt; - &lt;code&gt;15&lt;/code&gt; quantity of an item.
The new order is logged in the &lt;code&gt;orders&lt;/code&gt;, &lt;code&gt;new_orders&lt;/code&gt;, and &lt;code&gt;order_line&lt;/code&gt; tables, and the &lt;code&gt;item&lt;/code&gt; and &lt;code&gt;stock&lt;/code&gt; tables are updated accordingly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Percent Run&lt;/strong&gt;:
&lt;code&gt;43.49% (10/23)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;# of SQL Statements&lt;/strong&gt;:
&lt;code&gt;25&lt;/code&gt; - &lt;code&gt;65&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reads Tables&lt;/strong&gt;:
&lt;code&gt;customer&lt;/code&gt;, &lt;code&gt;district&lt;/code&gt;, &lt;code&gt;item&lt;/code&gt;, &lt;code&gt;stock&lt;/code&gt;, &lt;code&gt;warehouse&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Writes Tables&lt;/strong&gt;:
&lt;code&gt;district&lt;/code&gt;, &lt;code&gt;orders&lt;/code&gt;, &lt;code&gt;order_line&lt;/code&gt;, &lt;code&gt;new_orders&lt;/code&gt;, &lt;code&gt;stock&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="2-payment"&gt;2. &lt;code&gt;payment&lt;/code&gt;&lt;a class="anchor-link" aria-label="Link to heading" href="#2-payment"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;:
This transaction simulates a customer making a purchase.
It reads the customer’s payment details (name, address, etc.) from the &lt;code&gt;customer&lt;/code&gt; table, update their account balance, and logs the transaction in the &lt;code&gt;history&lt;/code&gt; table.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Percent Run&lt;/strong&gt;:
&lt;code&gt;43.48% (10/23)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;# of SQL Statements&lt;/strong&gt;:
&lt;code&gt;6&lt;/code&gt; - &lt;code&gt;10&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reads Tables&lt;/strong&gt;:
&lt;code&gt;customer&lt;/code&gt;, &lt;code&gt;district&lt;/code&gt;, &lt;code&gt;warehouse&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Writes Tables&lt;/strong&gt;:
&lt;code&gt;customer&lt;/code&gt;, &lt;code&gt;district&lt;/code&gt;, &lt;code&gt;history&lt;/code&gt;, &lt;code&gt;warehouse&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="3-order_status"&gt;3. &lt;code&gt;order_status&lt;/code&gt;&lt;a class="anchor-link" aria-label="Link to heading" href="#3-order_status"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;:
This transaction simulates a customer inquiring about their order details.
It performs a series of &lt;code&gt;SELECT&lt;/code&gt; queries into the &lt;code&gt;customer&lt;/code&gt;, &lt;code&gt;orders&lt;/code&gt; and &lt;code&gt;order_line&lt;/code&gt; tables.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Percent Run&lt;/strong&gt;:
&lt;code&gt;4.34% (1/23)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;# of SQL Statements&lt;/strong&gt;:
&lt;code&gt;3&lt;/code&gt; - &lt;code&gt;4&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reads Tables&lt;/strong&gt;:
&lt;code&gt;customer&lt;/code&gt;, &lt;code&gt;orders&lt;/code&gt;, &lt;code&gt;order_line&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Writes Tables&lt;/strong&gt;:
&lt;code&gt;NONE&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="4-delivery"&gt;4. &lt;code&gt;delivery&lt;/code&gt;&lt;a class="anchor-link" aria-label="Link to heading" href="#4-delivery"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;:
This transaction simulates a customer’s order getting delivered.
An order is removed from the &lt;code&gt;new_orders&lt;/code&gt; table and the appropriate entries are updated in &lt;code&gt;orders&lt;/code&gt;, &lt;code&gt;order_line&lt;/code&gt; and &lt;code&gt;customer&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Percent Run&lt;/strong&gt;:
&lt;code&gt;4.34% (1/23)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;# of SQL Statements&lt;/strong&gt;:
&lt;code&gt;1&lt;/code&gt; - &lt;code&gt;6&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reads Tables&lt;/strong&gt;:
&lt;code&gt;orders&lt;/code&gt;, &lt;code&gt;order_line&lt;/code&gt;, &lt;code&gt;new_orders&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Writes Tables&lt;/strong&gt;:
&lt;code&gt;customer&lt;/code&gt;, &lt;code&gt;orders&lt;/code&gt;, &lt;code&gt;order_line&lt;/code&gt;, &lt;code&gt;new_orders&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="5-stocklevel"&gt;5. &lt;code&gt;stocklevel&lt;/code&gt;&lt;a class="anchor-link" aria-label="Link to heading" href="#5-stocklevel"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;:
This transaction simulates a query over existing inventory.
It is a few &lt;code&gt;SELECT&lt;/code&gt; queries that aggregate over the &lt;code&gt;order_line&lt;/code&gt; and &lt;code&gt;stock&lt;/code&gt; tables that count the quantity of certain items.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Percent Run&lt;/strong&gt;:
&lt;code&gt;4.34% (1/23)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;# of SQL Statements&lt;/strong&gt;:
&lt;code&gt;3+&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reads Tables&lt;/strong&gt;:
&lt;code&gt;district&lt;/code&gt;, &lt;code&gt;orders&lt;/code&gt;, &lt;code&gt;stock&lt;/code&gt;, &lt;code&gt;order_line&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Writes Tables&lt;/strong&gt;:
&lt;code&gt;NONE&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;You can explore the TPC-C database in more detail here:
&lt;a href="https://www.dolthub.com/repositories/jcor/sbtest"&gt;https://www.dolthub.com/repositories/jcor/sbtest&lt;/a&gt;&lt;/p&gt;
&lt;h1 id="conclusion"&gt;Conclusion&lt;a class="anchor-link" aria-label="Link to heading" href="#conclusion"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We have been focused on Dolt performance on TPC-C, which aims to simulate a real user experience with an OLTP database.
Over the last few months we have made substantial improvements to TPC-C.
Stay tuned for a future blog describing how we’ve broken the 2x MySQL multiplier on TPC-C.
Have any performance issues? Cut a bug on our &lt;a href="https://github.com/dolthub/dolt/issues"&gt;GitHub issues page&lt;/a&gt;.
Want to talk to anyone on our team? Join &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;our Discord&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <dc:creator>James Cor</dc:creator>
      <category>technical</category>
      <category>performance</category>
    </item>
    <item>
      <title>Dolt 2.0</title>
      <link>https://dolthub.com/blog/2026-05-11-dolt-2-dot-0/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-05-11-dolt-2-dot-0/</guid>
      <description>Almost exactly three years ago, we announced Dolt 1.0. Today, we announce Dolt 2.0.</description>
      <pubDate>Mon, 11 May 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;Three years ago, we &lt;a href="https://www.dolthub.com/blog/2023-05-05-dolt-1-dot-0/"&gt;announced Dolt 1.0&lt;/a&gt;, signalling that Dolt was ready for production workloads. We haven’t stopped improving &lt;a href="https://www.dolthub.com/blog/2022-08-04-database-versioning/"&gt;the world’s first and only version-controlled SQL database&lt;/a&gt;. Today, we are excited to announce &lt;a href="https://github.com/dolthub/dolt/releases/tag/v2.0.0"&gt;Dolt 2.0&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/dolt-2_0.png/35df9fbddbb4f701cb124b70d8c1fe657b29a4f14c94606770a8996d40bc41ea.webp" alt="Dolt 2.0"&gt;&lt;/p&gt;
&lt;h1 id="what-did-dolt-10-mean"&gt;What Did Dolt 1.0 Mean?&lt;a class="anchor-link" aria-label="Link to heading" href="#what-did-dolt-10-mean"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://www.dolthub.com/blog/2023-05-05-dolt-1-dot-0/"&gt;Dolt 1.0&lt;/a&gt; meant four things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Forward Storage Compatibility&lt;/li&gt;
&lt;li&gt;Production Performance&lt;/li&gt;
&lt;li&gt;MySQL Compatibility&lt;/li&gt;
&lt;li&gt;Stable Version Control Interface&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Dolt 2.0 maintains the promises of Dolt 1.0. Dolt 2.0 improves on the performance and correctness metrics established in Dolt 1.0.&lt;/p&gt;
&lt;h1 id="what-does-dolt-20-mean"&gt;What Does Dolt 2.0 Mean?&lt;a class="anchor-link" aria-label="Link to heading" href="#what-does-dolt-20-mean"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Dolt 2.0 means five things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Automated Garbage Collection on by Default&lt;/li&gt;
&lt;li&gt;Archive Compression on by Default&lt;/li&gt;
&lt;li&gt;Faster than MySQL on &lt;code&gt;sysbench&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Beta Vector Support&lt;/li&gt;
&lt;li&gt;Adaptive Storage&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Unlike Dolt 1.0, Dolt 2.0 is fully backwards compatible with all Dolt 1.0 versions. No storage migration using &lt;code&gt;dolt migrate&lt;/code&gt; is required. Let’s dive into the details of each of these points.&lt;/p&gt;
&lt;h2 id="garbage-collection"&gt;Garbage Collection&lt;a class="anchor-link" aria-label="Link to heading" href="#garbage-collection"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Dolt makes a lot of disk garbage, especially during import. Dolt is copy-on-write so all intermediate committed transaction state is preserved to disk. Any intermediate state that is not in a Dolt commit is garbage and can be collected.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/how-garbage-is-created.png/c719463f830464444cce6a285c5a4125cc88710480ad62d28a3108f60a25739b.webp" alt="Garbage"&gt;&lt;/p&gt;
&lt;p&gt;Dolt already must preserve all history in the commit graph on disk. Adding extra garbage can eat through your disk very quickly.&lt;/p&gt;
&lt;p&gt;Dolt 2.0 has &lt;a href="https://www.dolthub.com/blog/2025-02-28-announcing-automatic-gc-in-sql-server/"&gt;automatic garbage collection&lt;/a&gt; on by default, meaning most users don’t have to care about disk garbage. Many users have been running in this mode for over a year. We’re confident it is stable.&lt;/p&gt;
&lt;p&gt;Dolt 2.0 databases do not require extra garbage maintenance, just like other modern SQL engines.&lt;/p&gt;
&lt;h2 id="archives"&gt;Archives&lt;a class="anchor-link" aria-label="Link to heading" href="#archives"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Following on the disk space theme, we also have a &lt;a href="https://www.dolthub.com/blog/2024-04-29-dolt-storage-v2/"&gt;new on disk format we call archives&lt;/a&gt; that can reduce Dolt’s storage footprint by an additional 30-50%. Archives use dictionary compression to de-duplicate storage in the deepest layers of Dolt, saving even more disk space.&lt;/p&gt;
&lt;p&gt;As with automatic garbage collection, archives have been the default format for new Dolt databases for months. We’re confident the format is stable and delivers real disk space wins.&lt;/p&gt;
&lt;p&gt;Dolt 2.0 databases are kind to your disk with automatic garbage collection and archives. Version control already requires more disk space than traditional databases. Dolt 2.0 preserves that disk for your data’s history.&lt;/p&gt;
&lt;h2 id="faster-than-mysql-on-sysbench"&gt;Faster than MySQL on &lt;code&gt;sysbench&lt;/code&gt;&lt;a class="anchor-link" aria-label="Link to heading" href="#faster-than-mysql-on-sysbench"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We’ve long used the &lt;a href="https://github.com/akopytov/sysbench"&gt;industry standard &lt;code&gt;sysbench&lt;/code&gt;&lt;/a&gt; to measure and benchmark &lt;a href="https://dolthub.com/docs/sql-reference/benchmarks/latency"&gt;the latency of simple SQL queries in Dolt&lt;/a&gt;. We started at about 10X slower on reads and 20X slower on writes than MySQL. We’ve worked tirelessly to improve Dolt’s performance and we are now 13% faster than MySQL on writes and 5% faster on reads, averaging out to 8% faster than MySQL on &lt;code&gt;sysbench&lt;/code&gt; style workloads.&lt;/p&gt;
&lt;p&gt;Dolt 2.0 databases deliver real production database performance coupled with version control functionality.&lt;/p&gt;
&lt;h2 id="beta-vector-support"&gt;Beta Vector Support&lt;a class="anchor-link" aria-label="Link to heading" href="#beta-vector-support"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We announced &lt;a href="https://www.dolthub.com/blog/2025-01-16-announcing-vector-indexes/"&gt;vector index support&lt;/a&gt; early last year. We have a much bigger challenge than traditional databases with vector indexes because our vector indexes must be version-controlled. We’ve done &lt;a href="https://www.dolthub.com/blog/2025-06-23-vector-index-deep-dive/"&gt;the hard computer science&lt;/a&gt; to achieve this. We &lt;a href="https://www.dolthub.com/blog/2025-09-03-improving-vector-performance/"&gt;adopted the Vector type from MariaDB&lt;/a&gt; in September 2025.&lt;/p&gt;
&lt;p&gt;Dolt 2.0 databases have Beta vector support. Dolt is the only database where your vectors are version-controlled. We still have some edge cases on the read query path where a vector index should be used but it is not. Closing these gaps will remove the Beta tag from Dolt’s vector support.&lt;/p&gt;
&lt;h2 id="adaptive-storage-for-large-column-types"&gt;Adaptive storage for large column types&lt;a class="anchor-link" aria-label="Link to heading" href="#adaptive-storage-for-large-column-types"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Borrowing from our &lt;a href="https://www.dolthub.com/blog/2025-04-14-adaptive-encoding/"&gt;Doltgres adaptive storage work&lt;/a&gt; to support &lt;a href="https://www.postgresql.org/docs/current/storage-toast.html"&gt;TOAST types&lt;/a&gt;, we’re excited to announce Dolt 2.0 has adaptive storage.&lt;/p&gt;
&lt;p&gt;For large column types like TEXT, BLOB, and JSON, databases generally store the value “out of band”, as a file on disk with a pointer to the file in the actual table structure. A different strategy, popularized by Postgres, is to examine the size of the value and store small values in the table structure while preserving the files and pointers strategy for large values. This strategy allows the user to be less disciplined about sizing &lt;code&gt;VARCHAR&lt;/code&gt; columns and just use &lt;code&gt;TEXT&lt;/code&gt; instead. It’s also a big performance win for these types when the values are small.&lt;/p&gt;
&lt;p&gt;Dolt 2.0 has adaptive storage making MySQL databases that use &lt;code&gt;TEXT&lt;/code&gt;, &lt;code&gt;BLOB&lt;/code&gt;, &lt;code&gt;GEOMETRY&lt;/code&gt;, or &lt;code&gt;JSON&lt;/code&gt; columns a good fit regardless of whether they need version control or not.&lt;/p&gt;
&lt;h1 id="conclusion"&gt;Conclusion&lt;a class="anchor-link" aria-label="Link to heading" href="#conclusion"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Dolt 2.0 is here. It’s kinder to your disk and it’s fast. Questions? Stop by &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;our Discord&lt;/a&gt; and just ask.&lt;/p&gt;</content:encoded>
      <dc:creator>Tim Sehn</dc:creator>
      <category>dolt</category>
      <category>feature release</category>
    </item>
    <item>
      <title>Announcing DumboDB: A MongoDB Clone Built on Dolt</title>
      <link>https://dolthub.com/blog/2026-05-07-announcing-dumbodb/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-05-07-announcing-dumbodb/</guid>
      <description>MongoDB and Git had a baby, and it's named Dumbo. Release 0.1 is now public!</description>
      <pubDate>Thu, 07 May 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/dumbo-logo.png/c02da7b39168585c4dc1adf3ebf6ffe77404dd9b8fc5a35f6dc765bb9dea9e16.webp" alt="DumboDB Logo"&gt;&lt;/p&gt;
&lt;p&gt;Today, I’m pleased to announce the &lt;a href="https://github.com/dolthub/dumbodb"&gt;release of DumboDB 0.1&lt;/a&gt;, a &lt;a href="https://github.com/mongodb/mongo"&gt;MongoDB&lt;/a&gt; clone built on top of Dolt’s storage system.&lt;/p&gt;
&lt;p&gt;MongoDB and Git had a baby, and it’s named DumboDB.&lt;/p&gt;
&lt;h2 id="tldr"&gt;TL;DR;&lt;a class="anchor-link" aria-label="Link to heading" href="#tldr"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Grab the code and give it a try! We are excited to see what the community can do with it. You can find the code on GitHub: &lt;a href="https://github.com/dolthub/dumbodb"&gt;https://github.com/dolthub/dumbodb&lt;/a&gt;. See the README for installation instructions. If you have feedback, questions, or want to contribute, join us on &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;Discord&lt;/a&gt;!&lt;/p&gt;
&lt;h2 id="how-did-we-get-here"&gt;How Did We Get Here?&lt;a class="anchor-link" aria-label="Link to heading" href="#how-did-we-get-here"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Like everyone else in the software industry, we have been kicking around the AI tools that are getting so much hype these days. No joke, &lt;a href="https://www.dolthub.com/blog/2026-03-25-doltlite/"&gt;my boss is vibe coding now&lt;/a&gt;. What a stereotype, right? A couple of weeks ago &lt;a href="https://www.dolthub.com/blog/2026-04-16-two-weeks-in-gastown/"&gt;I talked about testing Gas Town&lt;/a&gt;, a coding agent orchestrator, only to get swept up in the excitement of building something new insanely fast. Turns out that a dozen agents can make a really compelling proof of concept in a couple of weeks. Ultimately, we decided to turn that proof of concept into a real product, and here we are.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/dumbo_i_made_this.jpg/721f49f2a93edb921e59fafa20922b2ade612be7731c0cac557987dae2523add.webp" alt="I Made This"&gt;&lt;/p&gt;
&lt;p&gt;Since then, the pace of change has slowed to allow for human-speed verification and testing. The firehose of code generation provided by Gas Town hasn’t been necessary, and it’s mostly been slower 1-on-1 coding with &lt;a href="https://code.claude.com/docs/en/overview"&gt;Claude Code&lt;/a&gt;. I’ve even read some of the code and directed Claude to clean up some nonsense which we are all used to seeing with coding agents at this point. Nevertheless, the 6 weeks of development to get to a viable 0.1 release has been far, far faster than I could have ever done on my own. Say what you want about the AI bubble, coding agents are going to help us write a mountain of code.&lt;/p&gt;
&lt;h2 id="dumbodbs-dna"&gt;DumboDB’s DNA&lt;a class="anchor-link" aria-label="Link to heading" href="#dumbodbs-dna"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;DumboDB started with the &lt;a href="https://github.com/FerretDB/FerretDB"&gt;FerretDB code base&lt;/a&gt;, which is an open-source MongoDB clone. FerretDB operates as a proxy that translates MongoDB queries into SQL queries that are executed against a PostgreSQL database. It’s written in Go.&lt;/p&gt;
&lt;p&gt;Dolt is written in Go as well, so we ripped out the proxy approach of FerretDB and made a standalone server that uses Dolt’s storage engine.&lt;/p&gt;
&lt;p&gt;Dolt’s storage engine is a &lt;a href="https://dolthub.com/docs/architecture/storage-engine/prolly-tree"&gt;Prolly Tree&lt;/a&gt;, which is a data structure that allows for structural sharing of data. Using &lt;a href="https://en.wikipedia.org/wiki/Merkle_tree"&gt;Merkle Trees and DAGs&lt;/a&gt;, Dolt can represent a very granular set of snapshots of your data. This is the same approach used by Git to model your source code history.&lt;/p&gt;
&lt;p&gt;Our Prolly Tree implementation has been getting our love and attention for more than a &lt;a href="https://github.com/dolthub/dolt/commit/68c3ac02058e559367534aeeb7d9f8f483a4db1b"&gt;decade now&lt;/a&gt;. It is what enables our primary product, Dolt, to be a version-controlled database. And when we say version-controlled, we mean it. You can branch, merge, diff, send pull requests, rebase, and so on - just like you would with Git. Dolt is a drop-in replacement for MySQL and is &lt;a href="https://dolthub.com/docs/sql-reference/benchmarks/latency"&gt;as fast as MySQL for many workloads&lt;/a&gt;. It gives you all the &lt;a href="https://www.dolthub.com/blog/2026-05-04-database-insurance/"&gt;safety of Git for your data&lt;/a&gt;. Honestly, most software engineers hear about what we’ve built in Dolt, and they are astonished because it seems impossible. It’s real! &lt;a href="https://github.com/dolthub/dolt"&gt;Check it out&lt;/a&gt; if you haven’t already!&lt;/p&gt;
&lt;p&gt;DumboDB is using the same storage engine as Dolt, but with a different access layer. Instead of using SQL, DumboDB uses the MongoDB query language. This means that you can use all the same tools and libraries that you would use with MongoDB, but with the added benefits of Dolt’s storage engine. To be crystal clear, there is no SQL layer in DumboDB. DumboDB uses the storage objects of Dolt. Therefore, it uses the same indexes, journal code, and commit model — but no SQL. It’s a NoSQL document database — not a facade on top of a SQL database.&lt;/p&gt;
&lt;h2 id="what-can-you-do-with-dumbodb"&gt;What Can You Do With DumboDB?&lt;a class="anchor-link" aria-label="Link to heading" href="#what-can-you-do-with-dumbodb"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;DumboDB is alpha-quality software, so what you &lt;em&gt;should not&lt;/em&gt; do is run it in production.&lt;/p&gt;
&lt;p&gt;That said, it should be able to do most basic MongoDB operations. If you are familiar with MongoDB, you should be able to pick up DumboDB pretty quickly. You can use the same drivers and libraries that you would use with MongoDB, so probably the best thing to do is just kick the tires and tell us when something doesn’t work. We are sure there are bugs, and we want to know about them!&lt;/p&gt;
&lt;p&gt;There are some glaring gaps. DumboDB has no concept of user accounts or permissions yet. There are no isolated sessions or transactions with rollbacks (though you can &lt;code&gt;reset --hard&lt;/code&gt;!). Text search and geo features aren’t implemented. We don’t have a replication or sharding story yet, and we may just stick to the Git model of clone/push/pull. We’ll see. It all depends on what our users ask for. The joy of open source is that we aren’t hiding behind a proprietary roadmap. We’ll build what makes sense, and take PRs for all the rest.&lt;/p&gt;
&lt;p&gt;Being a drop-in replacement for MongoDB is the eventual goal, but we aren’t there yet. If you are bold, you can try running your existing MongoDB workloads against DumboDB and see what happens. Start your server with the &lt;code&gt;--auto-commit&lt;/code&gt; flag and witness how your application changes your data over time.&lt;/p&gt;
&lt;h3 id="version-control-features"&gt;Version Control Features&lt;a class="anchor-link" aria-label="Link to heading" href="#version-control-features"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;All the basic operations you would expect from a Git-inspired product are available. This includes: &lt;code&gt;commit&lt;/code&gt;, &lt;code&gt;branch&lt;/code&gt;, &lt;code&gt;merge&lt;/code&gt;, &lt;code&gt;cherry-pick&lt;/code&gt;, &lt;code&gt;rebase&lt;/code&gt;, &lt;code&gt;log&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;diff&lt;/code&gt;, &lt;code&gt;reset&lt;/code&gt;, &lt;code&gt;revert&lt;/code&gt;, and &lt;code&gt;tag&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Read the documentation for each command &lt;a href="https://github.com/dolthub/dumbodb/wiki/Commands"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There is no “staging” concept in DumboDB, which is a departure from how Git works. Instead, you just make your changes to the database, and then when you are ready to commit, you commit and whatever content is in your workspace will be committed. No need to “add” changes, like you would in Git.&lt;/p&gt;
&lt;p&gt;There are two additional commands for working with merge conflicts: &lt;code&gt;conflicts&lt;/code&gt; and &lt;code&gt;resolveConflict&lt;/code&gt;. Unlike Git, but similar to Dolt, merge conflicts are structured. When merge conflicts arise, the three-way merge details are available to your application so that it can resolve the conflicts reliably. See examples below.&lt;/p&gt;
&lt;p&gt;Note the lack of &lt;code&gt;checkout&lt;/code&gt;. There is no checkout in DumboDB. Instead, you get a database instance using the &lt;code&gt;getSiblingDB&lt;/code&gt; operation. Check out the examples…&lt;/p&gt;
&lt;h2 id="examples"&gt;Examples&lt;a class="anchor-link" aria-label="Link to heading" href="#examples"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You’ll need to grab a prebuilt binary or build from source to run these examples. See the &lt;a href="https://github.com/dolthub/dumbodb#install-dumbodb"&gt;README&lt;/a&gt; for instructions.&lt;/p&gt;
&lt;p&gt;Run the server in its own terminal window:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;dumbodb&lt;/span&gt;&lt;span&gt; --data-dir&lt;/span&gt;&lt;span&gt; /tmp/dumbodb-data&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then in another terminal window, connect to the server using the &lt;a href="https://www.mongodb.com/docs/mongodb-shell/"&gt;MongoDB shell&lt;/a&gt;:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; mongosh&lt;/span&gt;&lt;span&gt; mongodb://localhost:27017/&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;   The&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; generated&lt;/span&gt;&lt;span&gt; these&lt;/span&gt;&lt;span&gt; startup&lt;/span&gt;&lt;span&gt; warnings&lt;/span&gt;&lt;span&gt; when&lt;/span&gt;&lt;span&gt; booting&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;   2026-05-06T21:36:58.547Z:&lt;/span&gt;&lt;span&gt; Powered&lt;/span&gt;&lt;span&gt; by&lt;/span&gt;&lt;span&gt; DumboDB&lt;/span&gt;&lt;span&gt; v0.1.0&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;   2026-05-06T21:36:58.547Z:&lt;/span&gt;&lt;span&gt; Star&lt;/span&gt;&lt;span&gt; Us!&lt;/span&gt;&lt;span&gt; https://github.com/dolthub/dumbodb&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;test&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;mongosh&lt;/code&gt; is a JavaScript shell, so you execute JavaScript code to interact with the database. The &lt;code&gt;test&gt;&lt;/code&gt; prompt indicates that you are connected to the &lt;code&gt;test&lt;/code&gt; database. The way you change the database is you set the &lt;code&gt;db&lt;/code&gt; variable to a different database. For example, if you want to switch to the &lt;code&gt;mydb&lt;/code&gt; database, you would run:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="javascript"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;test&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; db &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; db.&lt;/span&gt;&lt;span&gt;getSiblingDB&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;"mydb"&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mydb&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mydb&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See how the prompt changed to &lt;code&gt;mydb&gt;&lt;/code&gt;? That indicates that we are now using the &lt;code&gt;mydb&lt;/code&gt; database. Now let’s use it!&lt;/p&gt;
&lt;h3 id="create-a-new-collection-and-insert-some-documents"&gt;Create a new collection, and insert some documents:&lt;a class="anchor-link" aria-label="Link to heading" href="#create-a-new-collection-and-insert-some-documents"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The MongoDB approach is to create collections implicitly when you first insert a document into them. So there is no &lt;code&gt;createCollection&lt;/code&gt; command. Instead, you just start inserting documents into a collection, and it will be created for you. Let’s insert two documents into a new collection called &lt;code&gt;customers&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="javascript"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;mydb&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; db.customers.&lt;/span&gt;&lt;span&gt;insertOne&lt;/span&gt;&lt;span&gt;({ name: &lt;/span&gt;&lt;span&gt;"Alice"&lt;/span&gt;&lt;span&gt;, phone: &lt;/span&gt;&lt;span&gt;"555-1234"&lt;/span&gt;&lt;span&gt; })&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  acknowledged&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  insertedId&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;ObjectId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'69fbcb932a4aeea4bc4de9b5'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mydb&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; db.customers.&lt;/span&gt;&lt;span&gt;insertOne&lt;/span&gt;&lt;span&gt;({ name: &lt;/span&gt;&lt;span&gt;"Bob"&lt;/span&gt;&lt;span&gt;, phone: &lt;/span&gt;&lt;span&gt;"555-5678"&lt;/span&gt;&lt;span&gt; })&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  acknowledged&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  insertedId&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;ObjectId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'69fbbb46a26d8df3b3ab5cf6'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mydb&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s all vanilla Mongo behavior. By inserting these two documents, we have made changes to the database, but those changes are not committed yet. It’s like editing a source file in Git: you need to commit it. It works exactly the same with DumboDB. Make as many changes as you need to, then commit when ready.&lt;/p&gt;
&lt;p&gt;DumboDB’s version control operations are executed with the &lt;code&gt;db.runCommand&lt;/code&gt; method. We can see the status of our database with the &lt;code&gt;dumboStatus&lt;/code&gt; command:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="javascript"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;mydb&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; db.&lt;/span&gt;&lt;span&gt;runCommand&lt;/span&gt;&lt;span&gt;({ dumboStatus: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt; })&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  branch&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'main'&lt;/span&gt;&lt;span&gt;,                   &lt;/span&gt;&lt;span&gt;// `db` is on the main branch&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  dirty&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;,                      &lt;/span&gt;&lt;span&gt;// there are uncommitted changes&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  readonly&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;,                  &lt;/span&gt;&lt;span&gt;// we can write to this database, as demonstrated by our inserts&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  collections&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      name: &lt;/span&gt;&lt;span&gt;'customers'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      status: &lt;/span&gt;&lt;span&gt;'added'&lt;/span&gt;&lt;span&gt;,              &lt;/span&gt;&lt;span&gt;// the customers collection is new, so it's status is "added"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      added: &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;,                     &lt;/span&gt;&lt;span&gt;// we added 2 documents to the customers collection&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      modified: &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      deleted: &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ],&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ok&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;                             // the command was successful. Standard MongoDB.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can commit our changes to the database. The commit will create a new snapshot of the database, and the dirty flag will return to &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="javascript"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;mydb&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; db.&lt;/span&gt;&lt;span&gt;runCommand&lt;/span&gt;&lt;span&gt;({ dumboCommit: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;                      message: &lt;/span&gt;&lt;span&gt;"Add customers collection with Alice and Bob"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;                      author: &lt;/span&gt;&lt;span&gt;"neil &amp;#x3C;neil@dolthub.com&gt;"&lt;/span&gt;&lt;span&gt; })&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  commitId&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'6nc94olva9m81ofdjnnhp3018100qs5f'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  branch&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'main'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  message&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'Add customers collection with Alice and Bob'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  author&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'neil &amp;#x3C;neil@dolthub.com&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  timestamp&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;ISODate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'2026-05-06T22:12:28.240Z'&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  committer&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'neil &amp;#x3C;neil@dolthub.com&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  committerTimestamp&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;ISODate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'2026-05-06T22:12:28.240Z'&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ok&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mydb&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; db.&lt;/span&gt;&lt;span&gt;runCommand&lt;/span&gt;&lt;span&gt;({ dumboStatus: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt; })&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  branch&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'main'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  dirty&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  readonly&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  commitId&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'6nc94olva9m81ofdjnnhp3018100qs5f'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;// commitId is shown whenever dirty is false.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  collections&lt;/span&gt;&lt;span&gt;: [],&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ok&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="branch-merge-and-resolve-conflicts"&gt;Branch, Merge, and Resolve Conflicts&lt;a class="anchor-link" aria-label="Link to heading" href="#branch-merge-and-resolve-conflicts"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let’s create a new branch, called &lt;code&gt;feature&lt;/code&gt;, and change the phone number for Alice:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="javascript"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;mydb&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; db.&lt;/span&gt;&lt;span&gt;runCommand&lt;/span&gt;&lt;span&gt;({ dumboBranch: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, branch: &lt;/span&gt;&lt;span&gt;"feature"&lt;/span&gt;&lt;span&gt; })&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;{ &lt;/span&gt;&lt;span&gt;branch&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'feature'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;ok&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;// Specify the branch or revision number with &amp;#x3C;db&gt;@&amp;#x3C;branchOrRevision&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mydb&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt; feature &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; db.&lt;/span&gt;&lt;span&gt;getSiblingDB&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;"mydb@feature"&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;// `feature` variable is a database instance that is now "pointing" to the `feature` branch.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;// We can run commands against it, just like we do with `db`.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mydb&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; feature.&lt;/span&gt;&lt;span&gt;runCommand&lt;/span&gt;&lt;span&gt;({ dumboStatus: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  branch&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'feature'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  dirty&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  readonly&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  commitId&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'6nc94olva9m81ofdjnnhp3018100qs5f'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  collections&lt;/span&gt;&lt;span&gt;: [],&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ok&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;// Update Alice's phone number in the feature branch&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mydb&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; feature.customers.&lt;/span&gt;&lt;span&gt;updateOne&lt;/span&gt;&lt;span&gt;({ name: &lt;/span&gt;&lt;span&gt;"Alice"&lt;/span&gt;&lt;span&gt; }, { $set: { phone: &lt;/span&gt;&lt;span&gt;"555-4321"&lt;/span&gt;&lt;span&gt; } })&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  acknowledged&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  insertedId&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  matchedCount&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  modifiedCount&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,   &lt;/span&gt;&lt;span&gt;// Indicates that one document was modified.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  upsertedCount&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mydb&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; feature.&lt;/span&gt;&lt;span&gt;runCommand&lt;/span&gt;&lt;span&gt;({ dumboStatus: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  branch&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'feature'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  dirty&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  readonly&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  collections&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      name: &lt;/span&gt;&lt;span&gt;'customers'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      status: &lt;/span&gt;&lt;span&gt;'modified'&lt;/span&gt;&lt;span&gt;,  &lt;/span&gt;&lt;span&gt;// The customers collection is modified, because we changed Alice's phone number.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      added: &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      modified: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,         &lt;/span&gt;&lt;span&gt;// Alice's document was modified.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      deleted: &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ],&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ok&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;dumboStatus&lt;/code&gt; gives a high-level summary of what has changed in our working copy of the database, but if we want to see the actual changes, we can use the &lt;code&gt;dumboDiff&lt;/code&gt; command:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="javascript"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;mydb&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; feature.&lt;/span&gt;&lt;span&gt;runCommand&lt;/span&gt;&lt;span&gt;({ dumboDiff: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  collections&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      name: &lt;/span&gt;&lt;span&gt;'customers'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      status: &lt;/span&gt;&lt;span&gt;'modified'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      added: [],&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      removed: [],&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      modified: [&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;          _id: &lt;/span&gt;&lt;span&gt;ObjectId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'69fbcb932a4aeea4bc4de9b5'&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;          diff: [&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;            // the "phone" field was changed from "555-1234" to "555-4321"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;            { type: &lt;/span&gt;&lt;span&gt;'modified'&lt;/span&gt;&lt;span&gt;, path: &lt;/span&gt;&lt;span&gt;'$.phone'&lt;/span&gt;&lt;span&gt;, from: &lt;/span&gt;&lt;span&gt;'555-1234'&lt;/span&gt;&lt;span&gt;, to: &lt;/span&gt;&lt;span&gt;'555-4321'&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;          ]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      ]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ],&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ok&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;// dumboCommit will always commit the content shown in the output of dumboDiff without arguments.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;// Run dumboCommit now, it will commit the change to Alice's phone number.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mydb&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; feature.&lt;/span&gt;&lt;span&gt;runCommand&lt;/span&gt;&lt;span&gt;({ dumboCommit: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, message: &lt;/span&gt;&lt;span&gt;"Update Alice's phone number"&lt;/span&gt;&lt;span&gt;, author: &lt;/span&gt;&lt;span&gt;"neil &amp;#x3C;neil@dolthub.com&gt;"&lt;/span&gt;&lt;span&gt; })&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  commitId&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'p7p99vndl9d11hjloivlu1lcuvt3n9qa'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  branch&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'feature'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  message&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;"Update Alice's phone number"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  author&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'neil &amp;#x3C;neil@dolthub.com&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  timestamp&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;ISODate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'2026-05-06T23:27:52.848Z'&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  committer&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'neil &amp;#x3C;neil@dolthub.com&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  committerTimestamp&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;ISODate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'2026-05-06T23:27:52.848Z'&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ok&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let’s change the same field, but on the &lt;code&gt;main&lt;/code&gt; branch. Note that the &lt;code&gt;db&lt;/code&gt; instance was created on the default branch, which is &lt;code&gt;main&lt;/code&gt;, so when we run commands against &lt;code&gt;db&lt;/code&gt;, we are running them against the &lt;code&gt;main&lt;/code&gt; branch. We’ll perform a ‘find’ to demonstrate:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="javascript"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;mydb&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; db.customers.&lt;/span&gt;&lt;span&gt;find&lt;/span&gt;&lt;span&gt;({name: &lt;/span&gt;&lt;span&gt;'Alice'&lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    _id: &lt;/span&gt;&lt;span&gt;ObjectId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'69fbcb932a4aeea4bc4de9b5'&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    name: &lt;/span&gt;&lt;span&gt;'Alice'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    phone: &lt;/span&gt;&lt;span&gt;'555-1234'&lt;/span&gt;&lt;span&gt; // Still unchanged on the main branch.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mydb&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; db.customers.&lt;/span&gt;&lt;span&gt;updateOne&lt;/span&gt;&lt;span&gt;({ name: &lt;/span&gt;&lt;span&gt;"Alice"&lt;/span&gt;&lt;span&gt; }, { $set: { phone: &lt;/span&gt;&lt;span&gt;"555-9999"&lt;/span&gt;&lt;span&gt; } })&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  acknowledged&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  insertedId&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  matchedCount&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  modifiedCount&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  upsertedCount&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mydb&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; db.&lt;/span&gt;&lt;span&gt;runCommand&lt;/span&gt;&lt;span&gt;({dumboCommit:&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, message: &lt;/span&gt;&lt;span&gt;"update Alice on main"&lt;/span&gt;&lt;span&gt;, author: &lt;/span&gt;&lt;span&gt;"neil &amp;#x3C;neil@dolthub.com&gt;"&lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  commitId&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'22gvmftrbf995mn924hl0ounoo4quhqh'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  branch&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'main'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  message&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'update Alice on main'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  author&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'neil &amp;#x3C;neil@dolthub.com&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  timestamp&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;ISODate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'2026-05-06T23:28:51.139Z'&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  committer&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'neil &amp;#x3C;neil@dolthub.com&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  committerTimestamp&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;ISODate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'2026-05-06T23:28:51.139Z'&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ok&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To recap: We’ve updated Alice’s phone number to “555-4321” on the &lt;code&gt;feature&lt;/code&gt; branch, and “555-9999” on the &lt;code&gt;main&lt;/code&gt; branch. We can see the differences between the two branches with &lt;code&gt;dumboDiff&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="javascript"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;mydb&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; db.&lt;/span&gt;&lt;span&gt;runCommand&lt;/span&gt;&lt;span&gt;({ dumboDiff: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, from: &lt;/span&gt;&lt;span&gt;"main"&lt;/span&gt;&lt;span&gt;, to: &lt;/span&gt;&lt;span&gt;"feature"&lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  collections&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      name: &lt;/span&gt;&lt;span&gt;'customers'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      status: &lt;/span&gt;&lt;span&gt;'modified'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      added: [],&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      removed: [],&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      modified: [&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;          _id: &lt;/span&gt;&lt;span&gt;ObjectId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'69fbcb932a4aeea4bc4de9b5'&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;          diff: [&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;            { type: &lt;/span&gt;&lt;span&gt;'modified'&lt;/span&gt;&lt;span&gt;, path: &lt;/span&gt;&lt;span&gt;'$.phone'&lt;/span&gt;&lt;span&gt;, from: &lt;/span&gt;&lt;span&gt;'555-9999'&lt;/span&gt;&lt;span&gt;, to: &lt;/span&gt;&lt;span&gt;'555-4321'&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;          ]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      ]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ],&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ok&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is just a flat diff between the branches, but we know that they have a common ancestor with a third value for Alice’s phone number. When we attempt to merge the &lt;code&gt;feature&lt;/code&gt; branch into &lt;code&gt;main&lt;/code&gt;, we will get a merge conflict, because the same field was modified in both branches. DumboDB will give us the details of the merge conflict, so that we can resolve it:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="javascript"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;mydb&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; db.&lt;/span&gt;&lt;span&gt;runCommand&lt;/span&gt;&lt;span&gt;({dumboMerge: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;                     merge_in: &lt;/span&gt;&lt;span&gt;"feature"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;                     message: &lt;/span&gt;&lt;span&gt;"merge in feature branch"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;                     author: &lt;/span&gt;&lt;span&gt;"neil &amp;#x3C;neil@dolthub.com&gt;"&lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;MongoServerError&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;dumboMerge&lt;/span&gt;&lt;span&gt;: unresolved conflicts &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; collection&lt;/span&gt;&lt;span&gt;(s)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We got the merge conflict, as expected. To make sense of what happened, we can run the &lt;code&gt;dumboConflicts&lt;/code&gt; command:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="javascript"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;mydb&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; db.&lt;/span&gt;&lt;span&gt;runCommand&lt;/span&gt;&lt;span&gt;({dumboConflicts: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  collections&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      collection: &lt;/span&gt;&lt;span&gt;'customers'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      conflicts: [&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;          conflictId: &lt;/span&gt;&lt;span&gt;'1I7p9HPnc+ff2JXl+sLqgw'&lt;/span&gt;&lt;span&gt;,          &lt;/span&gt;&lt;span&gt;// Unique identifier for this specific conflict.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;          _id: &lt;/span&gt;&lt;span&gt;ObjectId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'69fbcb932a4aeea4bc4de9b5'&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;          base: { name: &lt;/span&gt;&lt;span&gt;'Alice'&lt;/span&gt;&lt;span&gt;, phone: &lt;/span&gt;&lt;span&gt;'555-1234'&lt;/span&gt;&lt;span&gt; },    &lt;/span&gt;&lt;span&gt;// Original value.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;          ours: { name: &lt;/span&gt;&lt;span&gt;'Alice'&lt;/span&gt;&lt;span&gt;, phone: &lt;/span&gt;&lt;span&gt;'555-9999'&lt;/span&gt;&lt;span&gt; },    &lt;/span&gt;&lt;span&gt;// Value on the main branch (ours)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;          theirs: { name: &lt;/span&gt;&lt;span&gt;'Alice'&lt;/span&gt;&lt;span&gt;, phone: &lt;/span&gt;&lt;span&gt;'555-4321'&lt;/span&gt;&lt;span&gt; },  &lt;/span&gt;&lt;span&gt;// Value on the feature branch (theirs)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;          ourDiffType: &lt;/span&gt;&lt;span&gt;'modified'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;          theirDiffType: &lt;/span&gt;&lt;span&gt;'modified'&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      ]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ],&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ok&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can resolve the conflict with the &lt;code&gt;dumboResolveConflict&lt;/code&gt; command. We have three options to resolve the conflict: we can choose either “ours” or “theirs”, or we can provide a custom resolution. For this example, we’ll choose a custom resolution, where we set Alice’s phone number to “555-0000”:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="javascript"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;mydb&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; db.&lt;/span&gt;&lt;span&gt;runCommand&lt;/span&gt;&lt;span&gt;({dumboResolveConflict: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;                     collection: &lt;/span&gt;&lt;span&gt;"customers"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;                     conflictId: &lt;/span&gt;&lt;span&gt;"1I7p9HPnc+ff2JXl+sLqgw"&lt;/span&gt;&lt;span&gt;,    &lt;/span&gt;&lt;span&gt;// Unique identifier from above. required.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;                     resolution: &lt;/span&gt;&lt;span&gt;"custom"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;                     value: { name: &lt;/span&gt;&lt;span&gt;'Alice'&lt;/span&gt;&lt;span&gt;, phone: &lt;/span&gt;&lt;span&gt;'555-0000'&lt;/span&gt;&lt;span&gt; }})&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;{ &lt;/span&gt;&lt;span&gt;ok&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;// dumboStatus prints merge state:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mydb&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; db.&lt;/span&gt;&lt;span&gt;runCommand&lt;/span&gt;&lt;span&gt;({dumboStatus: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  branch&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'main'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  dirty&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  readonly&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  collections&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      name: &lt;/span&gt;&lt;span&gt;'customers'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      status: &lt;/span&gt;&lt;span&gt;'modified'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      added: &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      modified: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      deleted: &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ],&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  mergeState&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'merge'&lt;/span&gt;&lt;span&gt;,  &lt;/span&gt;&lt;span&gt;// Currently in the middle of a merge.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  conflicts&lt;/span&gt;&lt;span&gt;: [],        &lt;/span&gt;&lt;span&gt;// No more conflicts, because we resolved the only conflict.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ok&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;// Complete the merge with the `continue` flag on the dumboMerge command.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mydb&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; db.&lt;/span&gt;&lt;span&gt;runCommand&lt;/span&gt;&lt;span&gt;({dumboMerge: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;                     continue: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;                     message: &lt;/span&gt;&lt;span&gt;"merge in feature branch"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;                     author: &lt;/span&gt;&lt;span&gt;"neil &amp;#x3C;neil@dolthub.com&gt;"&lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  commitId&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'7iraa088995v304n61egkm45dcge2a78'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  message&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'merge in feature branch'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  author&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'neil &amp;#x3C;neil@dolthub.com&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  timestamp&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;ISODate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'2026-05-06T23:59:11.995Z'&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  committer&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;'neil &amp;#x3C;neil@dolthub.com&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  committerTimestamp&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;ISODate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'2026-05-06T23:59:11.995Z'&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ok&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, you can use the &lt;code&gt;dumboLog&lt;/code&gt; command to see the history of commits on the &lt;code&gt;main&lt;/code&gt; branch, including the merge commit we just made:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="javascript"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;mydb&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; db.&lt;/span&gt;&lt;span&gt;runCommand&lt;/span&gt;&lt;span&gt;({dumboLog: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  commits&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      commitId: &lt;/span&gt;&lt;span&gt;'7iraa088995v304n61egkm45dcge2a78'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      refs: [ &lt;/span&gt;&lt;span&gt;'HEAD'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;'main'&lt;/span&gt;&lt;span&gt; ],                               &lt;/span&gt;&lt;span&gt;// refs tell you which branches or tags are pointing to this commit.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      parent1: &lt;/span&gt;&lt;span&gt;'22gvmftrbf995mn924hl0ounoo4quhqh'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      parent2: &lt;/span&gt;&lt;span&gt;'p7p99vndl9d11hjloivlu1lcuvt3n9qa'&lt;/span&gt;&lt;span&gt;,            &lt;/span&gt;&lt;span&gt;// Second parent because this is a merge commit!&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      message: &lt;/span&gt;&lt;span&gt;'merge in feature branch'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      timestamp: &lt;/span&gt;&lt;span&gt;ISODate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'2026-05-06T23:59:11.980Z'&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      author: &lt;/span&gt;&lt;span&gt;'neil &amp;#x3C;neil@dolthub.com&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      committer: &lt;/span&gt;&lt;span&gt;'neil &amp;#x3C;neil@dolthub.com&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      committerTimestamp: &lt;/span&gt;&lt;span&gt;ISODate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'2026-05-06T23:59:11.980Z'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      commitId: &lt;/span&gt;&lt;span&gt;'22gvmftrbf995mn924hl0ounoo4quhqh'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      parent1: &lt;/span&gt;&lt;span&gt;'9t4t592jqddgj1elcfnaal7c8o6boj26'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      message: &lt;/span&gt;&lt;span&gt;'update Alice on main'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      timestamp: &lt;/span&gt;&lt;span&gt;ISODate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'2026-05-06T23:28:51.139Z'&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      author: &lt;/span&gt;&lt;span&gt;'neil &amp;#x3C;neil@dolthub.com&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      committer: &lt;/span&gt;&lt;span&gt;'neil &amp;#x3C;neil@dolthub.com&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      committerTimestamp: &lt;/span&gt;&lt;span&gt;ISODate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'2026-05-06T23:28:51.139Z'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      commitId: &lt;/span&gt;&lt;span&gt;'p7p99vndl9d11hjloivlu1lcuvt3n9qa'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      refs: [ &lt;/span&gt;&lt;span&gt;'feature'&lt;/span&gt;&lt;span&gt; ],                                 &lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      parent1: &lt;/span&gt;&lt;span&gt;'9t4t592jqddgj1elcfnaal7c8o6boj26'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      message: &lt;/span&gt;&lt;span&gt;"Update Alice's phone number"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      timestamp: &lt;/span&gt;&lt;span&gt;ISODate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'2026-05-06T23:27:52.848Z'&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      author: &lt;/span&gt;&lt;span&gt;'neil &amp;#x3C;neil@dolthub.com&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      committer: &lt;/span&gt;&lt;span&gt;'neil &amp;#x3C;neil@dolthub.com&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      committerTimestamp: &lt;/span&gt;&lt;span&gt;ISODate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'2026-05-06T23:27:52.848Z'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      commitId: &lt;/span&gt;&lt;span&gt;'9t4t592jqddgj1elcfnaal7c8o6boj26'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      parent1: &lt;/span&gt;&lt;span&gt;'6h1nv5qcnkesp3ahg5vn7shp6airkkn7'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      message: &lt;/span&gt;&lt;span&gt;'Add customers collection with Alice and Bob'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      timestamp: &lt;/span&gt;&lt;span&gt;ISODate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'2026-05-06T23:16:04.348Z'&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      author: &lt;/span&gt;&lt;span&gt;'neil &amp;#x3C;neil@dolthub.com&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      committer: &lt;/span&gt;&lt;span&gt;'neil &amp;#x3C;neil@dolthub.com&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      committerTimestamp: &lt;/span&gt;&lt;span&gt;ISODate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'2026-05-06T23:16:04.348Z'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      commitId: &lt;/span&gt;&lt;span&gt;'6h1nv5qcnkesp3ahg5vn7shp6airkkn7'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      message: &lt;/span&gt;&lt;span&gt;'Initialize database'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      timestamp: &lt;/span&gt;&lt;span&gt;ISODate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'2026-05-06T23:15:31.054Z'&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      author: &lt;/span&gt;&lt;span&gt;'dumbodb &amp;#x3C;dumbodb@dumbodb&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      committer: &lt;/span&gt;&lt;span&gt;'dumbodb &amp;#x3C;dumbodb@dumbodb&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      committerTimestamp: &lt;/span&gt;&lt;span&gt;ISODate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'2026-05-06T23:15:31.054Z'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ],&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ok&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;dumboLog&lt;/code&gt; command is not very flexible yet, but you can see a summary of the documents changed with the &lt;code&gt;stat&lt;/code&gt; flag, and the full diff of each with the &lt;code&gt;patch&lt;/code&gt; flag. Both are inspired by the &lt;code&gt;git log&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;To read the specifics of each command, see the &lt;a href="https://github.com/dolthub/dumbodb/wiki/Commands"&gt;documentation&lt;/a&gt;!&lt;/p&gt;
&lt;h2 id="roadmap"&gt;Roadmap&lt;a class="anchor-link" aria-label="Link to heading" href="#roadmap"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are plenty of ways we can expand this product’s features, and we are just at the beginning. Here is our current rough roadmap:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;v0.2&lt;/strong&gt;: Garbage Collection and zstd compression. Reduce the footprint of your database. Simplified configuration for user details (name and email) so you don’t have to specify them on every commit.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;v0.3&lt;/strong&gt;: Add Clone, Push, and Pull support. This will allow you to sync your DumboDB repositories with remote servers, and collaborate with others.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;v0.4&lt;/strong&gt;: Add support for Replication (as a secondary backup to your existing MongoDB instance).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;v0.5&lt;/strong&gt;: Isolated Session and Transaction support.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;v0.6&lt;/strong&gt;: Add Authentication and Authorization support.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;v0.7&lt;/strong&gt;: Add MCP server support, allowing you to use agents to work with the DumboDB database.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;v0.8&lt;/strong&gt;: Visualization and operations via a custom Workbench UI.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;v1.0&lt;/strong&gt;: General availability release, with a focus on stability, performance, and usability improvements.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;No dates are assigned on any of this, mainly because we will invest our engineering resources in balance with the other DoltHub products. We’ll go faster if you bang on our doors!&lt;/p&gt;
&lt;h2 id="call-to-action"&gt;Call to Action!&lt;a class="anchor-link" aria-label="Link to heading" href="#call-to-action"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here at &lt;a href="https://www.dolthub.com/"&gt;DoltHub&lt;/a&gt;, we strongly believe in the power of version-controlled databases. Users have told us for a long time that a NoSQL option would appeal to them, and now we have one! Real-world usage and feedback is the surest way to make sure we are building the right features. For that, we require your help. If you are interested in this space (you must be because you read this far), try DumboDB out and tell us what needs to be improved, extended, thrown out, etc. We want to hear from you!&lt;/p&gt;
&lt;p&gt;Want to impact the future of DumboDB? Join us on &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;Discord&lt;/a&gt;!&lt;/p&gt;</content:encoded>
      <dc:creator>Neil Macneale</dc:creator>
      <category>dumbo</category>
      <category>feature release</category>
    </item>
    <item>
      <title>Announcing Azure Private Link Support for Hosted Dolt</title>
      <link>https://dolthub.com/blog/2026-05-06-azure-private-link-networking/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-05-06-azure-private-link-networking/</guid>
      <description>Hosted Dolt now supports Azure Private Link. You can create a new Hosted Dolt instance on Azure with Private Link support in just a few clicks.</description>
      <pubDate>Wed, 06 May 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;&lt;a href="https://hosted.doltdb.com"&gt;Hosted Dolt&lt;/a&gt; is a fully managed &lt;a href="https://doltdb.com"&gt;Dolt&lt;/a&gt; deployment available on AWS, GCP,
and, most recently, &lt;a href="https://www.dolthub.com/blog/2026-04-13-hosted-dolt-on-azure/"&gt;Azure&lt;/a&gt;. The initial offering of
&lt;a href="https://hosted.doltdb.com"&gt;Hosted Dolt&lt;/a&gt; on Azure only supported publicly accessible deployments. Today we are excited to
announce the same level of private networking support for Azure that we already have for AWS and GCP.&lt;/p&gt;
&lt;h1 id="what-is-azure-private-link"&gt;What is Azure Private Link?&lt;a class="anchor-link" aria-label="Link to heading" href="#what-is-azure-private-link"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/private-link/"&gt;Azure Private Link&lt;/a&gt; is a service that allows you to access VNets
in other Azure subscriptions and tenants securely through Azure’s network. This means that you can create a
&lt;a href="https://hosted.doltdb.com"&gt;Hosted Dolt&lt;/a&gt; deployment on Azure that is only accessible to your private Azure infrastructure,
and not accessible over the public internet.&lt;/p&gt;
&lt;h1 id="creating-a-deployment-with-azure-private-link"&gt;Creating a Deployment with Azure Private Link&lt;a class="anchor-link" aria-label="Link to heading" href="#creating-a-deployment-with-azure-private-link"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The first thing you will need to do is get the subscription ID of the Azure subscription that you want to use for your
private network (You can find this in the Azure portal). Once you have the subscription ID, create a new
&lt;a href="https://hosted.doltdb.com"&gt;Hosted Dolt&lt;/a&gt; deployment on Azure and enable the “Private deployment” option on the “Advanced”
tab of the deployment creation form. Then in the “Allowed subscription IDs” box enter the subscription ID(s) that you
want to allow access to your deployment.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/azpl-private-deployment.png/3f91ea8acc2765d125f344103f351d837be35af7358f3bab29ecd5d149f65246.webp" alt="Private Deployment"&gt;&lt;/p&gt;
&lt;p&gt;Once you have that filled out, click “Next” and review your deployment choices. Finally, click “Create Deployment” and
your instance will be up and running in minutes. Once your deployment is running, you will see the connections tab populated.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/azpl-connections-tab.png/ea3fe6603afd7178aa0b2c6c6888803c860d335ba81f4fa2dd79e27bb675b3a3.webp" alt="Connections Tab"&gt;&lt;/p&gt;
&lt;p&gt;And the “Azure Private Link Networking” section of the connections tab will show you the information you will need to
connect your private Azure infrastructure to your &lt;a href="https://hosted.doltdb.com"&gt;Hosted Dolt&lt;/a&gt; deployment.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/azpl-azure-private-link-networking.png/0d99904e90b1c2937de67f46bd6ffc0be0976d3578631a5aa793554f612576ca.webp" alt="Azure Private Link Networking"&gt;&lt;/p&gt;
&lt;h1 id="connecting-to-your-private-deployment"&gt;Connecting to your Private Deployment&lt;a class="anchor-link" aria-label="Link to heading" href="#connecting-to-your-private-deployment"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;By taking the information from the “Azure Private Link Networking” section of the connections tab, you can connect
your private Azure infrastructure using the web portal, Azure CLI, or you could use Terraform. I won’t go through
the web portal, but I will cover the Azure CLI and Terraform options.&lt;/p&gt;
&lt;h2 id="connecting-your-infrastructure-with-the-azure-cli"&gt;Connecting your Infrastructure with the Azure CLI&lt;a class="anchor-link" aria-label="Link to heading" href="#connecting-your-infrastructure-with-the-azure-cli"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In order to connect your infrastructure you will need the region, resource group, virtual network, and subnet of the
private network that you want to connect to your deployment.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;RESOURCE_GROUP&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;"my-resource-group"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;REGION&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;"eastus2"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;VNET&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;"my-vnet"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;SUBNET&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;"my-subnet"&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;then we will take the information from the “Azure Private Link Networking” section of the connections tab&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;PRIVATE_LINK_SERVICE_ID&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;"/subscriptions/01234567-89ab-cdef-fedc-ba9876543210/resourceGroups/networking-dev/providers/Microsoft.Network/privateLinkServices/pls-01234567-89ab-cdef-fedc-ba9876543210"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;ENDPOINT_NAME&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;"test-az-priv"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;URL&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;"test-az-priv.pls.dbs.hosted.doltdb.com"&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that information you need to create an Azure “Private Endpoint” and then set up DNS resolution for the private
endpoint so that you can connect to your deployment using the url provided in the “Azure Private Link Networking” section
of the connections tab.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;# Create primary&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;az&lt;/span&gt;&lt;span&gt; network&lt;/span&gt;&lt;span&gt; private-endpoint&lt;/span&gt;&lt;span&gt; create&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --resource-group&lt;/span&gt;&lt;span&gt; "&lt;/span&gt;&lt;span&gt;$RESOURCE_GROUP&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --name&lt;/span&gt;&lt;span&gt; "dolt-${&lt;/span&gt;&lt;span&gt;ENDPOINT_NAME&lt;/span&gt;&lt;span&gt;}-private-endpoint"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --location&lt;/span&gt;&lt;span&gt; "&lt;/span&gt;&lt;span&gt;$REGION&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --vnet-name&lt;/span&gt;&lt;span&gt; "&lt;/span&gt;&lt;span&gt;$VNET&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --subnet&lt;/span&gt;&lt;span&gt; "&lt;/span&gt;&lt;span&gt;$SUBNET&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --private-connection-resource-id&lt;/span&gt;&lt;span&gt; "&lt;/span&gt;&lt;span&gt;$PRIVATE_LINK_SERVICE_ID&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --connection-name&lt;/span&gt;&lt;span&gt; "dolt-${&lt;/span&gt;&lt;span&gt;ENDPOINT_NAME&lt;/span&gt;&lt;span&gt;}-connection"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;# Retrieve private IP from the endpoint NIC&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;PE_NIC_ID&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span&gt;az&lt;/span&gt;&lt;span&gt; network&lt;/span&gt;&lt;span&gt; private-endpoint&lt;/span&gt;&lt;span&gt; show&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --resource-group&lt;/span&gt;&lt;span&gt; "&lt;/span&gt;&lt;span&gt;$RESOURCE_GROUP&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --name&lt;/span&gt;&lt;span&gt; "dolt-${&lt;/span&gt;&lt;span&gt;ENDPOINT_NAME&lt;/span&gt;&lt;span&gt;}-private-endpoint"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --query&lt;/span&gt;&lt;span&gt; "networkInterfaces[0].id"&lt;/span&gt;&lt;span&gt; -o&lt;/span&gt;&lt;span&gt; tsv&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;PE_IP&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span&gt;az&lt;/span&gt;&lt;span&gt; network&lt;/span&gt;&lt;span&gt; nic&lt;/span&gt;&lt;span&gt; show&lt;/span&gt;&lt;span&gt; --ids&lt;/span&gt;&lt;span&gt; "&lt;/span&gt;&lt;span&gt;$PE_NIC_ID&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --query&lt;/span&gt;&lt;span&gt; "ipConfigurations[0].privateIPAddress"&lt;/span&gt;&lt;span&gt; -o&lt;/span&gt;&lt;span&gt; tsv&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;# Create DNS zone and VNet link&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; az&lt;/span&gt;&lt;span&gt; network&lt;/span&gt;&lt;span&gt; private-dns&lt;/span&gt;&lt;span&gt; zone&lt;/span&gt;&lt;span&gt; create&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --resource-group&lt;/span&gt;&lt;span&gt; "&lt;/span&gt;&lt;span&gt;$RESOURCE_GROUP&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --name&lt;/span&gt;&lt;span&gt; "pls.dbs.hosted.doltdb.com"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;az&lt;/span&gt;&lt;span&gt; network&lt;/span&gt;&lt;span&gt; private-dns&lt;/span&gt;&lt;span&gt; link&lt;/span&gt;&lt;span&gt; vnet&lt;/span&gt;&lt;span&gt; create&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --resource-group&lt;/span&gt;&lt;span&gt; "&lt;/span&gt;&lt;span&gt;$RESOURCE_GROUP&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --zone-name&lt;/span&gt;&lt;span&gt; "pls.dbs.hosted.doltdb.com"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --name&lt;/span&gt;&lt;span&gt; "dolt-${&lt;/span&gt;&lt;span&gt;ENDPOINT_NAME&lt;/span&gt;&lt;span&gt;}-vnet-link"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --virtual-network&lt;/span&gt;&lt;span&gt; "&lt;/span&gt;&lt;span&gt;$VNET&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --registration-enabled&lt;/span&gt;&lt;span&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;# Register primary DNS&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;az&lt;/span&gt;&lt;span&gt; network&lt;/span&gt;&lt;span&gt; private-dns&lt;/span&gt;&lt;span&gt; record-set&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt; add-record&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --resource-group&lt;/span&gt;&lt;span&gt; "&lt;/span&gt;&lt;span&gt;$RESOURCE_GROUP&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --zone-name&lt;/span&gt;&lt;span&gt; "pls.dbs.hosted.doltdb.com"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --record-set-name&lt;/span&gt;&lt;span&gt; "&lt;/span&gt;&lt;span&gt;$ENDPOINT_NAME&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --ipv4-address&lt;/span&gt;&lt;span&gt; "&lt;/span&gt;&lt;span&gt;$PE_IP&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you should be able to connect to your deployment from your instances within the given VNet using the provided URL. If
you SSH onto one of your instances with the MySQL client installed, you can connect to your deployment using the MySQL
command provided on the “Connections” tab of your deployment.&lt;/p&gt;
&lt;p&gt;The process for connecting a read endpoint is very similar if you are using replication.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;READ_PRIVATE_LINK_SERVICE_ID&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;"/subscriptions/01234567-89ab-cdef-fedc-ba9876543210/resourceGroups/networking-dev/providers/Microsoft.Network/privateLinkServices/pls-read-01234567-89ab-cdef-fedc-ba9876543210"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;READ_ENDPOINT_NAME&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;"read-test-az-priv"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;READ_URL&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;"read-test-az-priv.pls.dbs.hosted.doltdb.com"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;az&lt;/span&gt;&lt;span&gt; network&lt;/span&gt;&lt;span&gt; private-endpoint&lt;/span&gt;&lt;span&gt; create&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --resource-group&lt;/span&gt;&lt;span&gt; "&lt;/span&gt;&lt;span&gt;$RESOURCE_GROUP&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --name&lt;/span&gt;&lt;span&gt; "dolt-${&lt;/span&gt;&lt;span&gt;READ_ENDPOINT_NAME&lt;/span&gt;&lt;span&gt;}-private-endpoint"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --location&lt;/span&gt;&lt;span&gt; "&lt;/span&gt;&lt;span&gt;$REGION&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --vnet-name&lt;/span&gt;&lt;span&gt; "&lt;/span&gt;&lt;span&gt;$VNET&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --subnet&lt;/span&gt;&lt;span&gt; "&lt;/span&gt;&lt;span&gt;$SUBNET&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --private-connection-resource-id&lt;/span&gt;&lt;span&gt; "&lt;/span&gt;&lt;span&gt;$READ_PRIVATE_LINK_SERVICE_ID&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --connection-name&lt;/span&gt;&lt;span&gt; "dolt-${&lt;/span&gt;&lt;span&gt;READ_ENDPOINT_NAME&lt;/span&gt;&lt;span&gt;}-connection"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;READ_PE_NIC_ID&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span&gt;az&lt;/span&gt;&lt;span&gt; network&lt;/span&gt;&lt;span&gt; private-endpoint&lt;/span&gt;&lt;span&gt; show&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --resource-group&lt;/span&gt;&lt;span&gt; "&lt;/span&gt;&lt;span&gt;$RESOURCE_GROUP&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --name&lt;/span&gt;&lt;span&gt; "dolt-${&lt;/span&gt;&lt;span&gt;READ_ENDPOINT_NAME&lt;/span&gt;&lt;span&gt;}-private-endpoint"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --query&lt;/span&gt;&lt;span&gt; "networkInterfaces[0].id"&lt;/span&gt;&lt;span&gt; -o&lt;/span&gt;&lt;span&gt; tsv&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;READ_PE_IP&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span&gt;az&lt;/span&gt;&lt;span&gt; network&lt;/span&gt;&lt;span&gt; nic&lt;/span&gt;&lt;span&gt; show&lt;/span&gt;&lt;span&gt; --ids&lt;/span&gt;&lt;span&gt; "&lt;/span&gt;&lt;span&gt;$READ_PE_NIC_ID&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --query&lt;/span&gt;&lt;span&gt; "ipConfigurations[0].privateIPAddress"&lt;/span&gt;&lt;span&gt; -o&lt;/span&gt;&lt;span&gt; tsv&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;az&lt;/span&gt;&lt;span&gt; network&lt;/span&gt;&lt;span&gt; private-dns&lt;/span&gt;&lt;span&gt; record-set&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt; add-record&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --resource-group&lt;/span&gt;&lt;span&gt; "&lt;/span&gt;&lt;span&gt;$RESOURCE_GROUP&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --zone-name&lt;/span&gt;&lt;span&gt; "pls.dbs.hosted.doltdb.com"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --record-set-name&lt;/span&gt;&lt;span&gt; "${&lt;/span&gt;&lt;span&gt;READ_ENDPOINT_NAME&lt;/span&gt;&lt;span&gt;}"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    --ipv4-address&lt;/span&gt;&lt;span&gt; "&lt;/span&gt;&lt;span&gt;$READ_PE_IP&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="terraform"&gt;Terraform&lt;a class="anchor-link" aria-label="Link to heading" href="#terraform"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The same thing can be accomplished with Terraform.  Here is an example Terraform configuration that will create a private
endpoint and set up DNS resolution for that endpoint. The “Variables” section of the configuration should be filled out
with the appropriate values for your deployment and private network. Many of these values may come from the output of other
Terraform configurations that manage your Azure infrastructure, or you could just fill them out manually.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="hcl"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;terraform&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  required_providers&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    azurerm&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      source  &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; "hashicorp/azurerm"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      version &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; "~&gt; 3.0"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;provider&lt;/span&gt;&lt;span&gt; "azurerm"&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  features&lt;/span&gt;&lt;span&gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;# ---------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;# Variables&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;# ---------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;variable&lt;/span&gt;&lt;span&gt; "resource_group"&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  type&lt;/span&gt;&lt;span&gt;        =&lt;/span&gt;&lt;span&gt; string&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  description&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; "Azure resource group to create the private endpoints in"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;variable&lt;/span&gt;&lt;span&gt; "region"&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  type&lt;/span&gt;&lt;span&gt;        =&lt;/span&gt;&lt;span&gt; string&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  description&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; "Azure region (e.g. eastus)"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;variable&lt;/span&gt;&lt;span&gt; "vnet"&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  type&lt;/span&gt;&lt;span&gt;        =&lt;/span&gt;&lt;span&gt; string&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  description&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; "Name of the VNet to attach the private endpoints to"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;variable&lt;/span&gt;&lt;span&gt; "subnet"&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  type&lt;/span&gt;&lt;span&gt;        =&lt;/span&gt;&lt;span&gt; string&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  description&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; "Name of the subnet within the VNet for the private endpoints"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;variable&lt;/span&gt;&lt;span&gt; "endpoint_name"&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  type&lt;/span&gt;&lt;span&gt;        =&lt;/span&gt;&lt;span&gt; string&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  description&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; "Hosted Dolt endpoint name (used to name Azure resources and DNS records)"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;variable&lt;/span&gt;&lt;span&gt; "read_endpoint_name"&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  type&lt;/span&gt;&lt;span&gt;        =&lt;/span&gt;&lt;span&gt; string&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  description&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; "Hosted Dolt read endpoint name (used to name Azure resources and DNS records)"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;variable&lt;/span&gt;&lt;span&gt; "private_link_service_id"&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  type&lt;/span&gt;&lt;span&gt;        =&lt;/span&gt;&lt;span&gt; string&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  description&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; "Resource ID of the primary Private Link Service"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;variable&lt;/span&gt;&lt;span&gt; "read_private_link_service_id"&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  type&lt;/span&gt;&lt;span&gt;        =&lt;/span&gt;&lt;span&gt; string&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  description&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; "Resource ID of the read-replica Private Link Service"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;# ---------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;# Data sources&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;# ---------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; "azurerm_subnet"&lt;/span&gt;&lt;span&gt; "endpoint_subnet"&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  name&lt;/span&gt;&lt;span&gt;                 =&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;subnet&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  virtual_network_name&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;vnet&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  resource_group_name&lt;/span&gt;&lt;span&gt;  =&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;resource_group&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;# ---------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;# Private endpoints&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;# ---------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;resource&lt;/span&gt;&lt;span&gt; "azurerm_private_endpoint"&lt;/span&gt;&lt;span&gt; "primary"&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  name&lt;/span&gt;&lt;span&gt;                =&lt;/span&gt;&lt;span&gt; "dolt-&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;endpoint_name&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;-private-endpoint"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  location&lt;/span&gt;&lt;span&gt;            =&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;region&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  resource_group_name&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;resource_group&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  subnet_id&lt;/span&gt;&lt;span&gt;           =&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;azurerm_subnet&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;endpoint_subnet&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  private_service_connection&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    name&lt;/span&gt;&lt;span&gt;                              =&lt;/span&gt;&lt;span&gt; "dolt-&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;endpoint_name&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;-connection"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    private_connection_resource_id&lt;/span&gt;&lt;span&gt;    =&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;private_link_service_id&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    is_manual_connection&lt;/span&gt;&lt;span&gt;              =&lt;/span&gt;&lt;span&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;resource&lt;/span&gt;&lt;span&gt; "azurerm_private_endpoint"&lt;/span&gt;&lt;span&gt; "read"&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  name&lt;/span&gt;&lt;span&gt;                =&lt;/span&gt;&lt;span&gt; "dolt-&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;read_endpoint_name&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;-private-endpoint"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  location&lt;/span&gt;&lt;span&gt;            =&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;region&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  resource_group_name&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;resource_group&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  subnet_id&lt;/span&gt;&lt;span&gt;           =&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;azurerm_subnet&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;endpoint_subnet&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  private_service_connection&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    name&lt;/span&gt;&lt;span&gt;                              =&lt;/span&gt;&lt;span&gt; "dolt-&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;read_endpoint_name&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;-connection"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    private_connection_resource_id&lt;/span&gt;&lt;span&gt;    =&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;read_private_link_service_id&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    is_manual_connection&lt;/span&gt;&lt;span&gt;              =&lt;/span&gt;&lt;span&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;# ---------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;# Private DNS zone and VNet link&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;# ---------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;resource&lt;/span&gt;&lt;span&gt; "azurerm_private_dns_zone"&lt;/span&gt;&lt;span&gt; "dolt"&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  name&lt;/span&gt;&lt;span&gt;                =&lt;/span&gt;&lt;span&gt; "pls.dbs.hosted.doltdb.com"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  resource_group_name&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;resource_group&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;resource&lt;/span&gt;&lt;span&gt; "azurerm_private_dns_zone_virtual_network_link"&lt;/span&gt;&lt;span&gt; "dolt"&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  name&lt;/span&gt;&lt;span&gt;                  =&lt;/span&gt;&lt;span&gt; "dolt-&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;endpoint_name&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;-vnet-link"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  resource_group_name&lt;/span&gt;&lt;span&gt;   =&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;resource_group&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  private_dns_zone_name&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; azurerm_private_dns_zone&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;dolt&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  virtual_network_id&lt;/span&gt;&lt;span&gt;    =&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;azurerm_subnet&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;endpoint_subnet&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;virtual_network_id&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  registration_enabled&lt;/span&gt;&lt;span&gt;  =&lt;/span&gt;&lt;span&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;# ---------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;# DNS A records&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;# ---------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;resource&lt;/span&gt;&lt;span&gt; "azurerm_private_dns_a_record"&lt;/span&gt;&lt;span&gt; "primary"&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  name&lt;/span&gt;&lt;span&gt;                =&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;endpoint_name&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  zone_name&lt;/span&gt;&lt;span&gt;           =&lt;/span&gt;&lt;span&gt; azurerm_private_dns_zone&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;dolt&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  resource_group_name&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;resource_group&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ttl&lt;/span&gt;&lt;span&gt;                 =&lt;/span&gt;&lt;span&gt; 300&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  records&lt;/span&gt;&lt;span&gt;             =&lt;/span&gt;&lt;span&gt; [azurerm_private_endpoint&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;primary&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;private_service_connection[&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;private_ip_address]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;resource&lt;/span&gt;&lt;span&gt; "azurerm_private_dns_a_record"&lt;/span&gt;&lt;span&gt; "read"&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  name&lt;/span&gt;&lt;span&gt;                =&lt;/span&gt;&lt;span&gt; "&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;read_endpoint_name&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  zone_name&lt;/span&gt;&lt;span&gt;           =&lt;/span&gt;&lt;span&gt; azurerm_private_dns_zone&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;dolt&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  resource_group_name&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;resource_group&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ttl&lt;/span&gt;&lt;span&gt;                 =&lt;/span&gt;&lt;span&gt; 300&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  records&lt;/span&gt;&lt;span&gt;             =&lt;/span&gt;&lt;span&gt; [azurerm_private_endpoint&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;read&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;private_service_connection[&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;private_ip_address]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id="conclusion"&gt;Conclusion&lt;a class="anchor-link" aria-label="Link to heading" href="#conclusion"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://hosted.doltdb.com"&gt;Hosted Dolt&lt;/a&gt; now supports Azure Private Link. You can create a new &lt;a href="https://hosted.doltdb.com"&gt;Hosted Dolt&lt;/a&gt;
deployment on Azure with Private Link support in just a few clicks. If you have any questions about using &lt;a href="https://hosted.doltdb.com"&gt;Hosted Dolt&lt;/a&gt;
on Azure, or any other cloud provider, or if you have feedback or feature requests, please join our &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;Discord&lt;/a&gt; and let us know.&lt;/p&gt;</content:encoded>
      <dc:creator>Brian Hendriks</dc:creator>
      <category>hosted</category>
      <category>feature release</category>
    </item>
    <item>
      <title>Database Insurance</title>
      <link>https://dolthub.com/blog/2026-05-04-database-insurance/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-05-04-database-insurance/</guid>
      <description>Use a Dolt replica for database insurance against catastrophe or more mundane bad writes. In the human operator era, a Dolt replica was nice to have. In the agentic operator era, a Dolt replica is essential.</description>
      <pubDate>Mon, 04 May 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;Did you know &lt;a href="https://www.doltdb.com"&gt;Dolt&lt;/a&gt; and &lt;a href="https://www.doltgres.com"&gt;Doltgres&lt;/a&gt; can be &lt;a href="https://www.dolthub.com/blog/2023-03-15-getting-started-versioned-mysql-replica/"&gt;run as replicas&lt;/a&gt; to your existing MySQL, MariaDB, or Postgres databases? In this mode, Dolt acts as database insurance. Each transaction commit on your primary becomes a Dolt commit on your replica, preserving the history of your database in Dolt. You can use Dolt’s version control functionality on your replica for &lt;a href="https://www.dolthub.com/blog/2022-09-23-dolt-rollback-options/"&gt;all manner of rollback&lt;/a&gt;, including complex reverse patches of multiple transactions.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/this-is-fine.png/61736ebe94d4d0c9b65b8a311b6b4af5637c8c844953d5c95e4445049f7b0f28.webp" alt="Dolt. This is fine."&gt;&lt;/p&gt;
&lt;p&gt;Database insurance is becoming all the more important with the threat of agents going off the rails. It seems like not a month goes by without another “an agent deleted my database” story. Dolt can protect you from rogue agents without switching out your primary. Just add a Dolt replica. This article explains.&lt;/p&gt;
&lt;h1 id="agents-delete-databases"&gt;Agents Delete Databases&lt;a class="anchor-link" aria-label="Link to heading" href="#agents-delete-databases"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This is no longer hypothetical. Agents delete databases.&lt;/p&gt;
&lt;p&gt;Last week, &lt;a href="https://www.tomshardware.com/tech-industry/artificial-intelligence/claude-powered-ai-coding-agent-deletes-entire-company-database-in-9-seconds-backups-zapped-after-cursor-tool-powered-by-anthropics-claude-goes-rogue"&gt;Pocket’s Claude-powered coding agent turned a staging task into a production incident&lt;/a&gt;. It deleted the company database and the attached backups in one shot. This is the cleanest possible example of the new failure mode: give an agent broad infra access and eventually it will speedrun your disaster recovery plan.&lt;/p&gt;
&lt;p&gt;In March, Alexey Grigorev asked Claude to help clean up AWS resources and &lt;a href="https://alexeyondata.substack.com/p/how-i-dropped-our-production-database"&gt;got an unexpected terraform destroy adventure instead&lt;/a&gt;. Production database gone. Snapshots gone. Support upgraded mid-incident. It reads like a normal ops postmortem except the culprit was an agent with cloud credentials.&lt;/p&gt;
&lt;p&gt;And in July last year, &lt;a href="https://www.pcmag.com/news/vibe-coding-fiasco-replite-ai-agent-goes-rogue-deletes-company-database"&gt;after Replit’s agent deleted a database&lt;/a&gt;, Replit’s CEO said the lesson was that agents should not have access to production databases. Fair enough. But is that achievable? Agents are going to find their way into production workflows, whether through direct SQL, admin tools, or application APIs. The practical question is not whether mistakes will happen but rather how much damage is done when they do.&lt;/p&gt;
&lt;p&gt;These stories get attention because they are spectacular. “Entire company database deleted in nine seconds” is a headline. But the underlying issue is not new. Any tool, human- or agent-driven, that has production credentials, broad access, and enough autonomy to make a lot of changes very quickly is dangerous.&lt;/p&gt;
&lt;p&gt;Databases were already at-risk. Agents just increased the blast radius.&lt;/p&gt;
&lt;p&gt;The old production failure mode was a tired human typing &lt;code&gt;DROP TABLE&lt;/code&gt; into the wrong terminal. The new production failure mode is an enthusiastic agent with API keys, shell access, a task list, and a limited context window.&lt;/p&gt;
&lt;h1 id="agents-write-junk"&gt;Agents Write Junk&lt;a class="anchor-link" aria-label="Link to heading" href="#agents-write-junk"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Outright deletion is the catastrophe case. It is easy to notice. It makes the news. Much more common is quiet failure when an agent writes junk to production.&lt;/p&gt;
&lt;p&gt;Maybe it backfills the wrong values. Maybe it misinterprets a schema. Maybe it “fixes” a bug by overwriting a field everywhere. Maybe it makes a long sequence of individually valid writes that are collectively nonsense. In many cases the agent is not even talking SQL directly. It is calling your production API, which is often worse because the damage looks like legitimate application traffic. I would guess for every “the agent deleted my database” story, there are hundreds of “the agent wrote bad data into production” stories.&lt;/p&gt;
&lt;p&gt;A recent article on the subject, &lt;a href="https://arpitbhayani.me/blogs/defensive-databases/"&gt;“Databases Were Not Designed For This”&lt;/a&gt; by Arpit Bhayani, generated &lt;a href="https://news.ycombinator.com/item?id=47897140"&gt;a lively Hacker News discussion&lt;/a&gt;. Arpit’s point is that databases were built for boring callers: deterministic apps, reviewed writes, short-lived connections, obvious failures. Agents break every one of those assumptions at once, so a bunch of database hygiene practices that were once “nice to have” — statement timeouts, idempotency keys, soft deletes, append-only logs, role-per-agent, query tagging, the works — suddenly become load-bearing infrastructure. I think that framing is right. The database is no longer talking to careful application code but to an agent who must fix the issue before its context fills up.&lt;/p&gt;
&lt;p&gt;This is where normal backups start to feel insufficient. Backups are great for disaster recovery. They are less great for “between 2:13 PM and 2:21 PM, the agent wrote garbage into three related tables, and I need to surgically undo those writes specifically”.&lt;/p&gt;
&lt;p&gt;That is a version control problem, and Dolt is the world’s &lt;a href="https://www.dolthub.com/blog/2022-08-04-database-versioning/"&gt;first and only version-controlled database&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id="protect-yourself"&gt;Protect Yourself&lt;a class="anchor-link" aria-label="Link to heading" href="#protect-yourself"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The easiest way to get database insurance is to run a Dolt replica on a separate host. You keep your existing primary. MySQL stays MySQL. MariaDB stays MariaDB. Postgres stays Postgres. Dolt or Doltgres sits downstream as a replica, ingesting &lt;code&gt;binlog&lt;/code&gt; or WAL changes and turning each committed transaction into a durable Dolt commit.&lt;/p&gt;
&lt;p&gt;Setup is the same basic shape as standard replication. No application rewrite. No cutover. No “replace your database with our database” project. Just add a replica.&lt;/p&gt;
&lt;p&gt;The result is useful immediately. You get:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A continuously updated copy of production.&lt;/li&gt;
&lt;li&gt;A commit history of every transaction.&lt;/li&gt;
&lt;li&gt;Diffs over time.&lt;/li&gt;
&lt;li&gt;Branches if you need to experiment.&lt;/li&gt;
&lt;li&gt;Rollback tools much more expressive than “restore last night’s backup”.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the pre-agent era, this was nice to have. With Claude and Codex in all your engineer’s hands, it looks more like a necessity.&lt;/p&gt;
&lt;h2 id="catastrophe"&gt;Catastrophe&lt;a class="anchor-link" aria-label="Link to heading" href="#catastrophe"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Backups are still your number one defense here. If a machine dies, a region disappears, or an attacker wipes out infrastructure, backups are what save you. A Dolt replica is defense in depth.&lt;/p&gt;
&lt;p&gt;It gives you another live copy of the database and a detailed transaction history. If your primary gets destroyed by a rogue agent, the Dolt replica can tell you exactly what happened and when. If you push that replica to DoltHub or another remote, you now have true off-host safety with different access credentials as well.&lt;/p&gt;
&lt;p&gt;This is the right layering:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Backups for disaster recovery.&lt;/li&gt;
&lt;li&gt;Replication for availability.&lt;/li&gt;
&lt;li&gt;Dolt replication for history, auditability, and surgical undo.&lt;/li&gt;
&lt;li&gt;Dolt remote as disaster recovery if all else fails.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You want all four.&lt;/p&gt;
&lt;h2 id="bad-writes"&gt;Bad Writes&lt;a class="anchor-link" aria-label="Link to heading" href="#bad-writes"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Bad writes are where a Dolt replica really shines.&lt;/p&gt;
&lt;p&gt;First, find the bad writes. Use &lt;a href="https://dolthub.com/docs/sql-reference/version-control/dolt-system-tables#dolt_log"&gt;&lt;code&gt;dolt_log&lt;/code&gt;&lt;/a&gt; to identify the suspicious time window or commit range. Use &lt;a href="https://dolthub.com/docs/sql-reference/version-control/dolt-sql-functions#dolt_diff"&gt;&lt;code&gt;dolt_diff()&lt;/code&gt;&lt;/a&gt; to inspect exactly what changed. Because the writes are preserved as commits, you are not guessing. You are looking at history.&lt;/p&gt;
&lt;p&gt;Then undo them on &lt;a href="https://dolthub.com/docs/sql-reference/version-control/branches"&gt;a branch&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Sometimes a simple &lt;a href="https://dolthub.com/docs/sql-reference/version-control/dolt-sql-procedures#dolt_revert"&gt;&lt;code&gt;dolt_revert()&lt;/code&gt;&lt;/a&gt; is enough. Other times, you want to reverse a sequence of commits or a custom patch that keeps the good changes and removes only the bad ones. Dolt gives you those tools. Once you have the corrective patch, you can get the SQL you need to apply to your primary with &lt;a href="https://dolthub.com/docs/sql-reference/version-control/dolt-sql-functions#dolt_patch"&gt;&lt;code&gt;dolt_patch()&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is a much better story than:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Restore backup to staging.&lt;/li&gt;
&lt;li&gt;Diff it manually against production.&lt;/li&gt;
&lt;li&gt;Write custom SQL.&lt;/li&gt;
&lt;li&gt;Hope you found all the bad rows.&lt;/li&gt;
&lt;li&gt;Hope you didn’t revert good writes too.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;With Dolt, the database history is already organized into commits. That makes complex rollback possible.&lt;/p&gt;
&lt;p&gt;That is what “database insurance” means in practice. Not just “I have a copy somewhere”, but “I can understand what happened and undo it precisely”.&lt;/p&gt;
&lt;h1 id="conclusion"&gt;Conclusion&lt;a class="anchor-link" aria-label="Link to heading" href="#conclusion"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Use a Dolt replica for database insurance against catastrophe or more mundane bad writes. In the human operator era, a Dolt replica was nice to have. In the agentic operator era, a Dolt replica is essential. Questions? Come by &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;our Discord&lt;/a&gt;. We’re happy to help get your replica set up.&lt;/p&gt;</content:encoded>
      <dc:creator>Tim Sehn</dc:creator>
      <category>dolt</category>
      <category>doltgres</category>
      <category>use case</category>
    </item>
    <item>
      <title>Announcing Functional Indexes in Dolt</title>
      <link>https://dolthub.com/blog/2026-04-29-announcing-functional-indexes-in-dolt/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-04-29-announcing-functional-indexes-in-dolt/</guid>
      <description>Dolt now supports functional indexes, allowing you to index expressions and function results for faster queries on computed values.</description>
      <pubDate>Wed, 29 Apr 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;&lt;a href="https://doltdb.com/"&gt;Dolt&lt;/a&gt; is the world’s first SQL database with Git-style version control built in. Dolt gives you all the power of SQL combined with the ability to branch, merge, diff, clone, and push your data, just like you would with source code in Git. Today we’re excited to announce that Dolt now supports &lt;strong&gt;functional indexes&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;Functional indexes have been part of &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/create-index.html#create-index-functional-key-parts"&gt;MySQL since MySQL 8.0&lt;/a&gt;. They’re not something every application needs, but when they are needed, they can have a &lt;strong&gt;big&lt;/strong&gt; impact on query performance, as we’ll see later in this post. This is a feature we’ve wanted to build for a long time, and after receiving a few customer requests for it, we decided to prioritize it. We’ve launched the initial support in Dolt and are now expanding that to add this feature to Doltgres, add additional syntax support, enable usage of the functional indexes in more queries, and fine tune performance.&lt;/p&gt;
&lt;p&gt;In this blog post, we’ll walk through what functional indexes are, how they work, how to use them, and see them in action.&lt;/p&gt;
&lt;h2 id="what-is-a-functional-index"&gt;What is a Functional Index?&lt;a class="anchor-link" aria-label="Link to heading" href="#what-is-a-functional-index"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A regular index stores the values of one or more columns and lets Dolt quickly look up rows by those raw column values. A functional index is similar, but instead of storing a column’s raw value, it stores the result of a function or expression applied to that column. That stored result is what gets indexed, so when a query contains the same expression in its &lt;code&gt;WHERE&lt;/code&gt; clause, Dolt can use the index to satisfy the query efficiently — without scanning the full table and evaluating the expression row by row.&lt;/p&gt;
&lt;p&gt;The syntax uses an extra set of parentheses to mark the expression:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;CREATE&lt;/span&gt;&lt;span&gt; INDEX&lt;/span&gt;&lt;span&gt; idx_lower_email&lt;/span&gt;&lt;span&gt; ON&lt;/span&gt;&lt;span&gt; users ((&lt;/span&gt;&lt;span&gt;LOWER&lt;/span&gt;&lt;span&gt;(email)));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The double parentheses are important — that’s how MySQL and Dolt distinguish a functional expression from a regular column reference inside an index definition.&lt;/p&gt;
&lt;h2 id="when-does-this-help"&gt;When Does This Help?&lt;a class="anchor-link" aria-label="Link to heading" href="#when-does-this-help"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let’s look at a common scenario for functional indexes. Imagine you have a &lt;code&gt;users&lt;/code&gt; table and you want to look up users by email address, but you don’t want &lt;code&gt;User@Example.COM&lt;/code&gt; and &lt;code&gt;user@example.com&lt;/code&gt; to be treated as different entries. There are several ways to handle this, including normalizing values to lowercase when filtering on them.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; FROM&lt;/span&gt;&lt;span&gt; users &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt; LOWER&lt;/span&gt;&lt;span&gt;(email) &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; LOWER&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'User@Example.COM'&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Without a functional index on &lt;code&gt;LOWER(email)&lt;/code&gt;, satisfying that query requires a full table scan. The database engine has to evaluate &lt;code&gt;LOWER(email)&lt;/code&gt; for every single row and compare it against your search value. On a large table, that’s going to be slow.&lt;/p&gt;
&lt;p&gt;A functional index solves this cleanly, without requiring you to store a redundant &lt;code&gt;email_lower&lt;/code&gt; column purely for indexing purposes.&lt;/p&gt;
&lt;p&gt;Other common cases for using a functional index include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Date part extraction&lt;/strong&gt; — index on &lt;code&gt;YEAR(created_at)&lt;/code&gt; or &lt;code&gt;MONTH(order_date)&lt;/code&gt; for reporting queries that filter by year or month&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JSON path extraction&lt;/strong&gt; — index on &lt;code&gt;JSON_UNQUOTE(JSON_EXTRACT(metadata, '$.type'))&lt;/code&gt; to speed up queries on specific fields inside a JSON column&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;String transformations&lt;/strong&gt; — indexing trimmed or normalized versions of values without duplicating the data in an extra column&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="getting-started"&gt;Getting Started&lt;a class="anchor-link" aria-label="Link to heading" href="#getting-started"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let’s see functional indexes in action. We’ll use the &lt;a href="https://www.dolthub.com/repositories/dolthub/employees"&gt;dolthub/employees&lt;/a&gt; database from DoltHub — a sample database with 300,024 employees and 443,308 title records, which gives us enough data to see a real difference in query performance.&lt;/p&gt;
&lt;p&gt;If you don’t have Dolt yet, &lt;a href="https://dolthub.com/docs/introduction/installation"&gt;install it here&lt;/a&gt;. Then clone the database:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sh"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; dolt&lt;/span&gt;&lt;span&gt; clone&lt;/span&gt;&lt;span&gt; dolthub/employees&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; cd&lt;/span&gt;&lt;span&gt; employees&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From here, you can run &lt;code&gt;dolt sql&lt;/code&gt; to start a SQL shell:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sh"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; dolt&lt;/span&gt;&lt;span&gt; sql&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;# Welcome to the DoltSQL shell.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;# Statements must be terminated with ';'.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;# "exit" or "quit" (or Ctrl-D) to exit. "\help" for help.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;employees/main&lt;/span&gt;&lt;span&gt;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then you can start exploring the database:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;employees&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; DESCRIBE employees;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;------------+---------------+------+-----+---------+-------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;| Field      | &lt;/span&gt;&lt;span&gt;Type&lt;/span&gt;&lt;span&gt;          | &lt;/span&gt;&lt;span&gt;Null&lt;/span&gt;&lt;span&gt; | &lt;/span&gt;&lt;span&gt;Key&lt;/span&gt;&lt;span&gt; | &lt;/span&gt;&lt;span&gt;Default&lt;/span&gt;&lt;span&gt; | Extra |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;------------+---------------+------+-----+---------+-------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;| emp_no     | &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;           | &lt;/span&gt;&lt;span&gt;NO&lt;/span&gt;&lt;span&gt;   | PRI | &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;    |       |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;| birth_date | &lt;/span&gt;&lt;span&gt;date&lt;/span&gt;&lt;span&gt;          | &lt;/span&gt;&lt;span&gt;NO&lt;/span&gt;&lt;span&gt;   |     | &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;    |       |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;| first_name | &lt;/span&gt;&lt;span&gt;varchar&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;14&lt;/span&gt;&lt;span&gt;)   | &lt;/span&gt;&lt;span&gt;NO&lt;/span&gt;&lt;span&gt;   |     | &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;    |       |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;| last_name  | &lt;/span&gt;&lt;span&gt;varchar&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;16&lt;/span&gt;&lt;span&gt;)   | &lt;/span&gt;&lt;span&gt;NO&lt;/span&gt;&lt;span&gt;   |     | &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;    |       |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;| gender     | enum(&lt;/span&gt;&lt;span&gt;'M'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;'F'&lt;/span&gt;&lt;span&gt;) | &lt;/span&gt;&lt;span&gt;NO&lt;/span&gt;&lt;span&gt;   |     | &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;    |       |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;| hire_date  | &lt;/span&gt;&lt;span&gt;date&lt;/span&gt;&lt;span&gt;          | &lt;/span&gt;&lt;span&gt;NO&lt;/span&gt;&lt;span&gt;   |     | &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;    |       |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;------------+---------------+------+-----+---------+-------+&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Out of the box, the only index is the primary key on &lt;code&gt;emp_no&lt;/code&gt;. There’s no index on &lt;code&gt;last_name&lt;/code&gt;. Suppose we want to find all employees by last name, but we need the search to be case-insensitive — the data was imported from multiple sources and the casing isn’t consistent. We write:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; emp_no, first_name, last_name &lt;/span&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; employees &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt; LOWER&lt;/span&gt;&lt;span&gt;(last_name) &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 'facello'&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="without-a-functional-index"&gt;Without a Functional Index&lt;a class="anchor-link" aria-label="Link to heading" href="#without-a-functional-index"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let’s look at the query plan Dolt uses when there’s no index. We’ll use &lt;code&gt;EXPLAIN FORMAT=TREE&lt;/code&gt; which gives us Dolt’s detailed execution plan:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;employees&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; EXPLAIN FORMAT&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;TREE &lt;/span&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; emp_no, first_name, last_name &lt;/span&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; employees &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt; LOWER&lt;/span&gt;&lt;span&gt;(last_name) &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 'facello'&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;----------------------------------------------------------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;| plan                                                                       |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;----------------------------------------------------------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;| Project                                                                    |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|  ├─ columns: [employees.emp_no, employees.first_name, employees.last_name] |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|  └─ &lt;/span&gt;&lt;span&gt;Filter&lt;/span&gt;&lt;span&gt;                                                                 |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      ├─ (&lt;/span&gt;&lt;span&gt;lower&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;employees&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;last_name&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 'facello'&lt;/span&gt;&lt;span&gt;)                           |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      └─ &lt;/span&gt;&lt;span&gt;Table&lt;/span&gt;&lt;span&gt;                                                              |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|          ├─ &lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;: employees                                                |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|          └─ columns: [emp_no first_name last_name]                         |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;----------------------------------------------------------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;7&lt;/span&gt;&lt;span&gt; rows&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;00&lt;/span&gt;&lt;span&gt; sec) &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The plan is a Project of three columns, over a &lt;code&gt;Filter&lt;/code&gt; node on top of a full &lt;code&gt;Table&lt;/code&gt; scan. Dolt reads all 300,024 rows, evaluates &lt;code&gt;LOWER(last_name)&lt;/code&gt; on each one, and discards the ones that don’t match. Against 300K rows, on my Apple M1 Max laptop, this query takes about &lt;strong&gt;150ms&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id="adding-the-functional-index"&gt;Adding the Functional Index&lt;a class="anchor-link" aria-label="Link to heading" href="#adding-the-functional-index"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now let’s create the functional index, using the same syntax we covered earlier:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;employees&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; CREATE&lt;/span&gt;&lt;span&gt; INDEX&lt;/span&gt;&lt;span&gt; idx_lower_last_name &lt;/span&gt;&lt;span&gt;ON&lt;/span&gt;&lt;span&gt; employees ((&lt;/span&gt;&lt;span&gt;LOWER&lt;/span&gt;&lt;span&gt;(last_name)));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s look at the query plan for the same query and see if it’s different after creating a functional index on &lt;code&gt;LOWER(last_name)&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;employees&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; EXPLAIN FORMAT&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;TREE &lt;/span&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; emp_no, first_name, last_name &lt;/span&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; employees &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt; LOWER&lt;/span&gt;&lt;span&gt;(last_name) &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 'facello'&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;----------------------------------------------------------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;| plan                                                                       |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;----------------------------------------------------------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;| Project                                                                    |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|  ├─ columns: [employees.emp_no, employees.first_name, employees.last_name] |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|  └─ IndexedTableAccess(employees)                                          |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      ├─ &lt;/span&gt;&lt;span&gt;index&lt;/span&gt;&lt;span&gt;: [employees.!hidden!idx_lower_last_name!0!0]                 |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      └─ filters: [{[facello, facello]}]                                    |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;----------------------------------------------------------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt; rows&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;00&lt;/span&gt;&lt;span&gt; sec) &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The full table scan is gone. The plan now shows &lt;code&gt;IndexedTableAccess&lt;/code&gt; — Dolt goes directly to the index, seeks to the entries where the indexed expression equals &lt;code&gt;'facello'&lt;/code&gt;, and returns only those rows. The same query now takes &lt;strong&gt;under 2ms&lt;/strong&gt;, a &lt;strong&gt;~75x improvement&lt;/strong&gt; on a 300K row table.&lt;/p&gt;
&lt;p&gt;Indexed lookups into a large table are one of the areas where functional indexes can have a huge impact on query performance. Going from a full table scan to a direct lookup resulted in a 75x improvement for this query against 300k rows, and as the table gets bigger, the full table scan performance gets slower, while the indexed lookup performance remains constant, resulting in a larger and larger improvement.&lt;/p&gt;
&lt;h2 id="functional-indexes-in-joins"&gt;Functional Indexes in Joins&lt;a class="anchor-link" aria-label="Link to heading" href="#functional-indexes-in-joins"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The functional index doesn’t just speed up point lookups — it also improves queries where the filtered table is one side of a join. Let’s look at a query that finds the current job title for every employee with the last name ‘Facello’:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; f&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;emp_no&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;first_name&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;last_name&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;from_date&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; emp_no, first_name, last_name &lt;/span&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; employees &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt; LOWER&lt;/span&gt;&lt;span&gt;(last_name) &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 'facello'&lt;/span&gt;&lt;span&gt;) f&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;JOIN&lt;/span&gt;&lt;span&gt; titles t &lt;/span&gt;&lt;span&gt;ON&lt;/span&gt;&lt;span&gt; f&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;emp_no&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; t&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;emp_no&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt; t&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;to_date&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; '9999-01-01'&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="without-the-index"&gt;Without the Index&lt;a class="anchor-link" aria-label="Link to heading" href="#without-the-index"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let’s start off by looking at the query plan for this query, just like we did earlier. To remove the index we just created on the &lt;code&gt;employees&lt;/code&gt; table, we can run:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;employees&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; DROP&lt;/span&gt;&lt;span&gt; INDEX&lt;/span&gt;&lt;span&gt; idx_lower_last_name &lt;/span&gt;&lt;span&gt;ON&lt;/span&gt;&lt;span&gt; employees;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here’s the query plan:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;employees&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; EXPLAIN FORMAT&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;TREE&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    SELECT&lt;/span&gt;&lt;span&gt; f&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;emp_no&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;first_name&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;last_name&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;from_date&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    FROM&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; emp_no, first_name, last_name &lt;/span&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; employees &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt; LOWER&lt;/span&gt;&lt;span&gt;(last_name) &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 'facello'&lt;/span&gt;&lt;span&gt;) f&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    JOIN&lt;/span&gt;&lt;span&gt; titles t &lt;/span&gt;&lt;span&gt;ON&lt;/span&gt;&lt;span&gt; f&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;emp_no&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; t&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;emp_no&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    WHERE&lt;/span&gt;&lt;span&gt; t&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;to_date&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; '9999-01-01'&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;--------------------------------------------------------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;| plan                                                                     |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;--------------------------------------------------------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;| Project                                                                  |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|  ├─ columns: [f.emp_no, f.first_name, f.last_name, t.title, t.from_date] |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|  └─ LookupJoin                                                           |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      ├─ SubqueryAlias                                                    |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      │   ├─ &lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;: f                                                      |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      │   ├─ outerVisibility: false                                       |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      │   ├─ isLateral: false                                             |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      │   ├─ cacheable: true                                              |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      │   ├─ colSet: (&lt;/span&gt;&lt;span&gt;7&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;9&lt;/span&gt;&lt;span&gt;)                                                |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      │   ├─ tableId: &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;                                                   |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      │   └─ &lt;/span&gt;&lt;span&gt;Filter&lt;/span&gt;&lt;span&gt;                                                       |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      │       ├─ (&lt;/span&gt;&lt;span&gt;lower&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;employees&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;last_name&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 'facello'&lt;/span&gt;&lt;span&gt;)                 |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      │       └─ &lt;/span&gt;&lt;span&gt;Table&lt;/span&gt;&lt;span&gt;                                                    |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      │           ├─ &lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;: employees                                      |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      │           └─ columns: [emp_no first_name last_name]               |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      └─ &lt;/span&gt;&lt;span&gt;Filter&lt;/span&gt;&lt;span&gt;                                                           |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|          ├─ (&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;to_date&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; '9999-01-01'&lt;/span&gt;&lt;span&gt;)                                   |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|          └─ TableAlias(t)                                                |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|              └─ IndexedTableAccess(titles)                               |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|                  ├─ &lt;/span&gt;&lt;span&gt;index&lt;/span&gt;&lt;span&gt;: [titles.emp_no,titles.title,titles.from_date] |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|                  ├─ columns: [emp_no title from_date to_date]            |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|                  └─ keys: &lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;emp_no&lt;/span&gt;&lt;span&gt;                                       |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;--------------------------------------------------------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;22&lt;/span&gt;&lt;span&gt; rows&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;00&lt;/span&gt;&lt;span&gt; sec) &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The subquery on one side of the &lt;code&gt;LookupJoin&lt;/code&gt; does a full table scan of all 300K employees to find the Facello employees. Then, for each matching employee, it does a fast indexed lookup into the &lt;code&gt;titles&lt;/code&gt; table using the primary key. The bottleneck is that first full scan — the query runs in about &lt;strong&gt;150ms&lt;/strong&gt;. This is very similar performance to our first un-indexed query, which makes sense, because the most significant factor in the performance of both queries is the full table scan over the 300k items in the &lt;code&gt;employees&lt;/code&gt; table.&lt;/p&gt;
&lt;h3 id="with-the-index"&gt;With the Index&lt;a class="anchor-link" aria-label="Link to heading" href="#with-the-index"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Just like before, let’s create a functional index over &lt;code&gt;LOWER(last_name)&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;employees&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; CREATE&lt;/span&gt;&lt;span&gt; INDEX&lt;/span&gt;&lt;span&gt; idx_lower_last_name &lt;/span&gt;&lt;span&gt;ON&lt;/span&gt;&lt;span&gt; employees ((&lt;/span&gt;&lt;span&gt;LOWER&lt;/span&gt;&lt;span&gt;(last_name)));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let’s look at the query plan:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;employees&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; EXPLAIN FORMAT&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;TREE&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    SELECT&lt;/span&gt;&lt;span&gt; f&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;emp_no&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;first_name&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;last_name&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;from_date&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    FROM&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; emp_no, first_name, last_name &lt;/span&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; employees &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt; LOWER&lt;/span&gt;&lt;span&gt;(last_name) &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 'facello'&lt;/span&gt;&lt;span&gt;) f&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    JOIN&lt;/span&gt;&lt;span&gt; titles t &lt;/span&gt;&lt;span&gt;ON&lt;/span&gt;&lt;span&gt; f&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;emp_no&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; t&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;emp_no&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    WHERE&lt;/span&gt;&lt;span&gt; t&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;to_date&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; '9999-01-01'&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;----------------------------------------------------------------------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;| plan                                                                                   |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;----------------------------------------------------------------------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;| Project                                                                                |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|  ├─ columns: [f.emp_no, f.first_name, f.last_name, t.title, t.from_date]               |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|  └─ LookupJoin                                                                         |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      ├─ SubqueryAlias                                                                  |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      │   ├─ &lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;: f                                                                    |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      │   ├─ outerVisibility: false                                                     |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      │   ├─ isLateral: false                                                           |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      │   ├─ cacheable: true                                                            |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      │   ├─ colSet: (&lt;/span&gt;&lt;span&gt;15&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;17&lt;/span&gt;&lt;span&gt;)                                                            |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      │   ├─ tableId: &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;                                                                 |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      │   └─ Project                                                                    |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      │       ├─ columns: [employees.emp_no, employees.first_name, employees.last_name] |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      │       └─ IndexedTableAccess(employees)                                          |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      │           ├─ &lt;/span&gt;&lt;span&gt;index&lt;/span&gt;&lt;span&gt;: [employees.!hidden!idx_lower_last_name!0!0]                 |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      │           └─ filters: [{[facello, facello]}]                                    |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      └─ &lt;/span&gt;&lt;span&gt;Filter&lt;/span&gt;&lt;span&gt;                                                                         |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|          ├─ (&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;to_date&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; '9999-01-01'&lt;/span&gt;&lt;span&gt;)                                                 |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|          └─ TableAlias(t)                                                              |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|              └─ IndexedTableAccess(titles)                                             |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|                  ├─ &lt;/span&gt;&lt;span&gt;index&lt;/span&gt;&lt;span&gt;: [titles.emp_no,titles.title,titles.from_date]               |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|                  ├─ columns: [emp_no title from_date to_date]                          |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|                  └─ keys: &lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;emp_no&lt;/span&gt;&lt;span&gt;                                                     |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;----------------------------------------------------------------------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;22&lt;/span&gt;&lt;span&gt; rows&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;00&lt;/span&gt;&lt;span&gt; sec) &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The join structure is identical — a &lt;code&gt;LookupJoin&lt;/code&gt; with a per-employee index seek into &lt;code&gt;titles&lt;/code&gt; — but now the employees side uses &lt;code&gt;IndexedTableAccess&lt;/code&gt; with the functional index instead of a full table scan. Dolt resolves only the 186 matching employees before doing any join work at all, which brings the query down to &lt;strong&gt;under 2ms&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Here’s a sample of the results:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;--------+------------+-----------+------------------+------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;| emp_no | first_name | last_name | title            | from_date  |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;--------+------------+-----------+------------------+------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|  &lt;/span&gt;&lt;span&gt;10001&lt;/span&gt;&lt;span&gt; | Georgi     | Facello   | Senior Engineer  | &lt;/span&gt;&lt;span&gt;1986&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;06&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;26&lt;/span&gt;&lt;span&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|  &lt;/span&gt;&lt;span&gt;15346&lt;/span&gt;&lt;span&gt; | Kirk       | Facello   | Senior Engineer  | &lt;/span&gt;&lt;span&gt;1997&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;12&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;06&lt;/span&gt;&lt;span&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|  &lt;/span&gt;&lt;span&gt;15685&lt;/span&gt;&lt;span&gt; | Kasturi    | Facello   | Senior Engineer  | &lt;/span&gt;&lt;span&gt;1997&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;03&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;13&lt;/span&gt;&lt;span&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|  &lt;/span&gt;&lt;span&gt;18686&lt;/span&gt;&lt;span&gt; | Kwangyoen  | Facello   | Senior Staff     | &lt;/span&gt;&lt;span&gt;1994&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;05&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;02&lt;/span&gt;&lt;span&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|  &lt;/span&gt;&lt;span&gt;21947&lt;/span&gt;&lt;span&gt; | Taisook    | Facello   | Senior Engineer  | &lt;/span&gt;&lt;span&gt;1998&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;08&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;28&lt;/span&gt;&lt;span&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|  &lt;/span&gt;&lt;span&gt;23938&lt;/span&gt;&lt;span&gt; | Nahum      | Facello   | Senior Engineer  | &lt;/span&gt;&lt;span&gt;1985&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;09&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;15&lt;/span&gt;&lt;span&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|  &lt;/span&gt;&lt;span&gt;24774&lt;/span&gt;&lt;span&gt; | Uno        | Facello   | Senior Staff     | &lt;/span&gt;&lt;span&gt;2002&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;05&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;15&lt;/span&gt;&lt;span&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|  &lt;/span&gt;&lt;span&gt;24806&lt;/span&gt;&lt;span&gt; | Charmane   | Facello   | Senior Engineer  | &lt;/span&gt;&lt;span&gt;1999&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;03&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;27&lt;/span&gt;&lt;span&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|  &lt;/span&gt;&lt;span&gt;25955&lt;/span&gt;&lt;span&gt; | Christoph  | Facello   | Technique Leader | &lt;/span&gt;&lt;span&gt;1995&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;08&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;21&lt;/span&gt;&lt;span&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|  &lt;/span&gt;&lt;span&gt;27732&lt;/span&gt;&lt;span&gt; | Girolamo   | Facello   | Senior Engineer  | &lt;/span&gt;&lt;span&gt;1986&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;06&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;30&lt;/span&gt;&lt;span&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;| ...    |            |           |                  |            |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;--------+------------+-----------+------------------+------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;186&lt;/span&gt;&lt;span&gt; rows&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="functional-indexes-and-dolt-branches"&gt;Functional Indexes and Dolt Branches&lt;a class="anchor-link" aria-label="Link to heading" href="#functional-indexes-and-dolt-branches"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One thing worth noting for Dolt users: functional indexes are part of your schema, and like everything else in Dolt, your schema lives on branches. If you create a functional index on a feature branch, it exists only on that branch until you merge it. Schema changes, including functional index additions and removals, show up in &lt;code&gt;dolt diff&lt;/code&gt; and in pull requests on DoltHub, so your team can review index changes the same way they review any other change to the database.&lt;/p&gt;
&lt;p&gt;This means you can safely experiment with different indexing strategies on isolated branches and only merge the ones that work the way you need them to. It also allows you to offload the work to build the initial index to be performed in the branch, then Dolt can often reuse the index data directly and update it from data differences when you merge it into another branch.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How It Works&lt;a class="anchor-link" aria-label="Link to heading" href="#how-it-works"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Under the hood, Dolt implements functional indexes the same way MySQL does: by automatically creating a hidden virtual generated column that stores the result of the expression, then building a regular index on that hidden column. The virtual column is entirely transparent — it won’t appear in &lt;code&gt;SHOW COLUMNS&lt;/code&gt; or &lt;code&gt;SELECT *&lt;/code&gt; output. Dolt handles computing and maintaining it automatically as rows are inserted and updated.&lt;/p&gt;
&lt;h2 id="future-enhancements"&gt;Future Enhancements&lt;a class="anchor-link" aria-label="Link to heading" href="#future-enhancements"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Our initial release of functional index support includes the features that customers told us they needed from functional indexes (e.g. support for a single functional expression, using functional indexes in joins and filters). Now that those customer use cases are unblocked, we’re following up with a few more enhancements:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Multiple expressions per functional index.&lt;/strong&gt; Each functional index currently supports exactly one functional expression. If you need indexes on multiple expressions, you’ll need a separate index for each one. This was an expedient way to build what our first customers needed, and we’re already working on expanding support for mixing functional expressions with column references in an index, and using multiple functional expressions in a single index. We expect to deliver this as a quick follow-up to the initial support.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Doltgres support.&lt;/strong&gt; &lt;a href="https://www.doltgres.com/"&gt;Doltgres is our PostgreSQL-compatible database engine&lt;/a&gt;. Dolt has a head start of a few years over Doltgres, but Doltgres is catching up quickly and moving towards a 1.0 milestone. We’ve already started working on enabling functional index support in Doltgres and expect to deliver this as another fast follow-up.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Use functional indexes for more queries.&lt;/strong&gt; Today, functional indexes are used in joins and filters to speed up queries. These are the main places where functional index speed up queries, but there are other places where functional indexes could also be used, such as to optimize sorting. For example, a query like &lt;code&gt;SELECT * FROM users ORDER BY LOWER(email)&lt;/code&gt; won’t yet use the functional index to avoid a sort.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Performance testing.&lt;/strong&gt; Our initial performance testing for functional indexes shows a dramatic speed up for queries that performed a full table scan before being optimized with a functional index. When compared to MySQL performance for those same queries and same index, Dolt matches or beats MySQL’s performance for those queries. We’ll be adding &lt;a href="https://www.dolthub.com/blog/2025-12-04-dolt-is-as-fast-as-mysql/"&gt;sysbench tests&lt;/a&gt; to track query performance with functional indexes and digging into other cases, like JSON usage with functional indexes to continue tuning performance.&lt;/p&gt;
&lt;h2 id="wrap-up"&gt;Wrap Up&lt;a class="anchor-link" aria-label="Link to heading" href="#wrap-up"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The ability to index functional expressions on your data and then use those precomputed values to speed up joins and filtering in queries is a big feature for Dolt. These functional indexes can turn slow table scans over large tables into lightning fast point lookups. In the examples we walked through here, on a table with 300k rows, a functional index improved performance by 75x. The performance impact gets larger as the table size grows.&lt;/p&gt;
&lt;p&gt;If you want to dig deeper into how Dolt uses indexes and plans joins, check out Nick’s recent post on &lt;a href="https://www.dolthub.com/blog/2026-02-27-index-selection-for-join-queries/"&gt;improving index selection for join queries&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you haven’t tried Dolt yet, &lt;a href="https://dolthub.com/docs/introduction/installation"&gt;install it here&lt;/a&gt; and give functional indexes a spin! If you have questions or feedback, swing by our &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;Discord server&lt;/a&gt; or &lt;a href="https://github.com/dolthub/dolt/issues/new"&gt;file an issue on GitHub&lt;/a&gt;. We love hearing from customers and are always happy to prioritize features or bug fixes that customers tell us they need.&lt;/p&gt;</content:encoded>
      <dc:creator>Jason Fulghum</dc:creator>
      <category>feature release</category>
      <category>dolt</category>
    </item>
    <item>
      <title>Why DoltLite?</title>
      <link>https://dolthub.com/blog/2026-04-27-why-doltlite/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-04-27-why-doltlite/</guid>
      <description>DoltLite redefines what is possible for local-first software. You can now use Git-style merges instead of CRDTs in sync engines.</description>
      <pubDate>Mon, 27 Apr 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;We shipped &lt;a href="https://github.com/dolthub/doltlite"&gt;DoltLite&lt;/a&gt;, a version-controlled SQLite. We already have &lt;a href="https://www.doltdb.com"&gt;Dolt&lt;/a&gt;. Dolt is free and open source. Dolt clones, branches, pushes, pulls, and merges. Why ship a second product? This article explains.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/dolthub/doltlite"&gt;&lt;img src="https://static.dolthub.com/blogimages/doltlite-logo.png/187cf16f99ea27a3199258d56892a3869221f9c9af529beeaffba3990bfc3f47.webp" alt="DoltLite Logo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id="local-first-software"&gt;Local-first Software&lt;a class="anchor-link" aria-label="Link to heading" href="#local-first-software"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://www.inkandswitch.com/essay/local-first/"&gt;Local-first software&lt;/a&gt;, coined by Ink &amp;#x26; Switch in 2019, has inspired a lot of software, mostly based on SQLite. SQLite puts the “local” in “local-first”. SQLite delivers complex tabular data and SQL query power as a C-library, embeddable in any language.&lt;/p&gt;
&lt;p&gt;Local-first defines seven ideals:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Fast&lt;/li&gt;
&lt;li&gt;Multi-device&lt;/li&gt;
&lt;li&gt;Offline&lt;/li&gt;
&lt;li&gt;Collaboration&lt;/li&gt;
&lt;li&gt;Longevity&lt;/li&gt;
&lt;li&gt;Privacy&lt;/li&gt;
&lt;li&gt;User control&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;SQLite gives you “Fast”, “Offline”, “Privacy”, and “User Control”.&lt;/p&gt;
&lt;p&gt;How do you get “Multi-device” and “Collaboration” from SQLite? You need a sync engine. There’s been a number of sync engines based around SQLite in the over half-a-decade since Ink &amp;#x26; Switch published this essay:
&lt;a href="https://turso.tech/"&gt;Turso&lt;/a&gt;, &lt;a href="https://www.powersync.com/"&gt;Powersync&lt;/a&gt;, &lt;a href="https://electric-sql.com/"&gt;ElectricSQL&lt;/a&gt;, and &lt;a href="https://github.com/vlcn-io/cr-sqlite"&gt;cr-sqlite&lt;/a&gt; to name a few.&lt;/p&gt;
&lt;p&gt;But, the fundamental problem with sync engines is “What do you do with conflicts?”. The &lt;a href="https://www.inkandswitch.com/essay/local-first/"&gt;Local-first software essay&lt;/a&gt; suggests Conflict Resistant Data Types (CRDTs) as the solution, rejecting Git because “Git has no capability for real-time, fine-grained collaboration, such as the automatic, instantaneous merging” and “other (non-text) file formats are treated as binary blobs that cannot meaningfully be edited or merged”.&lt;/p&gt;
&lt;p&gt;Enter &lt;a href="https://github.com/dolthub/doltlite"&gt;DoltLite&lt;/a&gt;, a version-controlled SQLite. DoltLite enables a new class of local-first application by supporting Git-style merging on tabular data directly accessible as a C-library.&lt;/p&gt;
&lt;h1 id="but-dolt"&gt;But Dolt?&lt;a class="anchor-link" aria-label="Link to heading" href="#but-dolt"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://www.doltdb.com"&gt;Dolt&lt;/a&gt; already existed and has been stable for years. Why not just use Dolt?&lt;/p&gt;
&lt;p&gt;Because Dolt is a server. To use Dolt from your application you stand up &lt;code&gt;dolt sql-server&lt;/code&gt;, point a MySQL client at port 3306, and talk wire protocol. That’s a fine model if you’re replacing MySQL or Postgres. It’s the wrong model for local-first.&lt;/p&gt;
&lt;p&gt;The whole point of local-first is the database lives on the user’s device. Asking the user to run a server defeats the purpose. Running a local server is a pain. There’s a process to manage, a port to not collide with, a daemon that can crash. SQLite has none of that. SQLite is a &lt;code&gt;.dylib&lt;/code&gt; your application links in. That’s the model local-first wants.&lt;/p&gt;
&lt;p&gt;DoltLite is that model with version control. People have been asking us for an embedded Dolt for years.&lt;/p&gt;
&lt;h1 id="sql-and-version-control-in-any-language"&gt;SQL and Version Control in Any Language&lt;a class="anchor-link" aria-label="Link to heading" href="#sql-and-version-control-in-any-language"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Dolt is written in Go. Go is great for a server. It is bad for a library you embed in someone else’s runtime, &lt;a href="https://www.dolthub.com/blog/2022-07-25-embedded/"&gt;unless it’s a Go runtime&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Go binaries are big. Go is awkward to link into iOS apps, Python C extensions, Ruby gems, Node addons, Erlang NIFs, and Rust crates. And Go’s WebAssembly (WASM) story produces multi-megabyte bundles with a runtime that doesn’t play well with the browser’s threading and storage primitives.&lt;/p&gt;
&lt;p&gt;C compiles to all of those. iOS, Android, Python, Ruby, Node, Rust, Erlang, and the one that matters most for local-first: a &lt;code&gt;.wasm&lt;/code&gt; bundle that runs inside a browser tab. &lt;a href="https://github.com/dolthub/doltlite#webassembly-extwasm"&gt;DoltLite compiles SQLite’s WASM target&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;WASM is what local-first looks like in 2026. The user opens a webpage. The webpage downloads a &lt;code&gt;.wasm&lt;/code&gt; file. The &lt;code&gt;.wasm&lt;/code&gt; is a full version-controlled SQL database backed by &lt;a href="https://developer.chrome.com/blog/sqlite-wasm-in-the-browser-backed-by-the-origin-private-file-system"&gt;the browser’s private filesystem&lt;/a&gt;. The user’s edits commit to a local branch. When they hit publish, the branch pushes to a DoltLite remote. When a teammate’s branch lands, the user pulls and merges.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;-- alice's laptop&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; dolt_clone(&lt;/span&gt;&lt;span&gt;'https://dolthub.com/team/users'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;'users.db'&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;INSERT INTO&lt;/span&gt;&lt;span&gt; users &lt;/span&gt;&lt;span&gt;VALUES&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;'alice'&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; dolt_commit(&lt;/span&gt;&lt;span&gt;'-Am'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;'add alice'&lt;/span&gt;&lt;span&gt;);                                       &lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; dolt_push(&lt;/span&gt;&lt;span&gt;'origin'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;'main'&lt;/span&gt;&lt;span&gt;);                                &lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;                                                                                &lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;-- bob's browser tab (WASM)                                        &lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; dolt_clone(&lt;/span&gt;&lt;span&gt;'https://dolthub.com/team/users'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;'users.db'&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;INSERT INTO&lt;/span&gt;&lt;span&gt; users &lt;/span&gt;&lt;span&gt;VALUES&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;'bob'&lt;/span&gt;&lt;span&gt;);                                          &lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; dolt_commit(&lt;/span&gt;&lt;span&gt;'-Am'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;'add bob'&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; dolt_pull(&lt;/span&gt;&lt;span&gt;'origin'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;'main'&lt;/span&gt;&lt;span&gt;);   &lt;/span&gt;&lt;span&gt;-- merges alice's commit                &lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; dolt_push(&lt;/span&gt;&lt;span&gt;'origin'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;'main'&lt;/span&gt;&lt;span&gt;);   &lt;/span&gt;&lt;span&gt;-- pushes the merged history &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No wire protocol. No port. No server. A C library call into a &lt;code&gt;.dylib&lt;/code&gt;, &lt;code&gt;.so&lt;/code&gt;, &lt;code&gt;.dll&lt;/code&gt;, or &lt;code&gt;.wasm&lt;/code&gt; you linked into your app. &lt;code&gt;dolt_push&lt;/code&gt; to share with everyone else holding a copy.&lt;/p&gt;
&lt;p&gt;In the example, Alice and Bob inserted different rows, so the merge was trivial. If they had both updated row two to different names, &lt;code&gt;dolt_pull&lt;/code&gt; would do what Git does: drop both versions into a &lt;code&gt;dolt_conflicts_users&lt;/code&gt; table and refuse to commit until a human picks. That’s the part CRDTs hide. For data with audit or rollback requirements, you want disagreement surfaced, not silently resolved.&lt;/p&gt;
&lt;p&gt;DoltLite is the local-first use case, with Git-style merging on structured data instead of CRDTs.&lt;/p&gt;
&lt;h1 id="try-doltlite"&gt;Try DoltLite&lt;a class="anchor-link" aria-label="Link to heading" href="#try-doltlite"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;All DoltLite needs is users. Have a local-first app you’ve been waiting to build because there was no Git-style sync model? Wait no longer. Questions? Bugs? Feature requests? Cut &lt;a href="https://github.com/dolthub/doltlite/issues"&gt;an issue&lt;/a&gt;. Otherwise, come by &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;our Discord&lt;/a&gt; to discuss. Meet me in the #doltlite🪶 channel.&lt;/p&gt;</content:encoded>
      <dc:creator>Tim Sehn</dc:creator>
      <category>doltlite</category>
      <category>use case</category>
    </item>
    <item>
      <title>How Dolt Represents and Evaluates Queries: A Case Study</title>
      <link>https://dolthub.com/blog/2026-04-21-how-dolt-represents-and-evaluates-queries/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-04-21-how-dolt-represents-and-evaluates-queries/</guid>
      <description>We look at a recent bug fix to understand how Dolt actually represents queries internally. It turns out, database engines and compilers have a lot in common.</description>
      <pubDate>Mon, 20 Apr 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;Want to know a cool secret about database engines? They’re literally the same thing as compilers.&lt;/p&gt;
&lt;p&gt;At my previous job, I worked on Google’s internal Java compiler. Now, I’m one of the developers of &lt;a href="https://github.com/dolthub/dolt"&gt;Dolt&lt;/a&gt;, the first version-controlled SQL database, as well as &lt;a href="https://github.com/dolthub/go-mysql-server/"&gt;go-mysql-server&lt;/a&gt;, the SQL engine that Dolt depends on.&lt;/p&gt;
&lt;p&gt;It turns out that the skills and techniques that I first learned while writing a compiler are the exact same techniques that Dolt uses in its database engine. And that’s because when you break it down, database engines are just a domain-specific compiler:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;General-purpose compilers turn human-readable source code into machine-readable programs that manipulate variables and produce side-effects.&lt;/li&gt;
&lt;li&gt;SQL engines turn human-readable SQL queries into machine-readable execution plans that manipulate table columns and produce a stream of rows.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most compiler concepts map directly onto database engines. &lt;a href="https://sqlite.org/opcode.html"&gt;Some database engines like SQLite even work by producing bytecode that executes in a special-purpose VM.&lt;/a&gt;. Dolt doesn’t do that, but it does create an &lt;a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree"&gt;abstract syntax tree&lt;/a&gt; almost exactly like one you would see in any other interpreted language.&lt;/p&gt;
&lt;p&gt;The main difference is that in most languages, evaluating a syntax tree produces a return value and side effects. In Dolt, evaluating a syntax tree produces an iterator. This also means that each intermediate node in the tree is an iterator defined in terms of one or more child iterators. This approach is often called the &lt;strong&gt;volcano model&lt;/strong&gt; or &lt;strong&gt;iterator model&lt;/strong&gt; of database engine design.&lt;/p&gt;
&lt;p&gt;This means that database engines can have the same types of bugs as traditional languages and a lot of the same thorns. We recently fixed a correctness issue in Dolt that does a good job demonstrating this. &lt;a href="https://github.com/dolthub/go-mysql-server/pull/3428"&gt;You can find the writeup and the fix here.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To trigger the incorrect behavior, you needed a query that looked like this.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;CREATE&lt;/span&gt;&lt;span&gt; TABLE&lt;/span&gt;&lt;span&gt; ab&lt;/span&gt;&lt;span&gt; (a &lt;/span&gt;&lt;span&gt;INT&lt;/span&gt;&lt;span&gt; PRIMARY KEY&lt;/span&gt;&lt;span&gt;, b &lt;/span&gt;&lt;span&gt;INT&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;CREATE&lt;/span&gt;&lt;span&gt; TABLE&lt;/span&gt;&lt;span&gt; three_pk&lt;/span&gt;&lt;span&gt; (pk1 &lt;/span&gt;&lt;span&gt;TINYINT&lt;/span&gt;&lt;span&gt;, pk2 &lt;/span&gt;&lt;span&gt;TINYINT&lt;/span&gt;&lt;span&gt;, pk3 &lt;/span&gt;&lt;span&gt;TINYINT&lt;/span&gt;&lt;span&gt;, col &lt;/span&gt;&lt;span&gt;TINYINT&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;PRIMARY KEY&lt;/span&gt;&lt;span&gt; (pk1, pk2, pk3));&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; FROM&lt;/span&gt;&lt;span&gt; ab &lt;/span&gt;&lt;span&gt;AS&lt;/span&gt;&lt;span&gt; ab1 &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt; EXISTS&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  SELECT&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; FROM&lt;/span&gt;&lt;span&gt; ab &lt;/span&gt;&lt;span&gt;AS&lt;/span&gt;&lt;span&gt; ab2 &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt; EXISTS&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    SELECT&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; FROM&lt;/span&gt;&lt;span&gt; ab &lt;/span&gt;&lt;span&gt;AS&lt;/span&gt;&lt;span&gt; ab3 &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt; EXISTS&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      SELECT&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; FROM&lt;/span&gt;&lt;span&gt; three_pk &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt; pk1 &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ab1&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt; and&lt;/span&gt;&lt;span&gt; pk2 &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ab2&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt; and&lt;/span&gt;&lt;span&gt; pk3 &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ab3&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  )&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Running this query on older versions of Dolt would trigger a panic. To understand why, let’s talk about scopes.&lt;/p&gt;
&lt;h1 id="scopes"&gt;Scopes&lt;a class="anchor-link" aria-label="Link to heading" href="#scopes"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Scopes are something that every programmer has to deal with even if they don’t realize it. It’s how programs resolve symbols to the things that are actually being referenced.&lt;/p&gt;
&lt;p&gt;SQL queries reference tables and columns by name, and Dolt needs to map those names onto the tables and columns they represent. This is not as simple as it looks, because the same name can refer to different tables based on where it appears in the statement. The following is a valid SQL query:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; FROM&lt;/span&gt;&lt;span&gt; test_table &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt; EXISTS&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; FROM&lt;/span&gt;&lt;span&gt; test_table &lt;/span&gt;&lt;span&gt;where&lt;/span&gt;&lt;span&gt; test_table&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;and&lt;/span&gt;&lt;span&gt; test_table&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this query, there are two tables named &lt;code&gt;test_table&lt;/code&gt; and two filter conditions that name &lt;code&gt;test_table&lt;/code&gt;. Which condition refers to which child iterator? If Dolt resolves these names incorrectly, it will produce incorrect output.&lt;/p&gt;
&lt;p&gt;Two names can also refer to the same table, again depending on where the names appear. Consider this simple query with a two-part primary key:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;CREATE&lt;/span&gt;&lt;span&gt; TABLE&lt;/span&gt;&lt;span&gt; test_table&lt;/span&gt;&lt;span&gt;(pk1 &lt;/span&gt;&lt;span&gt;INT&lt;/span&gt;&lt;span&gt;, pk2 &lt;/span&gt;&lt;span&gt;INT&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;PRIMARY KEY&lt;/span&gt;&lt;span&gt; (pk1, pk2));&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; FROM&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; FROM&lt;/span&gt;&lt;span&gt; test_table &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt; test_table&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;pk2&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;AS&lt;/span&gt;&lt;span&gt; table_alias &lt;/span&gt;&lt;span&gt;where&lt;/span&gt;&lt;span&gt; table_alias&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;pk1&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This query can be optimized into a simple table lookup, but only if Dolt can detect that the two &lt;code&gt;WHERE&lt;/code&gt; clauses refer to the same table, even though the two clauses use different table names.&lt;/p&gt;
&lt;p&gt;Thus, it does not suffice for Dolt to simply keep a global dictionary that maps names onto tables, because the rules for resolving references are not global. Different parts of the query introduce their own namespace, which changes how names are resolved. These namespaces are scopes.&lt;/p&gt;
&lt;p&gt;So how does a database engine keep these scopes straight? How are table references actually represented in the abstract syntax tree?&lt;/p&gt;
&lt;h2 id="scopes-at-analysis-time"&gt;Scopes at Analysis Time&lt;a class="anchor-link" aria-label="Link to heading" href="#scopes-at-analysis-time"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The most naive approach is to simply store the same names in the AST as they appear in the query. Then, whenever the engine wants to analyze, optimize, or execute part of the tree, it resolves the name using scope rules. This works, but it’s incredibly brittle:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Any optimization that transforms the AST needs to be very careful. If a node contains a reference, moving that node to another part of the tree could change the meaning of that reference, and change the behavior of the query. Whenever the engine transforms the tree, it would need to update any references.&lt;/li&gt;
&lt;li&gt;In fringe cases, a transformation may result in an impossible tree, where we need to reference a table but it’s impossible to do so because that table’s name is being shadowed by another.&lt;/li&gt;
&lt;li&gt;Needing to resolve references repeatedly is slow and wasteful.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is actually how Dolt used to operate years ago, and it was the source of subtle bugs. So we switched to a better approach: when analyzing a query, we assign incrementing globally unique IDs to tables and columns. Every reference is resolved once, and then the name gets replaced with the ID. Since each ID always refers to the same table or column, we can safely modify the AST without any risk of changing the query’s meaning.&lt;/p&gt;
&lt;p&gt;But this is only half of the situation of scopes.&lt;/p&gt;
&lt;h2 id="scopes-at-runtime"&gt;Scopes at Runtime&lt;a class="anchor-link" aria-label="Link to heading" href="#scopes-at-runtime"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It’s not enough to just be able to resolve references to the table or column they represent, we also need to track those values while the query is running. Operations that produce column values need to be able to send those values to the operations that read them.&lt;/p&gt;
&lt;p&gt;In general-purpose languages, this might be accomplished with registers, or by writing to values in memory. But SQL queries are declarative and functional and don’t have state: when evaluating a node in the syntax tree, the iterator it produces is often a pure function of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Columns inherited from parent nodes
&lt;ul&gt;
&lt;li&gt;Example: In &lt;code&gt;SELECT id FROM a WHERE EXISTS (SELECT id FROM b WHERE a.id = b.id)&lt;/code&gt;, the inner query references a column from the outer query.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Columns returned from child nodes
&lt;ul&gt;
&lt;li&gt;Example: In &lt;code&gt;SELECT id FROM (SELECT id FROM a) AS a_alias where a_alias.id = 1&lt;/code&gt;, the outer query references a column from the inner query.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Columns defined in sibling nodes
&lt;ul&gt;
&lt;li&gt;Example: In &lt;code&gt;SELECT id FROM a JOIN LATERAL (SELECT id FROM b WHERE a.id = b.id)&lt;/code&gt;, the right side of the join references a column from the left side of the join.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each of these columns can have multiple values over the lifetime of the query, but only one at a time. A SQL engine needs a strategy to represent this internally.&lt;/p&gt;
&lt;p&gt;A naive approach might be to maintain a mapping from each column name to its current value. Except as we already saw, names don’t map one-to-one onto columns. In fact, it’s perfectly valid MySQL to for a table alias to have multiple columns with the same name. For example, the below query produces a table alias with two columns both named &lt;code&gt;pk&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;CREATE&lt;/span&gt;&lt;span&gt; TABLE&lt;/span&gt;&lt;span&gt; test_table&lt;/span&gt;&lt;span&gt;(pk &lt;/span&gt;&lt;span&gt;INT&lt;/span&gt;&lt;span&gt; PRIMARY KEY&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; FROM&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; FROM&lt;/span&gt;&lt;span&gt; test_table &lt;/span&gt;&lt;span&gt;JOIN&lt;/span&gt;&lt;span&gt; test_table) &lt;/span&gt;&lt;span&gt;AS&lt;/span&gt;&lt;span&gt; table_alias;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Even more problematic is that a table alias column might have &lt;em&gt;no&lt;/em&gt; name:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; FROM&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;AS&lt;/span&gt;&lt;span&gt; table_alias;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In either case, it’s not possible to reference these columns in filters, but they can still impact the results of the query if the alias is used in a &lt;code&gt;SELECT *&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So if we can’t track values by their column name, another approach might be to use the unique column IDs we discussed in the previous section. But there could be many such IDs, and each node in the AST only cares about a small number of them. Managing lots of small maps is also not very performant, and we care about performance.&lt;/p&gt;
&lt;p&gt;Fortunately, there’s an approach to that gives us both clarity and performance. Every scope in a SQL query always has the same number of columns. So the number of columns referenceable from any node in the AST is a constant value that can be determined by statically analyzing the query. The number of columns in that node’s iterator is also a constant value.&lt;/p&gt;
&lt;p&gt;Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A table reference with N columns produces an iterator that returns a list of five values.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;SELECT col1, col2, ... colN WHERE EXISTS (...)&lt;/code&gt; construct creates N referenceable columns for every node within the subquery.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each node can have an array where we store the value of each of these columns. Each element in the array corresponds to a different column. Before we evaluate the query, we can analyze the AST to determine which column each array element represents. Now if we want to represent an expression that reads a column, we don’t need to store the name of the column in the AST, and we don’t need to store that column’s globally unique ID either: all we need to store is the offset within that node’s own array corresponding to that column.&lt;/p&gt;
&lt;p&gt;This is the approach that Dolt uses: it analyzes the tree, determines the exact set of columns visible to each node, and replaces column references with the correct offset into that node’s array that will contain that column at runtime.&lt;/p&gt;
&lt;p&gt;We can illustrate this process with some diagrams. In each case, we show the nodes in the AST, and each node has both an ordered sequence of columns it produces (the output schema), and an ordered lists of columns it can reference (the input schema). The color of each cell indicates the node that originally produced the value. Note how nodes can contain column references from children, siblings, or parents, but in each case the number of columns can be statically determined.&lt;/p&gt;
&lt;p&gt;A node referencing its child:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;CREATE&lt;/span&gt;&lt;span&gt; TABLE&lt;/span&gt;&lt;span&gt; test_table&lt;/span&gt;&lt;span&gt;(a &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;, b &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;, c &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt; AS&lt;/span&gt;&lt;span&gt; d &lt;/span&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; test_table;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Would result in an AST that looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/ast-child.svg/c1eb0eb3597c600cc5b743a41588051270245a20bc8e15c127188c15bb754b26.svg" alt="node with child reference"&gt;&lt;/p&gt;
&lt;p&gt;A node referencing its parent:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;CREATE&lt;/span&gt;&lt;span&gt; TABLE&lt;/span&gt;&lt;span&gt; test_table&lt;/span&gt;&lt;span&gt;(a &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;, b &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;, c &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; a &lt;/span&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; test_table &lt;/span&gt;&lt;span&gt;AS&lt;/span&gt;&lt;span&gt; t1 &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt; EXISTS&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; b &lt;/span&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; test_table &lt;/span&gt;&lt;span&gt;AS&lt;/span&gt;&lt;span&gt; t2 &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt; t1&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; t2&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Would result in an AST that looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/ast-parent.svg/5f8e321bc1841193cb1170493715d10ce03d971997b743c941aa25ecd95aeb8a.svg" alt="node with parent reference"&gt;&lt;/p&gt;
&lt;p&gt;In order for this optimization to work correctly, every node must agree on how many columns it receives from each of their children, and how many columns are visible from parent and sibling scopes. If these numbers don’t agree, it could lead to situations where Dolt accesses the wrong value at runtime, or accesses the array out-of-bounds and panics.&lt;/p&gt;
&lt;p&gt;So with all this in mind, let’s look back at the query that triggered the bug:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;CREATE&lt;/span&gt;&lt;span&gt; TABLE&lt;/span&gt;&lt;span&gt; ab&lt;/span&gt;&lt;span&gt; (a &lt;/span&gt;&lt;span&gt;INT&lt;/span&gt;&lt;span&gt; PRIMARY KEY&lt;/span&gt;&lt;span&gt;, b &lt;/span&gt;&lt;span&gt;INT&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;CREATE&lt;/span&gt;&lt;span&gt; TABLE&lt;/span&gt;&lt;span&gt; three_pk&lt;/span&gt;&lt;span&gt; (pk1 &lt;/span&gt;&lt;span&gt;TINYINT&lt;/span&gt;&lt;span&gt;, pk2 &lt;/span&gt;&lt;span&gt;TINYINT&lt;/span&gt;&lt;span&gt;, pk3 &lt;/span&gt;&lt;span&gt;TINYINT&lt;/span&gt;&lt;span&gt;, col &lt;/span&gt;&lt;span&gt;TINYINT&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;PRIMARY KEY&lt;/span&gt;&lt;span&gt; (pk1, pk2, pk3));&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; FROM&lt;/span&gt;&lt;span&gt; ab &lt;/span&gt;&lt;span&gt;AS&lt;/span&gt;&lt;span&gt; ab1 &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt; EXISTS&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  SELECT&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; FROM&lt;/span&gt;&lt;span&gt; ab &lt;/span&gt;&lt;span&gt;AS&lt;/span&gt;&lt;span&gt; ab2 &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt; EXISTS&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    SELECT&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; FROM&lt;/span&gt;&lt;span&gt; ab &lt;/span&gt;&lt;span&gt;AS&lt;/span&gt;&lt;span&gt; ab3 &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt; EXISTS&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      SELECT&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; FROM&lt;/span&gt;&lt;span&gt; three_pk &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt; pk1 &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ab1&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt; and&lt;/span&gt;&lt;span&gt; pk2 &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ab2&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt; and&lt;/span&gt;&lt;span&gt; pk3 &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ab3&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  )&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The simplest explanation for the root cause was this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When Dolt optimized this query, it would transform it into multiple nested join nodes.&lt;/li&gt;
&lt;li&gt;Each of these join nodes introduced a new table alias that could be referenced by its children.&lt;/li&gt;
&lt;li&gt;If a join condition referenced a column, then Dolt would need to compute the offset of that column in the join node’s array of column references. This required knowing how many of the columns in the array came from parent scopes, how many came from sibling scopes, and how many were from that node’s children.&lt;/li&gt;
&lt;li&gt;The logic for computing how many columns in the input schema came from outer scopes did not consider the fact scopes could be introduced in the middle of a nested join. This made it impossible to correctly calculate this for every node in the AST.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There were some attempts made to account for this issue, but in adjusting the calculations for common queries, it broke the calculations for less common queries. Ultimately, these adjustments made the logic harder to reason about. In the end, we fixed the issue by completely rewriting how we generated iterators during join in order to make it simpler to analyze them.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/dolthub/go-mysql-server/pull/3428"&gt;The full scope of the issue and the fix are more complicated, but this was the general idea.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I hope this illuminates what actually goes on inside a database engine.&lt;/p&gt;
&lt;p&gt;As always, if you have any thoughts about database design, or if you’re curious how a version-controlled database can benefit you, then you should hop into our &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;Discord&lt;/a&gt; and we’d love to discuss it with you.&lt;/p&gt;</content:encoded>
      <dc:creator>Nick Tobey</dc:creator>
      <category>dolt</category>
    </item>
  </channel>
</rss>
