Docs

Svelte Firebase Library

A comprehensive Svelte 5 library for Firebase integration with reactive state management

Svelte Firebase Library

A comprehensive, production-ready Firebase integration library for Svelte 5 applications. Built with reactive state management using Svelte 5 runes, providing a complete solution for authentication, Firestore, Storage, Realtime Database, Analytics, and more.

🚀 Features

  • Complete Firebase Integration - All Firebase products supported
  • Svelte 5 Runes - Reactive state management with optimal performance
  • TypeScript First - Full type safety and excellent developer experience
  • SSR Compatible - Server-side rendering support
  • Real-time Updates - Live data synchronization across all services
  • Authentication System - Complete auth solution with multiple providers
  • Advanced Querying - Complex Firestore queries with type safety
  • File Management - Storage upload/download with progress tracking
  • Presence System - User online/offline tracking with geolocation
  • Analytics Integration - Comprehensive event tracking
  • Error Handling - Robust error management with retry mechanisms
  • Performance Optimized - Persistent cache, memory management, and optimizations

📦 Installation

npm install svelte-firekit firebase

🔧 Quick Setup

1. Environment Variables

Create a .env file with your Firebase configuration:

PUBLIC_FIREBASE_API_KEY=your_api_key
PUBLIC_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.com
PUBLIC_FIREBASE_PROJECT_ID=your_project_id
PUBLIC_FIREBASE_STORAGE_BUCKET=your_project.appspot.com
PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your_sender_id
PUBLIC_FIREBASE_APP_ID=your_app_id
PUBLIC_FIREBASE_MEASUREMENT_ID=your_measurement_id

2. Initialize Firebase

<script>
	import { FirebaseApp } from 'svelte-firekit';
</script>

<FirebaseApp>
	<!-- Your app content -->
</FirebaseApp>

3. Basic Usage

<script>
	import { firekitUser, firekitCollection, firekitDoc } from 'svelte-firekit';

	// Reactive user state
	const user = $derived(firekitUser.user);
	const isAuthenticated = $derived(firekitUser.isAuthenticated);

	// Reactive document
	const userDoc = firekitDoc('users/123');

	// Reactive collection
	const posts = firekitCollection('posts', [
		where('published', '==', true),
		orderBy('createdAt', 'desc'),
		limit(10)
	]);
</script>

{#if isAuthenticated}
	<h1>Welcome, {user?.displayName}!</h1>

	{#if userDoc.loading}
		<p>Loading user data...</p>
	{:else if userDoc.data}
		<p>Email: {userDoc.data.email}</p>
	{/if}

	<h2>Recent Posts</h2>
	{#each posts.data as post}
		<article>
			<h3>{post.title}</h3>
			<p>{post.content}</p>
		</article>
	{/each}
{/if}

📚 Core Services

Authentication

import { firekitAuth, firekitUser } from 'svelte-firekit';

// Sign in methods
await firekitAuth.signInWithEmail('[email protected]', 'password');
await firekitAuth.signInWithGoogle();
await firekitAuth.signInWithFacebook();
await firekitAuth.signInWithApple();

// User registration
await firekitAuth.registerWithEmail('[email protected]', 'password', 'John Doe');

// Reactive user state
const user = $derived(firekitUser.user);
const isAuthenticated = $derived(firekitUser.isAuthenticated);
const isEmailVerified = $derived(firekitUser.isEmailVerified);

Firestore Documents

import { firekitDoc, firekitDocOnce } from 'svelte-firekit';

// Real-time document subscription
const userDoc = firekitDoc<User>('users/123', {
	name: 'Loading...',
	email: ''
});

// One-time document fetch
const userData = firekitDocOnce<User>('users/123');

// Access reactive state
const isLoading = $derived(userDoc.loading);
const userData = $derived(userDoc.data);
const userError = $derived(userDoc.error);

$effect(() => {
	if (isLoading) console.log('Loading...');
	if (userData) console.log('User:', userData);
	if (userError) console.error('Error:', userError);
});

Firestore Collections

import { firekitCollection, where, orderBy, limit } from 'svelte-firekit';

// Simple collection
const users = firekitCollection<User>('users');

// With query constraints
const activeUsers = firekitCollection<User>('users', [
	where('active', '==', true),
	orderBy('name'),
	limit(10)
]);

// Advanced options
const paginatedUsers = firekitCollection<User>('users', {
	pagination: { enabled: true, pageSize: 20 },
	cache: { enabled: true, ttl: 300000 }
});

// Access reactive state
const usersData = $derived(users.data);
const usersLoading = $derived(users.loading);
const usersError = $derived(users.error);

$effect(() => {
	console.log('Users:', usersData);
	console.log('Loading:', usersLoading);
	console.log('Error:', usersError);
});

Document Mutations

import { firekitDocMutations } from 'svelte-firekit';

// Create document
const result = await firekitDocMutations.add(
	'users',
	{
		name: 'John Doe',
		email: '[email protected]'
	},
	{
		timestamps: true,
		validate: true
	}
);

// Update document
await firekitDocMutations.update('users/123', {
	name: 'Jane Doe'
});

// Delete document
await firekitDocMutations.delete('users/123');

// Batch operations
const batchResult = await firekitDocMutations.batch([
	{ type: 'create', path: 'users', data: userData },
	{ type: 'update', path: 'profiles/123', data: profileUpdate }
]);

Storage Management

import { firekitDownloadUrl, firekitUploadTask, firekitStorageList } from 'svelte-firekit';

// Download URL
const imageUrl = firekitDownloadUrl('images/photo.jpg');
const downloadUrl = $derived(imageUrl.url);

// File upload with progress
const upload = firekitUploadTask('uploads/file.pdf', file);
const uploadProgress = $derived(upload.progress);
const uploadCompleted = $derived(upload.completed);
const uploadDownloadUrl = $derived(upload.downloadURL);

$effect(() => {
	if (downloadUrl) console.log('Image URL:', downloadUrl);
	console.log('Upload progress:', uploadProgress);
	if (uploadCompleted) console.log('Download URL:', uploadDownloadUrl);
});

// Storage listing
const files = firekitStorageList('uploads');
const fileItems = $derived(files.items);
const filePrefixes = $derived(files.prefixes);

$effect(() => {
	console.log('Files:', fileItems);
	console.log('Folders:', filePrefixes);
});

Realtime Database

import { firekitRealtimeDB, firekitRealtimeList } from 'svelte-firekit';

// Single value
const userStatus = firekitRealtimeDB<{ online: boolean }>('users/123/status');

// List data
const messages = firekitRealtimeList<Message>('messages');

// Access data
const statusData = $derived(userStatus.data);
const messagesList = $derived(messages.list);

$effect(() => {
	console.log('Status:', statusData);
	console.log('Messages:', messagesList);
});

// Update data
await userStatus.set({ online: true });
await messages.push({ text: 'Hello', userId: '123' });

Presence System

import { firekitPresence } from 'svelte-firekit';

// Initialize presence
await firekitPresence.initialize(user, {
	geolocation: {
		enabled: true,
		type: 'browser',
		requireConsent: true
	}
});

// Set presence status
await firekitPresence.setPresence('online');

// Access reactive state
const presenceStatus = $derived(firekitPresence.status);
const presenceLocation = $derived(firekitPresence.location);
const presenceSessions = $derived(firekitPresence.sessions);

Analytics

import { firekitAnalytics } from 'svelte-firekit';

// Track custom events
firekitAnalytics.trackEvent('button_click', {
	button_name: 'signup',
	page_location: '/home'
});

// Track purchases
firekitAnalytics.trackPurchase({
	transaction_id: 'T12345',
	value: 29.99,
	currency: 'USD',
	items: [{ item_id: 'prod_123', item_name: 'Premium Plan' }]
});

// Set user properties
firekitAnalytics.setUserProperties({
	user_type: 'premium',
	subscription_plan: 'pro'
});

🧩 Components

Authentication Components

<script>
	import { AuthGuard, SignedIn, SignedOut } from 'svelte-firekit';
</script>

<!-- Route protection -->
<AuthGuard requireAuth={true} redirectTo="/login">
	<h1>Protected Content</h1>
</AuthGuard>

<!-- Conditional rendering -->
<SignedIn>
	<h1>Welcome back!</h1>
</SignedIn>

<SignedOut>
	<h1>Please sign in</h1>
</SignedOut>

Data Components

<script>
	import { Doc, Collection } from 'svelte-firekit';
</script>

<!-- Document component -->
<Doc ref="users/123" let:data let:ref let:firestore>
	<h1>{data.name}</h1>
	<p>{data.email}</p>
</Doc>

<!-- Collection component -->
<Collection ref="posts" let:data let:ref let:firestore let:count>
	<h1>Posts ({count})</h1>
	{#each data as post}
		<article>
			<h2>{post.title}</h2>
			<p>{post.content}</p>
		</article>
	{/each}
</Collection>

Storage Components

<script>
	import { StorageList, DownloadURL, UploadTask } from 'svelte-firekit';
</script>

<!-- Storage listing -->
<StorageList path="uploads" let:items let:prefixes>
	<h2>Files</h2>
	{#each items as item}
		<p>{item.name}</p>
	{/each}

	<h2>Folders</h2>
	{#each prefixes as prefix}
		<p>{prefix.name}</p>
	{/each}
</StorageList>

<!-- Download URL -->
<DownloadURL path="images/photo.jpg" let:url let:loading let:error>
	{#if loading}
		<p>Loading image...</p>
	{:else if url}
		<img src={url} alt="Photo" />
	{:else if error}
		<p>Error: {error.message}</p>
	{/if}
</DownloadURL>

<!-- Upload with progress -->
<UploadTask path="uploads/file.pdf" file={selectedFile} let:progress let:completed let:error>
	{#if !completed}
		<div class="progress-bar">
			<div class="progress" style="width: {progress}%"></div>
		</div>
		<p>{progress}% uploaded</p>
	{:else}
		<p>Upload complete!</p>
	{/if}
</UploadTask>

🔧 Advanced Features

Query Builders

import { firekitCollection } from 'svelte-firekit';

const query = firekitCollection
	.createQuery()
	.where('status', '==', 'active')
	.where('category', 'in', ['tech', 'design'])
	.orderBy('createdAt', 'desc')
	.limit(20);

const results = firekitCollection('posts', query.build());

Custom Validation

import { firekitDocMutations } from 'svelte-firekit';

const validateUser = (data: any) => {
	if (!data.email || !data.email.includes('@')) {
		return { valid: false, message: 'Invalid email' };
	}
	return { valid: true };
};

await firekitDocMutations.add('users', userData, {
	validate: true,
	validator: validateUser
});

Error Handling

import { firekitDoc } from 'svelte-firekit';

const userDoc = firekitDoc('users/123');

const userError = $derived(userDoc.error);

$effect(() => {
	if (userError) {
		if (userError.isRetryable()) {
			// Retry the operation
			userDoc.retryIfNeeded();
	} else {
		// Handle non-retryable error
		console.error('Permanent error:', userDoc.error);
	}
}

Performance Monitoring

import { firekitCollection, firekitDocMutations } from 'svelte-firekit';

// Collection statistics
const users = firekitCollection('users');
const stats = $derived(users.getStats());

$effect(() => {
	console.log('Cache hit rate:', stats.cacheHitRate);
	console.log('Average query time:', stats.averageQueryTime);
});

// Mutation analytics
const analytics = $derived(firekitDocMutations.getAnalytics());

$effect(() => {
	console.log('Success rate:', analytics.successRate);
	console.log('Average duration:', analytics.averageDuration);
});

🎯 Best Practices

1. Use Reactive State

// ✅ Good - Reactive state
const user = $derived(firekitUser.user);
const isAuthenticated = $derived(firekitUser.isAuthenticated);

// ❌ Avoid - Direct service calls in templates
const user = firekitUser.getCurrentUser();

2. Handle Loading States

{#if userDoc.loading}
	<LoadingSpinner />
{:else if userDoc.error}
	<ErrorMessage error={userDoc.error} />
{:else if userDoc.data}
	<UserProfile user={userDoc.data} />
{/if}

3. Clean Up Subscriptions

import { onDestroy } from 'svelte';

const userDoc = firekitDoc('users/123');

onDestroy(() => {
	userDoc.dispose();
});

4. Use Type Safety

interface User {
	id: string;
	name: string;
	email: string;
	active: boolean;
}

const userDoc = firekitDoc<User>('users/123');
const users = firekitCollection<User>('users');

5. Optimize Queries

// ✅ Good - Specific queries
const activeUsers = firekitCollection('users', where('active', '==', true), limit(10));

// ❌ Avoid - Fetching all data
const allUsers = firekitCollection('users');

🔍 API Reference

Core Services

Components

Types

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

📄 License

MIT License - see LICENSE for details.

🆘 Support


Built with ❤️ for the Svelte community