Read the status code before changing anything
Call the auth health endpoint directly from outside your app. The status code points to the cause. You can also read it in the browser's DevTools Network tab on the failing page.
curl -s -o /dev/null -w "%{http_code}\n" \
"https://<project-ref>.supabase.co/auth/v1/health" \
-H "apikey: <your-publishable-key>"
# 200 healthy · 402 restricted (quota or billing) · 540 paused
Clear the account-level cause
For a paused Supabase project, open the dashboard, select the project and choose Resume project. For a 402, the response names the exceeded quota or overdue payment, so resolve that in billing. On Convex, raise, disable or delete the usage limit that was triggered. On Firebase Spark, upgrade to Blaze or wait for the next billing cycle.
Make every deployed key match the provider's current keys
Compare the keys in your hosting environment with Settings > API Keys in the dashboard. When you rotate a key, replace it everywhere it is used, then disable or delete the old one.
Rebuild after any environment change
List the production variables and confirm that every one the build needs is present. Then deploy again so the NEXT_PUBLIC_ values are inlined with the correct values.
vercel env ls production # every variable the build reads should be listed
vercel --prod # new deployment picks up the current values
Add a health route that covers sign-in and one real read
Point an external uptime monitor at this route so an outage alerts you before a customer reports it. The read targets a small health_check table with one row and a select policy that allows anon, so Row Level Security does not hide the result.
// app/api/health/route.ts
export async function GET() {
const url = process.env.SUPABASE_URL!;
const headers = { apikey: process.env.SUPABASE_PUBLISHABLE_KEY! };
const [auth, data] = await Promise.all([
fetch(`${url}/auth/v1/health`, { headers, cache: "no-store" }),
fetch(`${url}/rest/v1/health_check?select=id&limit=1`, { headers, cache: "no-store" }),
]);
const ok = auth.ok && data.ok;
return Response.json({ auth: auth.status, data: data.status }, { status: ok ? 200 : 503 });
}
Render an error state instead of an empty screen
Check the error your client library returns and show a 'service unavailable' message. An empty list tells customers their data is gone.
const { data, error } = await supabase.from("projects").select("id, name");
if (error) {
console.error("projects read failed", error.code, error.message);
return { state: "unavailable" as const }; // show a banner, not an empty list
}
Write down your plan's limits and who gets alerted
Record your plan's pause rules, quotas and restriction behavior. Firebase budget alerts do not cap usage or charges. Convex emails the whole team when a production or preview deployment reaches a usage threshold, so make sure the right inbox is on the team.