Ditching JSON & SQL Friction: Designing an Object-Shaped Memory Engine (Part 2)
For a long time, backend engineering has been divided into two camps: Relational databases (SQL) for rigid, structured tables, and Document stores (NoSQL/JSON) for flexible, unstructured data.
But when you are building for AI Agents, both of these traditional approaches introduce massive architectural friction. AI agents don't think in rows, columns, or complex foreign key joins. They don't want to parse heavily nested, arbitrary JSON text blobs either. Agents think in state, context, and entities. They operate best when data looks exactly like the object structures they manipulate in their runtime environments.
When I designed the core primitives for thingd, I wanted the absolute speed of a local relational database combined with the flexibility of an object-first paradigm. Here is how we bypassed the typical ORM bloat and built an object-shaped memory engine natively in Rust.
Why typical DB abstractions break for Agents
If you hook an autonomous agent loop up to a traditional Postgres or MySQL instance using an ORM like Prisma or TypeORM, you run into three main problems:
- Context Bloat: ORMs generate heavy, verbose SQL queries and return heavily structured responses packed with metadata that the agent doesn't need, wasting valuable context tokens.
- Schema Inflexibility: Agents are dynamic. They discover new data shapes, store arbitrary runtime memories, and alter data structures on the fly. Migrating a SQL schema mid-agent loop is an absolute nightmare.
- The Local I/O Bottleneck: Forcing a local agent loop to constantly hit a remote cloud database for every minor micro-step adds hundreds of milliseconds of network latency, compounding until the agent feels unusable.
We needed something local-first, structurally dynamic, and blazing fast.
Under the Hood: SQLite Performance + Rust Objects
To solve this, thingd uses SQLite as its storage engine, but exposes it completely as a high-performance Object Store. Instead of forcing developers (or agents) to write queries or handle migrations, thingd abstracts the database into an entity-first system.
Every data point is treated as a "thing"-an object primitive with its own identity, properties, and relationships. Because the underlying engine is written in Rust, we get to take advantage of zero-cost abstractions:
// A simplified look at how thingd handles dynamic object primitives internally
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ThingObject {
pub id: String,
pub entity_type: String,
pub properties: HashMap<String, serde_json::Value>,
pub updated_at: i64,
}
Comments
No comments yet. Start the discussion.