Keep secret and service-role keys on the server
Supabase publishable or legacy anon keys are designed for public clients when RLS protects the data. Secret and service-role keys grant elevated access and must never be exposed in browser code.
Action: search client bundles and public environment variables for secret or service-role credentials, rotate any exposed key, and move privileged calls to a trusted server.
Enable RLS on every exposed table
Tables reachable through Supabase's Data API need Row Level Security. Dashboard-created tables enable it by default, but tables created another way still need verification.
Action: inventory every table in exposed schemas and confirm RLS is enabled before production traffic reaches it.
Write explicit, least-privilege policies
Enabling RLS without policies blocks client access; broad policies can expose more rows or operations than intended. Separate read, insert, update, and delete rules where the permissions differ.
Action: document which role can perform each operation, then make each policy express that rule directly.
Test data access as a normal user
Admin tools and service-role clients bypass controls that ordinary sessions must satisfy. A test that only uses privileged access cannot validate the customer path.
Action: create two test users and verify that each can access their own allowed rows, cannot access the other's rows, and cannot call restricted operations.
Set the production Site URL and allowed auth redirects
OAuth, magic-link, confirmation, and password-reset flows depend on redirect configuration. Development wildcards should not silently become the production trust boundary.
Action: set the production Site URL, allow only the redirect destinations you use, and run each email or OAuth flow against the real domain.
Review the browser/server environment boundary
Next.js variables prefixed with NEXT_PUBLIC_ are inlined into browser JavaScript. Treat them as public and keep secrets in server-only variables.
Action: list every production variable, mark it public or server-only, remove unused values, and confirm environment files are excluded from version control.
Authorize every server-side mutation
Hiding a button or redirecting a page improves the interface, but it does not authorize the underlying Server Action, Route Handler, or database operation.
Action: authenticate and authorize inside every mutation path, then test direct requests without relying on the UI.
Ship metadata and crawl controls intentionally
Production pages need titles and descriptions; public products also benefit from Open Graph metadata, a sitemap, and robots directives. Private routes should not be made discoverable by accident.
Action: inspect rendered metadata for important pages and verify sitemap.xml and robots.txt match the intended public surface.
Test the production build, not only dev mode
Development mode can hide differences in caching, bundling, environment variables, and runtime behavior. A successful local dev session is not a production verification.
Action: run the production build and start commands, inspect build output, exercise critical routes, and review Lighthouse plus runtime logs.
Exercise failure paths before customers do
Launch readiness includes expired sessions, missing rows, rejected writes, unavailable services, slow requests, and unknown routes—not just the happy path.
Action: trigger representative 401, 403, 404, validation, and dependency-failure cases; confirm the user gets a safe message and operators get useful logs.