BETTER-CONVEX

Plugins

Runtime plugins with scaffold-owned schema extensions and user-owned runtime files.

Plugins are first-class in kitcn. Install the runtime package, scaffold local files with kitcn add, then keep customizing those local files.

Runtime vs schema

First-party plugins are split on purpose:

  • Runtime package: middleware, helpers, and types
  • Local schema extension: convex/lib/plugins/<plugin>/schema.ts
  • Local runtime files: convex/functions/plugins/<plugin>.ts and convex/lib/plugins/<plugin>/...

Schema is app-owned and uses defineSchemaExtension(...):

import { defineSchemaExtension } from 'kitcn/orm';

export function myExtension() {
  return defineSchemaExtension('my-plugin', {}).relations(() => ({}));
}

Discovery model

defineSchema(...).extend(...) is the source of truth for installed schema capabilities:

import { defineSchema } from 'kitcn/orm';
import { resendExtension } from '../lib/plugins/resend/schema';

export default defineSchema(tables).extend(resendExtension());

Extension composition rules:

  • Extension relations(...) merge before app relations.
  • Extension triggers merge before app triggers.
  • Duplicate relation fields and trigger hooks throw.

Ownership model (shadcn-style)

  • Packages own stable runtime helpers.
  • The CLI owns scaffold templates.
  • Your app owns scaffolded schema and runtime files.
  • kitcn add <plugin> creates or refreshes local plugin files.
  • If paths.env is missing, kitcn add <plugin> also bootstraps convex/lib/get-env.ts and writes paths.env into concave.json.
  • kitcn diff <plugin> previews scaffold drift.
  • Installed plugin state is tracked in <functionsDir>/plugins.lock.json.

Codegen behavior:

  • Installed extension keys drive generated plugin typing.
  • Plugin runtime modules stay scaffold-owned.
  • Stale generated/plugins/** artifacts are removed automatically.

Available plugins

PluginWhat it gives you
ratelimitConvex-native rate limiting with middleware + React hook support
resendDurable queued email delivery, batching, webhook status ingestion, and cleanup APIs

Built-in internal extensions

These are always active and do not require explicit registration:

ExtensionPurpose
aggregateAggregate storage + runtime support
migrationMigration state + runtime support

Next steps

On this page