Django or Supabase: why our ERP and our apps use different stacks
Almeebar uses Django REST and PostgreSQL; BIT Project, BIT Talents and our CMMS use React and Supabase. The criteria we use to choose backends for each project.

Our website states “technology tailored to each project”, and that is not marketing filler. If you inspect our production software, you will see two distinct architectural families:
- Almeebar ERP: Django REST framework, Next.js, PostgreSQL, and Docker.
- BIT Project, BIT Talents, and our maintenance manager (CMMS): React, TypeScript, and Supabase.
Both stacks store persistent state in PostgreSQL, but how they handle application logic is entirely different. Here are the engineering criteria we rely on to make that architectural choice.
The decisive question: where does business logic live?
If the domain logic is intricate, subject to frequent statutory updates, and carries legal or financial consequences, we want it in a dedicated custom backend. An ERP computes progressive tax rates, posts double-entry journal entries, applies vendor withholding based on regulatory category, and submits cryptographically chained records to tax authorities. These are multi-layered rules with numerous edge cases that belong in a centralized codebase, covered by automated domain tests, and strictly version-controlled.
Django excels at this: a battle-tested ORM, rock-solid schema migrations, a mature permissions system, an auto-generated administrative backoffice, and a comprehensive ecosystem of libraries (covering accounting, tax compliance, and async workflows).
If the core requirement centers on storing, listing, filtering, and sharing relational data with fine-grained access rules, a Backend-as-a-Service saves weeks of development time. A ticket tracker, a recruitment job board, or a maintenance work order registry fit this archetype cleanly. Supabase provides authentication, schema-generated REST and GraphQL APIs, file storage, and real-time WebSocket subscriptions right out of the box.
Architectural criteria comparison
| Criterion | Favors Django | Favors Supabase |
|---|---|---|
| Business logic | Complex, highly regulated, calculation-intensive | Primarily CRUD governed by row-level access rules |
| Background jobs | Heavy and persistent (queues, batch jobs, third-party syncs) | Lightweight and brief event triggers |
| External integrations | Diverse legacy protocols (SOAP, raw file parsing, mTLS) | Minimal, predominantly modern HTTP/JSON |
| Real-time subscriptions | Optional / niche | Essential out-of-the-box (dashboards, notifications) |
| Time to MVP | Longer initial setup | Extremely fast turnaround |
| Team specialization | Strong backend engineering focus | Strong frontend/fullstack TypeScript focus |
What we value in each stack (and what we monitor closely)
Django. The main advantage is complete operational sovereignty: domain-driven unit tests, explicit database transactions, and the freedom to containerize and deploy anywhere with Docker. The trade-off is higher operational surface area (managing application servers, Celery workers, Redis brokers, and auth services) and slower initial bootstrapping.
Supabase. The decisive advantage is delivery speed and security enforced directly in the database engine using Row Level Security (RLS): each table row determines who can read or mutate it. The trade-off is that RLS policies require rigorous discipline; a configuration flaw in a policy can leak confidential data. Furthermore, as application logic expands, developers must decide judiciously what logic belongs in database triggers/stored procedures versus Edge Functions to avoid unmaintainable logic sprawl.
Here is what a production RLS policy looks like in a support ticket board, ensuring users can only view and create their own tickets:
alter table tickets enable row level security;
-- Each user can only view their own tickets...
create policy "view own tickets" on tickets
for select to authenticated
using ( (select auth.uid()) = owner_id );
-- ...and can only insert tickets under their own identity.
create policy "create own tickets" on tickets
for insert to authenticated
with check ( (select auth.uid()) = owner_id );
With RLS enabled and no policies defined, all access is denied by default. The critical mistake is the inverse: creating a table and neglecting to enable RLS, which exposes it via the auto-generated API. For this reason, we treat RLS policy migrations with the exact same rigor as application source code: because they are production code.
The most important factor: the exit strategy
We adopt Supabase with confidence because the underlying engine is standard PostgreSQL. The relational schema, constraints, data types, and security policies are fully portable SQL. If a software project expands to the point of outgrowing BaaS patterns, migration remains straightforward: we can deploy a dedicated backend in front of the existing database and progressively migrate endpoints, using the exact patterns we detail in Migrating a system with zero downtime.
What you would replace is the managed platform envelope: auth handlers, object storage, and edge functions. Because Supabase is open-source, you also retain the option of self-hosting the complete stack.
We strictly avoid platforms that lock domain models into proprietary, non-portable database engines.
Summary
- ERP systems, automated billing, accounting, and government integrations → Dedicated backend (Django in our practice).
- Internal management tools, customer portals, collaborative apps → Supabase paired with a modern React frontend.
- In both cases → Standard PostgreSQL underneath, keeping your architectural exit doors wide open.
There is no best stack in the abstract—only the stack that cleanly matches the domain complexity, engineering team profile, and business budget of the project.
Deciding the architecture for your next software system? We can help you evaluate it before committing engineering resources.
Related articles
AI glossary in one image: token, embedding, RAG, agent, harness, and MCP
Six essential artificial intelligence concepts explained with technical clarity: how text is tokenized, vectorized, retrieved, and connected to external tools.
What is an LLM? Architecture, mechanics, and production limits
What a large language model (LLM) is, how it processes tokens through transformers, its real hallucination and context limits, and how to integrate it in production systems with RAG.
Migrating a system with zero downtime
Patterns we use to replace production systems that cannot go down: strangler fig, shadow traffic, continuous data synchronization, and rollback in minutes.


