Thread, Decoded

The multi-tenancy database debate

A real Cairo-dev-Twitter thread on how to keep one customer's data from leaking into another's — argued in a mix of Arabic and English, the way it actually happened. Jargon is highlighted right where it appears, with a plain note sitting directly beside that tweet the first time it comes up.

first mention = full note note = what it actually means repeat mention = already explained above
Before the thread — the three approaches everyone's comparing

Application-Level Only

The database is wide open. Your backend code (Python, Node, Go...) is trusted to add WHERE tenant_id = X to every single query itself.

ProsEasy to scale, change, and migrate. All logic stays in one place.
ConsHigh risk of data leaks — one forgotten filter on a new endpoint exposes another tenant's data.

Row-Level Security (RLS)

A database feature (e.g. PostgreSQL) that blocks any query from returning rows outside the current tenant — enforced by the database engine itself.

ProsExcellent safety net. Even a buggy query can't leak data across tenants.
ConsPushes logic into the database, complicates local testing, and can complicate connection pooling.

Separate DB / Schema per Tenant

Every tenant gets their own physical database or schema. Nothing is shared, so isolation is structural, not enforced by a rule.

ProsPerfect isolation. Easiest option to delete or move a single tenant's data.
ConsMigrations multiply fast — 500 tenants means 500 migrations to run.
Started the thread
M
Mohie @Mohhie · 13h
سؤال لو بتبني multi-tenant SaaS باستخدام shared schema، هل بتفضل تستخدم RLS على مستوي الdb ولا بتخلي الapplication code هو اللي يضمن
Multi-tenant SaaSA single software platform — like Slack or Shopify — that serves many separate business customers from one shared piece of infrastructure.
Shared schemaAll customers' data lives in the exact same database tables. A tenant_id column is what separates Company A's rows from Company B's.
RLSA database feature that blocks any query from returning rows outside the current tenant — enforced by the database engine itself, not by trusting the code.
Application codeThe backend code (Python, Node, Go...) is trusted to add WHERE tenant_id = X to every query itself, rather than the database enforcing it.
💬 12🔁 38❤ 180
AA
Alaa' Attya @AlaaAttya · 30m
هوا الأضمن انه تحطه علي مستوي ال database لان أكيد هتبقي واثق انه ال tenants isolation متطبق ولكن دا هيجي بشويه صداع وقت ما تيجي تعدل علي ال schema ولكن برضه لو حبيت تغير ال tenancy model الموضوع هيبقي أصعب من لو كنت عملته علي ال application level حاجه كمان لازم تعرف ازاي هت handle ال connection pooling ف حاله انك هتفصل ال tenants في اكتر من schema (بس اعتقد معظم ال orms بتقدر تظبطها) برضه لازم تفكر في مشكله ال constraints لو انت فاصل كل tenant في schema هيكون صعب انك تحقق الموضوع دا لأنك لازم تتاكد ان مثلا لو عندك unique constraint دا مطبق علي كل ال schema في حين لو shared schema الموضوع سهل مشكله كمان هيا ال indexing لو shared schema هتحتاج بنسبه كبير ان كل ال indexes تبقي composite indexes عشان دايما يبقي معاك ال tenant id و تخيل بقي لو في tenant منهم حجمه كبر هيبدأ يعملك مشاكل

أنا حاولت أحط كل اللي جه ف دماغي بس قولي لو نسيت حاجه
Tenants isolationMaking sure one customer's data is fully walled off from another's — the core problem this whole thread is about.
Tenancy modelThe overall strategy for how tenants are separated. Switching strategies later means rebuilding the data layer.
Connection poolingReusing a shared set of open database connections instead of creating a new one per request. RLS needs the database to know "who's asking" per query — pooled, reused connections can complicate that.
Unique constraintA rule that a value can't repeat. Enforcing it consistently is harder when each tenant has a separate schema.
Composite indexesA search index built from more than one column at once (tenant_id + another) — needed to keep shared-schema queries fast.
💬 12🔁 40❤ 210
AS
Ahmed Sheta @a_shetta · 8h
Neither is the full answer imo, RLS is a good safety net if you're already using shared schema, but true tenant isolation is usually separate DB/schema per tenant. The tradeoff is ops complexity vs stronger blast-radius control.
Blast radiusHow far damage spreads if something goes wrong. Smaller = fewer customers affected.
💬 8🔁 21❤ 95
M
Mohie @Mohhie · 2h
I wouldn't go DB/schema per tenant unless I have to. For a shared schema, I don't really see the downside of adding RLS as another layer of defense but I read PlanetScale are advising against it because of connection pooling quirks.
💬 6🔁 15❤ 60
A
Abdelrahman @AN4553R · 5h
على حسب السيستم بتاعي شكله عامل ازاي، وأساسي الthreat model هو اللي هيحدد عشان بفترض ان كل layer ممكن يحصل فيها مشكلة او تget compromised فكل اجابة لwhat could go wrong هفكر في الmitigation بتاعها. كمان لو توسعت و عاوز ابعت notifications/logs/events لل customers بقى عندي كمان مشكلة routing correctness المفروض افكر في ال isolation enforcement في الboundaries بتاعتها
Threat modelA structured guess at how your system could be attacked or broken — used to decide which risks are worth defending against.
MitigationThe specific fix or safeguard put in place to reduce a given risk.
Routing correctnessMaking sure a notification, log line, or event is actually delivered to the right tenant, not just that the database rows are separated.
Isolation enforcementActively making sure tenant boundaries are respected at every layer — not just the database, but wherever data moves.
💬 4🔁 9❤ 44
AO
Ahmed Osama @AhmedOsamaFT · 4h
انا كنت قريت رأي ان بلاش تحط business logic ف ال database layer لان وارد ان ده يتغير ف طبعا تغيرات ال DB و ال migrations هتكون صعبة اكتر من الكود
MigrationsScripted changes to a database's structure. Harder to roll back and coordinate than a normal code deploy.
💬 3🔁 5❤ 22
M
Mohie @Mohhie · 1h
ما هو الtenant isolation ده security invariant مش هيتغير الا لو قررنا منبقاش multitenant فان يكون فيه defense in depth mechanism اعتقد مقبول احنا مش بنعمل stored procedure
Security invariantA rule that must always hold true no matter what, unlike normal business logic which is expected to change over time.
Defense in depthStacking multiple independent safeguards, so if one fails, another still catches the problem.
Stored procedureA chunk of logic saved and run inside the database itself — generally seen as harder to maintain than logic kept in application code.
💬 2🔁 3❤ 18
SF
Shenouda Fawzy @ShenoudaFawzi · 4h
ال RLS على مستوى ال DB ده هيحميك من لو حد سهوا نسي يفصل على مستوى الابليكيشن ميحصلش unauthorized access. الحاجة التانية لو حبيت تخرِّج اي tenant بحيث يكون ليه infra resources لوحده لو الدنيا مش مفصولة على مستوى ال DB الموضوع هيحتاج مجهود اكبر.
Infra resourcesThe servers, storage, and compute assigned to run a tenant's workload — easier to carve out separately if the DB is already physically separated.
💬 3🔁 6❤ 30
M
Mohie @Mohhie · 1h
مش فاهم قصدك في النقطة التانية الRLS هيساعد ازاي في ال tenant migration؟
Tenant migrationMoving a specific customer's data — e.g. to give them their own dedicated infrastructure. Mohie's pushing back that RLS doesn't really help with this.
💬 1🔁 1❤ 9
AK
Al Sherif Khalaf @KhalafAl31381 · 21m
لو فيه validation كويس لل api ممكن تعتمد علي application code شخصياً، بفضل استخدام الاثنين (Defense in Depth)، بحيث يكون الـ Application Code هو الأساس لتوجيه العمليات، والـ RLS (Row Level Security) هو الطبقة الأخيرة التي لا يمكن تجاوزها
💬 2🔁 4❤ 16
A
Ali @elasadeltayyeb · 10h
لو هستخدم mongo db بحس ان احسن حاجة الsharding by tenant id بس بصراحة حاسه ممكن يكون حل over engineered شوية الميزة ان mongo db بتسهل اوي موضوع الsharding وكمان هيبقى فيه data isolation
Sharding by tenant idSplitting the database across multiple servers, using the tenant as the dividing line — each customer's data physically lives on a specific shard.
Over engineeredBuilding a more complex solution than the problem actually needs right now.
Data isolationCustomer data kept structurally separate — here, achieved by which shard the data lives on rather than a filter rule.
💬 5🔁 11❤ 48
SK
KoZman @SherifKozman · 9h
RLS on the database level ensures hard gated isolation that is not bound to unforeseen issues of code that might behave differently under different circumstances or underlying environment
Database levelEnforced at the lowest layer of the stack — closest to where the data actually lives.
Hard gated isolationIsolation that can't be accidentally bypassed by a bug, an edge case, or a different runtime environment — it's structurally guaranteed rather than just "usually correct."
💬 4🔁 19❤ 88