# Not all tables get deleted, esp m:m, 1:m etc

**URL:** https://community.directus.com/t/not-all-tables-get-deleted-esp-m-m-1-m-etc/900
**Category:** Help
**Created:** [August 3, 2025, 5:52am UTC](https://community.directus.com/t/not-all-tables-get-deleted-esp-m-m-1-m-etc/900 "2025-08-03T05:52:05Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![rowild](https://sea2.discourse-cdn.com/flex002/user_avatar/community.directus.com/rowild/32/647_2.png) [@rowild](https://community.directus.com/u/rowild)
#### Post date: [August 3, 2025, 5:52am UTC](https://community.directus.com/t/not-all-tables-get-deleted-esp-m-m-1-m-etc/900/1 "2025-08-03T05:52:05Z")

</div>

Hi, folks!

I am developing and testing Directus and build lots of collections with various relations. Often I delete a relation again – I assume this happens often in planning stage.

But it seems those tables and fields are not actually deleted. When I create a new relation and use the same names, I get an error message, when saving, saying the field already exists and has a relation.

I am sure I am doing something wrong. There is a section called “Relational Trigger”, where all the option are now set to “Nullify …”. And I think this is what I want, otherwise, whenever a user deletes a file or item, bad things would happen to the DB.

Is there a way to figure out, which tables and fields are unused in my Directus project, so I can really delete them? Currently I have the impression that developing could leave lots of “garbage” behind the DB…

---

<div class="post-metadata">

### Author: ![Nik](https://avatars.discourse-cdn.com/v4/letter/n/6de8d8/32.png) [@Nik](https://community.directus.com/u/Nik)
#### Post date: [August 4, 2025, 10:39am UTC](https://community.directus.com/t/not-all-tables-get-deleted-esp-m-m-1-m-etc/900/5 "2025-08-04T10:39:25Z")

</div>

Just stumbled across [this beauty](https://github.com/directus-labs/extensions/tree/main/packages/related-items-bundle). So much good stuff lingering in the dark.

It’s available on the marketplace, but it’s not sandboxed, so you need to set `MARKETPLACE_TRUST=all` to show it on the marketplace.

Although not showing the exact join table name, it might help you better understand the data schema from within Data Studio.

---

<div class="post-metadata">

### Author: ![ahmad\_quvor](https://sea2.discourse-cdn.com/flex002/user_avatar/community.directus.com/ahmad_quvor/32/310_2.png) [@ahmad\_quvor](https://community.directus.com/u/ahmad_quvor)
#### Post date: [August 3, 2025, 6:22am UTC](https://community.directus.com/t/not-all-tables-get-deleted-esp-m-m-1-m-etc/900/2 "2025-08-03T06:22:20Z")

</div>

Hello,

This is happening because of the cache, it will be best to disable the caching while you are in the planing stage. Set `CACHE_ENABLED` as false

---

<div class="post-metadata">

### Author: ![rowild](https://sea2.discourse-cdn.com/flex002/user_avatar/community.directus.com/rowild/32/647_2.png) [@rowild](https://community.directus.com/u/rowild)
#### Post date: [August 3, 2025, 6:37am UTC](https://community.directus.com/t/not-all-tables-get-deleted-esp-m-m-1-m-etc/900/3 "2025-08-03T06:37:03Z")

</div>

It seems that caching is not the reason for that. Here is my docker-compose.yaml file:

```yaml
version: '3'

services:
  directus_jvds:
    image: directus/directus:11.9.3
    ports:
      - 8056:8055
    volumes:
      - ./uploads:/directus/uploads
      - ./database:/directus/database
      - ./extensions:/directus/extensions
    environment:
      KEY: ''
      SECRET: ''
      DB_HOST: 'localhost'
      DB_CLIENT: 'sqlite3'
      DB_FILENAME: './database/data.db'
      ADMIN_EMAIL: ''
      ADMIN_PASSWORD: ''
      PUBLIC_URL: 'https://...:8056'
      STORAGE_LOCATIONS: 'local'
      STORAGE_LOCAL_DRIVER: 'local'
      STORAGE_LOCAL_ROOT: './uploads'
      WEBSOCKETS_ENABLED: true

      CORS_ENABLED: true
      CORS_ORIGIN: http://localhost
      CORS_METHODS: GET,POST,PATCH,DELETE
      CORS_ALLOWED_HEADERS: Content-Type,Authorization

      REDIS_ENABLED: false
      CACHE_ENABLED: false

```

Do I maybe have to change some other configuration?  
This Directus instance is hosted on DigitalOcean – maybe I have to change some settings there?

---

<div class="post-metadata">

### Author: ![Nik](https://avatars.discourse-cdn.com/v4/letter/n/6de8d8/32.png) [@Nik](https://community.directus.com/u/Nik)
#### Post date: [August 3, 2025, 12:08pm UTC](https://community.directus.com/t/not-all-tables-get-deleted-esp-m-m-1-m-etc/900/4 "2025-08-03T12:08:31Z")

</div>

Since it might not be an cache issue, it might just be an issue of orphaned collections or FK constraints. Directus magically creates join tables and foreign key constraints when adding relational interfaces, but cleaning those up might require additional steps.

I was too lazy to write a removal guide on my own, so I asked ChatGPT to do it for me. It basically looks good to me, but let me know if you encounter any failures.

Even if that doesn’t solve this problem, it may serve others as reference. It may help you tho, identifying orphan collections, based on the naming convention Directus uses when creating join tables.

Additional remark: The “Relational Trigger” you mentioned, just affects how referential integrity is handled on the join table rows while the relation is in effect. It doesn’t delete the join table or alter join table rows when dropping the interface.

# 🧹 Removing Relationships in Directus (Data Modeling Phase)

If you’re still designing your schema in **Directus Data Studio** and decide to remove relationships — such as many-to-many, many-to-any, one-to-many, or many-to-one — it’s important to follow the correct deletion order:

> 🔄 **Always delete relationship fields first** , then delete any join collections.

To illustrate each type, we’ll consistently use the following collections:

- `countries`
- `cities`
- `mountains`
- `countries_cities` (M2M join collection)
- `countries_points_of_interest` (M2A polymorphic join collection)

* * *

## 🔁 Many-to-Many (M2M): `countries` ↔ `cities` (via `countries_cities`)

### Structure

- `countries` and `cities` are linked by a **many-to-many** relationship.
- Directus automatically creates a join collection: **`countries_cities`**.

### Removal Steps

1. Go to the **`countries`** collection.
2. Delete the relationship field pointing to `cities`.
3. Go to **`cities`**.
4. Delete the inverse relationship field pointing to `countries`, if added.
5. Go to the **`countries_cities`** collection.
6. Delete the collection itself.

✅ M2M is fully removed.

* * *

## 🌀 Many-to-Any (M2A): `countries`, `cities`, `mountains` → `countries_points_of_interest`

### Structure

- Each of the collections (`countries`, `cities`, `mountains`) uses a **many-to-any** field called **`points_of_interest`**.
- The field is originally created in `countries`, so Directus names the join collection: **`countries_points_of_interest`**.

This is useful when multiple resource types (like countries, cities, and mountains) can reference shared items (e.g., tourist attractions).

### Removal Steps

1. Go to the **`countries`** collection.
2. Delete the `points_of_interest` field.
3. Go to the **`cities`** collection.
4. Delete the `points_of_interest` field, if added.
5. Go to the **`mountains`** collection.
6. Delete the `points_of_interest` field, if added.
7. Go to the **`countries_points_of_interest`** collection.
8. Delete the collection.

✅ M2A and its polymorphic join table are fully removed.

* * *

## 🔗 One-to-Many (O2M): `countries` → `cities`

### Structure

- Each **city** belongs to one **country**.
- `cities` has a **foreign key** field (e.g., `country_id`).
- `countries` may have a **virtual field** (e.g., `cities`) to show the related records.

### Removal Steps

1. Go to the **`cities`** collection.
2. Delete the foreign key field (`country_id`).
3. Go to the **`countries`** collection.
4. Delete the virtual field (`cities`), if present.

✅ O2M is now fully removed.

* * *

## 🔁 Many-to-One (M2O): `cities` → `countries`

### Structure

- Each **city** references a single **country** — the inverse of the O2M relationship.
- `cities` has a field like `country_id`.
- `countries` may show related cities in a virtual field.

### Removal Steps

1. Go to the **`cities`** collection.
2. Delete the `country_id` field.
3. Go to the **`countries`** collection.
4. Delete the virtual field (`cities`), if present.

✅ M2O is also removed — same structure as O2M but viewed from the reverse direction.

* * *

## ✅ Summary Table

| Relationship Type | Example | Step 1: Delete Fields | Step 2: Delete Collection |
| --- | --- | --- | --- |
| Many-to-Many | `countries` ↔ `cities` | Relationship fields in `countries` and `cities` | `countries_cities` |
| Many-to-Any | `countries`, `cities`, `mountains` → shared | `points_of_interest` fields in all three collections | `countries_points_of_interest` |
| One-to-Many | `countries` → `cities` | `country_id` in `cities`, `cities` virtual field in `countries` | _(no join collection)_ |
| Many-to-One | `cities` → `countries` | `country_id` in `cities`, `cities` virtual field in `countries` | _(no join collection)_ |

* * *

---

<div class="post-metadata">

### Author: ![Abdallah](https://sea2.discourse-cdn.com/flex002/user_avatar/community.directus.com/abdallah/32/105_2.png) [@Abdallah](https://community.directus.com/u/Abdallah)
#### Post date: [August 4, 2025, 12:44pm UTC](https://community.directus.com/t/not-all-tables-get-deleted-esp-m-m-1-m-etc/900/6 "2025-08-04T12:44:24Z")

</div>

I think I faced the same issue you are having with a sqlite db as well, as far as I remember I solved that by accessing the database directly and deleted the field from the directus\_fields collection.
