Skip to content

Instantly share code, notes, and snippets.

@HyperBrain
Last active March 20, 2024 00:17
Show Gist options
  • Save HyperBrain/50d38027a8f57778d5b0f135d80ea406 to your computer and use it in GitHub Desktop.
Save HyperBrain/50d38027a8f57778d5b0f135d80ea406 to your computer and use it in GitHub Desktop.
Serverless Lifecycle Cheat Sheet

Serverless plugin author's cheat sheet

This cheat sheet provides a detailed overview of the exposed lifecycle events and available commands (and entrypoints) of the Serverless framework, that can be hooked by plugins (internal and external ones). The document is structured by the commands invoked by the user.

Lifecycle events are shown as the globally available outer events (all providers) and sub lifecycle events that are provider specific in the called order. Currently only the AWS provider is shown. If you have information about the other provider, please let me know and I will add the sub lifecycles accordingly.

The current event system can be improved in the future. Only package, deploy and info provide detailed event lifecycles for now, that make the plugin integration much more fine-grained.

Plugins can spawn any command or entrypoint with this.serverless.pluginManager.spawn() and invoke a sub lifecycle.

Lifecycle events / commands

package

package:cleanup

-> aws:common:validate:validate
-> aws:common:cleanupTempDir:cleanup

package:initialize

package:setupProviderConfiguration

package:createDeploymentArtifacts

package:compileFunctions

package:compileEvents

package:finalize

-> aws:package:finalize:mergeCustomProviderResources
-> aws:package:finalize:saveServiceState
-> aws:common:moveArtifactsToPackage:move

deploy

before:deploy:deploy

-> aws:common:validate:validate
-> aws:common:moveArtifactsToTemp:move

deploy:deploy

-> aws:deploy:deploy:createStack
-> aws:deploy:deploy:checkForChanges (1.17->)
-> aws:deploy:deploy:uploadArtifacts
-> aws:deploy:deploy:validateTemplate
-> aws:deploy:deploy:updateStack

deploy:finalize

-> aws:deploy:finalize:cleanup

deploy function

deploy:function:initialize

deploy:function:packageFunction

-> package:function:package

deploy:function:deploy

-> aws:common:cleanupTempDir:cleanup

deploy list

deploy:list:log

info

info:info

-> aws:info:validate
-> aws:info:gatherData
-> aws:info:displayServiceInfo
-> aws:info:displayApiKeys
-> aws:info:displayEndpoints
-> aws:info:displayFunctions
-> aws:info:displayStackOutputs

remove

remove:remove

rollback

rollback:initialize

rollback:rollback

rollback function

rollback:function:rollback

logs

logs:logs

invoke

invoke:invoke

invoke local

invoke:local:loadEnvVars

invoke:local:invoke

create

create:create

config

config:credentials:config

install

install:install

login

login:login

logout

logout:logout

metrics

metrics:metrics

slstats

slstats:slstats

@iDVB
Copy link

iDVB commented Dec 4, 2017

Anyone know the order plugins execute when they share the same hook? It doesn’t seem to be based on the order in the serverless.yml file.

I have a plugin set to after:deploy:finalize and its still running before another plugin. (I want it after)

@HyperBrain
Copy link
Author

@iDVB The order should definitely be set by the order in which the plugins appear in the serverless.yml. Internally the hooks are stored in an array and when the serverless.yml:plugins array is evaluated in order the hooks are pushed into the hooks array.
In general, that means, that the system plugins are executed first and then the 3rd party plugin in order.

@HyperBrain
Copy link
Author

HyperBrain commented Dec 11, 2017

Regarding the after:deploy:finalize you have to be careful: For AWS, it spawns a sublifecycle (aws:deploy:...). If another plugin hooks some after:aws:deploy:finalize:cleanup it will naturally be called before your hook, because the after:deploy:finalize event is the very last event in the whole outer lifecycle. If your plugin is AWS only, you should hook into the more fine-grained sublifecycle instead.

@tommedema
Copy link

tommedema commented Dec 11, 2017

The cheat sheet is very useful, thanks!

My major concern is to what extent we are supposed to fiddle with serverless internals. I.e. when is something good / bad practice when done with plugins.

For example, take this practical case: I have created a custom resource that requests ACM certificates. This works fine. However, cloudfront only accepts ACM certificates that have been fully validated (i.e. issued). This means that you can only pass such certificate to cloudfront after it has been validated. Unfortunately, you cannot have a custom resource wait until validation has passed due to the 5 minute timeout of Lambda. The only solution seems to be to create a cloudformation condition like so:

resources:
  Conditions:
    # true when requested SSL certificate can be consumed (is valid)
    # this is automatically determined and substituted during build
    ShouldConsumeCertificate:
      Fn::Equals: ['%SCRIPT_SUBSTITUTE_CERTIFICATE_IS_VALID%', 'true']

And then have cloudfront only consume the certificate if it is indeed said to be valid:

...
          ViewerCertificate:
            Fn::If:
              - ShouldConsumeCertificate
              - 
                AcmCertificateArn:
                  Fn::GetAtt: [CertificateResource, acmArn]
                SslSupportMethod: sni-only
              - CloudFrontDefaultCertificate: true

Now, something has to substitute this string for it to equal true or false, depending on whether the certificate is ready to be consumed by cloudfront. I created a plugin that does this. This plugin is then run before the package:createDeploymentArtifacts event. But are these expected practices? Or are there cleaner way to do these sort of things? I think it would be great to add some guidelines in terms of "dos" and "donts" to the developer documentation.

@HyperBrain
Copy link
Author

@tommedema. thanks for the question. In general, the package lifecycle is executed on a build server and the deploy lifecycle on a deployment server in a CI/CD system. So my advise here is, that plugins that are invoked somewhere during the package lifecycle should not access external resources (like the AWS REST API) as build servers might not have access to them. It is safer to have a plugin that does that hooked into one of the deploy lifecycles and let it operate on the generated CF template (that is available during deploy in-memory).
I fully agree that there should be a section of dos and don'ts in the docs - good idea.

@HyperBrain
Copy link
Author

HyperBrain commented Jan 10, 2018

Just saw, that I missed the deploy:function lifecycle completely in the document. I will add them soon.
UPDATE: Added "deploy function" and "deploy list" commands.

@bodhiprice
Copy link

@HyperBrain Thank you for this resource! It doesn't look like it's in the official docs, though. Is there a reason? I'm asking because this is super useful information. Would you be interested in having help making a PR?

@falconmick
Copy link

Why isn't this in the docs... This isn't even enough..

@anwarhamr
Copy link

anwarhamr commented Apr 3, 2019

I'm trying to get a file copied to the project directory when the user types sls deploy, can this be done? I've tried so many versions of this

custom:
  scripts:
    hooks:
      'package:initialize': cp ../../deployment_configurations/aura_cloud/${self:service}/env.yml .
      'deploy:createDeploymentArtifacts':  node scripts/replace_stage_in_env.js ${opt:stage, self:provider.stage} && node scripts/createParameters.js ${opt:service, self:service} ${opt:stage, self:provider.stage}

I've tried these but not limited to these...

before:deploy:deploy
before:initialize
deploy:deploy:checkForChanges
deploy:deploy:validateTemplate
...

the second hook works but I've added the cp and get this message when the file does not exist for my env.yml

Serverless Warning --------------------------------------

  A valid file to satisfy the declaration 'file(./env.yml):dev.artifacts.s3ReportingBucket' could not be found.

is it possible to run a script prior to loading the provider object at time of run?

@lielran
Copy link

lielran commented Apr 4, 2019

@anwarhamr you can link your plugin project directly via npm/yarn link

@hayd
Copy link

hayd commented Dec 6, 2019

It reads like before:package:initialize would occur only on the first deploy but actually it occurs every deploy, before:create:create doesn't seem to be triggered. Is there a hook I am missing that would be called on the first deploy only?

@nspeet
Copy link

nspeet commented Sep 14, 2020

Does this list exist for GCP?

@lionheart2013
Copy link

best hooks to use before running a tests?

@joeythomaschaske
Copy link

Adding information on when to use a specific lifecycle hook would be great.

@s1mrankaur
Copy link

s1mrankaur commented Dec 17, 2022

This looks great! I have a quick question.

I am trying to use https://www.serverless.com/framework/docs/guides/output-variables . I have it configured like the

outputs:
  app-version: ${ssm:/app/${self:provider.stage}/versions/${self:service}, ''}

in my serverless.yml file. I update the mentioned SSM parameter using after:aws:deploy:deploy:updateStack hook .

However, the value of the outputs variable that I see on the dashboard is always the last value and not the one that was updated after the deployment. Is there a way to resolve this?

I need to update the SSM value after deployment as the value is the version number that should be updated only after a deployment has gone through.

I thought the serverless dashboard outputs variables could be a good way to keep track of that. Open to suggestions/modifications to make it work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment