# Plugins

Extend Nextly with official and custom plugins that add collections, admin views, hooks, and API endpoints.

> **Parts of this page need the release after 0.0.2-alpha.66:** the typed, owner-checked `db` and `db.raw` (on 0.0.2-alpha.66 `db` is the Drizzle instance itself).

> **Alpha (`0.x`) — pin your versions.**
>
> The plugin SDK is alpha: its `@public` surface becomes semver-protected at 1.0 (see [API stability](https://nextlyhq.com/docs/plugins/stability.md)). Build against `@nextlyhq/plugin-sdk` — the stability boundary — and until then pin exact `nextly` / `@nextlyhq/plugin-sdk` versions.

Plugins extend Nextly with new functionality without modifying core code. A plugin can add collections, register lifecycle hooks, inject custom admin views, and transform configuration -- all through a single `plugins` array in your config.

## Official Plugins

| Plugin                                                            | Package                         | Description                                                                                                                                                                                         |
| ----------------------------------------------------------------- | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Form Builder](https://nextlyhq.com/docs/plugins/form-builder.md) | `@nextlyhq/plugin-form-builder` | Visual drag-and-drop form builder with submission management, email notifications, spam protection, and export                                                                                      |
| [Page Builder](https://nextlyhq.com/docs/page-builder.md)         | `@nextlyhq/plugin-page-builder` | Blocks your team arranges on a page, rendered on the server with no client JavaScript by default                                                                                                    |
| [SEO](https://nextlyhq.com/docs/plugins/seo.md)                   | `@nextlyhq/plugin-seo`          | An SEO field group on the collections you name, and a sitemap of published content over plain HTTP. Turning those fields into `<meta>` tags is `buildMetadata` from `nextly/runtime`, which is core |

## Community Plugins

Community plugins are distributed on npm — search the [`nextly-plugin`](https://www.npmjs.com/search?q=keywords:nextly-plugin) keyword. To get yours listed here, see [Contributing a plugin](https://nextlyhq.com/docs/plugins/contributing.md).

*No community plugins listed yet — be the first.*

## Adding a Plugin

Install the plugin package, then add it to your `defineConfig` call.

```typescript
// nextly.config.ts
import { defineConfig } from "nextly";
import { formBuilder } from "@nextlyhq/plugin-form-builder";

const fb = formBuilder();

export default defineConfig({
  plugins: [fb.plugin],
  collections: [Posts, Users, Media],
});
```

Plugin collections are merged automatically -- you do not need to spread them into the `collections` array yourself. The plugin's `config()` transformer handles this during initialization.

For simpler setups where you do not need to customize plugin options, use the pre-configured default instance:

```typescript
// nextly.config.ts
import { defineConfig } from "nextly";
import { formBuilderPlugin } from "@nextlyhq/plugin-form-builder";

export default defineConfig({
  plugins: [formBuilderPlugin],
  collections: [Posts, Users, Media],
});
```

## How Plugins Work

Every plugin implements the `PluginDefinition` interface from `@nextlyhq/plugin-sdk`, the stable import surface for plugin authors. The lifecycle has two phases:

### 1. Declarative + setup phase

Plugins declare schema, permissions, routes, and admin UI in `contributes` (read by the host without running the plugin). Before services start, Nextly also runs each plugin's optional `setup(config)` escape hatch — all `setup`s run before any `init`. It receives copies of the plain settings and the plugin definitions, without the database adapter, logger or any other live handle, and returns the config the boot continues with.

```typescript
import { definePlugin } from "@nextlyhq/plugin-sdk";

export const myPlugin = definePlugin({
  name: "@acme/nextly-plugin-example",
  version: "1.0.0",
  nextly: ">=0.0.2-alpha.66",
  contributes: {
    collections: [MyCollection], // merged automatically by the pipeline
  },
  setup(config) {
    return { ...config }; // escape hatch for advanced config transforms
  },
});
```

### 2. Initialization Phase

After all services are registered, Nextly calls each plugin's `init(ctx)` with a `PluginContext`. It provides:

* **`services`** -- managed, secure-by-default data access (`{ as: 'system' }` to elevate)
* **`db`** -- typed, owner-checked access to your plugin's tables and its dependencies' tables (unmanaged); `db.raw` is the Drizzle builder
* **`hooks`** / **`events`** / **`filters`** / **`actions`** -- in-transaction hooks, post-commit events, typed seams
* **`self`** -- your entities' resolved slugs after any host `.rename()`
* **`logger`**, **`config`**, **`nextlyVersion`**

```typescript
import { definePlugin } from "@nextlyhq/plugin-sdk";

export const auditPlugin = definePlugin({
  name: "audit-log",
  version: "1.0.0",
  nextly: ">=0.0.2-alpha.66",

  async init(ctx) {
    ctx.hooks.on("afterCreate", "*", async context => {
      ctx.logger.info("Created entry", {
        collection: context.collection,
        id: context.data?.id,
      });
    });
  },
});
```

See the **[Plugin Author Guide](https://nextlyhq.com/docs/plugins/author-guide.md)** for the full workflow.

## Plugin Admin Integration

Plugins can control where their collections appear in the admin sidebar and customize their visual appearance.

```typescript
import type { PluginDefinition } from "@nextlyhq/plugin-sdk";
import { MyCollection } from "./collections/my-collection";

const plugin: PluginDefinition = {
  name: "my-plugin",
  version: "0.1.0",
  nextly: ">=0.0.2-alpha.63",
  contributes: { collections: [MyCollection] },

  // Placement and appearance stay at the top level. This is complementary to
  // `contributes.admin`, which is the declarative menu, pages and views surface.
  admin: {
    order: 50,
    description: "What this plugin does",
    appearance: {
      icon: "BarChart",
      label: "Analytics",
      badge: "Beta",
      badgeVariant: "secondary",
    },
  },
};
```

Plugins can also register custom admin view components. The Form Builder plugin, for example, replaces the default collection edit view with a visual drag-and-drop builder. Components are referenced by path strings (e.g., `@nextlyhq/plugin-form-builder/admin#FormBuilderView`) and auto-registered when the admin panel loads.

## Overriding Plugin Behavior

Host applications can override a plugin's sidebar placement and appearance through the `admin.pluginOverrides` section of `defineConfig`:

```typescript
// nextly.config.ts
import { AdminPlacement } from "nextly";

export default defineConfig({
  plugins: [fb.plugin],
  admin: {
    pluginOverrides: {
      "@nextlyhq/plugin-form-builder": {
        placement: AdminPlacement.COLLECTIONS,
        order: 10,
        appearance: {
          label: "Contact Forms",
        },
      },
    },
  },
});
```

## Next Steps

**Build a plugin**

* [Plugin Author Guide](https://nextlyhq.com/docs/plugins/author-guide.md) -- the overview: lifecycle, `ctx`, and the scaffold → dev → test → publish loop
* [Lifecycle, dependencies & order](https://nextlyhq.com/docs/plugins/lifecycle.md) -- `setup`/`init`/`destroy`, load order, `dependsOn`, version compatibility, `enabled`
* [Data access](https://nextlyhq.com/docs/plugins/services.md) -- `ctx.services`, queries, bulk ops, `{ as: "system" }`
* [Permissions](https://nextlyhq.com/docs/plugins/permissions.md) -- declare-but-never-grant, route gating, `useCan`/`<Can>`
* [HTTP routes](https://nextlyhq.com/docs/plugins/routes.md) -- `contributes.routes`, secure-by-default, middleware
* [Admin UI](https://nextlyhq.com/docs/plugins/admin-ui.md) -- menu, pages, view overrides, placement
* [Schema & data lifecycle](https://nextlyhq.com/docs/plugins/schema.md) -- collections, `extend`, relations, provenance, uninstall
* [Testing](https://nextlyhq.com/docs/plugins/testing.md) -- `createTestNextly` + real-database tests

**Ship & maintain**

* [API stability](https://nextlyhq.com/docs/plugins/stability.md) -- what's `@public` vs `@experimental`, semver + deprecation policy
* [Publishing & distribution](https://nextlyhq.com/docs/plugins/distribution.md) -- publish, discovery, the trust model
* [Contributing a plugin](https://nextlyhq.com/docs/plugins/contributing.md) -- the quality checklist + how to get listed

**Reference**

* [Plugin API Reference](https://nextlyhq.com/docs/plugins/api-reference.md) -- the public `@nextlyhq/plugin-sdk` surface
* [Plugin Error Reference](https://nextlyhq.com/docs/plugins/error-reference.md) -- fail-fast boot errors and how to fix them
* [Configuration Reference](https://nextlyhq.com/docs/configuration/nextly-config.md) -- full `defineConfig` options including the `plugins` array
