create-convex-monorepo 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/README.md +306 -59
  2. package/assets/backend-better-auth/PROVENANCE.md +3 -0
  3. package/assets/backend-better-auth/convex/_generated/api.d.ts +57 -0
  4. package/assets/backend-better-auth/convex/_generated/api.js +23 -0
  5. package/assets/backend-better-auth/convex/_generated/dataModel.d.ts +60 -0
  6. package/assets/backend-better-auth/convex/_generated/server.d.ts +162 -0
  7. package/assets/backend-better-auth/convex/_generated/server.js +101 -0
  8. package/assets/backend-better-auth/convex/messages.ts +38 -0
  9. package/assets/backend-better-auth/convex/schema.ts +9 -0
  10. package/assets/backend-blank-better-auth/PROVENANCE.md +3 -0
  11. package/assets/backend-blank-better-auth/convex/_generated/api.d.ts +53 -0
  12. package/assets/backend-blank-better-auth/convex/_generated/api.js +23 -0
  13. package/assets/backend-blank-better-auth/convex/_generated/dataModel.d.ts +60 -0
  14. package/assets/backend-blank-better-auth/convex/_generated/server.d.ts +162 -0
  15. package/assets/backend-blank-better-auth/convex/_generated/server.js +101 -0
  16. package/assets/backend-blank-better-auth/convex/schema.ts +3 -0
  17. package/assets/backend-blank-convex-auth/PROVENANCE.md +3 -0
  18. package/assets/backend-blank-convex-auth/convex/_generated/api.d.ts +51 -0
  19. package/assets/backend-blank-convex-auth/convex/_generated/api.js +23 -0
  20. package/assets/backend-blank-convex-auth/convex/_generated/dataModel.d.ts +60 -0
  21. package/assets/backend-blank-convex-auth/convex/_generated/server.d.ts +162 -0
  22. package/assets/backend-blank-convex-auth/convex/_generated/server.js +101 -0
  23. package/assets/backend-blank-convex-auth/convex/schema.ts +4 -0
  24. package/assets/backend-convex-auth/PROVENANCE.md +3 -0
  25. package/assets/backend-convex-auth/convex/_generated/api.d.ts +55 -0
  26. package/assets/backend-convex-auth/convex/_generated/api.js +23 -0
  27. package/assets/backend-convex-auth/convex/_generated/dataModel.d.ts +60 -0
  28. package/assets/backend-convex-auth/convex/_generated/server.d.ts +162 -0
  29. package/assets/backend-convex-auth/convex/_generated/server.js +101 -0
  30. package/assets/backend-convex-auth/convex/messages.ts +38 -0
  31. package/assets/backend-convex-auth/convex/schema.ts +11 -0
  32. package/assets/setup/better-auth-env.mjs +187 -0
  33. package/assets/setup/convex-auth-keys.mjs +139 -0
  34. package/assets/setup/convex-auth-site.mjs +129 -0
  35. package/assets/setup/convex-setup.d.mts +9 -1
  36. package/assets/setup/convex-setup.mjs +64 -10
  37. package/dist/cli/index.js +3 -3
  38. package/dist/cli/index.js.map +1 -1
  39. package/dist/commands/create.d.ts +1 -1
  40. package/dist/commands/create.js +39 -7
  41. package/dist/commands/create.js.map +1 -1
  42. package/dist/commands/entry.d.ts +1 -0
  43. package/dist/commands/entry.js +99 -0
  44. package/dist/commands/entry.js.map +1 -0
  45. package/dist/commands/workspace.d.ts +5 -3
  46. package/dist/commands/workspace.js +118 -38
  47. package/dist/commands/workspace.js.map +1 -1
  48. package/dist/generator/context.js +5 -2
  49. package/dist/generator/context.js.map +1 -1
  50. package/dist/generator/format.d.ts +9 -0
  51. package/dist/generator/format.js +61 -0
  52. package/dist/generator/format.js.map +1 -0
  53. package/dist/generator/index.js +7 -5
  54. package/dist/generator/index.js.map +1 -1
  55. package/dist/generator/options.d.ts +4 -1
  56. package/dist/generator/options.js +38 -5
  57. package/dist/generator/options.js.map +1 -1
  58. package/dist/generator/types.d.ts +8 -3
  59. package/dist/index.d.ts +2 -2
  60. package/dist/index.js +1 -1
  61. package/dist/index.js.map +1 -1
  62. package/dist/integrations/auth/better-auth/controls.d.ts +1 -0
  63. package/dist/integrations/auth/better-auth/controls.js +67 -0
  64. package/dist/integrations/auth/better-auth/controls.js.map +1 -0
  65. package/dist/integrations/auth/better-auth/index.d.ts +2 -0
  66. package/dist/integrations/auth/better-auth/index.js +109 -0
  67. package/dist/integrations/auth/better-auth/index.js.map +1 -0
  68. package/dist/integrations/auth/better-auth/providers.d.ts +2 -0
  69. package/dist/integrations/auth/better-auth/providers.js +63 -0
  70. package/dist/integrations/auth/better-auth/providers.js.map +1 -0
  71. package/dist/integrations/auth/better-auth/setup.d.ts +2 -0
  72. package/dist/integrations/auth/better-auth/setup.js +37 -0
  73. package/dist/integrations/auth/better-auth/setup.js.map +1 -0
  74. package/dist/integrations/auth/clerk/index.js +15 -3
  75. package/dist/integrations/auth/clerk/index.js.map +1 -1
  76. package/dist/integrations/auth/convex-auth/controls.d.ts +2 -0
  77. package/dist/integrations/auth/convex-auth/controls.js +88 -0
  78. package/dist/integrations/auth/convex-auth/controls.js.map +1 -0
  79. package/dist/integrations/auth/convex-auth/index.d.ts +3 -0
  80. package/dist/integrations/auth/convex-auth/index.js +100 -0
  81. package/dist/integrations/auth/convex-auth/index.js.map +1 -0
  82. package/dist/integrations/auth/convex-auth/providers.d.ts +2 -0
  83. package/dist/integrations/auth/convex-auth/providers.js +36 -0
  84. package/dist/integrations/auth/convex-auth/providers.js.map +1 -0
  85. package/dist/integrations/auth/convex-auth/setup.d.ts +2 -0
  86. package/dist/integrations/auth/convex-auth/setup.js +76 -0
  87. package/dist/integrations/auth/convex-auth/setup.js.map +1 -0
  88. package/dist/integrations/auth/index.d.ts +2 -1
  89. package/dist/integrations/auth/index.js +22 -0
  90. package/dist/integrations/auth/index.js.map +1 -1
  91. package/dist/integrations/auth/none/index.js +16 -1
  92. package/dist/integrations/auth/none/index.js.map +1 -1
  93. package/dist/integrations/auth/shared.d.ts +7 -1
  94. package/dist/integrations/auth/shared.js +91 -6
  95. package/dist/integrations/auth/shared.js.map +1 -1
  96. package/dist/integrations/auth/workos/controls.d.ts +2 -0
  97. package/dist/integrations/auth/workos/controls.js +53 -0
  98. package/dist/integrations/auth/workos/controls.js.map +1 -0
  99. package/dist/integrations/auth/workos/index.d.ts +6 -0
  100. package/dist/integrations/auth/workos/index.js +104 -0
  101. package/dist/integrations/auth/workos/index.js.map +1 -0
  102. package/dist/integrations/auth/workos/providers.d.ts +3 -0
  103. package/dist/integrations/auth/workos/providers.js +53 -0
  104. package/dist/integrations/auth/workos/providers.js.map +1 -0
  105. package/dist/integrations/auth/workos/setup.d.ts +2 -0
  106. package/dist/integrations/auth/workos/setup.js +27 -0
  107. package/dist/integrations/auth/workos/setup.js.map +1 -0
  108. package/dist/package-manager/index.d.ts +7 -1
  109. package/dist/package-manager/index.js +20 -0
  110. package/dist/package-manager/index.js.map +1 -1
  111. package/dist/templates/apps/astro/index.d.ts +2 -0
  112. package/dist/templates/apps/astro/index.js +69 -0
  113. package/dist/templates/apps/astro/index.js.map +1 -0
  114. package/dist/templates/apps/index.js +8 -0
  115. package/dist/templates/apps/index.js.map +1 -1
  116. package/dist/templates/apps/nuxt/index.d.ts +2 -0
  117. package/dist/templates/apps/nuxt/index.js +123 -0
  118. package/dist/templates/apps/nuxt/index.js.map +1 -0
  119. package/dist/templates/apps/react-router/index.d.ts +2 -0
  120. package/dist/templates/apps/react-router/index.js +85 -0
  121. package/dist/templates/apps/react-router/index.js.map +1 -0
  122. package/dist/templates/apps/shared.d.ts +1 -1
  123. package/dist/templates/apps/shared.js +25 -5
  124. package/dist/templates/apps/shared.js.map +1 -1
  125. package/dist/templates/apps/sveltekit/index.d.ts +2 -0
  126. package/dist/templates/apps/sveltekit/index.js +155 -0
  127. package/dist/templates/apps/sveltekit/index.js.map +1 -0
  128. package/dist/templates/backend/index.js +4 -4
  129. package/dist/templates/backend/index.js.map +1 -1
  130. package/dist/templates/root/index.js +104 -41
  131. package/dist/templates/root/index.js.map +1 -1
  132. package/dist/templates/versions.d.ts +46 -0
  133. package/dist/templates/versions.js +46 -0
  134. package/dist/templates/versions.js.map +1 -1
  135. package/dist/workspace/add.d.ts +7 -2
  136. package/dist/workspace/add.js +745 -115
  137. package/dist/workspace/add.js.map +1 -1
  138. package/dist/workspace/doctor.js +326 -36
  139. package/dist/workspace/doctor.js.map +1 -1
  140. package/dist/workspace/env.js +1 -1
  141. package/dist/workspace/env.js.map +1 -1
  142. package/dist/workspace/planning.d.ts +11 -0
  143. package/dist/workspace/planning.js +70 -0
  144. package/dist/workspace/planning.js.map +1 -0
  145. package/dist/workspace/project.d.ts +6 -2
  146. package/dist/workspace/project.js +22 -5
  147. package/dist/workspace/project.js.map +1 -1
  148. package/dist/workspace/upgrade.d.ts +2 -0
  149. package/dist/workspace/upgrade.js +153 -0
  150. package/dist/workspace/upgrade.js.map +1 -1
  151. package/docs/adding-a-framework.md +30 -4
  152. package/docs/adding-an-auth-provider.md +23 -6
  153. package/docs/architecture.md +13 -6
  154. package/docs/research.md +148 -1
  155. package/docs/verification.md +182 -0
  156. package/package.json +11 -3
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # create-convex-monorepo
2
2
 
3
- A TypeScript CLI that generates pnpm and Turborepo workspaces with multiple frontends sharing one typed Convex backend. Choose Next.js, Vite + React, TanStack Start, Expo, or a combination, with optional Clerk authentication.
3
+ A TypeScript CLI that generates pnpm or bun workspaces. Turborepo runs multiple frontends sharing one typed Convex backend. Choose Next.js, Vite + React, TanStack Start, React Router v7, Expo, Astro + React island, SvelteKit, Nuxt, or a combination. React apps support optional Clerk, Convex Auth, WorkOS AuthKit, or Better Auth authentication on their supported frameworks. SvelteKit and Nuxt support auth `none` only.
4
4
 
5
5
  The generator composes framework templates and auth adapters. It does not copy a single starter and delete unwanted pieces. Choose blank apps or a messages example. The example includes a query and mutation, plus compile-time assertions for the shared API's argument and return types.
6
6
 
@@ -10,7 +10,7 @@ Convex already generates an API from your backend functions. Sharing that API be
10
10
 
11
11
  ## Usage
12
12
 
13
- Requires Node.js 22.12 or newer and pnpm for the generated workspace.
13
+ Requires Node.js 22.12 or newer and pnpm or bun for the generated workspace.
14
14
 
15
15
  ```sh
16
16
  pnpm create convex-monorepo@latest
@@ -22,60 +22,85 @@ Or use npx:
22
22
  npx create-convex-monorepo@latest
23
23
  ```
24
24
 
25
- Both commands run the same CLI. You can also install it globally with `npm install --global create-convex-monorepo` and run `create-convex-monorepo` directly. Running through npx does not change the generated workspace's package manager, which is pnpm.
25
+ Both commands run the same CLI. You can also install it globally with `npm install --global create-convex-monorepo` and run `create-convex-monorepo` directly. Running through npx does not change the generated workspace's package manager. The default is pnpm; select bun with `--package-manager bun` or the interactive prompt.
26
26
 
27
27
  Contributors can run the checkout with `pnpm dev`; see [CONTRIBUTING.md](CONTRIBUTING.md).
28
28
 
29
29
  ## Manage an existing workspace
30
30
 
31
- The same npm package also provides the `convex-monorepo` command. Install it in the generated workspace:
31
+ Run the same CLI from the workspace root or any subdirectory. No global or project installation is needed:
32
32
 
33
33
  ```sh
34
- pnpm add -Dw create-convex-monorepo@latest
35
- pnpm exec convex-monorepo add
34
+ npx create-convex-monorepo@latest
35
+ ```
36
+
37
+ With a terminal attached, it detects `convex-monorepo.json` and offers a menu to add an app, add a shared package, add authentication, check the workspace, sync frontend URLs, update dependencies, or check for updates. Without a terminal, it prints management help without changing files.
38
+
39
+ You can also run each command directly:
40
+
41
+ ```sh
42
+ npx create-convex-monorepo@latest add app admin --framework vite --example none --dry-run
43
+ npx create-convex-monorepo@latest add app admin --framework vite --example none --install
44
+ npx create-convex-monorepo@latest add app mobile --framework expo --no-install
45
+ npx create-convex-monorepo@latest add package shared --dry-run
46
+ npx create-convex-monorepo@latest add package shared --no-install
47
+ npx create-convex-monorepo@latest add auth clerk --dry-run
48
+ npx create-convex-monorepo@latest add auth clerk --install
49
+ npx create-convex-monorepo@latest add auth convex-auth --dry-run
50
+ npx create-convex-monorepo@latest add auth convex-auth --install
51
+ npx create-convex-monorepo@latest add auth better-auth --dry-run
52
+ npx create-convex-monorepo@latest add auth better-auth --install
53
+ npx create-convex-monorepo@latest add auth workos --dry-run
54
+ npx create-convex-monorepo@latest add auth workos --install
55
+ npx create-convex-monorepo@latest env sync --app mobile
56
+ npx create-convex-monorepo@latest doctor
57
+ npx create-convex-monorepo@latest upgrade --check
58
+ npx create-convex-monorepo@latest upgrade --dry-run
59
+ npx create-convex-monorepo@latest upgrade --install
36
60
  ```
37
61
 
38
- Or run it without installing a project dependency:
62
+ The same commands work through pnpm:
39
63
 
40
64
  ```sh
41
- pnpm --package create-convex-monorepo@latest dlx convex-monorepo doctor
42
- npx --yes --package create-convex-monorepo@latest convex-monorepo doctor
65
+ pnpm create convex-monorepo@latest add app admin --framework vite --no-install
66
+ pnpm create convex-monorepo@latest doctor
43
67
  ```
44
68
 
45
- Run commands from the workspace root or any subdirectory:
69
+ The separate `convex-monorepo` binary remains available for users who install the package locally or globally. For example, after `pnpm add -Dw create-convex-monorepo@latest`, run `pnpm exec convex-monorepo doctor`.
70
+
71
+ To explicitly generate a new project, use `create <project-name>`. This also lets you use a command name such as `doctor` as the project name:
46
72
 
47
73
  ```sh
48
- pnpm exec convex-monorepo add app admin --framework vite --example none --dry-run
49
- pnpm exec convex-monorepo add app admin --framework vite --example none --install
50
- pnpm exec convex-monorepo add app mobile --framework expo --no-install
51
- pnpm exec convex-monorepo add auth clerk --dry-run
52
- pnpm exec convex-monorepo add auth clerk --install
53
- pnpm exec convex-monorepo env sync --app mobile
54
- pnpm exec convex-monorepo doctor
55
- pnpm exec convex-monorepo upgrade --check
74
+ npx create-convex-monorepo@latest create doctor --apps vite --no-install --no-git
56
75
  ```
57
76
 
58
- | Command | Behavior |
59
- | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
60
- | `add app` | Creates an app using the existing backend and auth, updates root scripts and metadata, and links the public backend URL when configured. |
61
- | `add auth clerk` | Adds Clerk to generated app providers and the backend auth configuration. Customized files that need replacement cause a conflict. |
62
- | `env sync` | Links only the public backend URL, using each framework's variable prefix. Supports `--app` and `--dry-run`. |
63
- | `doctor` | Checks workspace configuration, installed dependencies, environment settings, and shared API types. Supports `--json`; errors exit with status 1. |
64
- | `upgrade --check` | Compares generator versions with npm's latest stable release and reports the running CLI's tested dependency baseline through `--json`. Makes no changes. |
77
+ | Command | Behavior |
78
+ | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
79
+ | `add app` | Creates an app using the existing backend and auth, updates root scripts and metadata, and links the public backend URL when configured. |
80
+ | `add package` | Creates a blank shared TypeScript package under `packages/<name>` and records it in metadata. |
81
+ | `add auth` | Adds Clerk, Convex Auth, WorkOS AuthKit, or Better Auth to generated app providers and the backend auth configuration. Customized files that need replacement cause a conflict. |
82
+ | `env sync` | Links only the public backend URL, using each framework's variable prefix. Supports `--app` and `--dry-run`. |
83
+ | `doctor` | Checks workspace configuration, installed dependencies, environment settings, and shared API types. Supports `--json`; errors exit with status 1. |
84
+ | `upgrade` | Updates existing exact dependency pins and the recorded package-manager version to the running CLI's tested baseline. Keeps newer pins and rejects non-exact customizations. |
85
+ | `upgrade --check` | Compares generator versions with npm's latest stable release and reports the running CLI's tested dependency baseline through `--json`. Makes no changes. |
65
86
 
66
- The add commands support `--dry-run`, `--install`, `--no-install`, and `--yes`. Without prompts, provide the app name and framework; dependency installation defaults to off. `--yes` enables installation unless `--no-install` is set, and never overrides conflicts. A dry run shows file paths without printing environment values or installing dependencies.
87
+ The `add app`, `add package`, `add auth`, and `upgrade` commands support `--dry-run`, `--install`, `--no-install`, and `--yes`. Without prompts, provide the app name and framework for `add app`, the package name for `add package`, or `clerk`, `convex-auth`, `workos`, or `better-auth` for `add auth`. Dependency installation defaults to off. `--yes` enables installation unless `--no-install` is set, and never overrides conflicts. A dry run shows file paths without printing environment values or installing dependencies.
67
88
 
68
- Existing workspaces with metadata version 1, including projects created with 0.2.1, are supported. Preserve `convex-monorepo.json`; the CLI reads it rather than guessing which directories belong to your project. Per-app starter choices are recorded there when they differ from the original selection.
89
+ Existing pnpm workspaces with metadata version 1, including projects created with 0.2.1, are supported. Bun workspaces also use metadata version 1. Preserve `convex-monorepo.json`; the CLI reads it rather than guessing which directories belong to your project. Per-app starter choices are recorded there when they differ from the original selection. Shared packages added by the CLI are recorded in the optional `packages` list as `{ "name": "shared" }` entries.
69
90
 
70
91
  ### Changes and conflicts
71
92
 
72
- Commands plan every file before applying changes. They reject unsafe paths, symlinks, existing app directories, conflicting scripts or dependencies, and customized auth files that would need replacement. App addition requires the generated `apps/*` and `packages/*` workspace layout and Turbo dev script. Adding a messages UI also requires the generated messages backend contract; use `--example none` with a customized backend.
93
+ Commands plan every file before applying changes. They reject unsafe paths, symlinks, existing app or package paths, conflicting scripts or dependencies, and customized auth files that would need replacement. App addition requires the generated `apps/*` and `packages/*` workspace layout and Turbo dev script. Adding a messages UI also requires the generated messages backend contract; use `--example none` with a customized backend. Adding SvelteKit also updates an unchanged older URL setup script and adds formatter ignores for its generated output; customized setup scripts cause a conflict. Adding Astro or Nuxt to an older workspace also updates its recognized setup helper, adds the framework's public environment prefix to Turbo settings, and ignores its generated output. Astro adds `PUBLIC_*` and `.astro/`; Nuxt adds `NUXT_PUBLIC_*`, `.nuxt/`, and `.output/`. A customized setup helper that cannot be upgraded causes a conflict before writes. Restore the generated helper, add the app, then reapply custom changes.
94
+
95
+ Package addition creates plain TypeScript source with shared lint and typecheck settings. Add `"@<scope>/<name>": "workspace:*"` to each consuming app's dependencies, then run `pnpm install`. Next configs are updated when they match the generated config apart from the `transpilePackages` string list, so repeated `add package` calls keep appending. A missing config or any other customization produces a note with the required manual edit. Other frameworks need no config change.
73
96
 
74
- Auth addition supports `none` to Clerk. It preserves backend schemas, functions, generated internals, unrelated package fields, and existing README content. Follow the new `CLERK_SETUP.md` for account configuration. Existing public messages do not acquire an owner automatically and will not appear in authenticated accounts. Review stored-data migration separately. Already configured Clerk is a no-op; replacing an auth provider is not supported.
97
+ Auth addition supports `none` to Clerk, Convex Auth, WorkOS AuthKit, or Better Auth. It preserves user functions, generated internals, unrelated package fields, and existing README content. Convex Auth adds `authTables` to a generated schema or a customized schema with a single `defineSchema` call taking an object literal. Other schema shapes need the two manual edits named in the conflict. A customized HTTP router needs a manual `auth.addHttpRoutes(http)` call. Follow the new `CLERK_SETUP.md`, `CONVEX_AUTH_SETUP.md`, `WORKOS_SETUP.md`, or `BETTER_AUTH_SETUP.md` for setup. For Convex Auth, run `pnpm install`, then `pnpm convex:auth-keys`; refresh generated types with `pnpm convex:dev` or `convex codegen`. Existing public messages do not acquire an owner automatically and will not appear in authenticated accounts. Review stored-data migration separately. Adding the configured provider again is a no-op; replacing an auth provider is not supported.
75
98
 
76
99
  A workspace lock prevents two CLI edits from running together. Each planned file is checked again before writing. Failed edits roll back files that still contain this command's output; observed concurrent edits are preserved and reported. Filesystem checks are optimistic, so avoid editing affected files while a command is applying. A failed dependency installation leaves the applied files available for retry with `pnpm install`.
77
100
 
78
- Doctor is read-only and uses an in-memory TypeScript probe. It does not run application scripts, start services, configure a deployment, validate a real Clerk session, or prove a native Expo build works. Missing installation or environment configuration is reported with suggested steps. The upgrade command does not rewrite files, migrate templates, or update dependency versions.
101
+ Doctor is read-only and uses an in-memory TypeScript probe. It does not run application scripts, start services, configure a deployment, validate a real Clerk session, or prove a native Expo build works. Missing installation or environment configuration is reported with suggested steps.
102
+
103
+ Upgrade updates matching dependency entries in root, app, and shared-package manifests and records the running CLI version in metadata. It never downgrades exact pins. Non-exact managed pins, such as `^` ranges, cause a conflict before any writes. User-added dependencies and unrelated package fields are preserved; missing tested dependencies are reported but not added. Manifests are rewritten from parsed JSON, so comments are not supported and integer values above 2^53 lose precision. Upgrade does not migrate template files or write the lockfile itself. Run `pnpm install` afterward, or use `--install`, to update the lockfile.
79
104
 
80
105
  ## Interactive usage
81
106
 
@@ -83,14 +108,15 @@ With a terminal attached, the CLI asks for missing choices:
83
108
 
84
109
  ```text
85
110
  Project name? my-app
86
- Package manager? pnpm
111
+ Package manager? pnpm / bun (default: pnpm)
87
112
  Application framework? Next.js
88
113
  Application name? web
89
114
  Add another frontend? Yes
90
115
  Application framework? Expo / React Native
91
116
  Application name? mobile
92
117
  Add another frontend? No
93
- Authentication? Clerk
118
+ Authentication? Convex Auth (email + password)
119
+ OAuth providers? None
94
120
  Starter content? Blank project
95
121
  Initialize git? Yes
96
122
  Initialize Convex and link frontend URLs? Yes
@@ -107,20 +133,43 @@ pnpm create convex-monorepo@latest my-app --apps web:next,admin:vite --no-instal
107
133
  pnpm create convex-monorepo@latest my-app --apps app:tanstack-start,dashboard:next --auth none --package-manager pnpm --yes
108
134
  ```
109
135
 
110
- | Option | Meaning |
111
- | ----------------------------------- | ----------------------------------------------------------- |
112
- | `--apps` | Comma-separated framework IDs or `name:framework` entries |
113
- | `--auth` | `none`, the default, or `clerk` |
114
- | `--example` | `messages`, the default, or `none` for blank projects |
115
- | `--package-manager` | `pnpm`; other managers are rejected in v0.1 |
116
- | `--install`, `--no-install` | Enable or skip dependency installation |
117
- | `--init-convex`, `--no-init-convex` | Initialize Convex and link URLs; enables installation |
118
- | `--git`, `--no-git` | Enable or skip `git init`; no commit is created |
119
- | `--yes`, `-y` | Skip prompts and accept defaults, including install and git |
120
- | `--help`, `--version` | Show usage or the generator version |
136
+ | Option | Meaning |
137
+ | ----------------------------------- | ----------------------------------------------------------------------- |
138
+ | `--apps` | Comma-separated framework IDs or `name:framework` entries |
139
+ | `--auth` | `none`, the default, `clerk`, `convex-auth`, `workos`, or `better-auth` |
140
+ | `--oauth` | Optional comma list `github,google`; requires `--auth convex-auth` |
141
+ | `--example` | `messages`, the default, or `none` for blank projects |
142
+ | `--package-manager` | `pnpm`, the default, or `bun`; npm and yarn are rejected |
143
+ | `--install`, `--no-install` | Enable or skip dependency installation |
144
+ | `--init-convex`, `--no-init-convex` | Initialize Convex and link URLs; enables installation |
145
+ | `--git`, `--no-git` | Enable or skip `git init`; no commit is created |
146
+ | `--yes`, `-y` | Skip prompts and accept defaults, including install and git |
147
+ | `--help`, `--version` | Show usage or the generator version |
121
148
 
122
149
  Without a terminal, prompts are disabled and install/git default to off unless explicitly enabled or `--yes` is passed. Explicit negative flags override `--yes`. Convex initialization defaults to off when prompts are skipped, including with `--yes`; request it explicitly with `--init-convex`. That flag still lets Convex prompt for an account or deployment, and conflicts with `--no-install`. The default app is Next.js. Project and app names must be lowercase letters, digits, and hyphens, at most 100 characters, with no path separators or reserved device names.
123
150
 
151
+ ## Bun workspaces
152
+
153
+ Select bun in the "Package manager?" prompt or pass the flag:
154
+
155
+ ```sh
156
+ npx create-convex-monorepo@latest my-app --apps next,expo --package-manager bun --install --no-git
157
+ cd my-app
158
+ bun run convex:setup
159
+ bun run dev
160
+ bun run typecheck
161
+ bun run lint
162
+ bun run build
163
+ ```
164
+
165
+ If installation was skipped, run `bun install` first. Use `bun run convex:link`, `bun run convex:dev`, for Convex Auth, `bun run convex:auth-keys`, and for Better Auth, `bun run convex:better-auth-env`. The pnpm script examples in this README use `bun run <script>` in bun workspaces. Run backend binaries from the root with `bun run --cwd packages/backend convex <command>`.
166
+
167
+ Bun workspaces put `apps/*` and `packages/*` in the root manifest's `workspaces` list and pin bun in `packageManager`. They keep Turborepo and `workspace:*` dependencies. Commit `bun.lock`; no `pnpm-workspace.yaml` is generated. Existing-workspace commands read the recorded manager, including when invoked through npx or pnpm. `--install` uses that manager, and upgrade updates its version pin. This does not migrate existing pnpm workspaces.
168
+
169
+ Keep Node.js 22.12+ installed for the CLI and framework tools. Bun's dependency lifecycle policy differs from pnpm's; the template trusts only esbuild, sharp, and unrs-resolver, matching the pnpm template's build allowlist. Review scripts before trusting additional dependencies. Expo keeps its default Metro configuration; JavaScript export does not verify native Xcode or Gradle builds. See [bun and Expo findings](docs/research.md#bun-workspaces).
170
+
171
+ Metadata stays at version 1. Older CLI releases that validate the manager as pnpm-only reject bun workspaces; use a CLI release with bun support to manage them.
172
+
124
173
  ## Blank projects
125
174
 
126
175
  Choose **Blank project** in the starter-content prompt, or pass `--example none`:
@@ -129,22 +178,34 @@ Choose **Blank project** in the starter-content prompt, or pass `--example none`
129
178
  pnpm create convex-monorepo@latest my-app --apps next,expo --example none --yes
130
179
  ```
131
180
 
132
- Every selected app starts with a minimal page or screen showing its name. Convex providers, workspace dependencies, environment setup, and the selected auth integration remain configured. The backend has an empty schema and official generated types. There are no example tables, messages functions, access helpers, query/mutation screens, or demo-specific type-test files to remove.
181
+ Every selected app starts with a minimal page or screen showing its name. Convex providers, workspace dependencies, environment setup, and the selected auth integration remain configured. The backend has official generated types and an empty schema, except Convex Auth projects retain their auth tables and functions. Better Auth keeps its tables in the component and exposes the current-user query. There are no example tables, messages functions, access helpers, query/mutation screens, or demo-specific type-test files to remove.
133
182
 
134
- Add your tables to `packages/backend/convex/schema.ts` and your functions beside it. Run `pnpm convex:dev` to generate their shared API references. With Clerk, add server-side identity and authorization checks to your protected functions. The blank starter retains sign-in controls and the existing authenticated provider behavior.
183
+ Add your tables to `packages/backend/convex/schema.ts` and your functions beside it. Run `pnpm convex:dev` to generate their shared API references. With any auth provider, add server-side identity and authorization checks to your protected functions. The blank starter retains sign-in controls and the existing authenticated provider behavior.
135
184
 
136
185
  The choice applies to the whole workspace. `--example messages` keeps the existing query/mutation demo and remains the default, including with `--yes`.
137
186
 
138
187
  ## Supported frameworks
139
188
 
140
- | ID | Application | Public Convex variable |
141
- | ---------------- | ------------------------ | ------------------------ |
142
- | `next` | Next.js App Router | `NEXT_PUBLIC_CONVEX_URL` |
143
- | `vite` | Vite + React | `VITE_CONVEX_URL` |
144
- | `tanstack-start` | TanStack Start with Vite | `VITE_CONVEX_URL` |
145
- | `expo` | Expo / React Native | `EXPO_PUBLIC_CONVEX_URL` |
189
+ | ID | Application | Public Convex variable | Convex data loading |
190
+ | ---------------- | ------------------------------------------------------------------- | ------------------------ | ------------------------------------------------------ |
191
+ | `next` | Next.js App Router | `NEXT_PUBLIC_CONVEX_URL` | Client React hooks |
192
+ | `vite` | Vite + React | `VITE_CONVEX_URL` | Client React hooks |
193
+ | `tanstack-start` | TanStack Start with Vite | `VITE_CONVEX_URL` | Client React hooks, no server prefetch |
194
+ | `react-router` | React Router v7 framework mode, SSR enabled | `VITE_CONVEX_URL` | Client React hooks, no server prefetch or data loaders |
195
+ | `expo` | Expo / React Native | `EXPO_PUBLIC_CONVEX_URL` | Client React hooks |
196
+ | `astro` | Astro + React island | `PUBLIC_CONVEX_URL` | Client React hooks in a client-only island |
197
+ | `sveltekit` | SvelteKit with Svelte 5 | `PUBLIC_CONVEX_URL` | Client Svelte queries, no server preloading |
198
+ | `nuxt` | Nuxt, auth `none` only; Node `^22.19.0 \|\| ^24.11.0 \|\| >=26.0.0` | `NUXT_PUBLIC_CONVEX_URL` | Client Vue composables inside `ClientOnly` |
146
199
 
147
- Versions are pinned in the templates. Start uses ordinary Convex React hooks; server-side Convex prefetching is not configured. Expo's build command exports JavaScript, not native application binaries. See [research and upstream caveats](docs/research.md).
200
+ Nuxt uses Vue and supports only `--auth none`, including workspaces that mix Nuxt, SvelteKit, and React apps. Adding Nuxt to an authenticated workspace or adding auth to a workspace containing Nuxt is rejected before files change.
201
+
202
+ Nuxt keeps SSR enabled, but its Convex plugin and messages component run only in the browser. `NUXT_PUBLIC_CONVEX_URL` maps to `runtimeConfig.public.convexUrl`. Dev, build, and preview read `.env.local`; production servers accept the variable at runtime. Typechecking runs `nuxt prepare`, then `vue-tsc --noEmit` against both `.nuxt/tsconfig.json` and `.nuxt/tsconfig.server.json` to check app and server code. Lint uses `eslint-plugin-vue` with the shared TypeScript rules.
203
+
204
+ SvelteKit currently supports only `--auth none`, for both starters. It can share a workspace with any of the React frameworks when auth is `none`. Adding SvelteKit to an authenticated workspace or adding auth to a workspace containing SvelteKit fails before files are written.
205
+
206
+ Astro generates a static page with a React island mounted through `client:only="react"`. Convex and auth run in the browser. Its `typecheck` script uses `astro check`; Clerk uses the official `@clerk/astro` integration and middleware. No SSR adapter is needed for the static page.
207
+
208
+ Versions are pinned in the templates. React Router follows the Vite framework scaffold with `app/root.tsx`, `app/routes.ts`, and `app/routes/home.tsx`. Its typecheck script generates route types before running TypeScript. Its root loader handles auth only; Convex queries and mutations use the shared client components. Expo's build command exports JavaScript, not native application binaries. See [research and upstream caveats](docs/research.md).
148
209
 
149
210
  ## Generated architecture
150
211
 
@@ -164,7 +225,7 @@ my-app/
164
225
  │ ├── typescript-config/
165
226
  │ └── eslint-config/
166
227
  ├── convex-monorepo.json
167
- ├── pnpm-workspace.yaml
228
+ ├── pnpm-workspace.yaml # pnpm only
168
229
  ├── turbo.json
169
230
  └── package.json
170
231
  ```
@@ -179,7 +240,7 @@ Use explicit names to choose folders and repeat a framework:
179
240
  pnpm create convex-monorepo@latest acme --apps web:next,admin:next,mobile:expo --yes
180
241
  ```
181
242
 
182
- Apps become `@acme/web`, `@acme/admin`, and `@acme/mobile`. All depend on `@acme/backend` through `workspace:*`. The generator assigns distinct web development ports. v0.1 creates a new workspace; adding an app to an existing workspace is not implemented.
243
+ Apps become `@acme/web`, `@acme/admin`, and `@acme/mobile`. All depend on `@acme/backend` through `workspace:*`. The generator assigns distinct web development ports. Use `npx create-convex-monorepo@latest add app` to add another frontend later.
183
244
 
184
245
  ## First run and development
185
246
 
@@ -203,7 +264,20 @@ pnpm lint
203
264
  pnpm build
204
265
  ```
205
266
 
206
- Complete setup in a normal terminal before starting Turbo. Stop a separately running backend watcher before `pnpm dev`, which starts its own. Public environment values are embedded at build time; rebuild frontends when they change. Backend build checks types and does not deploy.
267
+ Complete setup in a normal terminal before starting Turbo. Stop a separately running backend watcher before `pnpm dev` or `bun run dev`, which starts its own. SvelteKit reads `PUBLIC_CONVEX_URL` from `$env/static/public`, so set it before typechecking or building. Its root layout mounts the Svelte Convex provider; messages subscribe with `useQuery`.
268
+
269
+ Public environment values are embedded at build time; rebuild frontends when they change. Backend build checks types and does not deploy.
270
+
271
+ ## Code formatting
272
+
273
+ Generated source and configuration files are formatted with Prettier before they are written, including when using `--no-install`. New workspaces include a pinned Prettier dependency and matching configuration:
274
+
275
+ ```sh
276
+ pnpm format
277
+ pnpm format:check
278
+ ```
279
+
280
+ Svelte components use the pinned `prettier-plugin-svelte` formatter. Convex `_generated` files, TanStack's generated route tree, React Router's `.react-router` types, SvelteKit's generated files, build output, lockfiles, and environment files are excluded. Adding an app formats its new files; it does not reformat existing application code. Auth migration accepts formatting differences in older starters while still rejecting customized code that would be replaced.
207
281
 
208
282
  ## Convex backend sharing
209
283
 
@@ -218,7 +292,153 @@ Dynamic Convex declarations refer to backend source modules. Client TypeScript p
218
292
 
219
293
  ## Authentication
220
294
 
221
- `--auth clerk` adds SDK-specific bindings, a Convex auth configuration, and provider wiring. The messages example also includes backend identity checks and an owner index that keeps messages private. With `--auth none`, that example is a public message board. Blank projects have no data or functions; add authorization checks when writing protected functions. UI visibility alone is not authorization.
295
+ New projects accept `none`, `clerk`, `convex-auth`, or `better-auth` across the six React frameworks and both starters. SvelteKit and Nuxt support only `none`; the generator has no Svelte or Vue binding for Clerk, Convex Auth, WorkOS, or Better Auth. Existing no-auth workspaces without Nuxt or SvelteKit accept `add auth clerk`, `add auth convex-auth`, `add auth workos`, or `add auth better-auth`. All providers support `add app` for their supported frameworks. WorkOS AuthKit supports Next.js, Vite, and TanStack Start with both starters. Expo, Astro, React Router, SvelteKit, and Nuxt are rejected before writing files. Expo has no official React Native AuthKit SDK. The [official Astro SDK](https://github.com/workos/authkit-astro) requires a server adapter and on-demand rendering; this generator uses static Astro output.
296
+ React Router has an official SDK, but this generator has no binding for it yet.
297
+
298
+ `--auth convex-auth` and `add auth convex-auth` configure email and password sign-up/sign-in, sign-out, and per-user backend access. Web apps use the client ConvexAuthProvider; Expo persists tokens with expo-secure-store. No frontend public auth keys or password-flow redirect scheme are needed. Next.js, TanStack Start, and React Router do not configure server-side authentication or authenticated SSR. GitHub and Google OAuth are opt-in with `--oauth github,google`. Magic links, email verification, password reset, and MFA are outside this starter.
299
+
300
+ Run `pnpm convex:setup`, then `pnpm convex:auth-keys`. The key script generates an RSA 2048 key pair and sets `JWT_PRIVATE_KEY` and `JWKS` on the deployment through the installed Convex CLI. It never stores the key locally or prints either value. The initial push can finish before keys exist, but sign-in fails until they are configured. Run `pnpm convex:auth-keys --prod` to set a separate pair for production. `SITE_URL` is a deployment setting for redirects and is optional for this Password-only flow. The generated `.env.convex-auth.example` belongs to the backend package. See the [official manual setup](https://labs.convex.dev/auth/setup/manual).
301
+
302
+ ### Optional GitHub and Google OAuth
303
+
304
+ Keep Password sign-in and add either or both providers:
305
+
306
+ ```sh
307
+ pnpm create convex-monorepo@latest my-app --apps next,expo --auth convex-auth --oauth github,google
308
+ npx create-convex-monorepo@latest add auth convex-auth --oauth google --install
309
+ ```
310
+
311
+ OAuth supports both package managers. The examples below use pnpm. For bun workspaces, use `bun install`, replace `pnpm <script>` with `bun run <script>`, and replace `pnpm --filter @my-app/backend exec convex` with `bun run --cwd packages/backend convex`. Generated setup instructions use the selected manager.
312
+
313
+ The interactive OAuth multiselect defaults to none. `--oauth` is valid only with Convex Auth; unknown providers fail before generation. Both starters and all six React frameworks support it, including the Astro React island. Nuxt and SvelteKit reject Convex Auth, including OAuth, before generation or workspace changes. Metadata version 1 records the selected providers in an optional `oauth` array. `add auth` accepts this flag only on a no-auth workspace. Adding OAuth to a workspace with authentication already configured requires the manual edits below.
314
+
315
+ For OAuth, `SITE_URL` is required on the Convex deployment. Generated OAuth workspaces include a helper that leaves signing keys unchanged:
316
+
317
+ ```sh
318
+ pnpm convex:auth-site http://localhost:3000
319
+ pnpm convex:auth-site https://your-app.example --prod
320
+ ```
321
+
322
+ Set `AUTH_GITHUB_ID`, `AUTH_GITHUB_SECRET`, `AUTH_GOOGLE_ID`, and `AUTH_GOOGLE_SECRET` for the selected providers with `pnpm --filter @my-app/backend exec convex env set <name> <value>` or the Convex dashboard. These are deployment settings, never frontend public environment variables. The backend `.env.convex-auth.example` lists the selected settings.
323
+
324
+ Create the OAuth applications in GitHub's developer settings and Google's Cloud console. Register the callback for each selected provider:
325
+
326
+ | Provider | Callback URL |
327
+ | -------- | -------------------------------------------- |
328
+ | GitHub | `<CONVEX_SITE_URL>/api/auth/callback/github` |
329
+ | Google | `<CONVEX_SITE_URL>/api/auth/callback/google` |
330
+
331
+ `CONVEX_SITE_URL` is the deployment's HTTPS `.convex.site` URL. Use separate provider applications and credentials for development and production. Web buttons start `signIn('github')` or `signIn('google')`; successful sign-ins return to `SITE_URL`. Browser OAuth must start on the SITE_URL origin so the returning page can read its stored verifier. For additional web origins, change the web handler to `signIn(provider, { redirectTo: window.location.href })` and allow those origins in the backend redirect callback. Changing only the callback is insufficient.
332
+
333
+ Expo uses the scheme already defined in `app.json`, `ccm-<project>-<app>`, with return URL `ccm-<project>-<app>://auth`. Use `pnpm ios` or `pnpm android` in the app directory to create a development build. Expo Go cannot handle this custom scheme. The provider console uses the HTTPS Convex callback above, then Convex redirects to the app scheme. Register the scheme return URL in any native redirect allowlist required by the provider console. Do not replace the GitHub or Google web client's HTTPS callback with the app scheme.
334
+
335
+ The generated native handler uses `expo-linking` to create the return URL and `expo-web-browser` to open the URL returned by `signIn(provider, { redirectTo })`. It completes successful browser sessions with `signIn(provider, { code })`. The backend allows only the generated native return URLs and the configured web origin. Keep those URLs and the app scheme aligned if you rename an app. See [Convex Auth OAuth](https://labs.convex.dev/auth/config/oauth) and [Expo authentication](https://docs.expo.dev/guides/authentication/).
336
+
337
+ ### Add OAuth to an existing Convex Auth workspace
338
+
339
+ This is a manual edit. In `packages/backend/convex/auth.ts`, retain Password and add the selected imports and array entries. These OAuth providers come from the existing pinned `@auth/core` dependency; `@convex-dev/auth@0.0.95` does not export GitHub or Google provider modules.
340
+
341
+ ```ts
342
+ import { convexAuth } from '@convex-dev/auth/server';
343
+ import { Password } from '@convex-dev/auth/providers/Password';
344
+ import GitHub from '@auth/core/providers/github';
345
+ import Google from '@auth/core/providers/google';
346
+
347
+ export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({
348
+ providers: [Password, GitHub, Google],
349
+ });
350
+ ```
351
+
352
+ Remove the import and array entry for any provider you do not want. In each web app's `src/auth-controls.tsx`, add these buttons inside the signed-out form, beside the Password controls:
353
+
354
+ ```tsx
355
+ <button type="button" disabled={pending} onClick={() => {
356
+ void signIn('github').catch(() => setError('Could not sign in. Try again.'));
357
+ }}>Sign in with GitHub</button>
358
+ <button type="button" disabled={pending} onClick={() => {
359
+ void signIn('google').catch(() => setError('Could not sign in. Try again.'));
360
+ }}>Sign in with Google</button>
361
+ ```
362
+
363
+ For Expo, add exact dependencies `"expo-web-browser": "57.0.3"` and `"expo-linking": "57.0.10"` to the app's `package.json`, then run `pnpm install`. Confirm the `expo.scheme` value in `app.json`. Add these imports to `src/auth-controls.tsx`:
364
+
365
+ ```ts
366
+ import * as Linking from 'expo-linking';
367
+ import { openAuthSessionAsync } from 'expo-web-browser';
368
+ ```
369
+
370
+ Add this handler inside `AuthControls`, replacing `ccm-my-app-mobile` with the actual scheme:
371
+
372
+ ```tsx
373
+ async function authenticateOAuth(provider: 'github' | 'google') {
374
+ if (pending) return;
375
+ setPending(true);
376
+ setError(null);
377
+ try {
378
+ const redirectTo = Linking.createURL('auth', {
379
+ scheme: 'ccm-my-app-mobile',
380
+ });
381
+ const { redirect } = await signIn(provider, { redirectTo });
382
+ if (!redirect) throw new Error('Missing sign-in URL.');
383
+ const result = await openAuthSessionAsync(redirect.toString(), redirectTo);
384
+ if (result.type === 'success') {
385
+ const code = new URL(result.url).searchParams.get('code');
386
+ if (!code) throw new Error('Missing sign-in code.');
387
+ await signIn(provider, { code });
388
+ }
389
+ } catch (cause) {
390
+ setError(cause instanceof Error ? cause.message : 'Could not sign in.');
391
+ } finally {
392
+ setPending(false);
393
+ }
394
+ }
395
+ ```
396
+
397
+ Add native buttons inside the signed-out `View`:
398
+
399
+ ```tsx
400
+ <Button title="Sign in with GitHub" disabled={pending} onPress={() => { void authenticateOAuth('github'); }} />
401
+ <Button title="Sign in with Google" disabled={pending} onPress={() => { void authenticateOAuth('google'); }} />
402
+ ```
403
+
404
+ For a shared web and native backend, add this `callbacks` property beside `providers` in `convexAuth`. Replace the example native URL with the actual scheme, adding each native app's exact return URL to the array:
405
+
406
+ ```ts
407
+ callbacks: {
408
+ async redirect({ redirectTo }) {
409
+ const siteUrl = process.env.SITE_URL;
410
+ if (!siteUrl) throw new Error('Set SITE_URL on the Convex deployment.');
411
+ if (['ccm-my-app-mobile://auth'].includes(redirectTo)) return redirectTo;
412
+ const target = new URL(redirectTo, siteUrl);
413
+ if (target.origin === new URL(siteUrl).origin && ['http:', 'https:'].includes(target.protocol)) {
414
+ return target.toString();
415
+ }
416
+ throw new Error('Invalid OAuth redirect destination.');
417
+ },
418
+ },
419
+ ```
420
+
421
+ To enable OAuth from multiple web frontends, pass `{ redirectTo: window.location.href }` as the second argument to each web `signIn` call. Replace the callback's same-origin condition above with an explicit list of trusted origins, using your actual addresses:
422
+
423
+ ```ts
424
+ const allowedOrigins = [new URL(siteUrl).origin, 'http://localhost:3001'];
425
+ if (
426
+ allowedOrigins.includes(target.origin) &&
427
+ ['http:', 'https:'].includes(target.protocol)
428
+ ) {
429
+ return target.toString();
430
+ }
431
+ ```
432
+
433
+ Use production origins in production. Do not allow arbitrary URLs supplied by the client.
434
+
435
+ Configure credentials and callbacks as above. Set `SITE_URL` with `pnpm --filter @my-app/backend exec convex env set SITE_URL http://localhost:3000`, or use the scheme return URL for a mobile-only workspace. Add `"oauth": ["github", "google"]` to `convex-monorepo.json`, omitting unselected providers. Add `# SITE_URL is required for OAuth` and the selected `AUTH_*` variable names to `packages/backend/.env.convex-auth.example`. Run `pnpm convex:dev` to push the auth configuration, then rebuild the frontends and native development client. The backend module set is unchanged, so no codegen asset edits are needed.
436
+
437
+ Convex Auth message owners are `users` table IDs returned by `getAuthUserId`. Clerk owners are `tokenIdentifier` values. WorkOS owners are `identity.subject` values from `ctx.auth.getUserIdentity()`. Switching providers changes these keys and needs a data migration; the CLI does not replace auth providers.
438
+
439
+ `--auth workos` and `add auth workos` configure hosted AuthKit sign-in, SDK token refresh, sign-out, and Convex identity validation. The blank starter keeps the providers and sign-in controls. Append each app's `.env.workos.example` to `.env.local` and follow the generated README's WorkOS setup section, or `WORKOS_SETUP.md` after adding auth. The client ID uses each framework's public prefix. Next.js and TanStack Start also need its unprefixed server SDK value, plus server-only `WORKOS_API_KEY` and `WORKOS_COOKIE_PASSWORD`. Vite receives no server secrets. See [WorkOS research and configuration constraints](docs/research.md#workos-authkit).
440
+
441
+ `--auth clerk` adds SDK-specific bindings, a Convex auth configuration, and provider wiring. The messages example also includes backend identity checks and an owner index that keeps messages private. With `--auth none`, that example is a public message board. Blank projects omit the messages example; Convex Auth retains its auth tables and functions. Add authorization checks when writing protected functions. UI visibility alone is not authorization.
222
442
 
223
443
  Use one Clerk application across the frontends. Configure Clerk's Convex integration and a JWT template named `convex`. Set `CLERK_JWT_ISSUER_DOMAIN` on the Convex deployment:
224
444
 
@@ -228,7 +448,34 @@ pnpm --filter @my-app/backend exec convex env set CLERK_JWT_ISSUER_DOMAIN https:
228
448
 
229
449
  On a fresh deployment, first run `pnpm convex:setup` to select it. If the push reports a missing issuer, set that value and rerun setup. Repeat the configuration for production.
230
450
 
231
- Append the variables from each app's `.env.clerk.example` to its `.env.local`, alongside the Convex URL. Publishable keys belong in the appropriate public variables. Next.js and Start use a server-only `CLERK_SECRET_KEY`; Vite and Expo must never receive that secret. See [Convex's Clerk guide](https://docs.convex.dev/auth/clerk).
451
+ Append the variables from each app's `.env.clerk.example` to its `.env.local`, alongside the Convex URL. Publishable keys belong in the appropriate public variables. Next.js, Start, and React Router use a server-only `CLERK_SECRET_KEY`; Vite and Expo must never receive that secret. React Router uses `@clerk/react-router`, `clerkMiddleware`, and `rootAuthLoader`, with `v8_middleware` enabled. Its provider receives the root loader's session data and connects Convex through `ConvexProviderWithClerk`. For production, set `VITE_CLERK_PUBLISHABLE_KEY` at build time and both Clerk keys in the server runtime environment; `react-router-serve` does not load `.env.local` automatically. See [Convex's Clerk guide](https://docs.convex.dev/auth/clerk) and [Clerk's React Router setup](https://clerk.com/docs/react-router/getting-started/quickstart).
452
+
453
+ ## Better Auth setup
454
+
455
+ Astro uses Better Auth inside its React island with `PUBLIC_CONVEX_URL` and `PUBLIC_CONVEX_SITE_URL`. React Router uses client authentication. Both support messages and blank starters. `--oauth` is only supported with Convex Auth.
456
+
457
+ `--auth better-auth` uses the official `@convex-dev/better-auth` component for email and password sign-up, sign-in, and sign-out on Next.js, Vite, TanStack Start, React Router, Expo, and Astro. Both starters include loading and error states. Next.js, TanStack Start, and React Router use client authentication. Social providers, magic links, email verification, and authenticated SSR are not configured.
458
+
459
+ Both package managers are supported. The examples below use pnpm; for bun workspaces, replace `pnpm <script>` with `bun run <script>`. Generated setup instructions use the selected manager.
460
+
461
+ Run `pnpm convex:setup` to select a deployment. If its first push requests auth configuration, set the deployment variables below and rerun setup. From the generated workspace root, configure your primary web origin and any additional frontend origins or native schemes:
462
+
463
+ ```sh
464
+ pnpm convex:better-auth-env --site-url http://localhost:3000 --trusted-origins http://localhost:3001,ccm-my-app-mobile://
465
+ pnpm convex:better-auth-env --site-url https://example.com --trusted-origins https://admin.example.com,ccm-my-app-mobile:// --prod
466
+ ```
467
+
468
+ Use the actual scheme from the Expo app's `app.json`. For Expo-only development, use its web origin for `SITE_URL` and include its native scheme in the trusted origins. Use a cloud deployment for physical devices and a development build for your custom scheme.
469
+
470
+ The script generates `BETTER_AUTH_SECRET` in memory and sets it, `SITE_URL`, and `BETTER_AUTH_TRUSTED_ORIGINS` through the installed Convex CLI. It does not store or print the secret. Run the production command separately for production. Re-running rotates the secret, which can invalidate existing sessions. Convex supplies the backend's `CONVEX_SITE_URL`.
471
+
472
+ Set the public HTTP endpoint in every app's `.env.local`: `NEXT_PUBLIC_CONVEX_SITE_URL` for Next.js, `VITE_CONVEX_SITE_URL` for Vite, TanStack Start, and React Router, `PUBLIC_CONVEX_SITE_URL` for Astro, and `EXPO_PUBLIC_CONVEX_SITE_URL` for Expo. Use your deployment's HTTP URL, normally ending in `.convex.site`. Keep the existing public `CONVEX_URL` setting, normally ending in `.convex.cloud`. `convex:link` and `env sync` copy only `CONVEX_URL`; enter the site URL yourself. Never put `BETTER_AUTH_SECRET` in frontend files.
473
+
474
+ Better Auth stores its tables inside the component. Message ownership uses the Better Auth user ID returned by `authComponent.getAuthUser(ctx)`. Blank projects keep an empty application schema and the auth query. Expo uses `@better-auth/expo` with SecureStore on native platforms and the cross-domain client on web.
475
+
476
+ `add auth better-auth` writes `BETTER_AUTH_SETUP.md` and preserves your schema and generated internals. A missing `convex/convex.config.ts` is created. An existing component config or HTTP router that needs integration produces a conflict with the exact manual edit. After installation and configuration, run `pnpm convex:dev` to refresh component types. Provider replacement and stored-data migration remain manual.
477
+
478
+ See the [official React guide](https://labs.convex.dev/better-auth/framework-guides/react), [Expo guide](https://labs.convex.dev/better-auth/framework-guides/expo), and [email/password documentation](https://www.better-auth.com/docs/authentication/email-password).
232
479
 
233
480
  ## Expo notes
234
481
 
@@ -242,7 +489,7 @@ Typechecking and Metro export checks do not establish that real OAuth, device pe
242
489
 
243
490
  - **Destination already exists:** choose a new or empty directory. The CLI refuses non-empty directories and symlinks. Template failures remove staging output; install/git/Convex setup failures preserve the completed project and print a retry command.
244
491
  - **Missing URL screen:** run `pnpm convex:setup`, or `pnpm convex:link` if the backend is already configured, then restart development.
245
- - **Authentication never connects:** check the `convex` JWT template and deployment issuer. Use the same Clerk application across frontends.
492
+ - **Authentication never connects:** for Better Auth, check deployment `BETTER_AUTH_SECRET`, `SITE_URL`, trusted origins, and each frontend's public `CONVEX_SITE_URL`. For Convex Auth, check deployment signing keys and the generated auth modules. For Clerk, check the `convex` JWT template and deployment issuer, and use the same Clerk application across frontends.
246
493
  - **Missing API types:** keep both generated JavaScript and declarations, run the backend watcher, and verify matching Convex versions. Do not fix this by casting the API.
247
494
  - **Missing Start route tree:** run that app's `routes:generate` script. Its typecheck script runs route generation automatically.
248
495
  - **Metro resolution after dependency changes:** run `pnpm --filter @my-app/mobile exec expo start --clear`. Check SDK-compatible dependency versions before changing resolver settings.
@@ -255,7 +502,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md), [adding a framework](docs/adding-a-frame
255
502
 
256
503
  ## Roadmap
257
504
 
258
- The next release should add `doctor` to check deployment URLs, generated types, version alignment, and auth setup in an existing workspace. Later candidates are `add app`, another auth provider, and additional package-manager adapters. These commands are not available in v0.1.
505
+ Next candidates are Convex Auth installation in existing workspaces, reviewed upgrade migrations, and more package-manager adapters. `upgrade` updates dependency pins; template migrations remain manual.
259
506
 
260
507
  MIT licensed. See [LICENSE](LICENSE).
261
508
 
@@ -0,0 +1,3 @@
1
+ Generated files under convex/\_generated were produced unchanged by convex@1.45.0 using CONVEX_AGENT_MODE=anonymous pnpm exec convex dev --once on 2026-09-18, after pnpm install in a temporary generated workspace. Dynamic JS/declaration output. Auth dependencies: @convex-dev/better-auth@0.12.5, better-auth@1.6.15 and @better-auth/expo@1.6.15. Input modules: convex.config.ts, schema.ts, auth.ts, http.ts, messages.ts, access.ts. auth.config.ts configures the issuer and is excluded from the generated function API. No internal codegen entry point was called. Run normal convex dev after changing backend modules.
2
+
3
+ Convex SDK source is Apache-2.0 licensed: https://github.com/get-convex/convex-js/blob/main/LICENSE.
@@ -0,0 +1,57 @@
1
+ /* eslint-disable */
2
+ /**
3
+ * Generated `api` utility.
4
+ *
5
+ * THIS CODE IS AUTOMATICALLY GENERATED.
6
+ *
7
+ * To regenerate, run `npx convex dev`.
8
+ * @module
9
+ */
10
+
11
+ import type * as access from "../access.js";
12
+ import type * as auth from "../auth.js";
13
+ import type * as http from "../http.js";
14
+ import type * as messages from "../messages.js";
15
+
16
+ import type {
17
+ ApiFromModules,
18
+ FilterApi,
19
+ FunctionReference,
20
+ } from "convex/server";
21
+
22
+ declare const fullApi: ApiFromModules<{
23
+ access: typeof access;
24
+ auth: typeof auth;
25
+ http: typeof http;
26
+ messages: typeof messages;
27
+ }>;
28
+
29
+ /**
30
+ * A utility for referencing Convex functions in your app's public API.
31
+ *
32
+ * Usage:
33
+ * ```js
34
+ * const myFunctionReference = api.myModule.myFunction;
35
+ * ```
36
+ */
37
+ export declare const api: FilterApi<
38
+ typeof fullApi,
39
+ FunctionReference<any, "public">
40
+ >;
41
+
42
+ /**
43
+ * A utility for referencing Convex functions in your app's internal API.
44
+ *
45
+ * Usage:
46
+ * ```js
47
+ * const myFunctionReference = internal.myModule.myFunction;
48
+ * ```
49
+ */
50
+ export declare const internal: FilterApi<
51
+ typeof fullApi,
52
+ FunctionReference<any, "internal">
53
+ >;
54
+
55
+ export declare const components: {
56
+ betterAuth: import("@convex-dev/better-auth/_generated/component.js").ComponentApi<"betterAuth">;
57
+ };
@@ -0,0 +1,23 @@
1
+ /* eslint-disable */
2
+ /**
3
+ * Generated `api` utility.
4
+ *
5
+ * THIS CODE IS AUTOMATICALLY GENERATED.
6
+ *
7
+ * To regenerate, run `npx convex dev`.
8
+ * @module
9
+ */
10
+
11
+ import { anyApi, componentsGeneric } from "convex/server";
12
+
13
+ /**
14
+ * A utility for referencing Convex functions in your app's API.
15
+ *
16
+ * Usage:
17
+ * ```js
18
+ * const myFunctionReference = api.myModule.myFunction;
19
+ * ```
20
+ */
21
+ export const api = anyApi;
22
+ export const internal = anyApi;
23
+ export const components = componentsGeneric();