@interlace/serverless

Plugin Development

Build Serverless Framework plugins with @interlace/serverless-devkit.

Overview

@interlace/serverless-devkit provides all the types you need to build a Serverless Framework plugin with full TypeScript support.

Scaffold

mkdir my-serverless-plugin
cd my-serverless-plugin
npm init -y
npm install @interlace/serverless-devkit

Plugin Structure

src/index.ts
import type {
  ServerlessInstance,
  ServerlessOptions,
  ServerlessPlugin,
  ServerlessHooks,
  ServerlessCommands,
  AwsProvider,
} from '@interlace/serverless-devkit';

class MyPlugin implements ServerlessPlugin {
  public hooks: ServerlessHooks;
  public commands: ServerlessCommands;

  private serverless: ServerlessInstance;
  private provider: AwsProvider;

  constructor(serverless: ServerlessInstance, options: ServerlessOptions) {
    this.serverless = serverless;
    this.provider = serverless.providers.aws;

    this.commands = {
      'my-command': {
        usage: 'Description of my command',
        lifecycleEvents: ['run'],
        options: {
          stage: {
            usage: 'Stage to run against',
            shortcut: 's',
            type: 'string',
          },
        },
      },
    };

    this.hooks = {
      'before:package:finalize': this.onPackageFinalize.bind(this),
      'after:deploy:deploy': this.onDeploy.bind(this),
      'my-command:run': this.onMyCommand.bind(this),
    };
  }

  private async onPackageFinalize(): Promise<void> {
    // Modify CloudFormation template before packaging
    const template =
      this.serverless.service.provider.compiledCloudFormationTemplate;
    // ...
  }

  private async onDeploy(): Promise<void> {
    // Run after deployment completes
    const stage = this.provider.getStage();
    this.serverless.cli.log(`Deployed to ${stage}`);
  }

  private async onMyCommand(): Promise<void> {
    // Custom CLI command handler
  }
}

export default MyPlugin;

Lifecycle Hooks

Common hooks for plugin development:

HookWhen
before:package:initializeBefore packaging starts
before:package:finalizeAfter CF template is compiled
after:deploy:deployAfter deployment completes
before:remove:removeBefore stack removal

Making AWS API Calls

Use the provider's request method:

const response = await this.provider.request(
  'APIGateway',
  'getStage',
  {
    restApiId: 'abc123',
    stageName: 'dev',
  },
);

Config Validation

Register a JSON schema for your plugin's config:

const handler = this.serverless.configSchemaHandler;
if (handler?.defineCustomProperties) {
  handler.defineCustomProperties({
    type: 'object',
    properties: {
      myPluginConfig: {
        type: 'object',
        properties: {
          enabled: { type: 'boolean' },
          timeout: { type: 'number', minimum: 0 },
        },
      },
    },
  });
}

On this page