Firebase Security Rules: Copy-Paste Examples
Firestore, Realtime Database, and Cloud Storage rules you can paste in and adapt, each with a plain-English note on when to use it.
Most AI-generated Firebase apps ship with test-mode rules still on. This page shows what to replace them with.
What Firebase security rules actually control
Firebase doesn't put a traditional backend API between your app and your data. The client SDK talks to Firestore, Realtime Database, or Cloud Storage directly. Security rules are the only thing standing between a request and your data, there is no hidden server-side check happening anywhere else. If a rule allows it, it happens. If it doesn't, Firebase rejects the request before it touches storage.
That responsibility is split across three separate rule surfaces, each with its own file and its own syntax:
Firestore
Document-based rules in firestore.rules, written in the Firebase rules language.
Realtime Database
JSON rules in database.rules.json, evaluated per path in the tree.
Cloud Storage
File-path rules in storage.rules, similar syntax to Firestore.
Securing one doesn't secure the others. An app that locks down Firestore but leaves the default Storage rules in place is still exposing every uploaded file.
The test-mode trap
When you create a new Firestore database, the console offers a “Start in test mode” option so you can build without fighting rules first. It writes this:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}if true means the rule always passes. Anyone who has your project's config, which is public by design, can read and write every document in the database. No login, no API key check, nothing.
Test mode expires 30 days after creation and then defaults to denying everything, which breaks the app rather than securing it properly. The common failure mode isn't “forgot to write rules”, it's shipping to production inside that 30-day window with test rules still active, or extending the expiry date instead of writing real rules. Bots actively scan for exposed Firebase projects, so this isn't a hypothetical risk window.
Firestore security rules examples
Start from “locked by default” and add exactly the access your app needs. Each example below is a working match block you can adapt to your own collection names.
Locked by default
Use this when: Use this as your starting point before adding any access.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
}
}Authenticated users only
Use this when: Use this when any signed-in user should read and write, but anonymous visitors should not.
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
}User owns the document
Use this when: Use this for per-user data like profiles, orders, or settings, where each doc belongs to exactly one uid.
match /databases/{database}/documents {
match /orders/{orderId} {
allow read, write: if request.auth != null
&& request.auth.uid == resource.data.userId;
allow create: if request.auth != null
&& request.auth.uid == request.resource.data.userId;
}
}Role-based via custom claims
Use this when: Use this when some users need broader access, like admins or support staff, set through Firebase Auth custom claims.
match /databases/{database}/documents {
match /reports/{reportId} {
allow read: if request.auth != null
&& (request.auth.uid == resource.data.ownerId
|| request.auth.token.role == 'admin');
allow write: if request.auth != null
&& request.auth.token.role == 'admin';
}
}Validated writes
Use this when: Use this to stop clients from writing malformed or oversized data, even from an authenticated account.
match /databases/{database}/documents {
match /profiles/{userId} {
allow write: if request.auth.uid == userId
&& request.resource.data.keys().hasAll(['displayName', 'bio'])
&& request.resource.data.displayName is string
&& request.resource.data.displayName.size() < 60
&& request.resource.data.bio.size() < 500;
}
}Public read, authenticated write
Use this when: Use this for content like blog posts or listings, where anyone should read but only the author should write.
match /databases/{database}/documents {
match /posts/{postId} {
allow read: if true;
allow create: if request.auth != null
&& request.resource.data.authorId == request.auth.uid;
allow update, delete: if request.auth != null
&& resource.data.authorId == request.auth.uid;
}
}Realtime Database rules examples
Realtime Database rules are plain JSON, evaluated top-down by path. A $uid segment matches any key at that level, letting you write one rule that applies per user.
Default deny
Use this when: Use this at the root so nothing is exposed until you explicitly open a path.
{
"rules": {
".read": false,
".write": false
}
}Per-user node
Use this when: Use this for a /users/$uid structure where each user should only touch their own branch.
{
"rules": {
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}Validated fields
Use this when: Use this to enforce shape and type on writes, the Realtime Database equivalent of a schema check.
{
"rules": {
"messages": {
"$uid": {
"$messageId": {
".write": "$uid === auth.uid",
".validate": "newData.hasChildren(['text', 'createdAt']) && newData.child('text').isString() && newData.child('text').val().length < 1000"
}
}
}
}
}Cloud Storage rules examples
Storage rules match on file paths the same way Firestore rules match on documents. Scope every path to the uploading user, and constrain what they're allowed to upload.
User-scoped upload paths
Use this when: Use this so each user can only read and write inside their own folder, like /uploads/{uid}/.
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /uploads/{userId}/{fileName} {
allow read, write: if request.auth != null
&& request.auth.uid == userId;
}
}
}Content-type and size limits
Use this when: Use this to stop uploads from being used to store arbitrary files or exhaust your storage budget.
match /b/{bucket}/o {
match /avatars/{userId}/{fileName} {
allow write: if request.auth != null
&& request.auth.uid == userId
&& request.resource.size < 5 * 1024 * 1024
&& request.resource.contentType.matches('image/.*');
}
}Rules that look secure but are not
allow read, write: if auth != null on shared data
Validating on create but not on update
Using get() or exists() without expecting the cost
Enforcing limits only in client-side code
Testing rules before you deploy them
Firebase Emulator Suite
Run rules locally against a real emulator instead of production data:
firebase emulators:startPair it with @firebase/rules-unit-testing to write unit tests that assert specific reads and writes are allowed or denied, so a rule regression fails CI instead of shipping.
Rules Playground
For a quick manual check, the Rules tab in the Firebase console has a Playground that simulates a request as a chosen user, authenticated or not, against a chosen document or path. It shows exactly which line of your rules allowed or denied the request.
Useful for a fast sanity check, but the emulator and unit tests are what catch a regression before it reaches production.
Check whether your Firebase rules actually hold
vas tests your live Firebase app for exposed data, permissive rules, and test-mode configurations left on past launch. Run your first scan free to see your security score and every issue count in minutes. Unlock every finding with a copy-paste fix from $19/month.
Run your first scan freeFrequently Asked Questions
Are Firebase security rules enough?
For most apps, yes, as long as the rules actually deny by default and validate every field a client can write. Rules are your only backend-side access control on Firestore, Realtime Database, and Storage, since there's no separate API layer checking permissions. The gap is usually not "rules vs. no rules", it's rules that look strict but leave a hole, like checking request.auth != null without also checking ownership.
What happens if I have no rules, or test-mode rules?
allow read, write: if true grants anyone with your project ID full read and write access to every document, node, or file. No login required. Bots scan for exposed Firebase projects specifically, so an app left in test mode past its 30-day expiry window is not theoretical risk, it gets found.
Are Firebase API keys secret?
No. The apiKey in your Firebase client config is designed to be public, it identifies your project, the same way a URL does. It is not a credential and doesn't need to be hidden or rotated if it shows up in your bundled JS. Your security boundary is the rules, not the key.
How do I test Firebase rules before deploying them?
Run the Firebase Local Emulator Suite (firebase emulators:start) and write unit tests against @firebase/rules-unit-testing that assert specific reads and writes are allowed or denied. For a quick manual check, use the Rules Playground in the Firebase console, which lets you simulate a request as a given user without touching production data.
Do Firestore, Realtime Database, and Storage share one rules file?
No, each is a separate rules language and a separate deploy target: firestore.rules, database.rules.json (or storage.rules for Cloud Storage), all listed in firebase.json. Securing Firestore does nothing for a Storage bucket left wide open, they need to be written and deployed independently.
Last updated: August 29, 2026