# How to Set Up Data Expiry in Bubble

- Tool: Bubble
- Difficulty: Beginner
- Time required: 15-20 min
- Compatibility: Growth plan+ (backend workflows required)
- Last updated: March 2026

## TL;DR

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.

## Before you start

- 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

### 1. 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.

### 2. 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.

### 3. 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.

### 4. 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.

### 5. 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 code example

File: `Workflow summary`

```text
DATA EXPIRY — WORKFLOW SUMMARY
=================================

DATA TYPE FIELDS:
  expires_at (date) — when the record expires
  is_archived (yes/no) — for soft delete
  archived_date (date) — when it was archived

BACKEND: cleanup_expired_records
  Step 1: Search [Type] where
    expires_at < Current date/time
    is_archived = no
    Limit: 50 records
  Step 2 (hard delete): Delete list of Things
  Step 2 (soft delete): Make changes → is_archived = yes
  Step 3: Check remaining count
    If count > 0: reschedule self in 1 second
    If count = 0: schedule self in 24 hours

SETTING EXPIRY ON CREATION:
  Create [Thing] workflow:
    expires_at = Current date/time + 30 days

ADMIN MONITORING:
  Run Cleanup Now button → schedule immediately
  Display: total records, expired pending, last run
  Check Logs tab for workflow execution
```

## Common mistakes

- **Deleting all expired records in a single workflow step without batching** — Deleting thousands of records at once causes workflow timeouts and may fail silently Fix: Process records in batches of 50 and use recursive scheduling for the remaining records
- **Using hard delete when you might need the data for disputes or audits** — Hard-deleted data is gone forever — you cannot recover it if a user or regulator requests it Fix: Implement soft delete (is_archived = yes) with a secondary hard delete after a longer retention period
- **Not setting expiry dates when records are created** — Records without an expires_at value are never cleaned up, defeating the purpose of the system Fix: 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

## 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.

---

Source: https://www.rapidevelopers.com/bubble-tutorial/set-up-data-expiry-in-bubble
© RapidDev — https://www.rapidevelopers.com/bubble-tutorial/set-up-data-expiry-in-bubble
