[HN Gopher] Show HN: Oxyde - Pydantic-native async ORM with a Ru...
       ___________________________________________________________________
        
       Show HN: Oxyde - Pydantic-native async ORM with a Rust core
        
       Hi HN! I built Oxyde because I was tired of duplicating my models.
       If you use FastAPI, you know the drill. You define Pydantic models
       for your API, then define separate ORM models for your database,
       then write converters between them. SQLModel tries to fix this but
       it's still SQLAlchemy underneath. Tortoise gives you a nice Django-
       style API but its own model system. Django ORM is great but welded
       to the framework.  I wanted something simple: your Pydantic model
       IS your database model. One class, full validation on input and
       output, native type hints, zero duplication. The query API is
       Django-style (.objects.filter(), .exclude(), Q/F expressions)
       because I think it's one of the best designs out there.   _Explicit
       over implicit._ I tried to remove all the magic. Queries don 't
       touch the database until you call a terminal method like .all(),
       .get(), or .first(). If you don't explicitly call .join() or
       .prefetch(), related data won't be loaded. No lazy loading, no
       surprise N+1 queries behind your back. You see exactly what hits
       the database by reading the code.   _Type safety_ was a big
       motivation. Python 's weak spot is runtime surprises, so Oxyde
       tackles this on three levels: (1) when you run makemigrations, it
       also generates .pyi stub files with fully typed queries, so your
       IDE knows that filter(age__gte=...) takes an int, that create()
       accepts exactly the fields your model has, and that .all() returns
       list[User] not list[Any]; (2) Pydantic validates data going into
       the database; (3) Pydantic validates data coming back out via
       model_validate(). You get autocompletion, red squiggles on typos,
       and runtime guarantees, all from the same model definition.   _Why
       Rust?_ Not for speed as a goal. I don 't do "language X is better"
       debates. Each one is good at what it was made for. Python is hard
       to beat for expressing business logic. But infrastructure stuff
       like SQL generation, connection pooling, and row serialization is
       where a systems language makes sense. So I split it: Python handles
       your models and business logic, Rust handles the database plumbing.
       Queries are built as an IR in Python, serialized via MessagePack,
       sent to Rust which generates dialect-specific SQL, executes it, and
       streams results back. Speed is a side effect of this split, not the
       goal. But since you're not paying a performance tax for the
       convenience, here are the benchmarks if curious:
       https://oxyde.fatalyst.dev/latest/advanced/benchmarks/  What's
       there today: Django-style migrations (makemigrations / migrate),
       transactions with savepoints, joins and prefetch, PostgreSQL +
       SQLite + MySQL, FastAPI integration, and an auto-generated admin
       panel that works with FastAPI, Litestar, Sanic, Quart, and Falcon
       (https://github.com/mr-fatalyst/oxyde-admin).  It's v0.5, beta,
       active development, API might still change. This is my attempt to
       build the ORM I personally wanted to use. Would love feedback,
       criticism, ideas.  Docs: https://oxyde.fatalyst.dev/  Step-by-step
       FastAPI tutorial (blog API from scratch): https://github.com/mr-
       fatalyst/fastapi-oxyde-example
        
       Author : mr_Fatalyst
       Score  : 19 points
       Date   : 2026-03-13 13:35 UTC (3 days ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | throwawayffffas wrote:
       | Lol I never knew django orm is faster than SQLAlchemy. But having
       | used both that makes sense.
       | 
       | > Why Rust? ... Rust handles the database plumbing. Queries are
       | built as an IR in Python, serialized via MessagePack, sent to
       | Rust which generates dialect-specific SQL, executes it, and
       | streams results back. Speed is a side effect of this split, not
       | the goal.
       | 
       | Nice.
       | 
       | So what does it take to deploy this, dependency wise?
        
         | mr_Fatalyst wrote:
         | Just pip install oxyde, that's it. The Rust core (oxyde-core)
         | ships as pre-built wheels for Linux, macOS, and Windows, so no
         | Rust toolchain needed. Python-side dependencies are just
         | pydantic, msgpack, and typer for the CLI. Database drivers are
         | bundled in the Rust core (uses sqlx under the hood), so you
         | don't need to install asyncpg/aiosqlite/etc separately either.
        
         | kstrauser wrote:
         | > Lol I never knew django orm is faster than SQLAlchemy.
         | 
         | I don't believe that for a second. Both are wonderful projects,
         | but raw performance was never one of Django ORM's selling
         | points.
         | 
         | I think its real advantage is making it easy to model new
         | projects and make efficient CRUD calls on those tables.
         | Alchemy's strong point is "here's an existing database; let
         | users who grok DB theory query it as efficiently and
         | ergonomically as possible."
        
           | mr_Fatalyst wrote:
           | I was surprised too when I saw the results. The benchmarks
           | test standard ORM usage patterns, not the full power of any
           | ORM. SQLAlchemy is more flexible, but that flexibility comes
           | with some overhead. That said, the ORM layer is rarely the
           | bottleneck when working with a database. The benchmarks were
           | more about making sure that all the Pydantic validation I
           | added comes for free, not about winning a speed race.
        
       | ForHackernews wrote:
       | This sounds great and there's a real gap in the ecosystem for a
       | tool like this. https://sqlmodel.tiangolo.com/ looked promising
       | but it's actually worse than useless because if you add it to
       | your Pydantic models, it disables all validation:
       | https://github.com/fastapi/sqlmodel/issues/52
        
         | mr_Fatalyst wrote:
         | Thanks! Yeah, that SQLModel issue is actually one of the things
         | that pushed me to build this. In Oxyde the models are just
         | Pydantic BaseModel subclasses, so validation always works, both
         | on the way in and on the way out via model_validate().
        
       | roel_v wrote:
       | Why would one want to couple these two? Doesn't that couple, say,
       | your API interface with your database schema? Whereas in reality
       | these are separate concepts, even if, yes, sometimes you return a
       | 'user' from an API that looks the same as the 'user' in the
       | database? Honest question, I only just recently got into FastAPI
       | and I was a bit confused at first that yes, it seemed like a lot
       | of duplication, but after a little bit of experience, they are
       | different things that aren't always the same. So what am I
       | missing?
        
         | mr_Fatalyst wrote:
         | The ORM doesn't force you to use the DB model as your API
         | schema. It's a regular Pydantic BaseModel, so you can make
         | separate request/response schemas whenever you need to. For
         | simple CRUD, using the model directly saves boilerplate. For
         | complex cases, you decouple them as usual. The goal is not one
         | model for everything, it's one contract. Everything speaks
         | Pydantic, whether it's your API layer or your database layer.
        
       | instig007 wrote:
       | > But infrastructure stuff like SQL generation, connection
       | pooling, and row serialization is where a systems language makes
       | sense.
       | 
       | not really, what makes sense is being JIT-able and friendly to
       | PyPy.
       | 
       | > Type safety was a big motivation.
       | 
       | > https://oxyde.fatalyst.dev/latest/guide/expressions/#basic-u...
       | 
       | > F("views") + 1
       | 
       | If your typed query sub-language can't avoid stringly references
       | to the field names already defined by the schema objects, then
       | it's the lost battle already.
        
         | mr_Fatalyst wrote:
         | The Rust core is not just about speed. It bundles native
         | database drivers (sqlx), connection pooling, streaming
         | serialization. It's more about the full IO stack than just
         | making Python faster. On F("views"), fair point. It's a
         | conscious trade-off for now. The .pyi stubs cover filter(),
         | create(), and other query methods, but F() is still stringly-
         | typed. Room for improvement there.
        
       | TZubiri wrote:
       | Didn't the committee agree that ORMs were a mistale and a thing
       | of the past?
        
       ___________________________________________________________________
       (page generated 2026-03-16 23:00 UTC)