git:20260717.0774b8b to git:20260805.9009eae

18 added, 440 removed. Audit B to A.

---
name: convex-quickstart
- description:
- Creates or adds Convex to an app. Use for new Convex projects, npm create
- convex@latest, frontend setup, env vars, or the first npx convex dev run.
+ description: "Get a barebones Convex + web template running from a one-sentence idea."
---
- # Convex Quickstart
-
- Set up a working Convex project as fast as possible.
-
- ## When to Use
-
- - Starting a brand new project with Convex
- - Adding Convex to an existing React, Next.js, Vue, Svelte, or other app
- - Scaffolding a Convex app for prototyping
+ <!-- GENERATED from convex-agents content/capabilities/quickstart.json — do not edit by hand. -->
- ## When Not to Use
+ # Quickstart: a barebones Convex template, running
- - The project already has Convex installed and `convex/` exists - just start
- building
- - You only need to add auth to an existing Convex app - use the
- `convex-setup-auth` skill
+ Stand up a barebones Next.js + Convex template from the idea, locally, with an anonymous dev deployment. Minimal by design: no publish step, no feedback panel, no auth pre-bake.
## Workflow
- 1. Determine the starting point: new project or existing app
- 2. If new project, pick a template and scaffold with `npm create convex@latest`
- 3. If existing app, install `convex` and wire up the provider
- 4. Run `npx convex dev --once` to provision a local anonymous deployment, push
- the current `convex/` code, typecheck it, and regenerate types — all in one
- shot, exiting cleanly. The output tells the agent whether the schema and
- functions are valid.
- 5. Ask the user (or, for cloud agents, start in the background) `npm run dev` —
- Convex templates wire the watcher and the frontend into a single command. If
- the project has no combined dev script, use `npx convex dev` for the watcher
- and run the frontend separately.
- 6. Verify the setup works
-
- ## Path 1: New Project (Recommended)
-
- Use the official scaffolding tool. It creates a complete project with the
- frontend framework, Convex backend, and all config wired together.
-
- ### Pick a template
-
- | Template | Stack |
- | -------------------------- | ----------------------------------------- |
- | `react-vite-shadcn` | React + Vite + Tailwind + shadcn/ui |
- | `nextjs-shadcn` | Next.js App Router + Tailwind + shadcn/ui |
- | `react-vite-clerk-shadcn` | React + Vite + Clerk auth + shadcn/ui |
- | `nextjs-clerk` | Next.js + Clerk auth |
- | `nextjs-convexauth-shadcn` | Next.js + Convex Auth + shadcn/ui |
- | `nextjs-lucia-shadcn` | Next.js + Lucia auth + shadcn/ui |
- | `bare` | Convex backend only, no frontend |
-
- If the user has not specified a preference, default to `react-vite-shadcn` for
- simple apps or `nextjs-shadcn` for apps that need SSR or API routes.
-
- You can also use any GitHub repo as a template:
-
- ```bash
- npm create convex@latest my-app -- -t owner/repo
- npm create convex@latest my-app -- -t owner/repo#branch
- ```
-
- ### Scaffold the project
-
- Always pass the project name and template flag to avoid interactive prompts:
-
- ```bash
- npm create convex@latest my-app -- -t react-vite-shadcn
- cd my-app
- npm install
- ```
-
- The scaffolding tool creates files but does not run `npm install`, so you must
- run it yourself.
-
- To scaffold in the current directory (if it is empty):
-
- ```bash
- npm create convex@latest . -- -t react-vite-shadcn
- npm install
- ```
-
- ### Provision the deployment and push code
-
- Run this yourself — it is a one-shot command that exits cleanly:
-
- ```bash
- npx convex dev --once
- ```
-
- In a non-TTY environment (which is true for almost every agent run), this:
-
- - Provisions an _anonymous_ local Convex backend bound to `127.0.0.1`. No
- browser login, no team/project prompts.
- - Writes `CONVEX_DEPLOYMENT` and the framework's `*_CONVEX_URL` variables to
- `.env.local`.
- - Generates `convex/_generated/`.
- - Pushes the current `convex/` code to the deployment, **typechecks it**, and
- **validates the schema**. The agent reads this output to find out if the code
- it just wrote is broken.
-
- To be explicit (recommended), set `CONVEX_AGENT_MODE=anonymous` so the behavior
- does not depend on TTY detection:
-
- ```bash
- CONVEX_AGENT_MODE=anonymous npx convex dev --once
- ```
-
- The deployment lives under `~/.convex/` and persists across runs. Re-running
- `convex dev --once` after editing `convex/` files is the agent's main feedback
- loop while the user-launched `npm run dev` is not in use.
-
- If the template's `package.json` defines a `predev` script (Convex Auth
- templates and similar do), `npm run predev` runs `convex init` plus any one-time
- setup (e.g. minting auth keys). Use it _in addition to_ `convex dev --once` when
- present — `predev` handles the one-time setup, `convex dev --once` pushes and
- validates the code.
-
- ### Start the dev loop
-
- In most Convex templates, `npm run dev` runs both the Convex watcher and the
- frontend dev server together (typically `convex dev --start 'vite --open'` or
- the Next.js equivalent). That is what the user should run.
-
- ```bash
- npm run dev
- ```
-
- If the project does not have a combined `dev` script — e.g. the `bare` template,
- or an existing app where you haven't wired the frontend dev server into Convex's
- `--start` flag — the user can run the Convex watcher directly:
-
- ```bash
- npx convex dev
- ```
-
- `npx convex dev` is the same long-running watcher `npm run dev` invokes under
- the hood; it just doesn't start the frontend. Use it when there is no frontend,
- or when the user prefers to run the frontend in a separate terminal.
-
- Either way, the agent should not invoke the watcher in the foreground because it
- does not exit. Two options:
-
- - **Local development (user is at the keyboard):** ask the user to run
- `npm run dev` (or `npx convex dev`) in a terminal. The deployment provisioned
- by `convex dev --once` above is already selected, so the watcher picks up
- immediately with no prompts.
- - **Cloud or headless agents:** start `npm run dev` (or `npx convex dev`) in the
- background.
-
- Vite apps serve on `http://localhost:5173`, Next.js on `http://localhost:3000`.
-
- ### What you get
-
- After scaffolding, the project structure looks like:
-
- ```
- my-app/
- convex/ # Backend functions and schema
- _generated/ # Auto-generated types (check this into git)
- schema.ts # Database schema (if template includes one)
- src/ # Frontend code (or app/ for Next.js)
- package.json
- .env.local # CONVEX_URL / VITE_CONVEX_URL / NEXT_PUBLIC_CONVEX_URL
- ```
-
- The template already has:
-
- - `ConvexProvider` wired into the app root
- - Correct env var names for the framework
- - Tailwind and shadcn/ui ready (for shadcn templates)
- - Auth provider configured (for auth templates)
-
- Proceed to adding schema, functions, and UI.
-
- ## Path 2: Add Convex to an Existing App
-
- Use this when the user already has a frontend project and wants to add Convex as
- the backend.
-
- ### Install
-
- ```bash
- npm install convex
- ```
-
- ### Provision and push
-
- Run `npx convex dev --once` yourself to provision a local anonymous deployment,
- write `.env.local`, generate types, push the current `convex/` code, and
- typecheck it. This is one-shot and exits:
-
- ```bash
- npx convex dev --once
- ```
-
- The output tells you whether the schema and functions are valid — use it as your
- feedback loop while iterating.
-
- Then ask the user to start the watcher (or, for cloud/headless agents, start it
- in the background). You have two options:
-
- - **Wire Convex into `npm run dev`** — change the existing app's `dev` script to
- `convex dev --start '<existing dev command>'`. That's the standard pattern
- Convex templates use; the user then runs a single `npm run dev` to start both.
- - **Run them separately** — leave `npm run dev` for the frontend and tell the
- user to run `npx convex dev` in a second terminal for the Convex watcher.
-
- See "Start the dev loop" above for why the agent should not run the watcher in
- the foreground.
-
- ### Wire up the provider
-
- The Convex client must wrap the app at the root. The setup varies by framework.
-
- Create the `ConvexReactClient` at module scope, not inside a component:
-
- ```tsx
- // Bad: re-creates the client on every render
- function App() {
- const convex = new ConvexReactClient(
- import.meta.env.VITE_CONVEX_URL as string,
- );
- return <ConvexProvider client={convex}>...</ConvexProvider>;
- }
-
- // Good: created once at module scope
- const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL as string);
- function App() {
- return <ConvexProvider client={convex}>...</ConvexProvider>;
- }
- ```
-
- #### React (Vite)
-
- ```tsx
- // src/main.tsx
- import { StrictMode } from "react";
- import { createRoot } from "react-dom/client";
- import { ConvexProvider, ConvexReactClient } from "convex/react";
- import App from "./App";
-
- const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL as string);
-
- createRoot(document.getElementById("root")!).render(
- <StrictMode>
- <ConvexProvider client={convex}>
- <App />
- </ConvexProvider>
- </StrictMode>,
- );
- ```
-
- #### Next.js (App Router)
-
- ```tsx
- // app/ConvexClientProvider.tsx
- "use client";
-
- import { ConvexProvider, ConvexReactClient } from "convex/react";
- import { ReactNode } from "react";
-
- const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);
-
- export function ConvexClientProvider({ children }: { children: ReactNode }) {
- return <ConvexProvider client={convex}>{children}</ConvexProvider>;
- }
- ```
-
- ```tsx
- // app/layout.tsx
- import { ConvexClientProvider } from "./ConvexClientProvider";
-
- export default function RootLayout({
- children,
- }: {
- children: React.ReactNode;
- }) {
- return (
- <html lang="en">
- <body>
- <ConvexClientProvider>{children}</ConvexClientProvider>
- </body>
- </html>
- );
- }
- ```
-
- #### Other frameworks
-
- For Vue, Svelte, React Native, TanStack Start, Remix, and others, follow the
- matching quickstart guide:
-
- - [Vue](https://docs.convex.dev/quickstart/vue)
- - [Svelte](https://docs.convex.dev/quickstart/svelte)
- - [React Native](https://docs.convex.dev/quickstart/react-native)
- - [TanStack Start](https://docs.convex.dev/quickstart/tanstack-start)
- - [Remix](https://docs.convex.dev/quickstart/remix)
- - [Node.js (no frontend)](https://docs.convex.dev/quickstart/nodejs)
-
- ### Environment variables
-
- The env var name depends on the framework:
-
- | Framework | Variable |
- | ------------ | ------------------------ |
- | Vite | `VITE_CONVEX_URL` |
- | Next.js | `NEXT_PUBLIC_CONVEX_URL` |
- | Remix | `CONVEX_URL` |
- | React Native | `EXPO_PUBLIC_CONVEX_URL` |
-
- `npx convex dev` writes the correct variable to `.env.local` automatically.
-
- ## Agent Mode
-
- `CONVEX_AGENT_MODE=anonymous` forces an unauthenticated local backend. It is
- already the implicit default for any non-TTY run of `npx convex init` or
- `npx convex dev`, but set it explicitly so the behavior does not depend on TTY
- detection:
-
- ```bash
- CONVEX_AGENT_MODE=anonymous npx convex dev --once
- ```
-
- Use it for:
-
- - Any AI coding agent (local or cloud).
- - CI-like setup scripts.
- - Cases where the user is logged in but you do not want to touch their personal
- dev deployment.
-
- The resulting backend runs on `127.0.0.1` and is not associated with any team or
- project until the user later claims it via `npx convex login` and the
- `npx convex deployment` commands.
-
- ## Verify the Setup
-
- After setup, confirm everything is working:
-
- 1. `npx convex dev --once` exited without errors (deployment provisioned, code
- pushed, schema validated, typecheck clean)
- 2. The `convex/_generated/` directory exists and has `api.ts` and `server.ts`
- 3. `.env.local` contains a `CONVEX_DEPLOYMENT` value and the framework's
- `*_CONVEX_URL` variable
- 4. (If applicable) `npm run dev` (or `npx convex dev` for the watcher alone) is
- running without errors in another terminal or in the background
-
- ## Writing Your First Function
-
- Once the project is set up, create a schema and a query to verify the full loop
- works.
-
- `convex/schema.ts`:
-
- ```ts
- import { defineSchema, defineTable } from "convex/server";
- import { v } from "convex/values";
-
- export default defineSchema({
- tasks: defineTable({
- text: v.string(),
- completed: v.boolean(),
- }),
- });
- ```
-
- `convex/tasks.ts`:
-
- ```ts
- import { query, mutation } from "./_generated/server";
- import { v } from "convex/values";
-
- export const list = query({
- args: {},
- handler: async (ctx) => {
- return await ctx.db.query("tasks").collect();
- },
- });
-
- export const create = mutation({
- args: { text: v.string() },
- handler: async (ctx, args) => {
- await ctx.db.insert("tasks", { text: args.text, completed: false });
- },
- });
- ```
-
- Use in a React component (adjust the import path based on your file location
- relative to `convex/`):
-
- ```tsx
- import { useQuery, useMutation } from "convex/react";
- import { api } from "../convex/_generated/api";
-
- function Tasks() {
- const tasks = useQuery(api.tasks.list);
- const create = useMutation(api.tasks.create);
-
- return (
- <div>
- <button onClick={() => create({ text: "New task" })}>Add</button>
- {tasks?.map((t) => (
- <div key={t._id}>{t.text}</div>
- ))}
- </div>
- );
- }
- ```
-
- ## Development vs Production
-
- Always use `npx convex dev` during development. It runs against your personal
- dev deployment and syncs code on save.
-
- When ready to ship, deploy to production:
-
- ```bash
- npx convex deploy
- ```
-
- This pushes to the production deployment, which is separate from dev. Do not use
- `deploy` during development.
-
- ## Next Steps
-
- - Add authentication: use the `convex-setup-auth` skill
- - Design your schema: see
- [Schema docs](https://docs.convex.dev/database/schemas)
- - Build components: use the `convex-create-component` skill
- - Plan a migration: use the `convex-migration-helper` skill
- - Add file storage: see
- [File Storage docs](https://docs.convex.dev/file-storage)
- - Set up cron jobs: see [Scheduling docs](https://docs.convex.dev/scheduling)
+ 1. Run recipe `quickstart-recipe@^2` with {idea, template} (the pack fetches + caches it; pinned offline fallback). It creates the project, installs deps, starts the backend (anonymous) and the web dev server.
+ 2. When it prints the dev URL, open it for the user.
+ 3. Present a short plan and CONFIRM before building features beyond the template.
- ## Checklist
+ ## Rules
- - [ ] Determined starting point: new project or existing app
- - [ ] If new project: scaffolded with `npm create convex@latest` using
- appropriate template
- - [ ] If existing app: installed `convex` and wired up the provider
- - [ ] Agent ran `npx convex dev --once`: deployment provisioned, code pushed,
- typecheck clean
- - [ ] `npm run dev` (or `npx convex dev` for the watcher alone) is running —
- user-launched terminal, or background for cloud agents
- - [ ] `convex/_generated/` directory exists with types
- - [ ] `.env.local` has the deployment URL
- - [ ] Verified a basic query/mutation round-trip works
+ - Never re-run the recipe if it already reported success.
+ - Delegate any code under `convex/` to the `convex-expert` capability.
+ - Don't add Postgres/Redis/Express — use Convex primitives.
+ - Don't add hosting/publish, the feedback panel, or passkeys here — offer `labs-quickstart` if the user wants the full experience.
+ - DEGRADATION RULE — if the served scaffold/bootstrap cannot run (non-interactive/one-shot session, no network, a sandboxed temp dir, or the user just wants code, not an app): skip the recipe and write a standard Convex project directly. ALL backend code goes under `convex/` (schema.ts, functions) — NEVER at the project root; Convex functions only run from the `convex/` directory. Write ZERO scaffold/documentation files (no START_HERE.md, ARCHITECTURE.md, MANIFEST.txt, README walls) unless explicitly asked. "Build me a backend" means code, not ceremony.
+ - Data access + imports — before writing any convex/*.ts: never an unbounded `.collect()` on a table that can grow — use `.withIndex(...)` and `.paginate(...)`/`.take(n)`. Use an index, not `.filter()`, for anything that would be a SQL WHERE. `.withIndex(...)` callbacks only have `eq`/`gt`/`gte`/`lt`/`lte` — there is no `.range(...)` method. Imports: `query`/`mutation`/`action`/`internalQuery`/`internalMutation`/`internalAction` come from `./_generated/server`; `api`/`internal` come from `./_generated/api`; NEVER import from `convex/server` in application code. `v.literal("exact value")` for fixed string/enum members, not a bare string. `"use node"` only at the top of action-only modules — never in a file that also exports a `query` or `mutation`. Never import a Node builtin (`crypto`/`fs`/`path`/`http`/`child_process`/`os`, with or without the `node:` prefix) into a file lacking `"use node"` — including `http.ts` route handlers; use Web Crypto (`crypto.subtle`) instead of `import`ing `crypto` where possible.
+ - Reserved names — never `export const <jsReservedWord> = ...` (e.g. `delete`, `new`, `class`, `function`, `return`) as a query/mutation/action export name; esbuild fails to parse it. Never a table or index name starting with `_` (e.g. `_migrations: defineTable(...)`) — `_` is reserved and errors at push as `TableNameReserved`/`IndexNameReserved`.
+ - HTTP routes — `httpRouter` has no Express-style `:param` segments (`path: "/users/:id"` only matches that literal string and is dead code); use `pathPrefix` and parse the trailing segment yourself. Every `http.route({...})` `handler:` must be wrapped in `httpAction(...)` from `./_generated/server` — a bare `async (ctx, request) => {...}` type-checks but isn't a valid HTTP action.
+ - `ctx.runQuery`/`ctx.runMutation`/`ctx.runAction` need a codegen'd function reference (`api.foo.bar`/`internal.foo.bar`), never a raw imported module member (`import * as queries from "./queries"; ctx.runQuery(queries.getX, ...)` compiles but fails at runtime).
+ - SELF-VERIFY RULE — before declaring backend work done, verify it compiles and pushes: run `npx tsc --noEmit` and, when a deployment is available (or via a local anonymous one: `CONVEX_AGENT_MODE=anonymous npx convex dev --once`), push it. Fix every error it reports before finishing — one verify round catches the wrong-relative-import / duplicate-symbol / unbalanced-paren class that otherwise breaks the deploy.