• Documentation
  • Pricing
© 2026 Serverless, Inc. All rights reserved.

Framework

  • Overview
  • Documentation
  • Plugins360
  • Pricing

Learn

  • Blog
  • GuidesUpdated
  • Examples240
  • Courses

Resources

  • Support
  • Security
  • Trust Center
  • Status

Community

  • Slack
  • GitHub47k
  • Forum
  • Meetups

Company

  • About
  • Careers
  • Contact
  • Partners

Legal

  • Terms of Service
  • Privacy Policy
  • Trademark
  • DMCA
Serverless Framework Logo

Serverless Framework

Intro
SetupUpgrading To V4ConceptsTutorialAWS CredentialsLicense Keys
DeployingPackagingBuildingTestingServicesFunctions
OverviewHTTP (API Gateway v2)REST (API Gateway v1)ActiveMQApplication Load BalancerAlexa SkillAlexa Smart HomeCloudWatch EventCloudWatch LogCloudFrontCognito User PoolEventBridge EventIoTIoT Fleet ProvisioningKafkaKinesis & DynamoDBMSKRabbitMQS3ScheduleSNSSQSWebsocket
LayersManaged InstancesAlertsVersion PruningDomainsIAM Function PermissionsParameters
OverviewSelf-reference serverless.ymlServerless CoreEnvironment VariablesCLI OptionsExternal YAML/JSON FilesJavascript propertiesGitDoppler
OverviewS3 ObjectsSSM Parameter Store & Secrets ManagerCloudFormation Stack Outputs
OverviewVaultTerraform State Output
ResourcesComposing ServicesDeployment BucketStatePython support
OverviewRuntimeGatewayMemoryBrowserCode InterpreterDev Mode
API Gateway Proxy
OverviewGeneral ConfigurationAuthenticationAPI KeysData SourcesResolversPipeline FunctionsCachingDelta SyncCustom DomainWAFCLI Commands
Deploying SAM/CFN TemplatesWorkflow Tips
OverviewCreating PluginsCLI OutputCustom CommandsCustom VariablesExtending the Configuration schemaExtending and overriding configuration
OverviewDashboardAxiom
Overviewdeploydeploy functiondeploy listdevdiffinfoinvokeinvoke localloginlogin awslogin aws ssologsmetricspackageplugin installplugin uninstallprintprunereconcileremoverollbackrollback functionsupportusage
Overview
OverviewMetricsTracesTroubleshoot
OverviewNode.jsPython
OutputsProviders
OverviewBranch DeploymentsPreview DeploymentsCustom ScriptsTestingPrivate PackagesNotificationsMono ReposDeploy in your own CI/CDBest PracticesTroubleshootingFAQ
OverviewSetupToolsAWS Integration
Serverless.yml Reference
Examples and TutorialsConfiguration Validation
  1. Usage
  2. Plugins
  3. Creating Plugins

Creating custom plugins

Creating a custom plugin lets you:

  • Hook into lifecycle events to add new logic
  • Define new CLI commands
  • Define new variable sources
  • Extend the serverless.yml syntax
  • Write extra information to the CLI output
  • Add support for new cloud providers

Creating a plugin

You can create a plugin by writing a simple JavaScript or TypeScript file:

JavaScript (CommonJS)

// my-plugin.js
class MyPlugin {
  constructor() {
    // The plugin is loaded
    console.log('MyPlugin loaded')
  }
}

module.exports = MyPlugin

JavaScript (ESM)

// my-plugin.js
export default class MyPlugin {
  constructor() {
    // The plugin is loaded
    console.log('MyPlugin loaded')
  }
}

Note: For JavaScript, we currently only support .js file extensions, so For ESM, you'll also need to add "type": "module" to your package.json file.

TypeScript

// my-plugin.ts
export default class MyPlugin {
  constructor() {
    // The plugin is loaded
    console.log('MyPlugin loaded')
  }
}

The plugin can then be loaded in serverless.yml via a local path without the extension:

# serverless.yml
service: app

functions:
  # ...

plugins:
  - ./my-plugin

Prioritizing Build Plugins

If your plugin builds code that other plugins might depend on, you can tag your plugin as a build plugin with the optional tags static property. This ensures that it runs first before other non-build plugins that may depend on it.

class MyPlugin {
  static tags = ['build']

  constructor() {}
}

module.exports = MyPlugin

If your plugin doesn't build code, and/or doesn't need to be prioritized, don't set this tag. Otherwise users won't be able to use other build plugins along with your plugin.

Note: The build tag is the only tag we currently support.

Distributing a plugin via NPM

Plugins can also be published to NPM and later installed in separate projects.

To correctly configure the plugin's NPM package, set the main property to point to your plugin file in package.json:

{
  "main": "my-plugin.js"
}

It is also a good practice to add serverless to the peerDependencies section. That ensures that your plugin runs only with the Serverless Framework versions it supports.

{
  ...
  "peerDependencies": {
    "serverless": ">=2.60"
  }
}

Once the plugin is published on NPM, follow the documentation on Installing plugins to use the custom plugin.

Lifecycle events

Lifecycle events are events that fire sequentially during a CLI command.

Additionally, for each event an additional before and after event is created. For example:

  • before:package:package
  • package:package
  • after:package:package
  • before:deploy:deploy
  • deploy:deploy
  • after:deploy:deploy

The initialize event is shared across all CLI commands and runs when the CLI starts.

Plugins can "hook" into existing lifecycle events to add behavior to commands like deploy, package, etc. via the hooks helper:

class MyPlugin {
  constructor() {
    this.hooks = {
      initialize: () => this.init(),
      'before:deploy:deploy': () => this.beforeDeploy(),
      'after:deploy:deploy': () => this.afterDeploy(),
    }
  }

  init() {
    // Initialization
  }

  beforeDeploy() {
    // Before deploy
  }

  afterDeploy() {
    // After deploy
  }
}

module.exports = MyPlugin

Plugins can also create their own commands (with their own lifecycle events): read the Custom commands documentation.

Serverless instance

The serverless parameter provides access to the service configuration at runtime:

class MyPlugin {
  constructor(serverless, options, utils) {
    this.serverless = serverless
    this.options = options // CLI options
    this.utils = utils

    this.hooks = {
      initialize: () => this.init(),
    }
  }

  init() {
    // Use this custom logging method instead of console.log
    // to avoid conflicting with the spinner output
    this.utils.log('Serverless instance: ', this.serverless)

    // `serverless.service` contains the (resolved) serverless.yml config
    const service = this.serverless.service

    this.utils.log('Provider name: ', service.provider.name)
    this.utils.log('Functions: ', service.functions)
  }
}

module.exports = MyPlugin

Note: configuration values are only resolved after plugins are initialized. Do not try to read configuration in the plugin constructor, as variables aren't resolved yet. Read configuration in lifecycle events only.

CLI options

The options parameter provides access to the CLI options provided to the command:

class MyPlugin {
  constructor(serverless, options) {
    // Log if a --verbose option was passed:
    console.log(options.verbose)
  }
}

Provider-specific plugins

Plugins can be provider specific, which means that run only with a specific provider.

Note: Binding a plugin to a provider is optional. Serverless will always consider your plugin if you don't specify a provider.

To bind to a specific provider, retrieve it and set the this.provider property in the plugin constructor:

class MyPlugin {
  constructor(serverless, options) {
    // bind to a specific provider
    this.provider = serverless.getProvider('providerX')

    // ...
  }
}

The plugin will now only be executed when the service's provider matches the given provider.

Edit this page
Prev OverviewNextCLI Output

Contents

  • Creating custom plugins
  • Creating a plugin
  • JavaScript (CommonJS)
  • JavaScript (ESM)
  • TypeScript
  • Prioritizing Build Plugins
  • Distributing a plugin via NPM
  • Lifecycle events
  • Serverless instance
  • CLI options
  • Provider-specific plugins

Related

GuidesPluginsExamplesSlack CommunitySupport