REST API vs GraphQL
Twenty years of REST versus Facebook's GraphQL: query flexibility, performance, caching, tooling, and which fits modern API design in 2026.
Google's comprehensive mobile app development platform
Open-source Firebase alternative — PostgreSQL-based, self-hostable
For rapid development, an excellent iOS SDK, and real-time features, Firebase is strong. For relational data, SQL flexibility, open source, and concerns about vendor lock-in, choose Supabase. In 2025, Supabase is maturing fast and has become a serious contender — especially with its pgvector integration for AI-powered apps.
| Category | Firebase | Supabase |
|---|---|---|
| Performance | 9/10 | 9/10 |
| Ease of Learning | 8/10 | 7/10 |
| Ecosystem | 10/10 | 7/10 |
| Community | 9/10 | 8/10 |
| Job Market | 9/10 | 7/10 |
| Future-Proof | 7/10 | 9/10 |
// Firebase - Real-time chat messages
import FirebaseFirestore
import FirebaseAuth
import SwiftUI
@Observable
class ChatViewModel {
var messages: [Message] = []
private var listener: ListenerRegistration?
private let db = Firestore.firestore()
struct Message: Identifiable, Codable {
@DocumentID var id: String?
let senderId: String
let senderName: String
let text: String
let timestamp: Timestamp
}
func startListening(roomId: String) {
listener = db.collection("rooms")
.document(roomId)
.collection("messages")
.order(by: "timestamp", descending: false)
.limit(toLast: 50)
.addSnapshotListener { [weak self] snapshot, error in
guard let documents = snapshot?.documents else { return }
self?.messages = documents.compactMap {
try? $0.data(as: Message.self)
}
}
}
func sendMessage(text: String, roomId: String) async throws {
guard let user = Auth.auth().currentUser else { return }
let message = Message(
senderId: user.uid,
senderName: user.displayName ?? "Anonymous",
text: text,
timestamp: Timestamp()
)
try db.collection("rooms")
.document(roomId)
.collection("messages")
.addDocument(from: message)
}
func stopListening() { listener?.remove() }
}// Supabase - User posts CRUD
import Supabase
import Foundation
struct Post: Codable, Identifiable {
let id: UUID
let userId: UUID
let title: String
let content: String
let createdAt: Date
enum CodingKeys: String, CodingKey {
case id, title, content
case userId = "user_id"
case createdAt = "created_at"
}
}
class PostRepository {
private let client = SupabaseClient(
supabaseURL: URL(string: ProcessInfo.processInfo.environment["SUPABASE_URL"]!)!,
supabaseKey: ProcessInfo.processInfo.environment["SUPABASE_ANON_KEY"]!
)
func fetchPosts() async throws -> [Post] {
try await client
.from("posts")
.select("*")
.order("created_at", ascending: false)
.limit(20)
.execute()
.value
}
func createPost(title: String, content: String) async throws -> Post {
let userId = try await client.auth.session.user.id
return try await client
.from("posts")
.insert(["user_id": userId.uuidString, "title": title, "content": content])
.select()
.single()
.execute()
.value
}
func subscribeToNewPosts(onNewPost: @escaping (Post) -> Void) -> RealtimeChannelV2 {
let channel = client.channel("public:posts")
channel.onPostgresChange(
InsertAction.self,
table: "posts"
) { change in
if let post = try? change.record.decode(as: Post.self) {
onNewPost(post)
}
}
Task { await channel.subscribe() }
return channel
}
}For rapid development, an excellent iOS SDK, and real-time features, Firebase is strong. For relational data, SQL flexibility, open source, and concerns about vendor lock-in, choose Supabase. In 2025, Supabase is maturing fast and has become a serious contender — especially with its pgvector integration for AI-powered apps.
Get Free ConsultationIt's possible but not easy. Firestore's NoSQL structure has to be converted to a PostgreSQL schema, Auth users need to be migrated, and Storage files transferred. It requires a substantial migration project.