diff --git a/invenio_utilities_tuw/cli/drafts.py b/invenio_utilities_tuw/cli/drafts.py
index 45b386b1aefbb7cc1bfa06d767a68683b55b4c4e..14800e5afcbcf496dd70dc3839ec1faea5a97b19 100644
--- a/invenio_utilities_tuw/cli/drafts.py
+++ b/invenio_utilities_tuw/cli/drafts.py
@@ -11,6 +11,8 @@
 import json
 import os
 import sys
+from collections import namedtuple
+from datetime import datetime, timedelta
 from os.path import basename, isdir, isfile, join
 
 import click
@@ -430,3 +432,56 @@ def verify_files(pid, pid_type):
             err=True,
         )
         sys.exit(1)
+
+
+@drafts.command("list-stale")
+@click.option(
+    "--days",
+    "-d",
+    "num_days",
+    help="threshold after how many days a draft is considered stale",
+    default=30,
+    type=int,
+)
+@with_appcontext
+def list_stale_drafts(num_days):
+    """List all drafts that haven't been updated for a while."""
+    service = get_record_service()
+    dc, mc = service.draft_cls, service.draft_cls.model_cls
+    cutoff_date = datetime.utcnow() - timedelta(days=abs(num_days))
+
+    # `draft.status` uses the system field:
+    # `invenio_rdm_records.records.systemfields.draft_status.DraftStatus`
+    stale_drafts = [
+        draft
+        for draft in (
+            dc(model.data, model=model)
+            for model in mc.query.filter(mc.updated <= cutoff_date).all()
+        )
+        if draft and draft.status in ["new_version_draft", "draft"]
+    ]
+
+    # collect infos about stale drafts
+    draft_info = namedtuple("DraftInfo", ["recid", "title", "uploader", "updated"])
+    stale_draft_infos = []
+    for draft in stale_drafts:
+        recid = draft.pid.pid_value
+        title = draft.metadata.get("title", "[UNNAMED]")
+
+        # InvenioRDM v11 still supports several record owners
+        uploader = draft.parent.access.owned_by
+        if isinstance(uploader, list):
+            if uploader:
+                uploader = uploader[0]
+            else:
+                uploader = None
+
+        uploader_email = uploader.resolve().email if uploader else "[N/A]"
+        updated = draft.updated.date() if draft.updated else "[N/A]"
+        stale_draft_infos.append(draft_info(recid, title, uploader_email, updated))
+
+    # print the info about stale drafts, sorted by the owner's email address
+    max_email_len = max((len(di.uploader) for di in stale_draft_infos))
+    for info in sorted(stale_draft_infos, key=lambda di: di.uploader):
+        email = info.uploader.rjust(max_email_len)
+        click.echo(f'{info.recid} - {email} @ {info.updated} - "{info.title}"')