Data expiry in Bubble uses a scheduled backend workflow that runs daily, searches for records older than your retention period, and deletes or archives them. You add an 'expires_at' or 'created_date' field to your Data Type, create a recursive backend workflow to process expired records in batches, and schedule it to run automatically. This keeps your database lean and can help with privacy compliance.
Overview: Data Expiry in Bubble
This tutorial covers automating data cleanup by setting up expiry rules for database records. You will add expiry fields, create scheduled workflows, implement batch deletion, and choose between soft and hard delete approaches.
Prerequisites
- A Bubble app on a paid plan (Growth+ for backend workflows)
- A Data Type with records that should expire
- Backend workflows enabled in Settings → API
- Understanding of scheduled and recursive workflows
Step-by-step guide
Add expiry fields to your Data Type
Add expiry fields to your Data Type
In the Data tab, add an 'expires_at' (date) field to each Data Type that needs expiry. When creating records, set expires_at based on your retention policy — for example, Current date/time plus 30 days for temporary data, or plus 1 year for audit logs. For soft delete, also add 'is_archived' (yes/no, default no) and 'archived_date' (date).
Expected result: Data Types have expiry date fields that define when each record should be deleted or archived.
Create the cleanup backend workflow
Create the cleanup backend workflow
In the backend workflows editor, create 'cleanup_expired_records'. Add a search step: 'Do a search for [Type] where expires_at is less than Current date/time and is_archived is no'. Limit the search to 50 records per run to avoid timeouts. For hard delete: use 'Delete a list of Things' on the results. For soft delete: use 'Make changes to a list of Things' setting is_archived to yes and archived_date to Current date/time.
Pro tip: Process in batches of 50 to prevent workflow timeouts. The workflow will reschedule itself to handle remaining records.
Expected result: A backend workflow finds expired records and either deletes or archives them in manageable batches.
Make the workflow recursive for large datasets
Make the workflow recursive for large datasets
After processing a batch, check if there are more expired records. Add a step: 'Do a search for [Type] where expires_at < now' and check the count. If count is greater than 0, schedule 'cleanup_expired_records' to run again in 1 second. This creates a loop that processes all expired records regardless of volume. Add a termination condition to prevent infinite loops — stop when count is 0.
Expected result: The workflow processes all expired records in batches, automatically continuing until all are handled.
Schedule the cleanup to run daily
Schedule the cleanup to run daily
Use recursive scheduling to run the cleanup every 24 hours. At the end of the cleanup workflow (after all batches are processed), add 'Schedule API Workflow' targeting itself with a 24-hour delay. Kick off the initial run from an admin page button. Alternatively, use a 'Do every 24 hours' event on an admin page, but this only runs while the page is open.
Expected result: The cleanup workflow runs automatically every day, processing all newly expired records.
Add a manual cleanup trigger and monitoring
Add a manual cleanup trigger and monitoring
On an admin page, add a 'Run Cleanup Now' button that schedules the cleanup_expired_records workflow immediately. Below it, display statistics: count of total records, count of expired records pending cleanup, and last cleanup date (store this in an admin settings record). Check the Logs tab periodically to verify the workflow is running successfully.
Expected result: Admins can trigger manual cleanup, monitor pending expired records, and verify the automated schedule is running.
Complete working example
1DATA EXPIRY — WORKFLOW SUMMARY2=================================34DATA TYPE FIELDS:5 expires_at (date) — when the record expires6 is_archived (yes/no) — for soft delete7 archived_date (date) — when it was archived89BACKEND: cleanup_expired_records10 Step 1: Search [Type] where11 expires_at < Current date/time12 is_archived = no13 Limit: 50 records14 Step 2 (hard delete): Delete list of Things15 Step 2 (soft delete): Make changes → is_archived = yes16 Step 3: Check remaining count17 If count > 0: reschedule self in 1 second18 If count = 0: schedule self in 24 hours1920SETTING EXPIRY ON CREATION:21 Create [Thing] workflow:22 expires_at = Current date/time + 30 days2324ADMIN MONITORING:25 Run Cleanup Now button → schedule immediately26 Display: total records, expired pending, last run27 Check Logs tab for workflow executionCommon mistakes when setting up Data Expiry in Bubble
Why it's a problem: Deleting all expired records in a single workflow step without batching
How to avoid: Process records in batches of 50 and use recursive scheduling for the remaining records
Why it's a problem: Using hard delete when you might need the data for disputes or audits
How to avoid: Implement soft delete (is_archived = yes) with a secondary hard delete after a longer retention period
Why it's a problem: Not setting expiry dates when records are created
How to avoid: Set expires_at in every Create Thing workflow, calculating from Current date/time plus your retention period
Best practices
- Process deletions in batches of 50 to avoid timeouts
- Use soft delete first, then hard delete after a secondary retention period
- Set expiry dates at record creation time, not retroactively
- Schedule cleanup during off-peak hours to minimize performance impact
- Log cleanup results for audit and monitoring
- Consider different retention periods for different data types
- Ensure the recursive scheduling has a clear termination condition
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I need to automatically delete user-generated content in my Bubble.io app after 90 days for privacy compliance. How do I set up scheduled data expiry with batch processing?
Set up automatic data expiry for my app. Add an expires_at field to the Message data type. Create a daily backend workflow that finds and deletes messages older than 90 days in batches. Add an admin button to trigger manual cleanup.
Frequently asked questions
Can I recover hard-deleted records?
No. Hard-deleted records are permanently removed from Bubble's database with no recovery option. Always use soft delete if you might need the data later.
How many records can the cleanup process per day?
With batches of 50 and 1-second intervals, the workflow can process about 4,000-5,000 records per hour. For very large datasets, run it during off-peak hours.
Does data expiry reduce my workload unit consumption?
Indirectly, yes. Fewer records mean faster searches and less data transmission, which reduces WU consumption on all database operations.
Can I let users set their own data retention period?
Yes. Add a 'retention_days' field to the User type. When creating records, set expires_at to Current date/time plus the user's retention_days.
Can RapidDev help implement data compliance and expiry in Bubble?
Yes. RapidDev can build GDPR-compliant data management systems with automated expiry, user data export, right-to-deletion workflows, and audit logging.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation