Plugins
Extend Nextly with official and custom plugins that add collections, admin views, hooks, and API endpoints.
Alpha (
0.x) — pin your versions.The plugin API surface is now stable and semver-protected (see API stability); the packages themselves are still
0.xalpha. Build against@nextlyhq/plugin-sdk— the stability boundary — and pin yournextly/@nextlyhq/plugin-sdkversions.
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 | @nextlyhq/plugin-form-builder | Visual drag-and-drop form builder with submission management, email notifications, spam protection, and export |
| Page Builder | @nextlyhq/plugin-page-builder | Blocks your team arranges on a page, rendered on the server with no client JavaScript by default |
| SEO | @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 keyword. To get yours listed here, see Contributing a plugin.
No community plugins listed yet — be the first.
Adding a Plugin
Install the plugin package, then add it to your defineConfig call.
// 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:
// 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 setups run before any init. Don't mutate the config; spread and return a new object.
import { definePlugin } from "@nextlyhq/plugin-sdk";
export const myPlugin = definePlugin({
name: "@acme/nextly-plugin-example",
version: "1.0.0",
nextly: "^1.0.0",
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-- raw Drizzle escape hatch (unmanaged)hooks/events/filters/actions-- in-transaction hooks, post-commit events, typed seamsself-- your entities' resolved slugs after any host.rename()logger,config,nextlyVersion
import { definePlugin } from "@nextlyhq/plugin-sdk";
export const auditPlugin = definePlugin({
name: "audit-log",
version: "1.0.0",
nextly: "^1.0.0",
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 for the full workflow.
Plugin Admin Integration
Plugins can control where their collections appear in the admin sidebar and customize their visual appearance.
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:
// 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 -- the overview: lifecycle,
ctx, and the scaffold → dev → test → publish loop - Lifecycle, dependencies & order --
setup/init/destroy, load order,dependsOn, version compatibility,enabled - Data access --
ctx.services, queries, bulk ops,{ as: "system" } - Permissions -- declare-but-never-grant, route gating,
useCan/<Can> - HTTP routes --
contributes.routes, secure-by-default, middleware - Admin UI -- menu, pages, view overrides, placement
- Schema & data lifecycle -- collections,
extend, relations, provenance, uninstall - Testing --
createTestNextly+ real-database tests
Ship & maintain
- API stability -- what's
@publicvs@experimental, semver + deprecation policy - Publishing & distribution -- publish, discovery, the trust model
- Contributing a plugin -- the quality checklist + how to get listed
Reference
- Plugin API Reference -- the public
@nextlyhq/plugin-sdksurface - Plugin Error Reference -- fail-fast boot errors and how to fix them
- Configuration Reference -- full
defineConfigoptions including thepluginsarray
Routing and SEO
Turn content into pages with correct metadata, sitemap, and robots. The nextly/runtime helpers resolve a slug to a published, access-enforced entry, build a Next.js Metadata object from an seo field group, and deliver sitemap.xml and robots.txt.
Plugin Author Guide
Build a Nextly plugin — the lifecycle, the plugin context, and the scaffold → dev → test → publish loop.