- Overview
- Installation
- Add the Firebase Admin SDK to your server
- Usage
- Supported Services
- Additional Packages
- Contributing
- License
Firebase provides the tools and infrastructure you need to develop your app, grow your user base, and earn money. The Firebase Admin Dart SDK enables access to Firebase services from privileged environments (such as servers or cloud) in Dart.
For more information, visit the Firebase Admin SDK setup guide.
The Firebase Admin Dart SDK is available on pub.dev as dart_firebase_admin:
$ dart pub add dart_firebase_adminTo use the SDK in your application, import it from any Dart file:
import 'package:dart_firebase_admin/dart_firebase_admin.dart';Make sure that you have a server app.
Make sure that your server runs Dart SDK 3.9 or higher.
To use the Firebase Admin SDK, you'll need the following:
- A Firebase project.
- A Firebase Admin SDK service account to communicate with Firebase. This service account is created automatically when you create a Firebase project or add Firebase to a Google Cloud project.
- A configuration file with your service account's credentials.
If you don't already have a Firebase project, you need to create one in the Firebase console. Visit Understand Firebase Projects to learn more about Firebase projects.
If you are setting up a new project, you need to install the SDK for the language of your choice.
The Firebase Admin Dart SDK is available on pub.dev as dart_firebase_admin:
$ dart pub add dart_firebase_adminTo use the module in your application, import it from any Dart file:
import 'package:dart_firebase_admin/dart_firebase_admin.dart';Once you have created a Firebase project, you can initialize the SDK with Google Application Default Credentials. Because default credentials lookup is fully automated in Google environments, with no need to supply environment variables or other configuration, this way of initializing the SDK is strongly recommended for applications running in Google environments such as Firebase App Hosting, Cloud Run, App Engine, and Cloud Functions for Firebase.
final app = FirebaseApp.initializeApp();To optionally specify initialization options for services such as Realtime Database, Cloud Storage, or Cloud Functions, use the FIREBASE_CONFIG environment variable. If the content of the FIREBASE_CONFIG variable begins with a { it will be parsed as a JSON object. Otherwise the SDK assumes that the string is the path of a JSON file containing the options.
Note: The
FIREBASE_CONFIGenvironment variable is included automatically in App Hosting backends and Cloud Functions for Firebase functions.
export FIREBASE_CONFIG='{"projectId":"my-project"}'// Options are read automatically from FIREBASE_CONFIG
final app = FirebaseApp.initializeApp();If you are working in a non-Google server environment in which default credentials lookup can't be fully automated, you can initialize the SDK with an exported service account key file.
Important: Extremely high security awareness is required when working with service account keys, as they are vulnerable to certain types of threats. See Best practices for managing service account keys.
Firebase projects support Google service accounts, which you can use to call Firebase server APIs from your app server or trusted environment. If you're developing code locally or deploying your application on-premises, you can use credentials obtained via this service account to authorize server requests.
To generate a private key file for your service account:
- In the Firebase console, open Settings > Service Accounts.
- Click Generate New Private Key, then confirm by clicking Generate Key.
- Securely store the JSON file containing the key.
When authorizing via a service account, you have two choices for providing the credentials to your application. You can either set the GOOGLE_APPLICATION_CREDENTIALS environment variable, or you can explicitly pass the path to the service account key in code. The first option is more secure and is strongly recommended.
To set the environment variable:
Set the environment variable GOOGLE_APPLICATION_CREDENTIALS to the file path of the JSON file that contains your service account key. This variable only applies to your current shell session, so if you open a new session, set the variable again.
export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/service-account-file.json"After you've completed the above steps, Application Default Credentials (ADC) is able to implicitly determine your credentials, allowing you to use service account credentials when testing or running in non-Google environments.
The initializeApp method allows for creating multiple named app instances and specifying a custom credential, project ID and other options:
final app = FirebaseApp.initializeApp(
options: AppOptions(
credential: Credential.fromServiceAccount(File("path/to/credential.json")),
projectId: "custom-project-id",
),
name: "CUSTOM_APP",
);The following Credential constructors are available:
Credential.fromApplicationDefaultCredentials({String? serviceAccountId})β Uses Application Default Credentials (recommended for Google environments). Optionally accepts aserviceAccountIdto override the service account email.Credential.fromServiceAccount(File)β Loads credentials from a service account JSON file downloaded from the Firebase Console.Credential.fromServiceAccountParams({required String privateKey, required String email, required String projectId, String? clientId})β Builds credentials from individual service account fields directly.
Workload Identity Federation lets external workloads (such as GitHub Actions, AWS, or Azure) authenticate as a Google service account without a long-lived key file.
Once your WIF credential configuration file is generated, point GOOGLE_APPLICATION_CREDENTIALS to it:
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/wif-credential-config.json"Then initialize the SDK with ADC, providing the impersonated service account email via serviceAccountId. This is required because WIF credential configs do not embed a client_email field, unlike service account key files:
final app = FirebaseApp.initializeApp(
options: AppOptions(
credential: Credential.fromApplicationDefaultCredentials(
serviceAccountId: 'my-service-account@my-project.iam.gserviceaccount.com',
),
projectId: 'my-project',
),
);In most cases, you only have to initialize a single default app:
// Initialize the default app
final defaultApp = FirebaseApp.initializeApp();
print(defaultApp.name); // '[DEFAULT]'
// Access services from the default app
final defaultAuth = defaultApp.auth();
final defaultFirestore = defaultApp.firestore();Some use cases require you to create multiple apps at the same time. For example, you might want to read data from the Realtime Database of one Firebase project and mint custom tokens for another project. Or you might want to authenticate two apps with separate credentials. The Firebase SDK allows you create multiple apps at the same time, each with their own configuration information.
// Each AppOptions points to a different Firebase project
final defaultApp = FirebaseApp.initializeApp(
options: AppOptions(
credential: Credential.fromServiceAccount(File('path/to/default-service-account.json')),
projectId: 'my-default-project',
),
);
// Initialize another app with a different config
final otherApp = FirebaseApp.initializeApp(
options: AppOptions(
credential: Credential.fromServiceAccount(File('path/to/other-service-account.json')),
projectId: 'my-other-project',
),
name: 'other',
);
print(defaultApp.name); // '[DEFAULT]'
print(otherApp.name); // 'other'
// Access services from each app
final defaultAuth = defaultApp.auth();
final defaultFirestore = defaultApp.firestore();
final otherAuth = otherApp.auth();
final otherFirestore = otherApp.firestore();Note: Each app instance has its own configuration options and authentication state.
When testing the Admin SDK locally with Google Application Default Credentials obtained by running gcloud auth application-default login, additional changes are needed to use Firebase Authentication due to the following:
- Firebase Authentication does not accept gcloud end user credentials generated using the gcloud OAuth client ID.
- Firebase Authentication requires the project ID to be provided on initialization for these type of end user credentials.
You can specify the project ID explicitly on app initialization or just use the GOOGLE_CLOUD_PROJECT environment variable. The latter avoids the need to make any additional changes to test your code.
To explicitly specify the project ID:
final app = FirebaseApp.initializeApp(
options: AppOptions(
credential: Credential.fromApplicationDefaultCredentials(),
projectId: '<FIREBASE_PROJECT_ID>',
),
);Alternatively, set the GOOGLE_CLOUD_PROJECT environment variable to avoid changing your code:
export GOOGLE_CLOUD_PROJECT="<FIREBASE_PROJECT_ID>"Once you have initialized an app instance with a credential, you can use any of the supported services to interact with Firebase.
import 'package:dart_firebase_admin/dart_firebase_admin.dart';
import 'package:dart_firebase_admin/auth.dart';
final app = FirebaseApp.initializeApp();
final auth = app.auth();// Get user by UID
final userById = await auth.getUser('<user-id>');
print(userById.displayName);
// Get user by email
final userByEmail = await auth.getUserByEmail('user@example.com');
print(userByEmail.displayName);final user = await auth.createUser(
CreateRequest(
email: 'user@example.com',
password: 'password123',
displayName: 'John Doe',
),
);
print(user.uid);final updatedUser = await auth.updateUser(
'<user-id>',
UpdateRequest(
displayName: 'Jane Doe',
disabled: false,
),
);
print(updatedUser.displayName);// Delete a user
await auth.deleteUser('<user-id>');
// List users (max 1000 per page)
final result = await auth.listUsers(maxResults: 100);
final users = result.users;
final nextPageToken = result.pageToken;// Verify an ID token from a client application (e.g. from request headers)
final idToken = req.headers['Authorization'].split(' ')[1];
final decodedToken = await auth.verifyIdToken(idToken, checkRevoked: true);
print(decodedToken.uid);final customToken = await auth.createCustomToken(
'<user-id>',
developerClaims: {'role': 'admin'},
);await auth.setCustomUserClaims('<user-id>', customUserClaims: {'role': 'admin'});import 'package:dart_firebase_admin/dart_firebase_admin.dart';
final app = FirebaseApp.initializeApp();final response = await app.appCheck().verifyToken('<app-check-token>');
print('App ID: ${response.appId}');final result = await app.appCheck().createToken('<app-id>');
print('Token: ${result.token}');import 'dart:async';
import 'package:dart_firebase_admin/dart_firebase_admin.dart';
import 'package:google_cloud_firestore/google_cloud_firestore.dart';
final app = FirebaseApp.initializeApp();
final firestore = app.firestore();final ref = firestore.collection('users').doc('<user-id>');
// Set a document (creates or overwrites)
await ref.set({'name': 'John Doe', 'age': 27});
// Update specific fields
await ref.update({'age': 28});
// Delete a document
await ref.delete();// Get a single document
final snapshot = await firestore.collection('users').doc('<user-id>').get();
print(snapshot.data());
// Query a collection
final querySnapshot = await firestore
.collection('users')
.where('age', WhereFilter.greaterThan, 18)
.orderBy('age', descending: true)
.get();
print(querySnapshot.docs);// Fetch multiple documents at once
final snapshots = await firestore.getAll([
firestore.collection('users').doc('user-1'),
firestore.collection('users').doc('user-2'),
]);
for (final snap in snapshots) {
print(snap.data());
}final batch = firestore.batch();
batch.set(firestore.collection('users').doc('user-1'), {'name': 'Alice'});
batch.update(firestore.collection('users').doc('user-2'), {FieldPath(const ['age']): 30});
batch.delete(firestore.collection('users').doc('user-3'));
await batch.commit();final bulkWriter = firestore.bulkWriter();
for (var i = 0; i < 10; i++) {
unawaited(
bulkWriter.set(
firestore.collection('items').doc('item-$i'),
{'index': i},
),
);
}
await bulkWriter.close();final balance = await firestore.runTransaction((tsx) async {
final ref = firestore.collection('users').doc('<user-id>');
final snapshot = await tsx.get(ref);
final currentBalance = snapshot.exists ? snapshot.data()?['balance'] ?? 0 : 0;
final newBalance = currentBalance + 10;
tsx.update(ref, {'balance': newBalance});
return newBalance;
});import 'package:dart_firebase_admin/dart_firebase_admin.dart';
import 'package:dart_firebase_admin/functions.dart';
final app = FirebaseApp.initializeApp();
final queue = app.functions().taskQueue('<task-name>');await queue.enqueue({'userId': 'user-123', 'action': 'sendWelcomeEmail'});// Delay delivery by 1 hour
await queue.enqueue(
{'action': 'cleanupTempFiles'},
TaskOptions(schedule: DelayDelivery(3600)),
);
// Schedule at a specific time
await queue.enqueue(
{'action': 'sendReport'},
TaskOptions(schedule: AbsoluteDelivery(DateTime.now().add(Duration(hours: 1)))),
);
// Use a custom ID for deduplication
await queue.enqueue(
{'orderId': 'order-456', 'action': 'processPayment'},
TaskOptions(id: 'payment-order-456'),
);// Route the task to a custom URI (beta feature)
await queue.enqueue(
{'action': 'customHandler'},
TaskOptions(
experimental: TaskOptionsExperimental(
uri: 'https://my-service.example.com/task-handler',
),
),
);await queue.delete('payment-order-456');import 'package:dart_firebase_admin/dart_firebase_admin.dart';
import 'package:dart_firebase_admin/messaging.dart';
final app = FirebaseApp.initializeApp();
final messaging = app.messaging();// Send to a specific device
await messaging.send(
TokenMessage(
token: '<device-token>',
notification: Notification(title: 'Hello', body: 'World!'),
data: {'key': 'value'},
),
);
// Send to a topic
await messaging.send(
TopicMessage(
topic: '<topic-name>',
notification: Notification(title: 'Hello', body: 'World!'),
),
);
// Send to a condition
await messaging.send(
ConditionMessage(
condition: "'stock-GOOG' in topics || 'industry-tech' in topics",
notification: Notification(title: 'Hello', body: 'World!'),
),
);// Send up to 500 messages in a single call
final response = await messaging.sendEach([
TopicMessage(topic: 'topic-1', notification: Notification(title: 'Message 1')),
TopicMessage(topic: 'topic-2', notification: Notification(title: 'Message 2')),
]);
print('Sent: ${response.successCount}, Failed: ${response.failureCount}');// Send one message to multiple device tokens
final response = await messaging.sendEachForMulticast(
MulticastMessage(
tokens: ['<token-1>', '<token-2>', '<token-3>'],
notification: Notification(title: 'Hello', body: 'World!'),
),
);
print('Sent: ${response.successCount}, Failed: ${response.failureCount}');// Subscribe tokens to a topic
await messaging.subscribeToTopic(['<token-1>', '<token-2>'], 'news');
// Unsubscribe tokens from a topic
await messaging.unsubscribeFromTopic(['<token-1>', '<token-2>'], 'news');import 'dart:typed_data';
import 'package:dart_firebase_admin/dart_firebase_admin.dart';
import 'package:google_cloud_storage/google_cloud_storage.dart' as gcs;
final app = FirebaseApp.initializeApp();
final storage = app.storage();
final bucket = storage.bucket('<bucket-name>');await bucket.storage.uploadObject(
bucket.name,
'path/to/file.txt',
Uint8List.fromList('Hello, world!'.codeUnits),
metadata: gcs.ObjectMetadata(contentType: 'text/plain'),
);final bytes = await bucket.storage.downloadObject(bucket.name, 'path/to/file.txt');
print(String.fromCharCodes(bytes));final metadata = await bucket.storage.objectMetadata(bucket.name, 'path/to/file.txt');
print('Size: ${metadata.size} bytes');
print('Content type: ${metadata.contentType}');await bucket.storage.deleteObject(bucket.name, 'path/to/file.txt');Returns a long-lived public download URL backed by a Firebase download token, suitable for sharing with end-users.
final url = await storage.getDownloadURL(bucket, 'path/to/file.txt');
print('Download URL: $url');import 'package:dart_firebase_admin/dart_firebase_admin.dart';
final app = FirebaseApp.initializeApp();
final securityRules = app.securityRules();final ruleset = await securityRules.getFirestoreRuleset();
print(ruleset.name);final source = '''
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}
''';
final ruleset = await securityRules.releaseFirestoreRulesetFromSource(source);
print('Applied ruleset: ${ruleset.name}');final ruleset = await securityRules.getStorageRuleset();
print(ruleset.name);final source = '''
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
''';
final ruleset = await securityRules.releaseStorageRulesetFromSource(source);
print('Applied ruleset: ${ruleset.name}');// Create a ruleset without applying it
const source = "rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /{document=**} { allow read, write: if false; } } }";
final rulesFile = RulesFile(name: 'firestore.rules', content: source);
final ruleset = await securityRules.createRuleset(rulesFile);
print('Created ruleset: ${ruleset.name}');
// Delete a ruleset by name
await securityRules.deleteRuleset(ruleset.name);The Firebase Admin Dart SDK currently supports the following Firebase services:
π’ - Fully supported
π‘ - Partially supported / Work in progress
π΄ - Not supported
| Service | Status | Notes |
|---|---|---|
| App | π’ | |
| App Check | π’ | |
| Authentication | π’ | |
| Data Connect | π΄ | |
| Realtime Database | π΄ | |
| Event Arc | π΄ | |
| Extensions | π΄ | |
| Firestore | π’ | Excludes realtime capabilities |
| Functions | π’ | |
| Installations | π΄ | |
| Machine Learning | π΄ | |
| Messaging | π’ | |
| Project Management | π΄ | |
| Remote Config | π΄ | |
| Security Rules | π’ | |
| Storage | π’ |
Alongside the Firebase Admin Dart SDK, this repository contains additional workspace/pub.dev packages to accomodate the SDK:
- google_cloud_firestore: Standalone Google APIs Firestore SDK, which the Firebase SDK extends.
- google_cloud_storage: Standalone Google Cloud Storage SDK, which the Firebase SDK extends.
Contributions are welcome! Please read the contributing guide to get started.