Skip to content
View as Markdown

Plugins (Beta) ​

Beta Feature: The plugin system is currently in beta. APIs may change in future releases.

Plugins extend TailorDB tables by automatically generating additional tables, executors, and output files based on your table definitions.

Overview ​

When you run tailor generate, the SDK:

  1. Loads all TailorDB tables with plugin attachments
  2. Passes each table to the attached plugins
  3. Generates additional tables and executors based on plugin output
  4. Writes all generated files to the appropriate locations

This enables plugins to create derived functionality based on your application's schema.

Configuration ​

Registering Plugins ​

Define plugins in tailor.config.ts using definePlugins():

typescript
import { defineConfig, definePlugins } from "@tailor-platform/sdk";
import myPlugin from "./plugins/my-plugin";

export const plugins = definePlugins(myPlugin);

export default defineConfig({
  name: "my-app",
  // ...
});

Important: definePlugins() must be assigned to a named export called exactly plugins (not default, and not any other name).

Attaching Plugins to Tables ​

Use the .plugin() method to attach plugins to specific tables:

typescript
import { db } from "@tailor-platform/sdk";

export const user = db
  .table("User", {
    name: db.string(),
    email: db.string(),
  })
  .plugin({
    "@example/my-plugin": {},
  });

Plugin Configuration ​

Some plugins accept per-table configuration:

typescript
export const customer = db
  .table("Customer", {
    name: db.string(),
    // ...
  })
  .plugin({
    "@example/soft-delete": {
      archiveReason: true,
      retentionDays: 90,
    },
  });

Per-table Config Requirement ​

Per-table config is optional by default. Plugin authors can change this with tableConfigRequired (boolean or function). When a function is used, it receives the plugin-level config from definePlugins().

Global Plugin Configuration ​

Plugins can also accept global configuration via definePlugins():

typescript
import { definePlugins } from "@tailor-platform/sdk";
import { softDeletePlugin } from "./plugins/soft-delete";

export const plugins = definePlugins(
  // Custom plugin with global config (factory function)
  softDeletePlugin({
    archiveTablePrefix: "Deleted_",
    defaultRetentionDays: 90,
  }),
);

Generated Output ​

Plugins can generate:

  • Tables: Additional TailorDB tables (e.g., CustomerHistory, Deleted_Customer)
  • Executors: Event handlers triggered by record changes
  • Field Extensions: Additional fields added to the source table
  • Output Files: TypeScript code and other files via generation-time hooks

Tables produced by definition-time hooks are validated before registration. This includes generated tables and source tables after field extensions are applied. Malformed output stops the build with an error that identifies the plugin and relevant table output, without partially registering tables from that processing step.

Generated files are placed under .tailor/<plugin-id>/ (the plugin ID is sanitized, e.g. @example/soft-delete → example-soft-delete), such as:

  • .tailor/example-soft-delete/types
  • .tailor/example-soft-delete/executors

Plugin Lifecycle ​

Plugins have definition-time, generation-time, and deploy-time hooks. The generation lifecycle is:

tailor generate
│
├─ Load TailorDB tables
│   ├─ onTableLoaded       ← per table with .plugin() attached
│   └─ onNamespaceLoaded   ← once per namespace (namespace plugins)
│
├─ Resolve Auth
│
├─ onTailorDBReady           ← all tables finalized
│
├─ Load Resolvers
│
├─ onResolverReady           ← all resolvers finalized
│
├─ Load Executors
│
└─ onExecutorReady           ← all executors finalized

Definition-time hooks ​

HookTriggerCan do
onTableLoadedEach table with .plugin() attachedGenerate tables, resolvers, executors; extend source table fields
onNamespaceLoadedOnce per namespaceGenerate tables, resolvers, executors

These hooks produce TailorDB tables, resolvers, and executors that become part of the application. Requires importPath on the plugin.

Generation-time hooks ​

HookAvailable dataCan do
onTailorDBReadyTailorDB tables, AuthWrite output files
onResolverReadyTailorDB tables, Resolvers, AuthWrite output files
onExecutorReadyTailorDB tables, Resolvers, Executors, AuthWrite output files

These hooks receive all finalized data and produce output files (TypeScript code, etc.). No importPath required.

Deploy-time hooks ​

tailor deploy
│
├─ Build and review resource changes
├─ Apply all applications and services
└─ onDeployed                ← each registered plugin, in config order
HookAvailable dataCan do
onDeployedDeployed application URLs, website URLs, public OAuth client IDsBuild assets and publish static websites

Deploy hooks run even when there are no resource changes. They do not run during tailor generate, dry-run, build-only, or migration test deployments. Dry-run lists which hooks would run. A deploy-only plugin needs neither importPath nor table attachments.

A plugin can implement hooks from any combination of phases.

Deploying Frontends ​

See Frontend Plugin to build frontends and upload them to static websites as part of tailor deploy.

Creating Custom Plugins ​

See Custom Plugins for the full hook reference and examples.