Skip to main content

Firebase Auth vs AWS Cognito vs Supabase Auth 2026

·PkgPulse Team
0

Firebase Auth vs AWS Cognito vs Supabase Auth 2026

TL;DR

Managed authentication services eliminate the complexity of building login systems — OAuth flows, token refresh, MFA, session management — but they come with very different DX, pricing models, and lock-in profiles. Firebase Authentication is the simplest to integrate, with SDKs for every platform, Google Sign-In working in minutes, and generous free tier; it's part of the Firebase/Google ecosystem and ideal for apps that already use Firestore or Cloud Functions. AWS Cognito is the enterprise-grade option — deeply integrated with IAM, API Gateway, and the broader AWS ecosystem; complex to configure but powerful for organizations already running infrastructure on AWS. Supabase Auth is the Postgres-native option — open-source, self-hostable, row-level security that integrates directly with Supabase's PostgreSQL, and a Next.js helper library with SSR support that works well with App Router. For Firebase/Google ecosystem: Firebase Auth. For AWS-native apps: Cognito. For Postgres/Supabase apps or self-hosting: Supabase Auth.

Key Takeaways

  • Firebase free tier: 10k phone auth/month — email/OAuth are free unlimited
  • Cognito free: 50,000 MAU — then $0.0055/MAU (cheapest managed auth at scale)
  • Supabase Auth: 50,000 MAU free — same free tier as Cognito; open source self-hostable
  • Firebase uses Google Identity Platform — UID-based, not JWT-customizable without Cloud Functions
  • Cognito access tokens are JWTs — integrate directly with API Gateway authorizers
  • Supabase Auth integrates with RLSauth.uid() function in PostgreSQL policies
  • All three support OAuth — Google, GitHub, Apple, Microsoft, etc.

Capability Quick Reference

Single sign-on (SSO/SAML)     → Cognito (enterprise tier)
Google sign-in (1-click)      → Firebase Auth (trivial setup)
Row-level security in Postgres → Supabase Auth
AWS API Gateway integration   → Cognito (native JWT authorizer)
Self-hosted open source       → Supabase Auth (or Lucia/Better Auth)
React Native support          → All three (Firebase best SDK)
Phone/SMS auth                → All three (Firebase easiest)
Magic link email              → Supabase Auth, Firebase (via link)

Firebase Authentication

Firebase Auth is the Google-managed identity platform — supports email/password, phone, and 20+ OAuth providers with SDKs for Web, iOS, Android, and Unity.

Installation

npm install firebase

Initialize

// lib/firebase.ts
import { initializeApp, getApps } from "firebase/app";
import { getAuth } from "firebase/auth";

const firebaseConfig = {
  apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY!,
  authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN!,
  projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID!,
  storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET!,
  messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID!,
  appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID!,
};

const app = getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0];
export const auth = getAuth(app);

Email and Password

import {
  createUserWithEmailAndPassword,
  signInWithEmailAndPassword,
  signOut,
  sendPasswordResetEmail,
  updateProfile,
  onAuthStateChanged,
  type User,
} from "firebase/auth";
import { auth } from "@/lib/firebase";

// Sign up
async function signUp(email: string, password: string, displayName: string): Promise<User> {
  const credential = await createUserWithEmailAndPassword(auth, email, password);
  await updateProfile(credential.user, { displayName });
  return credential.user;
}

// Sign in
async function signIn(email: string, password: string): Promise<User> {
  const credential = await signInWithEmailAndPassword(auth, email, password);
  return credential.user;
}

// Sign out
async function logOut(): Promise<void> {
  await signOut(auth);
}

// Reset password
async function resetPassword(email: string): Promise<void> {
  await sendPasswordResetEmail(auth, email);
}

// Auth state listener
function onUserChange(callback: (user: User | null) => void) {
  return onAuthStateChanged(auth, callback);
}

OAuth (Google, GitHub, Apple)

import {
  GoogleAuthProvider,
  GithubAuthProvider,
  OAuthProvider,
  signInWithPopup,
  signInWithRedirect,
  getRedirectResult,
  type User,
} from "firebase/auth";
import { auth } from "@/lib/firebase";

const googleProvider = new GoogleAuthProvider();
googleProvider.addScope("email");
googleProvider.addScope("profile");

const githubProvider = new GithubAuthProvider();
githubProvider.addScope("user:email");

// Sign in with Google (popup)
async function signInWithGoogle(): Promise<User> {
  const result = await signInWithPopup(auth, googleProvider);
  return result.user;
}

// Sign in with GitHub
async function signInWithGitHub(): Promise<User> {
  const result = await signInWithPopup(auth, githubProvider);
  return result.user;
}

// Apple Sign-In
const appleProvider = new OAuthProvider("apple.com");
appleProvider.addScope("email");
appleProvider.addScope("name");

async function signInWithApple(): Promise<User> {
  const result = await signInWithPopup(auth, appleProvider);
  return result.user;
}

Server-Side Token Verification (Next.js)

// lib/firebase-admin.ts
import { initializeApp, getApps, cert } from "firebase-admin/app";
import { getAuth } from "firebase-admin/auth";

const adminApp =
  getApps().length === 0
    ? initializeApp({
        credential: cert({
          projectId: process.env.FIREBASE_PROJECT_ID,
          clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
          privateKey: process.env.FIREBASE_PRIVATE_KEY?.replace(/\\n/g, "\n"),
        }),
      })
    : getApps()[0];

export const adminAuth = getAuth(adminApp);
// middleware.ts — verify Firebase ID token
import { NextRequest, NextResponse } from "next/server";
import { adminAuth } from "@/lib/firebase-admin";

export async function middleware(request: NextRequest) {
  const token = request.cookies.get("firebaseToken")?.value;

  if (!token) {
    return NextResponse.redirect(new URL("/login", request.url));
  }

  try {
    const decodedToken = await adminAuth.verifyIdToken(token);
    // decodedToken.uid, .email, .name available
    const response = NextResponse.next();
    response.headers.set("x-user-id", decodedToken.uid);
    return response;
  } catch {
    return NextResponse.redirect(new URL("/login", request.url));
  }
}

Auth Context Hook

// contexts/AuthContext.tsx
"use client";
import { createContext, useContext, useEffect, useState } from "react";
import { onAuthStateChanged, type User } from "firebase/auth";
import { auth } from "@/lib/firebase";

interface AuthContextValue {
  user: User | null;
  loading: boolean;
}

const AuthContext = createContext<AuthContextValue>({ user: null, loading: true });

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const [user, setUser] = useState<User | null>(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      setUser(user);
      setLoading(false);
    });
    return unsubscribe;
  }, []);

  return (
    <AuthContext.Provider value={{ user, loading }}>
      {children}
    </AuthContext.Provider>
  );
}

export const useAuth = () => useContext(AuthContext);

AWS Cognito: Enterprise Auth

Cognito User Pools provide managed auth with JWTs that integrate natively with AWS API Gateway, Lambda authorizers, and IAM.

Installation

npm install aws-amplify @aws-amplify/auth
# Or for direct Cognito SDK:
npm install @aws-sdk/client-cognito-identity-provider

Amplify Setup

// lib/amplify.ts
import { Amplify } from "aws-amplify";

Amplify.configure({
  Auth: {
    Cognito: {
      userPoolId: process.env.NEXT_PUBLIC_COGNITO_USER_POOL_ID!,
      userPoolClientId: process.env.NEXT_PUBLIC_COGNITO_CLIENT_ID!,
      signUpVerificationMethod: "code",
      loginWith: {
        oauth: {
          domain: process.env.NEXT_PUBLIC_COGNITO_DOMAIN!,
          scopes: ["email", "openid", "profile"],
          redirectSignIn: [process.env.NEXT_PUBLIC_APP_URL + "/callback"],
          redirectSignOut: [process.env.NEXT_PUBLIC_APP_URL],
          responseType: "code",
        },
      },
    },
  },
});

Sign Up and Sign In

import {
  signUp,
  confirmSignUp,
  signIn,
  signOut,
  getCurrentUser,
  fetchAuthSession,
  resetPassword,
  confirmResetPassword,
} from "aws-amplify/auth";

// Sign up
async function registerUser(email: string, password: string, name: string) {
  const { isSignUpComplete, userId, nextStep } = await signUp({
    username: email,
    password,
    options: {
      userAttributes: {
        email,
        name,
      },
    },
  });

  return { isSignUpComplete, userId, nextStep };
}

// Confirm sign up with verification code
async function confirmRegistration(email: string, code: string) {
  const { isSignUpComplete } = await confirmSignUp({
    username: email,
    confirmationCode: code,
  });
  return isSignUpComplete;
}

// Sign in
async function loginUser(email: string, password: string) {
  const { isSignedIn, nextStep } = await signIn({ username: email, password });

  // Handle MFA or custom challenges
  if (nextStep.signInStep === "CONFIRM_SIGN_IN_WITH_TOTP_CODE") {
    return { requiresMFA: true };
  }

  return { isSignedIn };
}

// Get JWT tokens for API calls
async function getAccessToken(): Promise<string> {
  const session = await fetchAuthSession();
  return session.tokens?.accessToken.toString() ?? "";
}

OAuth with Cognito Hosted UI

import { signInWithRedirect, signOut } from "aws-amplify/auth";

// Redirect to Cognito hosted UI for Google login
async function signInWithGoogle() {
  await signInWithRedirect({
    provider: "Google",
  });
  // After redirect, user lands at redirectSignIn URL
  // Call getCurrentUser() to get the authenticated user
}

// Sign in with GitHub (custom OIDC provider configured in Cognito)
async function signInWithGitHub() {
  await signInWithRedirect({
    provider: { custom: "GitHub" },
  });
}

Verify Token Server-Side

// lib/cognito-verifier.ts
import { CognitoJwtVerifier } from "aws-jwt-verify";

const verifier = CognitoJwtVerifier.create({
  userPoolId: process.env.COGNITO_USER_POOL_ID!,
  tokenUse: "access",
  clientId: process.env.COGNITO_CLIENT_ID!,
});

export async function verifyCognitoToken(token: string) {
  try {
    const payload = await verifier.verify(token);
    return payload; // payload.sub = user ID, payload.username, payload["cognito:groups"]
  } catch {
    return null;
  }
}
// middleware.ts
import { verifyCognitoToken } from "@/lib/cognito-verifier";

export async function middleware(request: NextRequest) {
  const token = request.headers.get("Authorization")?.replace("Bearer ", "");
  if (!token) return NextResponse.redirect(new URL("/login", request.url));

  const payload = await verifyCognitoToken(token);
  if (!payload) return NextResponse.redirect(new URL("/login", request.url));

  return NextResponse.next();
}

Supabase Auth: Postgres-Native Auth

Supabase Auth provides authentication that integrates directly with PostgreSQL row-level security — auth.uid() in SQL policies references the authenticated user.

Installation

npm install @supabase/supabase-js @supabase/ssr

Setup (Next.js App Router)

// utils/supabase/client.ts
import { createBrowserClient } from "@supabase/ssr";

export function createClient() {
  return createBrowserClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
  );
}
// utils/supabase/server.ts
import { createServerClient } from "@supabase/ssr";
import { cookies } from "next/headers";

export async function createClient() {
  const cookieStore = await cookies();

  return createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        getAll() {
          return cookieStore.getAll();
        },
        setAll(cookiesToSet) {
          cookiesToSet.forEach(({ name, value, options }) => {
            cookieStore.set(name, value, options);
          });
        },
      },
    }
  );
}

Email/Password Auth

// Client component
import { createClient } from "@/utils/supabase/client";

const supabase = createClient();

// Sign up
async function signUp(email: string, password: string) {
  const { data, error } = await supabase.auth.signUp({
    email,
    password,
    options: {
      data: {
        full_name: "John Doe",  // Stored in auth.users.raw_user_meta_data
      },
    },
  });

  if (error) throw error;
  return data.user;
}

// Sign in
async function signIn(email: string, password: string) {
  const { data, error } = await supabase.auth.signInWithPassword({
    email,
    password,
  });

  if (error) throw error;
  return data.user;
}

// Sign out
async function logOut() {
  await supabase.auth.signOut();
}

OAuth

// Sign in with GitHub
async function signInWithGitHub() {
  const { error } = await supabase.auth.signInWithOAuth({
    provider: "github",
    options: {
      redirectTo: `${process.env.NEXT_PUBLIC_APP_URL}/auth/callback`,
      scopes: "read:user user:email",
    },
  });
  if (error) throw error;
}

// Sign in with Google
async function signInWithGoogle() {
  const { error } = await supabase.auth.signInWithOAuth({
    provider: "google",
    options: {
      redirectTo: `${process.env.NEXT_PUBLIC_APP_URL}/auth/callback`,
    },
  });
  if (error) throw error;
}

// Magic link (passwordless)
async function sendMagicLink(email: string) {
  const { error } = await supabase.auth.signInWithOtp({
    email,
    options: {
      emailRedirectTo: `${process.env.NEXT_PUBLIC_APP_URL}/auth/callback`,
    },
  });
  if (error) throw error;
}

OAuth Callback Route

// app/auth/callback/route.ts
import { createClient } from "@/utils/supabase/server";
import { NextRequest, NextResponse } from "next/server";

export async function GET(request: NextRequest) {
  const { searchParams, origin } = new URL(request.url);
  const code = searchParams.get("code");
  const next = searchParams.get("next") ?? "/dashboard";

  if (code) {
    const supabase = await createClient();
    const { error } = await supabase.auth.exchangeCodeForSession(code);
    if (!error) {
      return NextResponse.redirect(`${origin}${next}`);
    }
  }

  return NextResponse.redirect(`${origin}/auth/error`);
}

Server Component Session Check

// app/dashboard/page.tsx
import { createClient } from "@/utils/supabase/server";
import { redirect } from "next/navigation";

export default async function DashboardPage() {
  const supabase = await createClient();
  const { data: { user } } = await supabase.auth.getUser();

  if (!user) {
    redirect("/login");
  }

  // Fetch user's data — RLS automatically filters by auth.uid()
  const { data: posts } = await supabase
    .from("posts")
    .select("*")
    .order("created_at", { ascending: false });

  return <Dashboard user={user} posts={posts ?? []} />;
}

Row-Level Security Integration

-- SQL: Enable RLS with Supabase Auth
CREATE TABLE posts (
  id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
  user_id uuid REFERENCES auth.users(id) NOT NULL,
  title text NOT NULL,
  content text,
  created_at timestamptz DEFAULT now()
);

ALTER TABLE posts ENABLE ROW LEVEL SECURITY;

-- Users can only see their own posts
CREATE POLICY "Users see own posts"
  ON posts FOR SELECT
  USING (auth.uid() = user_id);

-- Users can only insert their own posts
CREATE POLICY "Users insert own posts"
  ON posts FOR INSERT
  WITH CHECK (auth.uid() = user_id);

-- Users can only update their own posts
CREATE POLICY "Users update own posts"
  ON posts FOR UPDATE
  USING (auth.uid() = user_id);

Feature Comparison

FeatureFirebase AuthAWS CognitoSupabase Auth
Setup complexityLowHighLow-Medium
Free tierUnlimited email/OAuth50k MAU50k MAU
Paid pricingGoogle Identity Platform$0.0055/MAU$25/month (Pro)
OAuth providers20+20+ (with OIDC)20+
Next.js SSRNeeds firebase-adminJWT verifyFirst-class
App RouterManual setupAmplify SSR@supabase/ssr
Postgres RLSNoNoYes (native)
Self-hostableNoNoYes
MFAYes (TOTP + SMS)Yes (TOTP + SMS)Yes (TOTP)
Phone/SMS authYesYesYes
Magic linkYes (email link)NoYes
SAML/SSOYes (GCIP)YesYes
AWS integrationNoYes (native)No
React NativeExcellent SDKAmplifyYes

Ecosystem and Community

Firebase Auth benefits from Google's investment in documentation and developer education. The Firebase console's Authentication section is well-designed with clear usage metrics per provider, and the documentation covers every edge case with code samples. Community resources — Stack Overflow, YouTube tutorials, blog posts — are abundant because Firebase Auth has been in production since 2014. The onAuthStateChanged pattern is one of the most searched React code snippets.

AWS Cognito has comprehensive documentation through the AWS Developer Guides, but the learning curve is steep. The Amplify library abstracts much of the complexity, but teams that need Cognito-native features (custom authentication flows, Lambda triggers, advanced SAML configuration) spend significant time in the AWS console and CloudFormation templates. The AWS re:Post community has helpful answers for complex enterprise auth configurations, and AWS Partners often specialize in Cognito integration for enterprise clients.

Supabase Auth's documentation is the most Next.js-centric of the three, with specific guides for the App Router, Pages Router, middleware patterns, and Server Components. The Supabase GitHub Discussions community is active with day-to-day auth questions, and the @supabase/ssr package's maintainers are responsive to issues. Because Supabase Auth builds on GoTrue (an open-source auth server), teams can inspect the implementation and contribute fixes directly.

Real-World Adoption

Firebase Auth powers authentication for a large fraction of consumer mobile apps built with Flutter and React Native. The combination of Google Sign-In, Apple Sign-In, and phone SMS auth with a single SDK is genuinely unmatched for mobile developers. Consumer-facing apps where the user expects to authenticate with their Google account and the developer wants that flow working in an afternoon consistently reach for Firebase Auth. For code-owned auth alternatives that run in your infrastructure rather than a third-party service, see Lucia Auth v3 vs better-auth vs Stack Auth self-hosted 2026.

AWS Cognito's strongest adoption is in enterprise B2B SaaS and AWS-native applications. When a company is already running API Gateway, Lambda, and RDS on AWS, using Cognito means authentication flows directly into IAM, Lambda authorizers work without additional token verification code, and security compliance is simplified by staying within the AWS ecosystem. The 50,000 MAU free tier and $0.0055/MAU pricing make it cost-competitive at scale — at 1 million MAU, Cognito costs $5,225/month versus Firebase Identity Platform's per-event pricing model.

Supabase Auth is the most-adopted auth solution in the bootstrapper and indie hacker communities in 2026. Projects starting with the Supabase stack get auth, database, and storage from a single platform, which dramatically reduces the number of services to configure and monitor. The magic link authentication flow is particularly popular for B2B tools where users prefer not to create passwords. The Row Level Security integration, where the same authenticated user identity governs both the auth session and data access policies in Postgres, is a compelling architectural simplification.

Developer Experience Deep Dive

Firebase Auth's developer experience excels at getting the first OAuth flow working quickly. The emulator suite — including an Auth emulator — means you can develop and test auth flows completely locally without hitting Google's servers. The firebase-admin SDK for server-side token verification is straightforward, though setting it up in Next.js middleware requires careful handling of edge runtime compatibility.

Cognito's developer experience is the weakest of the three for frontend developers. The Amplify library simplifies things considerably, but the underlying Cognito concepts — User Pools, Identity Pools, App Clients, Hosted UI, PKCE flows — require understanding the broader AWS auth architecture. Teams that invest in understanding Cognito deeply benefit from its flexibility, but the initial setup time is measured in days rather than hours.

Supabase Auth's developer experience for Next.js App Router is exceptional. The @supabase/ssr package's createServerClient and createBrowserClient pattern is clean, the middleware integration is well-documented, and the auth/callback route pattern is a one-time copy-paste. The most important DX advantage is that Row Level Security policies enforce data authorization at the database level — there's no risk of accidentally forgetting to add .eq('user_id', user.id) to a query because the policy rejects the row before it leaves the database.

When to Use Each

Choose Firebase Auth if:

  • Already using Firebase (Firestore, Cloud Functions, Storage) — same project, same SDK
  • Google Sign-In in under 10 minutes is appealing (trivial OAuth setup)
  • Mobile-first: excellent React Native and native iOS/Android SDKs
  • Phone/SMS authentication is a primary requirement
  • Google's infrastructure and reliability matter

Choose AWS Cognito if:

  • Your backend runs on AWS (API Gateway, Lambda, AppSync) — native JWT authorizer integration
  • SAML/SSO for enterprise customers is required
  • Fine-grained IAM-based authorization on AWS resources
  • 50k+ MAU where Cognito's pricing is competitive
  • Organization has existing AWS expertise and infrastructure

Choose Supabase Auth if:

  • Using Supabase's PostgreSQL for your database — RLS with auth.uid() is a killer feature
  • Next.js App Router with first-class SSR support (@supabase/ssr)
  • Open-source and self-hosting is important (vendor lock-in concern)
  • Magic link / passwordless email is a core auth method
  • Row-level security eliminates entire categories of authorization code

See also: NextAuth vs Clerk vs Supabase Auth in SaaS Boilerplates on StarterPick — StarterPick compared which auth solution works best in SaaS boilerplates.

Methodology

Data sourced from Firebase Authentication documentation (firebase.google.com/docs/auth), AWS Cognito documentation (docs.aws.amazon.com/cognito), Supabase Auth documentation (supabase.com/docs/guides/auth), pricing pages as of February 2026, npm download statistics, and community discussions from the Firebase Google Group, AWS re:Post, and Supabase Discord.

Pricing at Scale

Authentication pricing is a significant consideration at growth-stage companies, and the three platforms price very differently.

Firebase Authentication's email and OAuth flows are free with no MAU limit. Phone authentication costs $0.0060 per verification after 10,000 free monthly verifications. For most web applications that use email/OAuth rather than SMS, Firebase Auth is effectively free regardless of user count. The Google Identity Platform upgrade (required for SAML, multi-tenancy, and blocking functions) adds costs that scale with MAU.

AWS Cognito's 50,000 MAU free tier is the most generous of the three for teams just starting. After 50,000 MAU, the pricing is $0.0055/MAU — for a company with 500,000 MAU, that's $2,475/month. Cognito's pricing has no per-OAuth-provider premium (all OAuth is included in the MAU price), but the advanced security features (adaptive authentication, compromised credential protection) are an additional $0.050 per MAU. For enterprise-scale applications, Cognito's flat per-MAU pricing is predictable and competitive.

Supabase Auth is included in the Supabase platform pricing. The free tier includes 50,000 MAU. The Pro plan at $25/month includes 100,000 MAU with additional MAU billed at $0.00325/MAU — about 40% cheaper than Cognito at scale. For teams already using Supabase for their database, the bundled auth pricing makes Supabase Auth effectively free compared to alternatives that would require additional auth-specific payments.

Integration with Authorization Systems

Beyond authentication (who is this user?), authorization (what can this user do?) is where the platforms diverge most sharply.

Firebase Authentication provides the user identity (UID), and authorization is handled through Firestore Security Rules. The rules language is expressive but operates only within the Firebase ecosystem — it doesn't help you authorize access to external APIs, Lambda functions, or custom backend services.

Cognito's JWT access tokens carry claims that can be used by any system that validates JWTs — AWS API Gateway Lambda authorizers, third-party API management platforms, custom Express middleware. The Cognito User Pool Groups feature lets you put users into groups (Admin, Editor, Viewer) and include those groups as claims in the JWT, enabling role-based access control without additional configuration. This makes Cognito the most interoperable auth solution with non-AWS systems.

Supabase Auth's integration with Row Level Security is the deepest of the three. The auth.uid() and auth.jwt() Postgres functions let you write authorization rules that reference the authenticated user's identity and claims directly in SQL. This eliminates the entire category of "forgot to add a where clause" bugs — the database enforces authorization at the row level for every query, regardless of which application code path executed the query.

Related: Supabase vs Firebase vs Appwrite BaaS 2026, Best Realtime Libraries 2026, Best JavaScript Testing Frameworks 2026

See also: authentication SaaS tools on StackFYI — compare managed auth providers, SSO platforms, and identity services side by side.

Related: Lucia Auth v3 vs Better Auth vs Stack Auth for self-hosted, code-owned authentication alternatives, or Prisma vs Drizzle vs Kysely for the database ORMs that work alongside these auth systems.

The 2026 JavaScript Stack Cheatsheet

One PDF: the best package for every category (ORMs, bundlers, auth, testing, state management). Used by 500+ devs. Free, updated monthly.