Hi! I'd approach this as an **identity migration plus data migration**, rather than trying to merge both databases directly in one step. The most important part is handling users who already exist in both projects. Here's the approach I'd recommend: 1. **Back up both projects first**, and rehearse the migration on a staging project. 2. Build a mapping from each IS user ID to its intended BC user ID. If the person already exists in BC, retain the BC ID as the canonical identity. If not, plan how to import or create the user through a supported migration process. 3. For matching emails, don't automatically merge accounts based on email alone. Identity ownership needs to be verified, especially since one project uses Azure and the other uses magic links. 4. Migrate application records using the ID mapping, updating foreign keys consistently. Validate row counts and referential integrity afterward. 5. Migrate Storage buckets and files separately using supported Storage APIs or tooling. Copying database metadata alone won't migrate the actual image objects. 6. Enable the required Auth providers in BC, then carefully test the resulting login and account-linking flows. 7. Review RLS policies using both newly imported users and existing BC users before switching production traffic. Supabase documents migration of Auth schema data, including password hashes, but merging that data into an already populated Auth schema is a different problem and needs conflict handling. I'd strongly recommend doing a dry run with a few representative cases: an IS-only user, a BC-only user, and someone present in both. These docs are useful starting points: - /docs/guides/troubleshooting/migrating-auth-users-between-projects - /docs/guides/platform/migrating-within-supabase I'd be happy to help think through the user-ID mapping if you can share how your application tables reference `auth.users`.
One distinction worth making here is between the PostgreSQL password-verifier mechanism and the logging behavior of the hosted platform. PostgreSQL can store a SCRAM-SHA-256 verifier rather than a plaintext password, but that doesn't by itself guarantee that the original credential won't be captured when an administrative statement is submitted. `psql`'s `\password` command is preferable to writing a plaintext password directly in an SQL command or migration because it avoids placing the literal password in the generated SQL statement. However, it doesn't establish what Supabase's control plane, query capture, or error logging may retain. Given your requirement, I'd keep provisioning paused until Supabase confirms the logging boundary and officially supported procedure. I would also keep the restricted runtime role separate from the migration role, provision credentials outside source control, and use the Railway secret configuration for runtime delivery. The main unanswered question is whether Supabase can guarantee the absence of both plaintext credentials and authentication verifier material across all the logging surfaces you listed. That's something the provider needs to confirm rather than something we can infer from PostgreSQL behavior alone.
One implementation detail to add to the answers above: keep the Auth client and forwarded IP scoped to the current request. A module-level client whose headers or session are changed for each login can let concurrent requests interfere with one another. For a stateless login handler, disable persistent session storage and automatic refresh on that server client, and return/store each user's session separately. If you're using cookie-based SSR, use the request's cookie adapter instead. For the load test, use several synthetic users and verify that each response belongs to the intended user, as well as monitoring 429s and latency. That catches shared-session bugs which a single test account won't reveal. The official client setup and IP-forwarding examples are here: - /docs/guides/auth/server-side/creating-a-client - /docs/guides/auth/rate-limits The secret key used for forwarding should remain on the server.