Build a data export system using Cloud Functions that asynchronously gather all user data into a JSON file, upload it to Firebase Storage, and return a download link. A backup_jobs collection tracks job status so the UI polls for completion. Add a restore function that re-creates Firestore documents from a backup. For GDPR compliance, include a Delete All My Data action that removes all user documents, Storage files, and the Auth account.
Building User Data Export, Backup, and Deletion in FlutterFlow
Users deserve control over their data. This tutorial builds a complete data management system: export all personal data as a downloadable file, restore from a backup, and permanently delete everything for GDPR compliance. Cloud Functions handle the heavy lifting asynchronously so the UI stays responsive.
Prerequisites
- FlutterFlow project with Firebase authentication
- Firestore collections containing user data (profile, posts, orders, etc.)
- Firebase Storage configured for backup file storage
- Cloud Functions enabled on your Firebase project
Step-by-step guide
Create the backup jobs tracking schema in Firestore
Create the backup jobs tracking schema in Firestore
Create a backup_jobs collection with fields: userId (String), status (String: pending, processing, completed, failed), type (String: export, restore, delete), downloadUrl (String, set when complete), fileSize (int, bytes), error (String, if failed), createdAt (Timestamp), completedAt (Timestamp). When a user initiates an export, a backup_jobs document is created with status 'pending'. The Cloud Function picks it up, processes it, and updates the status. The FlutterFlow page polls this document to show progress and the download link when ready.
Expected result: Firestore has a backup_jobs collection for tracking async export, restore, and delete operations.
Build the Cloud Function for async data export
Build the Cloud Function for async data export
Deploy a Cloud Function called exportUserData triggered by Firestore onCreate on the backup_jobs collection (filtered to type 'export'). The function updates status to 'processing', then queries all collections containing user data: the user profile document, all posts where authorId equals the userId, all orders where userId matches, and any other user-scoped collections. It compiles everything into a JSON object, converts it to a Buffer, uploads the buffer to Firebase Storage at path backups/{userId}/{timestamp}.json, generates a signed download URL (24-hour expiry), and updates the backup_jobs document with status 'completed', the downloadUrl, and fileSize.
1// Cloud Function: exportUserData2const functions = require('firebase-functions');3const admin = require('firebase-admin');4admin.initializeApp();56exports.exportUserData = functions.firestore7 .document('backup_jobs/{jobId}')8 .onCreate(async (snap, context) => {9 const job = snap.data();10 if (job.type !== 'export') return;11 12 const jobRef = snap.ref;13 await jobRef.update({ status: 'processing' });14 15 try {16 const uid = job.userId;17 const db = admin.firestore();18 19 // Gather all user data20 const userData = {};21 userData.profile = (await db.collection('users').doc(uid).get()).data();22 userData.posts = (await db.collection('posts')23 .where('authorId', '==', uid).get())24 .docs.map(d => d.data());25 userData.orders = (await db.collection('orders')26 .where('userId', '==', uid).get())27 .docs.map(d => d.data());28 29 // Upload to Storage30 const bucket = admin.storage().bucket();31 const filename = `backups/${uid}/${Date.now()}.json`;32 const file = bucket.file(filename);33 const buffer = Buffer.from(JSON.stringify(userData, null, 2));34 await file.save(buffer, { contentType: 'application/json' });35 36 const [url] = await file.getSignedUrl({37 action: 'read',38 expires: Date.now() + 24 * 60 * 60 * 1000,39 });40 41 await jobRef.update({42 status: 'completed',43 downloadUrl: url,44 fileSize: buffer.length,45 completedAt: admin.firestore.FieldValue.serverTimestamp(),46 });47 } catch (err) {48 await jobRef.update({ status: 'failed', error: err.message });49 }50 });Expected result: The Cloud Function gathers all user data, creates a JSON file in Storage, and updates the job with a download URL.
Build the Export My Data UI with job status polling
Build the Export My Data UI with job status polling
On the Settings page, add a section called Data Management. Add a button labeled Export My Data. On tap, create a backup_jobs document with userId set to the current user, type 'export', and status 'pending'. Then display a progress section: query the backup_jobs document and show the current status with appropriate icons (clock for pending, spinner for processing, checkmark for completed, X for failed). When status is 'completed', show a Download button that launches the downloadUrl. Use a periodic Backend Query refresh (or FlutterFlow's real-time query with Single Time Query OFF) to automatically update the status display.
Expected result: Users tap Export My Data, see real-time progress, and get a download link when the export completes.
Build the data restore Cloud Function
Build the data restore Cloud Function
Deploy a Cloud Function called restoreUserData that receives a backup file URL and userId. The function downloads the JSON file from Storage, parses it, and re-creates the Firestore documents. For each collection (profile, posts, orders), it uses batch writes to create the documents. The function handles conflicts: if a document with the same ID already exists, it either merges or skips based on a parameter. Track the restore job in backup_jobs with type 'restore'. This is useful for recovering accidentally deleted data or migrating between accounts.
Expected result: The restore Cloud Function reads a backup JSON file and re-creates Firestore documents for the user.
Add GDPR-compliant Delete All My Data functionality
Add GDPR-compliant Delete All My Data functionality
Add a Delete All My Data button with a prominent red style and a two-step confirmation: first a dialog explaining what will be deleted, then a TextField requiring the user to type 'DELETE' to confirm. On confirmation, create a backup_jobs document with type 'delete'. The Cloud Function deletes all user documents across every collection (posts, orders, comments, etc.), deletes all Storage files under the user's path, and finally deletes the Firebase Auth account using admin.auth().deleteUser(uid). After deletion, the app signs the user out and navigates to a goodbye confirmation page.
Expected result: Users can permanently delete all their data across Firestore, Storage, and Auth with double confirmation.
Show backup history with past exports
Show backup history with past exports
Below the Export button, add a ListView querying backup_jobs where userId equals the current user, ordered by createdAt descending. Each item shows: the job type (export/restore/delete), status badge (color-coded), creation date, file size (for exports), and a re-download link if the URL has not expired. Add a note that download links expire after 24 hours. For expired links, show a Re-export button that creates a new backup job. This gives users a complete history of their data management actions.
Expected result: Users see a history of all their backup, restore, and delete operations with status and download links.
Complete working example
1FIRESTORE SCHEMA:2 backup_jobs (collection):3 userId: String4 status: String (pending|processing|completed|failed)5 type: String (export|restore|delete)6 downloadUrl: String (optional, set on completion)7 fileSize: int (bytes, optional)8 error: String (optional, on failure)9 createdAt: Timestamp10 completedAt: Timestamp (optional)1112CLOUD FUNCTION: exportUserData13 Triggered: onCreate backup_jobs where type == 'export'14 → Set status = 'processing'15 → Query user profile, posts, orders, etc.16 → Compile to JSON17 → Upload to Storage: backups/{uid}/{timestamp}.json18 → Generate 24-hour signed URL19 → Update job: status = 'completed', downloadUrl, fileSize2021CLOUD FUNCTION: restoreUserData22 Triggered: onCreate backup_jobs where type == 'restore'23 → Download backup JSON from Storage24 → Parse JSON → batch write documents to Firestore25 → Update job: status = 'completed'2627CLOUD FUNCTION: deleteUserData28 Triggered: onCreate backup_jobs where type == 'delete'29 → Delete all user docs across collections30 → Delete Storage files under user path31 → Delete Firebase Auth account32 → Update job: status = 'completed'3334PAGE: Settings — Data Management Section35 Button "Export My Data" (blue)36 → Create backup_jobs doc (type: export)37 → Show progress: pending → processing → completed38 → On complete: Download button with URL3940 Button "Delete All My Data" (red)41 → Confirmation dialog: explain what gets deleted42 → TextField: type 'DELETE' to confirm43 → Create backup_jobs doc (type: delete)44 → Sign out + navigate to goodbye page4546 Backup History:47 ListView: backup_jobs where userId == currentUser48 Each item: type badge + status badge + date + size + downloadCommon mistakes when creating a Secure Data Backup System in FlutterFlow
Why it's a problem: Exporting data synchronously in the Action Flow
How to avoid: Use async processing: create a backup_jobs document, let a Cloud Function handle the export in the background, and poll the job status from the UI.
Why it's a problem: Forgetting to delete data from all collections during GDPR deletion
How to avoid: Maintain a list of all collections that store user data. The delete Cloud Function must iterate through every collection. Add new collections to the list whenever your schema changes.
Why it's a problem: Using permanent download URLs for backup files
How to avoid: Generate signed URLs with a 24-hour expiry. After that, users must re-export to get a fresh download link.
Best practices
- Process data exports asynchronously via Cloud Functions with job status tracking
- Use signed URLs with expiry for backup file downloads
- Require double confirmation (dialog plus typed confirmation) for data deletion
- Delete data from ALL collections, Storage, and Auth during GDPR deletion
- Show backup history so users can track their data management actions
- Create a final backup before deletion so users can download their data first
- Log all data management operations for audit compliance
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
Build a user data backup system for a FlutterFlow app. I need: async data export via Cloud Function (queries all user collections, compiles JSON, uploads to Storage, returns signed URL), a backup_jobs Firestore collection for tracking, data restore from backup, and GDPR-compliant deletion of all user data across Firestore + Storage + Auth. Include the Cloud Function code and Firestore schema.
Create a Data Management section on the settings page with an Export My Data button (blue), a Delete All My Data button (red), and a ListView below showing backup history items with status badges and download links.
Frequently asked questions
How long does a data export take?
It depends on data volume. A typical user with a few hundred documents completes in 5-15 seconds. Users with thousands of documents may take up to a minute. The async job tracking keeps the UI responsive regardless of duration.
Can I schedule automatic backups?
Yes. Deploy a scheduled Cloud Function that runs daily or weekly. It creates a backup_jobs document for each user (or only active users) which triggers the export function. Store backups with dated filenames and implement retention (delete backups older than 30 days).
What format should the backup file use?
JSON is the simplest and most portable format. For larger datasets, consider generating a ZIP file containing separate JSON files per collection. This reduces download size and makes selective restoration easier.
Can users restore only part of their data?
Yes. Modify the restore Cloud Function to accept a collections parameter specifying which collections to restore (e.g., only posts, not orders). The UI can show checkboxes for each data type before starting the restore.
Is the data deletion reversible?
No. Once the Cloud Function deletes data, it is permanently gone. That is why the tutorial requires double confirmation and recommends creating a final backup before deletion. Make this clear to users in the confirmation dialog.
Can RapidDev help implement data compliance features?
Yes. RapidDev can build GDPR-compliant data management systems including automated backups, data export, right-to-erasure deletion, consent tracking, and audit logging for regulatory compliance.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation