Skip to main content
RapidDev - Software Development Agency
firebase-tutorial

How to Delete Data in Firebase Realtime Database

Delete data in Firebase Realtime Database using remove() on a database reference or by calling set(null) on the path you want to clear. Both approaches delete the node and all its children. For multi-path deletions, use update() with null values to atomically remove multiple nodes in a single operation. Always configure security rules to control who can delete data, and remember that deleting a parent node removes all its children automatically.

What you'll learn

  • How to delete a single node using remove() and set(null)
  • How to delete multiple paths atomically with update()
  • How to handle cascading deletions of child nodes
  • How to write security rules that control delete permissions
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner8 min read10-15 minFirebase (all plans), firebase 10.x+, Realtime Database modular SDK v9+March 2026RapidDev Engineering Team
TL;DR

Delete data in Firebase Realtime Database using remove() on a database reference or by calling set(null) on the path you want to clear. Both approaches delete the node and all its children. For multi-path deletions, use update() with null values to atomically remove multiple nodes in a single operation. Always configure security rules to control who can delete data, and remember that deleting a parent node removes all its children automatically.

Deleting Data in Firebase Realtime Database with remove and Multi-Path Updates

Firebase Realtime Database stores data as a single JSON tree, so deleting a node removes everything beneath it. This tutorial covers three deletion methods: remove() for single nodes, set(null) as an alternative, and multi-path update() for atomic deletions across different locations. You will also learn how to write security rules for delete permissions and handle common deletion patterns like cleaning up related data.

Prerequisites

  • A Firebase project with Realtime Database enabled (Firebase Console > Realtime Database > Create database)
  • Firebase SDK installed and initialized in your project
  • The getDatabase instance exported from your firebase.ts module
  • Some existing data in the database to delete

Step-by-step guide

1

Delete a single node with remove()

Use the remove() function on a database reference to delete a node and all its children. Import ref and remove from firebase/database. Create a reference to the specific path you want to delete, then call remove(). The operation returns a Promise that resolves when the deletion is committed to the server.

typescript
1import { db } from "@/lib/firebase"; // getDatabase() export
2import { ref, remove } from "firebase/database";
3
4async function deleteMessage(chatId: string, messageId: string) {
5 try {
6 const messageRef = ref(db, `chats/${chatId}/messages/${messageId}`);
7 await remove(messageRef);
8 console.log("Message deleted successfully");
9 } catch (error) {
10 console.error("Error deleting message:", error);
11 throw error;
12 }
13}

Expected result: The specified node and all its children are removed from the database.

2

Delete by setting a value to null

An alternative to remove() is calling set(null) on the reference. In Realtime Database, setting a value to null is equivalent to deleting it. This can be useful when you want to conditionally delete using the same code path as setting values.

typescript
1import { db } from "@/lib/firebase";
2import { ref, set } from "firebase/database";
3
4async function deleteUserProfile(userId: string) {
5 const userRef = ref(db, `users/${userId}`);
6 await set(userRef, null); // Equivalent to remove(userRef)
7}

Expected result: The node is deleted, identical in effect to calling remove().

3

Delete multiple paths atomically with update()

When you need to delete data from multiple locations at once (fan-out deletion), use update() with null values. This atomic operation ensures all paths are deleted together — either all succeed or all fail. This is essential for maintaining data consistency when related data exists in multiple locations.

typescript
1import { db } from "@/lib/firebase";
2import { ref, update } from "firebase/database";
3
4async function deletePost(postId: string, userId: string) {
5 const updates: Record<string, null> = {};
6
7 // Delete the post from the main posts list
8 updates[`posts/${postId}`] = null;
9
10 // Delete from the user's posts index
11 updates[`user-posts/${userId}/${postId}`] = null;
12
13 // Delete from any topic feeds
14 updates[`topic-feed/general/${postId}`] = null;
15
16 // Atomic multi-path delete
17 await update(ref(db), updates);
18 console.log("Post deleted from all locations");
19}

Expected result: All specified paths are deleted in a single atomic operation.

4

Delete specific child properties without removing the entire node

Sometimes you want to remove specific fields from a node without deleting the entire object. Use update() with null values for just the fields you want to remove. This keeps the rest of the node intact.

typescript
1import { db } from "@/lib/firebase";
2import { ref, update } from "firebase/database";
3
4async function removeOptionalFields(userId: string) {
5 const userRef = ref(db, `users/${userId}`);
6
7 // Remove specific fields, keep everything else
8 await update(userRef, {
9 phoneNumber: null, // Removes this field
10 temporaryData: null, // Removes this field
11 // displayName, email, etc. remain unchanged
12 });
13}

Expected result: Only the specified fields are removed; all other fields in the node remain unchanged.

5

Write security rules for delete permissions

Realtime Database security rules use .write to control both write and delete operations. There is no separate delete permission — any path where .write is true allows deletion. Use the data variable (existing data) and newData variable (incoming data) to distinguish between writes and deletes. When deleting, newData.exists() returns false.

typescript
1// database.rules.json
2{
3 "rules": {
4 "posts": {
5 "$postId": {
6 ".read": "auth != null",
7 ".write": "auth != null && (
8 // Allow create: no existing data
9 !data.exists() ||
10 // Allow update/delete: only by the author
11 data.child('authorId').val() === auth.uid
12 )"
13 }
14 },
15 "user-posts": {
16 "$userId": {
17 ".write": "auth != null && auth.uid === $userId"
18 }
19 }
20 }
21}

Expected result: Security rules are configured so only authorized users (e.g., the post author) can delete data.

6

Implement soft delete for recoverable data

For important data, implement soft delete by setting a deleted flag instead of actually removing the node. This lets you recover data if needed and filter it out of queries. You can set up a scheduled Cloud Function to permanently delete soft-deleted items after a retention period.

typescript
1import { db } from "@/lib/firebase";
2import { ref, update, serverTimestamp } from "firebase/database";
3
4// Soft delete — mark as deleted without removing
5async function softDeletePost(postId: string) {
6 const postRef = ref(db, `posts/${postId}`);
7 await update(postRef, {
8 deleted: true,
9 deletedAt: serverTimestamp(),
10 });
11}
12
13// Restore soft-deleted item
14async function restorePost(postId: string) {
15 const postRef = ref(db, `posts/${postId}`);
16 await update(postRef, {
17 deleted: null, // Remove the deleted flag
18 deletedAt: null,
19 });
20}
21
22// Query: filter out deleted items in your reads
23// Use orderByChild('deleted').equalTo(null) or filter client-side

Expected result: Data is marked as deleted but remains in the database for recovery. Queries filter out soft-deleted items.

Complete working example

src/lib/rtdb-delete.ts
1import { db } from "@/lib/firebase";
2import { ref, remove, set, update, serverTimestamp } from "firebase/database";
3
4// Delete a single node
5export async function deleteNode(path: string): Promise<void> {
6 await remove(ref(db, path));
7}
8
9// Delete multiple paths atomically
10export async function deleteMultiplePaths(
11 paths: string[]
12): Promise<void> {
13 const updates: Record<string, null> = {};
14 paths.forEach((path) => {
15 updates[path] = null;
16 });
17 await update(ref(db), updates);
18}
19
20// Delete a post and all its fan-out locations
21export async function deletePost(
22 postId: string,
23 userId: string,
24 topicId: string
25): Promise<void> {
26 await deleteMultiplePaths([
27 `posts/${postId}`,
28 `user-posts/${userId}/${postId}`,
29 `topic-feed/${topicId}/${postId}`,
30 ]);
31}
32
33// Soft delete with recovery option
34export async function softDelete(path: string): Promise<void> {
35 await update(ref(db, path), {
36 _deleted: true,
37 _deletedAt: serverTimestamp(),
38 });
39}
40
41// Restore soft-deleted node
42export async function restore(path: string): Promise<void> {
43 await update(ref(db, path), {
44 _deleted: null,
45 _deletedAt: null,
46 });
47}
48
49// Remove specific fields from a node
50export async function removeFields(
51 path: string,
52 fields: string[]
53): Promise<void> {
54 const updates: Record<string, null> = {};
55 fields.forEach((field) => {
56 updates[field] = null;
57 });
58 await update(ref(db, path), updates);
59}

Common mistakes when deleting Data in Firebase Realtime Database

Why it's a problem: Deleting a parent node without realizing it removes all children, causing unintended data loss

How to avoid: Realtime Database is a JSON tree — removing a node removes everything under it. Always verify the path before deleting. Use ref(db, 'specific/nested/path') not ref(db, 'specific') when you only want to remove a child.

Why it's a problem: Deleting data from one location but forgetting to clean up denormalized copies in other paths

How to avoid: Use multi-path update() with null values to atomically delete from all locations at once. This prevents orphaned data in fan-out patterns.

Why it's a problem: Not handling the error case when the user does not have permission to delete

How to avoid: Wrap delete operations in try/catch. Security rule rejections throw a PERMISSION_DENIED error. Display a user-friendly message like 'You do not have permission to delete this item.'

Best practices

  • Use multi-path update() with null values when deleting data that exists in multiple locations to maintain consistency
  • Implement soft delete for important data by setting a _deleted flag instead of using remove()
  • Always wrap delete operations in try/catch to handle permission errors and network failures gracefully
  • Configure security rules that restrict delete permissions to data owners or admins
  • Test delete operations in the Firebase Emulator before running them against production data
  • Consider creating a Cloud Function that listens for deletions and cleans up related data automatically

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

Show me how to delete data in Firebase Realtime Database using the modular v9+ SDK. I need to delete a single node with remove(), delete multiple paths atomically with update(), and implement soft delete. Include TypeScript types and security rules for delete permissions.

Firebase Prompt

Delete data from Firebase Realtime Database using the modular SDK. Show remove() for a single node, multi-path update() with null values for atomic deletion of denormalized data (posts, user-posts, topic-feed), and soft delete with a _deleted flag. Include the database.rules.json for owner-only delete permission.

Frequently asked questions

What is the difference between remove() and set(null)?

They are functionally identical. Both delete the node and all its children from the database. remove() is more explicit about the intent, while set(null) can be useful when you want to use the same code path for both setting and clearing values.

Does deleting a parent node delete all its children?

Yes. Realtime Database is a JSON tree. Deleting a node removes it and everything nested beneath it. If you delete 'users/abc123', all children like 'users/abc123/profile', 'users/abc123/settings', etc. are gone.

Can I undo a delete in Realtime Database?

No. There is no built-in undo or trash. Once remove() succeeds, the data is permanently deleted. Implement soft delete (marking with a _deleted flag) if you need recovery capability.

How do I delete a specific field without removing the whole node?

Use update() with null for the specific field: update(ref(db, 'users/abc'), { phoneNumber: null }). This removes only the phoneNumber field while keeping all other fields intact.

Is there a separate 'delete' permission in Realtime Database security rules?

No. Realtime Database uses .write for both writes and deletes. To distinguish, check newData.exists() — it returns false during a delete operation. Example: .write: auth.uid === data.child('authorId').val() && !newData.exists() allows only the author to delete.

Can I delete data from multiple locations atomically?

Yes. Use update() on the root reference with null values for each path: update(ref(db), { 'path/a': null, 'path/b': null }). All paths are deleted in a single atomic operation.

What happens if a delete fails due to security rules?

The Promise rejects with a PERMISSION_DENIED error. For multi-path updates, the entire operation rolls back — no paths are deleted if any path fails the security check.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.