You're reading docs for Nextly Alpha. APIs may change between releases.

Plugins

Plugins

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

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

PluginPackageDescription
Form Builder@nextlyhq/plugin-form-builderVisual drag-and-drop form builder with submission management, email notifications, spam protection, and export

Adding a Plugin

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

// nextly.config.ts
import { defineConfig } from '@nextlyhq/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 '@nextlyhq/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/nextly. The lifecycle has two phases:

1. Configuration Phase

Before services start, Nextly calls each plugin's optional config() function. This lets plugins inject collections, modify settings, or add fields to existing collections.

const plugin: PluginDefinition = {
  name: 'my-plugin',
  version: '1.0.0',
  collections: [MyCollection],

  config(config) {
    // Merge plugin collections with user collections
    return {
      ...config,
      collections: [...(config.collections || []), ...myCollections],
    };
  },
};

2. Initialization Phase

After all services are registered, Nextly calls each plugin's init() function with a PluginContext. This context provides access to:

  • services -- Collection CRUD, user management, media handling, and email sending
  • infra -- Direct database access and logger
  • config -- Read-only Nextly configuration
  • hooks -- Hook registration for lifecycle events
import { definePlugin } from '@nextlyhq/nextly';

export const auditPlugin = definePlugin({
  name: 'audit-log',
  version: '1.0.0',

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

Plugin Admin Integration

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

const plugin: PluginDefinition = {
  name: 'my-plugin',
  collections: [MyCollection],

  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
export default defineConfig({
  plugins: [fb.plugin],
  admin: {
    pluginOverrides: {
      '@nextlyhq/plugin-form-builder': {
        placement: AdminPlacement.COLLECTIONS,
        order: 10,
        appearance: {
          label: 'Contact Forms',
        },
      },
    },
  },
});

Next Steps