# Migrating Users from Supabase

Migrating your users from one auth source to another can seem scary. Fortunately, we're here to help! See our [Migrating Users to PropelAuth](https://docs.propelauth.com/migrations) guide for more general information or stay here for an advanced guide, including code snippets, on how to migrate your users from Supabase to PropelAuth.

## [Exporting Users from Supabase](https://docs.propelauth.com/migrations/supabase#exporting-users-from-supabase)

You can easily export a CSV of your user data and password hashes from Supabase by using [Supabase's SQL Editor](https://supabase.com/features/sql-editor). To do so, navigate to your Supabase instance and click **SQL Editor** on the left navbar.

Next, type the following into the SQL Editor, replacing `auth.users` with your user table and adding additional fields to export if you'd like.

```
-- Also include first_name, last_name, etc.
SELECT id, email, encrypted_password
FROM auth.users;
```

Make sure to select **Limit results to: No Limit** in the bottom right. Then, select **Export** followed by **Download CSV**.

## [Importing Users into PropelAuth](https://docs.propelauth.com/migrations/supabase#importing-users-into-propel-auth)

We can then use the CSV to import your user data to PropelAuth. PropelAuth offers an **[API endpoint to make migrating users](https://docs.propelauth.com/reference/api/user#migrate-user-from-external-source)** as simple as possible. Before we run the script, let's install [PropelAuth's Python library](https://docs.propelauth.com/reference/backend-apis/python):

```bash
pip install propelauth_py
```

This script will attempt to import each of the users found in your CSV file into PropelAuth. If any of the imports fail, it will automatically generate a `./unmigrated_users.csv` file for you.

To run the script we need to get your `PROPELAUTH_AUTH_URL` and `PROPELAUTH_AUTH_API_KEY`, both of which can be found in your **Backend Integration** page in PropelAuth.

Some of your users might not have passwords because they use OAuth/Social logins. If that’s the case, they can still log in via your **[social logins](https://docs.propelauth.com/features/login-methods#social-login-sso)** or **[magic links](https://docs.propelauth.com/features/login-methods#passwordless)**.

```python
from propelauth_py import init_base_auth
import csv

# Replace with your PropelAuth Auth URL and API key
PROPELAUTH_AUTH_URL = "https://auth.yourdomain.com"
PROPELAUTH_AUTH_API_KEY = "b1988511..."

# replace with your CSV path
user_csv_filename = "./user_data.csv"

# If we fail to migrate any users, we'll output them here
unmigrated_users_filename = "./unmigrated_users.csv"

auth = init_base_auth(PROPELAUTH_AUTH_URL, PROPELAUTH_AUTH_API_KEY)

def create_propelauth_user(user_data):
    auth.migrate_user_from_external_source(
        email = user_data.get('email'),
        email_confirmed = user_data.get('email_confirmed'),
        existing_user_id = user_data.get('id'),
        existing_password_hash = user_data.get('password_hash'),
        ask_user_to_update_password_on_login = False,
        enabled = True,
        username = user_data.get('username'),
        first_name = user_data.get('first_name'),
        last_name = user_data.get('last_name'),
        properties = user_data.get('properties'),
    )
    print(f"API call successful for user: {user_data.get('id')}")

def process_users():
    users_with_errors = []

with open(user_csv_filename, "r", newline='', encoding='utf-8') as user_csv_file:
        csv_reader = csv.DictReader(user_csv_file)

# Iterate through each user row
        for row in csv_reader:
            try:
                user_migrate_data = {
                    'id': row.get('id'),
                    'email': row.get('email'),
                    'email_confirmed': True,  # Assuming emails are confirmed, adjust as needed
                    'password_hash': row.get('encrypted_password'),

# Fields below this are dependent on your setup, you may need to modify
                    #'username': row.get('username'),
                    #'first_name': row.get('first_name'),
                    #'last_name': row.get('last_name'),
                    # Any custom user properties that aren't first_name, last_name, or username go here
                    #'properties': {
                    #    'sample_custom_property': row['sample']
                    #}
                }
                create_propelauth_user(user_migrate_data)
            except Exception as e:
                users_with_errors.append(dict(row))
                print(f"Error during processing user: {row.get('id', 'Unknown ID')}")
                print(f"Error: {e}")

if len(users_with_errors) > 0:
        with open(unmigrated_users_filename, "w", newline='', encoding='utf-8') as unmigrated_users_file:
            if users_with_errors:  # Only proceed if there are errors
                fieldnames = users_with_errors[0].keys()  # Get column names from first error
                csv_writer = csv.DictWriter(unmigrated_users_file, fieldnames=fieldnames)
                csv_writer.writeheader()
                csv_writer.writerows(users_with_errors)
        print(f"We couldn't migrate all users - the users we failed to migrate are here {unmigrated_users_filename}")

# Run the script
if __name__ == "__main__":
    process_users()
```

Need a do over? Here's a script to quickly delete **all** of your users so you can try again.

```python
import requests
from propelauth_py import init_base_auth

# Replace with your PropelAuth Auth URL and API key
PROPELAUTH_AUTH_URL = "https://auth.yourdomain.com"
PROPELAUTH_AUTH_API_KEY = "b1988511..."

auth = init_base_auth(PROPELAUTH_AUTH_URL, PROPELAUTH_AUTH_API_KEY)

def get_users():
    try:
        response = auth.fetch_users_by_query(
            page_size = 10,
            page_number = 0
        )
        return response
    except requests.exceptions.RequestException as e:
        print(f"Error making API call to retrieve users")
        print(f"Error: {e}")

def delete_user(user_id):
    try:
        auth.delete_user(user_id)
    except requests.exceptions.RequestException as e:
        print(f"Error making API call to delete user {user_id}")
        print(f"Error: {e}")

def delete_users():
    user_response = get_users()
    while len(user_response['users']) > 0:
        for user in user_response['users']:
            delete_user(user['user_id'])
        user_response = get_users()

# Run the script
if __name__ == "__main__":
    delete_users()
```

All of your users are now imported! If you run into any problems, do not hesitate to reach out to [support@propelauth.com](mailto:support@propelauth.com).
