Stop Using Django REST Framework: We Did, and Here's What We Learned
For years, Django REST Framework was the default answer whenever someone asked "how do I build an API in Django?" No questions asked. You just pip install djangorestframework and move on. We did it too — on project after project at Gerus-lab, across Web3 dashboards, AI platforms, SaaS tools, and GameFi backends.
Then we stopped.
This is the story of why we ditched DRF, tried django-ninja, got burned, and what we actually use now for production APIs.
The DRF Problem Nobody Wants to Admit
We've built 14+ production projects at Gerus-lab — from TON blockchain integrations to AI-powered SaaS platforms. Across all of them, DRF showed the same cracks every single time.
One serializer to rule them all. DRF's design decision to use the same serializer for both input and output is... bold. In theory it sounds clean. In practice, you spend half your time writing read_only=True everywhere or creating two separate serializer classes anyway. We've seen client data leak into responses because someone forgot to exclude an internal field. Not fun when you're building a fintech product.
Type safety? Never heard of her. request.data returns a dict. That's it. You get no type hints, no IDE autocomplete, no runtime guarantees. When you're working on a team of 4-5 developers across a complex AI product (like we do at Gerus-lab for our AI integrations), this becomes a massive source of bugs that are hard to trace.
OpenAPI as an afterthought. Need Swagger docs? You have to install drf-spectacular or drf-yasg, configure them separately, fight them when they misrepresent your schema, and pray they don't break on the next DRF update. This is 2026. OpenAPI should be first-class, not a plugin you bolt on.
ModelSerializer leaks your database. Add a new internal field to your model and forget to exclude it from your ModelSerializer — congrats, you just exposed it to your API clients. We've seen this happen in production.
We Tried django-ninja. It's... Fine. But.
After one particularly painful DRF project (a complex multi-tenant SaaS with 60+ endpoints), we switched to django-ninja. The pydantic integration felt great. FastAPI-style function decorators felt modern. The OpenAPI generation worked out of the box.
Then we hit the walls.
Functions don't compose. The core architecture of django-ninja is function-based views with decorators. This means zero code reuse through inheritance. When you have 10 endpoints that all do slightly different things with the same base logic, you're copy-pasting or writing wrapper utilities. In a large Web3 platform we built for Solana, this became genuinely painful to maintain.
Pydantic is hardcoded. You want to use msgspec for performance? attrs? dataclasses? Too bad — django-ninja assumes pydantic everywhere. When we were optimizing a high-throughput TON blockchain event processor, we wanted to use msgspec for its speed advantages. Not possible without hacks.
The JWT situation is embarrassing. django-ninja-jwt is a fork of a DRF plugin, barely maintained, wrapped inside django-ninja-extra, which itself is a third-party extension. For something as fundamental as authentication, this dependency chain should make anyone nervous.
What Actually Works in 2026
The article that triggered this post discussed django-modern-rest — a new framework that takes a fundamentally different approach. We've been watching this space closely because at Gerus-lab, API architecture is something we spend serious time on.
Here's what a modern Django REST stack actually needs:
1. Controller-Based Architecture (Not Functions)
Class-based controllers that you can actually inherit from. This is the only way to achieve proper code reuse across large APIs. When you have auth, pagination, rate limiting, and tenant isolation all needing to apply across 50+ endpoints, you need composition and inheritance — not decorators stacked 6 deep.
2. Type Safety From Top to Bottom
Every request object should be typed. Every response should be typed. Validation at the framework level, not as an afterthought. When you're building AI integrations where structured data flows between multiple services (like in our AI product work), types aren't optional.
3. First-Class OpenAPI 3.1
Not a plugin. Not bolted on. Built in, always accurate, validated against your actual code. Your API schema should be a source of truth, not a document you manually keep synchronized.
4. Serializer Flexibility
Different serializers for different contexts. pydantic for validation-heavy endpoints. msgspec for high-performance event streams. attrs for domain objects. The framework shouldn't dictate — you should.
5. Strict Mode in Development
One thing we found genuinely useful in the new framework landscape: strict validation of your own responses in dev mode. If your response doesn't match your declared schema, the framework errors. This catches an entire class of bugs before they hit production.
Our Current Stack for Django APIs
After iterating across multiple production projects, here's what we've settled on depending on context:
For new greenfield Django projects: We're evaluating django-modern-rest seriously. The philosophy aligns with how we think about API architecture — controllers, flexibility, strict typing.
For high-performance microservices: We've moved to FastAPI in some contexts, particularly for AI inference endpoints and blockchain event processors. When you need async-first and raw performance, FastAPI with pydantic v2 is hard to beat.
For legacy DRF projects: We migrate incrementally. Start by replacing ModelSerializers with explicit serializers. Then add drf-spectacular for real OpenAPI. Then consider whether the view layer needs a rewrite.
Never: django-ninja for large projects. The function-based architecture creates long-term maintenance debt that will bite you at scale.
The Bigger Point
The Django ecosystem is in a weird transitional moment. DRF powered an entire generation of web APIs and deserves respect for that. But it was designed in a different era, for a different set of constraints. The alternatives we've tried have each solved some problems while introducing others.
What the ecosystem actually needed was a framework that:
- Starts with modern Python (type hints, async, pydantic/attrs/msgspec) as core assumptions, not add-ons
- Treats OpenAPI as a first-class citizen
- Allows real code reuse through class-based architecture
- Doesn't hardcode you into any single serialization library
That framework is being built now. Whether it's django-modern-rest or something else that emerges, the right architectural principles are becoming clearer.
At Gerus-lab, we make these decisions for every client project. Backend stack, API architecture, database design — these aren't religious choices, they're engineering tradeoffs with real consequences for maintainability and performance.
What Should You Do Today?
If you're starting a new Django project: Don't default to DRF out of habit. Evaluate the options with fresh eyes. Try django-modern-rest or FastAPI depending on your needs.
If you have existing DRF code: Don't panic. DRF is still maintained and works fine. But plan a migration strategy for the parts that hurt you most.
If you're building a high-performance system: Consider whether Django is even the right choice, or if a lighter async framework serves you better.
If you're confused by all of this: That's what we're here for.
We've navigated these choices across SaaS products, Web3 platforms, GameFi backends, and AI tools. If you want a team that actually thinks about API architecture (instead of just defaulting to whatever they used last time), talk to us at Gerus-lab.
The Django REST framework wars aren't over. But the standards are finally clear enough that we can have an honest conversation about what "best" actually means.
Gerus-lab is an IT engineering studio specializing in Web3, AI, SaaS, and GameFi development. We've shipped 14+ production projects across TON, Solana, and traditional web stacks. See our work at gerus-lab.com.
Top comments (0)