Firebase Security Rules Examples

Firebase security rules decide who can read and write each piece of data in your app. Start every Firestore file with rules_version = '2', allow access only when request.auth is set, compare request.auth.uid with the document owner, and check incoming fields with request.resource.data. Test with the emulator before deploying.

The variables you use most in each product
ProductSigned-in userData being written
Cloud Firestorerequest.auth.uidrequest.resource.data
Cloud Storagerequest.auth.uidrequest.resource (size, contentType)
Realtime Databaseauth.uidnewData

Updated

If your app, shop or member area stores data in Firebase, the rules are the only thing standing between your customers' records and anyone with your project's public config. The recipes below cover the cases most small apps need. Filter by product, copy one, and change the collection names to match yours.

Rule recipes

Owner-only profiles

Each user reads and edits only the document whose id equals their user id.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read, update, delete: if request.auth != null && request.auth.uid == userId;
      allow create: if request.auth != null && request.auth.uid == userId;
    }
  }
}

Public read, admin write

Anyone can read the product catalogue; only users whose profile has role admin can change it.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    function isAdmin() {
      return request.auth != null
        && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == 'admin';
    }
    match /products/{productId} {
      allow read: if true;
      allow write: if isAdmin();
    }
  }
}

Validate new orders

A customer can create an order only for themselves, with a positive total and a known status, and cannot edit it afterwards.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /orders/{orderId} {
      allow read: if request.auth != null && request.auth.uid == resource.data.customerId;
      allow create: if request.auth != null
        && request.resource.data.customerId == request.auth.uid
        && request.resource.data.total is number
        && request.resource.data.total > 0
        && request.resource.data.status == 'pending';
      allow update, delete: if false;
    }
  }
}

Users cannot change their own role

Profile edits are allowed only when the role field stays exactly as it was.

match /users/{userId} {
  allow update: if request.auth != null
    && request.auth.uid == userId
    && request.resource.data.role == resource.data.role;
}

Users upload their own images under 5MB

Files live under each user's folder; uploads must be images smaller than 5MB, and anyone signed in can view them.

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /users/{userId}/{fileName} {
      allow read: if request.auth != null;
      allow write: if request.auth != null
        && request.auth.uid == userId
        && request.resource.size < 5 * 1024 * 1024
        && request.resource.contentType.matches('image/.*');
    }
  }
}

Owner-only data with validation

Realtime Database rules are JSON. $uid captures the key; newData is the value being written.

{
  "rules": {
    "users": {
      "$uid": {
        ".read": "auth !== null && auth.uid === $uid",
        ".write": "auth !== null && auth.uid === $uid",
        ".validate": "newData.hasChildren(['name', 'email'])"
      }
    }
  }
}

Rules to remove before launch

These patterns appear in starter projects and tutorials. Each one leaves data open.

Risky rules and safer replacements
Risky ruleWhy it is a problemReplace with
allow read, write: if true;Anyone can read or overwrite everythingOwner-only or role checks
allow read, write: if request.time < timestamp.date(...);Wide open until the date, then everything breaksReal rules per collection
allow read, write: if request.auth != null;Any signed-in stranger can edit any user's dataCompare request.auth.uid with the owner

Test rules with the emulator

Run the Firestore emulator, then check that the owner can write and a stranger cannot.

Rules unit test with @firebase/rules-unit-testing

Uses a demo project id so nothing reaches a live database. Run it while firebase emulators:start --only firestore is running.

import { readFileSync } from "node:fs";
import { initializeTestEnvironment, assertSucceeds, assertFails } from "@firebase/rules-unit-testing";
import { doc, setDoc } from "firebase/firestore";

const testEnv = await initializeTestEnvironment({
  projectId: "demo-shop",
  firestore: { rules: readFileSync("firestore.rules", "utf8") },
});

const alice = testEnv.authenticatedContext("alice").firestore();
const stranger = testEnv.unauthenticatedContext().firestore();

await assertSucceeds(setDoc(doc(alice, "users/alice"), { name: "Alice" }));
await assertFails(setDoc(doc(stranger, "users/alice"), { name: "Mallory" }));

await testEnv.cleanup();

How a rule is read

A match block names a path, and allow lines inside it name the actions, such as read, create, update and delete, with a condition after if. Access is granted when any matching allow line is true; there is no deny statement.

resource.data is the document as it exists now, and request.resource.data is how it would look after the write. Comparing the two is how you stop someone changing a field they should not touch.

Roles without a backend

A common pattern stores a role field on each user document and reads it with get() in other rules. Make sure users cannot edit their own role, or anyone could promote themselves to admin.

An alternative is custom claims on the sign-in token, set from server code and read as request.auth.token, which costs no extra document reads.

How it works

  1. Pick the recipe that matches your case and copy it into your rules file.
  2. Rename the collection or path names, such as users or orders, to match your database.
  3. Run the rules in the Local Emulator Suite and try both allowed and blocked requests.
  4. Deploy with the Firebase CLI or publish in the console once the tests pass.

Tips

Frequently asked questions

What is Firestore test mode?

One of the two starting choices when you create a database. Firebase describes test mode as good for getting started but says it allows anyone to read and overwrite your data. Production mode denies all reads and writes from mobile and web clients until you write rules.

Why did my app suddenly get permission denied errors?

Look for a condition comparing request.time with a fixed date, such as request.time < timestamp.date(2026, 11, 1). Once that date passes, every request fails. Replace it with real rules rather than moving the date.

How many get() calls can one rule make?

Firebase documents a limit of 10 document access calls for single-document requests and queries, and 20 for multi-document reads, transactions and batched writes. Going over results in a permission denied error.

Do security rules apply to my server code?

No. Rules guard requests from mobile and web clients. Firebase states that the server client libraries bypass all Cloud Firestore Security Rules, so check inputs in your server code separately.

How do I test rules without touching live data?

Start the emulator with firebase emulators:start --only firestore, then write tests with the @firebase/rules-unit-testing package, using assertSucceeds and assertFails for allowed and blocked actions.

Related: Supabase vs Firebase, Supabase Auth guide, How to add a contact form.

Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.

More in Guides

We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.

Product

Who It's For

Features

Resources

Company

View Sitemap