Skip to content

Meet Weasel: The Schema Engine Powering the Whole Critter Stack

Jeremy Miller28th August 2026
WeaselCritter Stack
Weasel

Every Marten user has relied on Weasel without ever knowing its name. When you spin up a Marten application and your PostgreSQL tables, indexes, and functions just quietly come into existence to match your configuration -- that's Weasel. When you run a schema migration and Marten tells you exactly what's out of sync between your code and your live database, that's Weasel too. It's the least-famous member of the Critter Stack, and I've come to think of it as the part of the machine that does the unglamorous but absolutely load-bearing work.

Weasel is our database schema-management and SQL-generation engine. Its job is to know how to describe database objects -- tables, indexes, functions, sequences, partitions -- as configuration, and then to diff that desired state against what's actually in the database and apply whatever changes are needed to reconcile the two. That "just make my database match my configuration" experience that Marten users take for granted is Weasel's entire reason to exist.

For most of its life, Weasel was a supporting actor with a fairly narrow role. Over this past summer, though, it's grown into something much more central, and I want to walk through what changed and why it matters -- even if you never type the word "Weasel" into your csproj.

Why we tore it open

The forcing function here is Polecat, our newer event store built on SQL Server. Marten and Polecat do fundamentally the same job -- they're event stores with document database capabilities -- but they'd historically been built against very different database plumbing. Marten's storage and LINQ layers were shot through with Npgsql-specific types, because for years there was no reason for them not to be. Marten was PostgreSQL, full stop.

That's a lousy foundation if you want two event stores that share features and fixes instead of drifting apart. So the work of this summer was to converge both event stores onto one shared runtime, and Weasel is where that runtime lives.

The centerpiece is a new library called Weasel.Storage, which showed up around Weasel 9.8.0. It's a dialect-neutral set of what I've been calling "closed-shape" storage contracts. Rather than describing storage in terms of a specific database engine, Weasel.Storage describes how a document or event store reads and writes in the abstract: there's a descriptor core that establishes the shared vocabulary, selectors that describe reads, metadata binders that map database columns back onto your documents and events, write operations, and an event-storage hierarchy on top. What it deliberately does not know is whether the database underneath is PostgreSQL reached through Npgsql, or SQL Server, or anything else. That knowledge lives on the far side of a clean seam.

With that seam in place, we did the surgery. Polecat -- through its internal epic #273 -- now implements the Weasel.Storage session, database, and operation contracts directly. And Marten (marten#4821) got its storage and LINQ layers retargeted off those Npgsql-specific types and onto the neutral seam. The net effect is the thing I'm proudest of this year: one storage engine, two event stores. Marten on PostgreSQL, Polecat on SQL Server, both sitting on the same machinery.

The schema-management niceties that came along

Converging the runtime wasn't the only Weasel work in that stretch. Because the schema-diff and migration machinery is now a first-class, reusable library instead of something buried inside Marten, improvements to it land in a single place and benefit everyone downstream. A handful of those landed alongside the convergence work:

  • Opt-in schema fingerprinting. Applying a full schema check and reconciliation across a large database can be expensive. With fingerprinting turned on, Weasel can recognize that nothing has changed since the last apply and skip the whole expensive dance.
  • Computed-column introspection and delta detection. Weasel can now read back computed columns and detect deltas on them -- on both PostgreSQL and SQL Server. That kind of parity is exactly what the shared engine is supposed to buy us.
  • Managed tenant-partition parity and idempotent partition creation. Partition creation now goes through CREATE TABLE IF NOT EXISTS, so re-running a schema apply won't blow up on partitions that already exist.
  • Bounded connection usage when applying across many databases, so a big multi-database apply doesn't try to open the world all at once.
  • Guid.CreateVersion7() for sequential-Guid identity generation, shared across the whole stack, for friendlier index locality on Guid-keyed data.

None of these are headline features on their own. Taken together, they're the difference between a schema engine that mostly works and one you can lean on hard in production across two different database platforms.

And that work hasn't stopped. The 9.25, 9.26, and 9.27 releases that shipped through August were mostly about read-back fidelity -- the unglamorous business of making sure that when Weasel introspects a schema, it sees what the database actually holds. A named foreign key on SQLite, a partition-aligned index on SQL Server, an invalid index on PostgreSQL: each one read back as something other than what was there, which produces a delta that can never converge. The patch applies, the read-back still differs, and the next run generates the identical patch forever. Those are precisely the bugs that turn "just restart and let it migrate" from a feature into a liability, which is why they got the attention they did.

What this actually means for you

If you're a user, here's the concrete payoff. First, because Marten and Polecat share one engine, a fix or a feature lands once and benefits both. That's why our cross-product velocity has been high lately -- we're not maintaining two parallel copies of the same hard problems. Second, you get more consistent schema behavior across PostgreSQL and SQL Server, because the same code is reasoning about both. The computed-column work above is a perfect example: it isn't a Postgres feature and a separately-written SQL Server feature that happen to look similar, it's one feature.

And third, the schema-diff and migration machinery is now a genuinely reusable library rather than an implementation detail hidden inside Marten. That opens doors we couldn't easily walk through before -- which is a nice segue.

One more thing

Because Weasel now understands schema as first-class, diffable configuration independent of any one database engine, it can do something we've wanted for a long time: generate Entity Framework Core migrations. If you've got a team that lives in EF Core but you want Weasel's diffing to author your migrations, that's now on the table. I wrote that story up separately -- read it here.

If your team is running Marten or Wolverine in production and you'd like a direct line to the people who build this stuff, take a look at our JasperFx support plans, or just come hang out with the Critter Stack community in Discord. Weasel may be the quiet one, but it's holding up an awful lot of the house.

RSS Feed · All Rights Reserved.