<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Grpc on MongrelDB</title><link>https://www.mongreldb.com/articles/tags/grpc/</link><description>Recent content in Grpc on MongrelDB</description><image><title>MongrelDB</title><url>https://www.mongreldb.com/assets/og-mongreldb.png</url><link>https://www.mongreldb.com/assets/og-mongreldb.png</link></image><generator>Hugo</generator><language>en-US</language><lastBuildDate>Sun, 02 Aug 2026 12:00:00 -0500</lastBuildDate><atom:link href="https://www.mongreldb.com/articles/tags/grpc/index.xml" rel="self" type="application/rss+xml"/><item><title>Embedded and Server Modes from One Database Engine</title><link>https://www.mongreldb.com/articles/2026/07/embedded-and-server-from-the-same-code-paths/</link><pubDate>Wed, 15 Jul 2026 09:00:00 -0500</pubDate><guid>https://www.mongreldb.com/articles/2026/07/embedded-and-server-from-the-same-code-paths/</guid><description>MongrelDB runs in-process or behind mongreldb-server, keeping one storage and query engine while changing ownership, authentication, serialization, and resource boundaries.</description><content:encoded><![CDATA[<p>An embedded database and a server database may share a storage format while living under different operational rules, because an in-process caller can hold a native handle and share memory directly, while a server has to authenticate identities, preserve session state across requests, bound concurrent work, serialize results, and own the storage root on behalf of many clients; MongrelDB keeps one engine under both modes, but it does not pretend the boundaries are interchangeable.</p>
<p>The engine crates own WAL, MVCC, tables, indexes, transactions, compaction, backup, recovery, and DataFusion query execution. Embedded clients call those capabilities through native Rust, NAPI, Python, C ABI, or JNI surfaces. <code>mongreldb-server</code> links the same engine and adds sessions, credentials, HTTP or gRPC transport, resource ceilings, and multi-process ownership.</p>
<h2 id="embedded-mode-owns-the-root-directly">Embedded mode owns the root directly</h2>
<p>A native application opens a database directory and the engine takes an exclusive lock on that storage core. Threads inside the process share the same <code>Database</code>; identity-specific handles can share one core through the database manager, but a second independent process cannot open the same root and hope filesystem locking will merge their transaction histories.</p>
<p>This is the right shape for desktop applications, local-first tools, edge jobs, test harnesses, and services where one process already owns the lifecycle. Calls avoid a transport hop, typed values stay native longer, and Arrow IPC can move columnar results without turning every cell into a JSON object.</p>
<p>The cost is application ownership. A process crash is also a database-process crash, native artifacts must ship for the target platform, blocking work must leave latency-sensitive runtime threads, and backup or maintenance has to respect the open handle.</p>
<h2 id="server-mode-centralizes-ownership">Server mode centralizes ownership</h2>
<p><code>mongreldb-server</code> opens the root once and accepts multiple client processes. The typed Kit HTTP surface covers schema, transactions, query, scored retrieval, search, and maintenance. Native gRPC carries Protobuf control messages and Arrow IPC batches over HTTP/2 with TLS. A MySQL-compatible listener supports existing client workflows for the SQL surface.</p>
<p>The server boundary is where authentication, row and column policy, request deadlines, AI candidate ceilings, session limits, cancellation, and audit behavior become centralized instead of repeated in every application process. Language-native HTTP clients can stay pure Clojure, Go, PHP, Ruby, Swift, or Zig while one Rust daemon carries the engine.</p>
<p>The cost is the service itself. Somebody must start it, stop it, upgrade it, monitor it, provision TLS and credentials, and decide what happens when the process is unavailable. Local HTTP is simpler than a remote cluster, but it is still a network protocol and an operational component.</p>
<h2 id="shared-semantics-do-not-require-identical-apis">Shared semantics do not require identical APIs</h2>
<p>Both modes use the same tables, RowIds, index families, transactions, and SQL planner, but the safest public surface can differ. Trusted embedded SQL may use a Boolean ANN predicate because the host application owns the work. Remote ranked queries use scored table functions and typed endpoints with deadlines and candidate ceilings so one request cannot turn an authenticated server into an unbounded vector worker.</p>
<p>Likewise, an embedded handle can preserve session-scoped views and prepared state for its lifetime, while a stateless HTTP route may create a fresh SQL session unless the server protocol explicitly associates requests with a durable session. The engine behavior is shared; connection lifetime is not.</p>
<p>Trying to hide those differences behind one magical interface would make the simple embedded path carry server concepts and the server path inherit unsafe local assumptions. The useful contract is same storage truth and query meaning, with an honest boundary around ownership and transport.</p>
<h2 id="the-latency-evidence">The latency evidence</h2>
<p>The current qualification fixtures measure a warm embedded begin/get/rollback point path at 1.037 microseconds p50 and 1.434 microseconds p95 on the documented benchmark host. A warm loopback HTTP SQL point query measured 1.287 milliseconds p50, 2.070 milliseconds p95, and 2.396 milliseconds p99 in one current fixture.</p>
<p>Those are not a protocol microbenchmark over identical work. The HTTP result includes request handling, session lookup, SQL planning, and JSON serialization, while the embedded result is a native point operation. The numbers show the scale of the boundary, not a clean subtraction that assigns every extra microsecond to TCP.</p>
<p>A service doing one row per request will feel that boundary more than a service moving one Arrow batch or committing a useful transaction per request. Batching is not a workaround for a slow server; it is how a remote database protocol stops making transport overhead the unit of work.</p>
<h2 id="choose-ownership-before-syntax">Choose ownership before syntax</h2>
<p>Embed when one process can own the root, native distribution is acceptable, and local-call latency matters. Run the server when many processes or languages need the same database, when centralized credentials and limits matter, or when native packaging is more expensive than one local daemon.</p>
<p>MongrelDB Viewer supports both boundaries. Direct mode embeds the official engine and takes the root lock; Server mode connects through the official client and leaves ownership with the daemon. The <a href="https://www.mongreldb.com/local-vector-database-gui/">Viewer guide</a> compares which maintenance operations are available through each path.</p>
<p>A project can start embedded and move to the daemon without converting the storage model, but application code still has to acknowledge that a function call became a request, that identities and failure modes changed, and that a remote result can time out after the server committed work. Same engine is a useful migration property. It is not permission to ignore the network.</p>
<p>Current deployment and client details live in the <a href="https://www.mongreldb.com/languages.html">35-language matrix</a> and the engine <a href="https://github.com/visorcraft/MongrelDB/blob/master/README.md"><code>README.md</code></a>.</p>
]]></content:encoded></item></channel></rss>