{"id":26462882,"url":"https://github.com/clerk/migration-script","last_synced_at":"2025-03-19T06:25:43.372Z","repository":{"id":207657877,"uuid":"717465058","full_name":"clerk/migration-script","owner":"clerk","description":null,"archived":false,"fork":false,"pushed_at":"2024-08-24T21:36:23.000Z","size":156,"stargazers_count":32,"open_issues_count":5,"forks_count":10,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-18T05:36:38.109Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/clerk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.Apache-2.0.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-11-11T15:04:14.000Z","updated_at":"2025-03-04T01:47:23.000Z","dependencies_parsed_at":"2024-08-21T21:55:22.012Z","dependency_job_id":null,"html_url":"https://github.com/clerk/migration-script","commit_stats":null,"previous_names":["devagrawal09/migration-script","clerk/migration-script"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clerk%2Fmigration-script","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clerk%2Fmigration-script/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clerk%2Fmigration-script/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clerk%2Fmigration-script/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/clerk","download_url":"https://codeload.github.com/clerk/migration-script/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244367432,"owners_count":20441886,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-19T06:25:42.665Z","updated_at":"2025-03-19T06:25:43.358Z","avatar_url":"https://github.com/clerk.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Clerk User Import Script\n\n## Description\n\nThis repository contains a script that takes a JSON file as input, containing a list of users, and creates a user in Clerk using Clerk's backend API. The script respects rate limits and handles errors.\n\n## Getting Started\n\nClone the repository and install the dependencies.\n\n```bash\ngit clone git@github.com/clerk/migration-script\n\ncd migration-script\n\nnpm install\n```\n\n### Users.json file\nCreate a `users.json` file. This file should be populated with all the users that need to be imported. The users should pass this schema:\n\n\n```ts\n[\n  {\n    \"userId\": \"string\",\n    \"email\": \"email\",\n    \"firstName\": \"string (optional)\",\n    \"lastName\": \"string (optional)\",\n    \"password\": \"string (optional)\",\n    \"passwordHasher\": \"argon2 | argon | bcrypt | md5 | pbkdf2_sha256 | pbkdf2_sha256_django | pbkdf2_sha1 | scrypt_firebase\",\n  }\n]\n```\n\nThe only required fields are `userId` and `email`. First and last names can be added if available. Clerk will also accept hashed password values along with the hashing algorithm used (the default is `bcrypt`).\n\nHere are a couple examples.\n\n```json\n[\n  {\n    \"userId\": \"1\",\n    \"email\": \"dev@clerk.com\",\n    \"firstName\": \"Dev\",\n    \"lastName\": \"Agrawal\"\n  },\n  {\n    \"userId\": \"2\",\n    \"email\": \"john@blurp.com\",\n    \"password\": \"$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy\",\n    \"passwordHasher\": \"bcrypt\"  // default value\n  }\n]\n```\n\nThe samples/ folder contains some samples, including issues that will produce errors when running the import. \n\n### Secret Key\n\nCreate a `.env` file in the root of the folder and add your `CLERK_SECRET_KEY` to it. You can find your secret key in the [Clerk dashboard](https://dashboard.clerk.dev/).\n\n```bash\nCLERK_SECRET_KEY=your-secret-key\n```\n\n### Run the script\n\n```bash\nnpm start\n```\n\nThe script will begin process the users and attempting to import them into Clerk. The script has a built in delay to respect the rate limits for the Clerk Backend API. If the script does hit a rate limit then it will wait the required 10 seconds and resume. Any errors will be logged to a `migration-log.json` file.\n\nThe script can be run on the same data multiple times, Clerk automatically uses the email as a unique key so users can't be created again.\n\n### Configuration\n\nThe script can be configured through the following environment variables:\n\n| Variable | Description | Default |\n| -------- | ----------- | ------- |\n| `CLERK_SECRET_KEY` | Your Clerk secret key | `undefined` |\n| `DELAY_MS` | Delay between requests to respect rate limits | `1000` |\n| `RETRY_DELAY_MS` | Delay when the rate limit is hit | `10000` |\n| `OFFSET` | Offset to start migration (number of users to skip) | `0` |\n\n## Handling the Foreign Key constraint\n\nIf you were using a database, you will have data tied to your previous auth system's userIDs. You will need to handle this in some way to maintain data consistency as you move to Clerk. Below are a few strategies you can use.\n\n### Custom session claims\n\nOur sessions allow for conditional expressions. This would allow you add a session claim that will return either the `externalId` (the previous id for your user) when it exists, or the `userId` from Clerk. This will result in your imported users returning their `externalId` while newer users will return the Clerk `userId`.\n\nIn your Dashboard, go to Sessions -\u003e Edit. Add the following: \n\n```json\n{\n\t\"userId\": \"{{user.externalId || user.id}}\"\n}\n```\n\nYou can now access this value using the following:\n```ts \nconst { sessionClaims } = auth();\nconsole.log(sessionClaims.userId) \n```\n\nYou can add the following for typescript: \n```js\n// types/global.d.ts\n\nexport { };\n\ndeclare global {\n  interface CustomJwtSessionClaims {\n    userId?: string;\n  }\n}\n```\n\n### Other options\n\nYou could continue to generate unique ids for the database as done previously, and then store those in `externalId`. This way all users would have an `externalId` that would be used for DB interactions.\n\nYou could add a column in your user table inside of your database called `ClerkId`. Use that column to store the userId from Clerk directly into your database.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclerk%2Fmigration-script","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fclerk%2Fmigration-script","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclerk%2Fmigration-script/lists"}