Thanks, appreciate the support (^_^)!
HN user
mr_Fatalyst
The way I see it, having everything as Pydantic makes this natural. Your DB model, your request schema, your response DTO are all BaseModels. Converting between them is just model_dump() and model_validate(), or plain inheritance. No adapters, no mapping layers. So when you need to split things apart, it's straightforward rather than painful.
One thing that might help here: if you subclass an Oxyde model without defining class Meta: is_table = True, the child class won't be a table and won't have ORM behavior. So you can inherit the fields and validation but without save()/delete(). Not exactly a Protocol-based approach, but it gives you a clean read-only DTO derived from the same model.
Right now makemigrations detects add/drop/alter columns, indexes, foreign keys, and constraints. Rename is treated as drop + create, same as Django's default. Automatic rename detection is on the roadmap but not there yet. For now you'd edit the generated migration manually if you need a rename. Splitting a model into two would be detected as one dropped table and two new ones, so you'd also want to adjust that migration by hand to preserve data.
That's exactly why Oxyde has no lazy loading at all. If you don't call .join() or .prefetch(), related data simply won't be there. N+1 is impossible by design, not by discipline.
Yep, there's a full comparison including SQLAlchemy async: https://oxyde.fatalyst.dev/latest/advanced/benchmarks/
Thanks! Not yet, it's still v0.5 and the API hasn't fully stabilized. But it's getting there.
1. We're all AI agents in a simulation anyway...
2. A converter still means maintaining two model systems. The point was to not have two in the first place.
3. MessagePack overhead is negligible compared to actual DB round-trips. And the Rust core isn't just SQL generation, it bundles the full driver stack (sqlx), pooling, and streaming, so you don't need asyncpg/aiosqlite as separate dependencies.
Well said, that's pretty much how I see it too. Thanks!
Right now it's CLI-based: 'oxyde migrate'. You can call 'apply_migrations()' programmatically, but that's not a publicly documented API yet. Good point though, worth adding.
Thanks! The admin panel supports Quart out of the box, so you should be good to go.
Good question. Working with Python objects in PyO3 requires holding the GIL. With MessagePack, Python serializes to bytes, hands them off, and Rust works completely GIL-free from that point. Same on the way back. So the GIL is held only for the brief serde step, not during SQL generation or execution.
You can't call filter() without a model. It's always Folder.objects.filter(user_id=user_id), so the context is right there in the code. Plus the generated .pyi stubs give your IDE full type info per model, so "go to usages" works through the type system.
Exactly, that's the idea.
For Oxyde specifically, it's still a young project, so the best public examples I have are the FastAPI tutorial (https://github.com/mr-fatalyst/fastapi-oxyde-example) and the admin panel examples (https://github.com/mr-fatalyst/oxyde-admin). Bigger real-world showcases will come with time. But in general, ORMs pay for themselves when you have lots of models, relations, and standard CRUD with validation. The moment you hand-write the same INSERT/UPDATE/SELECT with joins for every endpoint, it adds up fast.
Thanks! Haven't used Prisma much myself, but glad the approach resonates.
Thanks, appreciate it! Felt wrong to ship an ORM without one.
Right, it's not DBAPI compliant. The whole IO stack goes through Rust/sqlx, so PEP-249 doesn't apply. Oxyde has its own exception hierarchy (OxydeError, IntegrityError, NotFoundError, etc.). In practice most people catch ORM-level exceptions rather than DBAPI ones, but fair to call out.
On F(), good point. The descriptor approach is something I've been thinking about. Definitely on the radar.
Yeah, we're running out of ways to spell oxide (^_^)
Thanks! Not really trying to replace Django ORM though, it's great at what it does. Just trying to build the ORM I'd personally want to use in 2026.
Must have missed that meeting. ORMs are not for everything, but for CRUD-heavy apps with validation they save a lot of boilerplate. And there's always execute_raw() for when you need to go off-script.
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.
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.
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.
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().
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.
Hi all,
About a month ago I shared FastOpenAPI on Show HN. The response was far beyond what I expected with thoughtful feedback, feature requests, technical questions and even a great PR. I tried to sum it all up in this write-up including what the community focused on, what was improved and how it shaped the project going forward.
Thanks again to everyone who took part!
Big thanks to everyone for the feedback and your reactions! I've started working on version 0.5.0 and will try to include as much as possible of what was highlighted here.
I added the draft in 0.5.0-dev
https://github.com/mr-fatalyst/fastopenapi/tree/0.5.0-dev
Example: https://github.com/mr-fatalyst/fastopenapi/tree/0.5.0-dev/ex...
Thanks! I have a draft for aiohttp integration. I think I'll add it later.