BETTER-CONVEX

CLI

Backend

Drive Convex or Concave, verify local runtime, generate files, deploy, migrate, reset, and analyze.

dev

npx kitcn dev

Options:

FlagDescription
--api <dir>Output directory for api.ts (default: convex/shared)
--backend <convex|concave>Backend CLI to drive
--bootstrapRun one-shot local Convex bootstrap and exit
--config <path>Path to kitcn config file (default: ./concave.json)
--backfill=auto|on|offDev aggregate backfill mode toggle (default: auto)
--backfill-wait / --no-backfill-waitWait for all target indexes to become READY
--backfill-batch-size <n>Batch size for aggregate backfill kickoff
--migrations=auto|on|offDev migration mode toggle (default: auto)
--migrations-wait / --no-migrations-waitWait for migration run completion
--migrations-allow-drift / --no-migrations-allow-driftOverride drift policy in dev

Wraps the selected backend dev command, generates runtime files on startup, watches for changes, and passes all other flags through.

On backend convex, kitcn dev runs convex init before codegen, watchers, and the main convex dev process.

Set meta["kitcn"].dev.preRun in concave.json to run one Convex setup function inside the main dev loop. It is Convex-only; backend concave has no equivalent --run flow.

dev.preRun maps to Convex's native convex dev --run <function> flow with the same deployment-target args as the main dev command.

Local backend state depends on the selected backend:

  • Convex: .convex/ at project root
  • Concave Bun/Node: .concave/local/

kitcn dev always runs full cRPC generation by default. Use kitcn codegen --scope ... for one-off scoped generation.

When aggregate backfill is enabled, kitcn dev kicks off aggregateBackfill and waits for READY by default (in background). When convex/functions/schema.ts changes, kitcn dev re-runs resume backfill automatically only if aggregate index signatures changed.

# One-shot local Convex bootstrap
npx kitcn dev --bootstrap

verify

npx kitcn verify

Runs a one-shot local Convex runtime proof through the kitcn dev path.

Use it when you want a CI-safe answer to one question: does local kitcn dev boot cleanly right now?

kitcn verify:

  • runs the runtime path through dev --once
  • reuses the current local Convex deployment when one is already configured
  • falls back to local anonymous setup for fresh non-interactive Convex verify

codegen

Generate api.ts once against the selected backend connection:

npx kitcn codegen

Options:

FlagDescription
--api <dir>Output directory (default: convex/shared)
--backend <convex|concave>Backend CLI to drive
--scope <all|auth|orm>Generation scope (default: all)
--config <path>Path to kitcn config file (default: ./concave.json)
--debugShow detailed output
--silentSuppress all output

See Scope Modes for the full output manifest per scope.

Plugin note:

  • kitcn codegen discovers plugins from schema extensions and local plugin scaffold registration.
  • Plugin discovery is used for typing/runtime context only.
  • codegen does not generate plugin runtime modules. Plugin runtime files are scaffold-owned.

env

Manage environment variables:

# Push all vars from convex/.env
npx kitcn env push

# Force overwrite existing values
npx kitcn env push --force

# Production deployment
npx kitcn env push --prod

# Rotate auth keys, then push fresh JWKS
npx kitcn env push --rotate

# Pull remote values to stdout
npx kitcn env pull

# Write remote values to a file
npx kitcn env pull --out convex/.env.remote

Push options:

FlagDescription
--rotateRotate auth keys before fetching fresh JWKS
--forceOverwrite existing values (default: skip if up to date)
--from-file <path>Push values from a file instead of convex/.env

Pull options:

FlagDescription
--out <path>Write pulled values to a file instead of stdout

Target options:

FlagDescription
--prodTarget the production deployment
--deployment-name <name>Target a named deployment
--preview-name <name>Target a named preview deployment
--env-file <path>Use an env file to resolve the target deployment

kitcn env push reads convex/.env by default, filters Convex-managed variables, then pushes one batch update through convex env set --from-file. If auth scaffold is installed, it also ensures BETTER_AUTH_SECRET exists locally, fetches JWKS with convex run generated/auth:getLatestJwks, and includes both in the push payload. With --rotate, it runs convex run generated/auth:rotateKeys first, then pushes the fresh JWKS.

On backend convex, kitcn dev handles the local auth bootstrap flow and watches convex/.env for later local edits. kitcn dev --bootstrap is the one-shot local setup version of that flow. kitcn verify is the one-shot local runtime proof. kitcn add auth --yes reuses the same local bootstrap path when it needs generated auth runtime and JWKS. Use kitcn env push for --prod, --rotate, or explicit repair against an already active deployment.

If --from-file is omitted and stdin is piped, kitcn env push reads the piped payload instead of convex/.env.

kitcn env pull wraps convex env list and preserves the exact payload format, so you can print it or write it to disk unchanged.

All env commands forward Convex deployment-target args such as --prod, --deployment-name, --preview-name, and --env-file.

Other env commands stay aligned with Convex:

npx kitcn env list
npx kitcn env get <name>
npx kitcn env set <name> <value>
npx kitcn env remove <name>

kitcn env set keeps Convex 1.33 behavior for interactive values, --from-file, and stdin input. kitcn env pull gives you the same robust export format, so env pull --out <path> and env set --from-file <path> round-trip cleanly.

On backend concave, kitcn env ... fails clearly because Concave has no upstream env command.

Unknown commands on backend convex pass straight through to the Convex CLI, so kitcn insights opens the same insights surface as convex insights.

deploy

npx kitcn deploy --prod

kitcn deploy runs:

  1. selected backend deploy ...
  2. post-deploy generated/server:migrationRun (direction: "up")
  3. status polling (generated/server:migrationStatus) until completion (default behavior)
  4. post-deploy generated/server:aggregateBackfill
  5. aggregate status polling (generated/server:aggregateBackfillStatus) until READY (default behavior)

Options:

FlagDescription
--backfill=auto|on|offEnable/disable post-deploy aggregate backfill
--backfill-wait / --no-backfill-waitWait for all target indexes to become READY
--backfill-batch-size <n>Batch size for backfill jobs
--backfill-poll-ms <n>Poll interval while waiting
--backfill-timeout-ms <n>Max wait duration before timeout
--backfill-strict / --no-backfill-strictFail deploy on timeout/backfill error
--migrations=auto|on|offEnable/disable post-deploy migrate up
--migrations-wait / --no-migrations-waitWait for migration completion
--migrations-batch-size <n>Batch size for migration workers
--migrations-poll-ms <n>Poll interval while waiting for migration completion
--migrations-timeout-ms <n>Max migration wait duration before timeout
--migrations-strict / --no-migrations-strictFail deploy on migration timeout/error
--migrations-allow-drift / --no-migrations-allow-driftOverride drift blocking policy

Already-READY indexes are skipped (noop). See Resume Compatibility for full behavior rules.

aggregate rebuild

npx kitcn aggregate rebuild --prod

Runs generated/server:aggregateBackfill in rebuild mode (clear + recompute) for the selected deployment, then waits for READY by default.

aggregate backfill

npx kitcn aggregate backfill --prod

Runs generated/server:aggregateBackfill in resume mode (no clear/rebuild) for the selected deployment, then waits for READY by default.

aggregate prune

npx kitcn aggregate prune --prod

Runs generated/server:aggregateBackfill in prune mode to delete storage/state for aggregate indexes no longer declared in schema.

migrate create

npx kitcn migrate create backfill_user_status

Creates a timestamped migration file under convex/functions/migrations/ and regenerates convex/functions/migrations/manifest.ts.

migrate up

npx kitcn migrate up --prod

Runs generated/server:migrationRun with direction: "up" and waits by default.

migrate down

# Roll back the latest migration
npx kitcn migrate down --steps 1 --prod

# Roll back everything after a target migration id
npx kitcn migrate down --to 20260227_000000_backfill_user_ban_reason --prod

Runs generated/server:migrationRun with direction: "down" in reverse applied order.

migrate status

npx kitcn migrate status --prod

Reads migration run/state internals from generated/server:migrationStatus.

migrate cancel

npx kitcn migrate cancel --prod

Cancels the active migration run (generated/server:migrationCancel).

reset

Wipe all table data in one step. Useful for dev resets and seeding workflows.

npx kitcn reset --yes

The --yes flag is required — reset is destructive. Under the hood it calls generated/server:reset (which uses ctx.orm.withoutTriggers to clear every table, including internal aggregate and migration state tables).

You can run custom functions before and after the reset:

# Seed data after reset
npx kitcn reset --yes --after generated/seed:seedAll

# Snapshot before, seed after
npx kitcn reset --yes --before generated/seed:snapshot --after generated/seed:seedAll

Options:

FlagDescription
--yesRequired. Confirm destructive reset
--before <fn>Run a Convex function before reset
--after <fn>Run a Convex function after reset

analyze

Analyze Convex runtime bundle size and dependency hotspots:

# Function-oriented hotspot ranking (default)
npx kitcn analyze

# Deploy-accurate bundle view
npx kitcn analyze --deploy

# Deep drilldown for one entry
npx kitcn analyze '^convex/functions/auth\\.ts$' --details

Options:

FlagDescription
--deployDeploy-accurate isolate bundle analysis
--detailsShow expanded per-entry package graph details
--inputInclude top internal inputs in expanded details
--interactive, -iEnable interactive hotspot UI (default: off, TTY only)
--all, -aInclude Convex-ignored entries (multi-dot files and generated/ modules)
--show-smallInclude tiny dependencies (hidden by default)
--warn-mb <n>WARN threshold in MB (default: 6)
--danger-mb <n>DANGER threshold in MB (default: 8)
--fail-mb <n>Exit with code 1 if largest output meets threshold
--width <n>Force terminal output width

See Mode Behavior for the full 12-item behavior reference.

Output

The CLI generates convex/shared/api.ts. Do not create this file manually — it is fully generated by kitcn dev / kitcn codegen.

The CLI extracts metadata from procedure exports automatically. See Metadata Extraction for supported patterns and base procedure mapping.

Configuration

kitcn supports a project config at ./concave.json (or pass --config <path>). It reads settings from meta["kitcn"].

The CLI reads from convex.json:

convex.json
{
  "functions": "convex"
}

The functions field specifies the Convex functions directory (default: convex).

Path Aliases

Add a path alias to import @convex/api:

tsconfig.json
{
  "compilerOptions": {
    "paths": {
      "@convex/*": ["./convex/shared/*"]
    }
  }
}

Then import:

import { api } from '@convex/api';

Next Steps


API Reference

Scope Modes

Scope modes apply to kitcn codegen.

ScopeGenerated outputs
all (default)convex/shared/api.ts, <functionsDir>/generated/server.ts, <functionsDir>/generated/auth.ts, runtime files
auth<functionsDir>/generated/server.ts, <functionsDir>/generated/auth.ts, <functionsDir>/generated/auth.runtime.ts (when <functionsDir>/auth.ts has a default export)
orm<functionsDir>/generated/server.ts, runtime files for ORM internals

In scoped modes, stale artifacts outside the current scope are removed automatically (for example convex/shared/api.ts and cRPC runtime modules in auth/orm mode).

Resume Compatibility

  • key shape changes (aggregateIndex(...).on(...) fields / .all() key shape) require rebuild; deploy exits in strict mode and instructs kitcn aggregate rebuild
  • metric additions (.count/.sum/.avg/.min/.max) are backfilled automatically
  • metric removals are metadata-only updates (no clear/rebuild)
  • removed aggregate indexes are pruned automatically (state + bucket/member/extrema rows)

Mode Behavior

  1. Default mode (kitcn analyze) ranks least optimized Convex function modules by output size and dependency weight.
  2. --deploy mirrors deploy shape by bundling the same selected entry set together with shared chunks.
  3. Convex-ignored entries with detected handlers are included by default in both modes. Add --all to include every ignored entry (including ones without detected handlers).
  4. --details adds a package graph view (size + top cross-package imports). Add --input to include the top internal inputs table.
  5. Filter to specific entries by passing a positional regex: kitcn analyze polar.* or kitcn analyze '^convex/functions/polar.*\\.ts$'.
  6. Hotspot output is agent-first: it prints an Agent queue with ready-to-run optimization commands.
  7. Use --interactive to open the keyboard-driven hotspot UI (--interactive is hotspot-only and rejected with --deploy).
  8. Ranking includes only modules with detected handler exports (cRPC _crpcMeta scan, plus native Convex handler exports).
  9. Interactive mode uses split panes by default (entry list left, detail preview right, key/status bar bottom).
  10. Right pane always follows the current selection (no pin mode).
  11. On narrow terminals (<120 columns), interactive mode falls back to stacked layout (list first, details second, key/status last).
  12. Interactive controls: j/k move, ←/→ pane cycle, / filter, s sort cycle, g all-toggle, r refresh, w watch toggle, q quit, ? help.

Metadata Extraction

Supported Patterns

// Base procedure auth is detected
export const list = publicQuery.query(...);           // auth: undefined
export const me = authQuery.query(...);               // auth: 'required'
export const profile = optionalAuthQuery.query(...);  // auth: 'optional'

// Function type is detected
export const get = publicQuery.query(...);      // type: 'query'
export const create = publicMutation.mutation(...);  // type: 'mutation'
export const sync = publicAction.action(...);   // type: 'action'

// .meta() is extracted
export const admin = authQuery
  .meta({ role: 'admin' })
  .query(...);  // { auth: 'required', role: 'admin', type: 'query' }

Base Procedure Mapping

Base ProcedureAuth Type
publicQueryundefined
publicMutationundefined
publicActionundefined
optionalAuthQuery'optional'
optionalAuthMutation'optional'
authQuery'required'
authMutation'required'
authAction'required'

Configuration Reference

kitcn supports a project config at ./concave.json (or --config <path>):

concave.json
{
  "meta": {
    "kitcn": {
      "paths": {
        "lib": "convex/lib",
        "shared": "convex/shared"
      },
      "dev": {
        "debug": false,
        "args": [],
        "preRun": "init",
        "aggregateBackfill": {
          "enabled": "auto",
          "wait": true,
          "batchSize": 1000,
          "pollIntervalMs": 1000,
          "timeoutMs": 900000,
          "strict": false
        },
        "migrations": {
          "enabled": "auto",
          "wait": true,
          "batchSize": 256,
          "pollIntervalMs": 1000,
          "timeoutMs": 900000,
          "strict": false,
          "allowDrift": true
        }
      },
      "codegen": {
        "debug": false,
        "scope": "all",
        "args": []
      },
      "deploy": {
        "args": [],
        "aggregateBackfill": {
          "enabled": "auto",
          "wait": true,
          "batchSize": 1000,
          "pollIntervalMs": 1000,
          "timeoutMs": 900000,
          "strict": true
        },
        "migrations": {
          "enabled": "auto",
          "wait": true,
          "batchSize": 256,
          "pollIntervalMs": 1000,
          "timeoutMs": 900000,
          "strict": true,
          "allowDrift": false
        }
      }
    }
  }
}

Precedence:

  1. CLI flags override config values.
  2. Config dev.args / codegen.args / deploy.args are prepended to CLI passthrough args.
  3. If codegen.scope is missing, it defaults to all.
  4. Plugin lockfile path is fixed at <functionsDir>/plugins.lock.json.

If no config file is found, defaults are used silently. If only kitcn.json exists, the CLI exits with a legacy-config error. If --config points to a missing file, the CLI exits with an error.

On this page