Deleting media from Postiz does not delete it from R2
📜 Description
Hi, I'm self hosting Postiz and encountered an issue when using R2 for storage and trying to delete media
Environment
- Docker config
STORAGE_PROVIDER=cloudflare
CLOUDFLARE_ACCOUNT_ID,=""
CLOUDFLARE_ACCESS_KEY=""
CLOUDFLARE_SECRET_ACCESS_KEY=""
CLOUDFLARE_BUCKETNAME=""
CLOUDFLARE_REGION=auto
- Public media URLs are served from a custom domain mapped to R2
- Objects are stored at the bucket root with no prefix (key = filename, e.g. cbbuTUM7DvUE3ai7KgXm.jpg).
- Uploading media works as expected and I can see and the images in the Media section and I can also use them to schedule posts
👟 Reproduction steps
- Upload an image — it is correctly stored in R2 at the bucket root and appears in the UI.
- Delete the image from the Postiz UI.
- API call: DELETE /api/media/
returns 200. - Response shows deletedAt is set.
- Refresh the page → the image disappears from the list.
- Check R2 bucket → the object is still present.
👍 Expected behavior
Deleting media in Postiz should also remove the corresponding object from R2.
👎 Actual Behavior with Screenshots
Only the DB row is soft-deleted (deletedAt set).
The R2 object is never removed.
💻 Operating system
Linux
🤖 Node Version
ghcr.io/gitroomhq/postiz-app:latest
📃 Provide any additional context for the Bug.
Using the same R2 credentials, a manual aws s3 rm s3://<bucket>/<filename> succeeds.
👀 Have you spent some time to check if this bug has been raised before?
- [x] I checked and didn't find similar issue
Are you willing to submit PR?
None
I'm experiencing the same behavior on release v2.7.0.
The file upload appears in Postiz and the R2 bucket. When I delete it from Postiz it is removed from the media library, however the file remains in the bucket.
Do You guys know how R2 Buckets are actually working ? You just need to set a retention window and the files get deleted after a certain time. Deleting is NOT a postiz task
@ozdreamwalk thank you for enlightening us.
Perhaps you'd also like to explain why removeFile is implemented in libraries/nestjs-libraries/src/upload/local.storage.ts but not in libraries/nestjs-libraries/src/upload/cloudflare.storage.ts.
I'm not an R2 expert so apologies in advance. I do not see an option for a deletion retention window aside from deleting uploads. I asked Gemini for some advice and it suggested this:
The option "Permanently delete expired object delete markers" will only appear if you have Object Versioning enabled on your R2 bucket.
When versioning is turned off (the default for new buckets), deleting a file removes it permanently and immediately. There are no "delete markers" to manage, so the option in the lifecycle rules is hidden.
When you enable versioning, deleting a file doesn't actually erase it. Instead, it places a "delete marker" on the object, making it invisible. The previous versions of the file are preserved. The lifecycle rule to "delete expired object delete markers" is specifically for cleaning up these markers in a versioned bucket.
Unfortunately, you cannot enable versioning on an existing R2 bucket at this time. You must configure versioning during the bucket creation process.
Is there not an S3 API call to delete a file without versioning enabled?
If not, the Postiz docs should be updated to note the need for Object Versioning when the bucket is created.