Serverless Components is now Generally Available. Click Here for the old Beta Version
English | 简体中文
Serverless Components are simple abstractions that enable developers to deploy serverless applications and use-cases easily, via the Serverless Framework.
- Ease - Deploy entire serverless applications/use-cases via Components, without being a cloud expert.
- Instant Deployments - Components deploy in 2-4 seconds, making rapid development on the cloud possible.
- Streaming Logs - Many Components stream logs from your app to your console in real-time, for fast debugging.
- Automatic Metrics - Many Components auto-set-up metrics upon deployment.
- Build Your Own - Components are easy to build.
- Registry - Share your Components with you, your team, and the world, via the Serverless Registry.
Deploy a serverless app rapidly, with any of these commands:
$ npx serverless init fullstack-app
$ npx serverless init express-starter
$ npx serverless init react-starter
$ npx serverless init vue-starter
$ npx serverless init graphql-starter
- Quick-Start
- Overview
- Using Components
- CLI Commands
- Building Components
- Components List
- F.A.Q.
To get started with Serverless Components, install the latest version of the Serverless Framework:
$ npm i -g serverless
After installation, run serverless registry
to see many Component-based templates you can deploy, or see more in the Serverless Framework Dashboard. These contain Components as well as boilerplate code, to get you started quickly.
Install anything from the registry via $ serverless init <template>
, like this:
$ serverless init express-starter
cd
into the generated directory.
Lastly, enter your cloud provider credentials into a .env
file within the folder that contains your serverless.yml
, or its immediate parent folder.
AWS_ACCESS_KEY_ID=12345
AWS_SECRET_ACCESS_KEY=5321
And deploy!
$ serverless deploy
After few seconds, you should get a URL as an output. If you visit that URL you'll see a successful "Request Received" message.
Fetch the your Component Instance's info...
$ serverless info
Run the serverless dev
command to auto-deploy on save, and have logs and errors stream in real-time to your console (if supported by the Component)...
$ serverless dev
Deploy other Components that you may want to use with your Express Component. For example, you may want to give your Express application permissions to other resources on your AWS account via the aws-iam-role
Component. You may also want an AWS DynamoDB table to use with your Express Component, via the aws-dynamodb
Component. You can initialize and deploy them just like the express component. You can then use them with your express
Component, like this:
org: your-org # Your Org
app: your-app # Your App
component: express
name: express-api
inputs:
src: ./src
roleName: ${output:my-role.name}
env:
dbTableName: ${output:${stage}:${app}:my-table.name}
Serverless Components are libraries of code that make it easy to deploy apps and other functionality onto serverless cloud infrastructure. They're instant serverless use-cases that contain the best infrastructure patterns for scale, performance, cost optimization, collaboration and more.
We (Serverless Inc) made Serverless Components because composing, configuring and managing low-level serverless infrastructure can be complicated for developers and teams. We've discovered many of the best patterns, and now we want to share them!
While Components can help you deploy and manage low-level infrastructure (e.g. an AWS S3 bucket). Their big use-case is on higher-order functionality and apps, like:
- A group of infrastructure with a purpose, like a type of data processing pipeline.
- A software feature, like user authentication, comments, or a payment system.
- An entire application, like a blog, video streaming service, or landing page.
Serverless Components are built around higher-order use-cases (e.g. a website, blog, payment system). Irrelevant low-level infrastructure details (that aren't necessary for the use-case) are abstracted away, and simpler configuration is offered instead.
For example, here's what it looks like to provision a serverless website hosted on AWS S3, delivered globally and quickly w/ AWS Cloudfront, via a custom domain on AWS Route 53, secured by a free AWS ACM SSL Certificate:
# serverless.yml
org: acme # Your Org
app: ecommerce # Your App
component: website # A Component in the Registry
name: my-website # The name of your Component Instance
inputs: # The configuration the Component accepts
src:
src: ./src
hook: npm run build
dist: ./dist
env:
# environment variables to pass to the website build environment
REACT_APP_API_URL: https://api.example.com
domain: mystore.com
Serverless Components that deploy instantly, removing the need to emulate cloud services locally for fast feedback during the development process.
$ serverless deploy
4s > my-express-app › Successfully deployed
Serverless Components are easily written in Javascript (serverless.js
), with simple syntax inspired by component-based frameworks, like React.
// serverless.js
const { Component } = require('@serverless/core');
class MyBlog extends Component {
async deploy(inputs) {
console.log('Deploying a serverless blog'); // Leave a status update for users deploying your Component with --debug
this.state.url = outputs.url; // Save state
return outputs;
}
}
module.exports = MyBlog;
Anyone can build a Serverless Component and share it in our Registry.
$ serverless publish
[email protected] › Published
Serverless Components favor cloud infrastructure with serverless qualities. They are also entirely vendor agnostic, enabling you to easily use services from different vendors, together. Like, AWS Lambda, AWS S3, Azure Functions, Google Big Query, Twilio, Stripe, Algolia, Cloudflare Workers and more.
Serverless Components are a Serverless Framework feature. You use them with the Serverless Framework CLI. Install it via:
$ npm i serverless -g
To use a Serverless Component, declare the name of one that exists in the Serverless Registry in your serverless.yml
.
The syntax looks like this:
# serverless.yml
component: [email protected] # The name and version of the Component in the Registry. To always use the latest, include no '@' and version (e.g. 'component: express').
org: acme # The name of your Serverless Framework Org
app: fullstack # Optional. The name of a high-level app container. Useful if you want to group apps together.
name: rest-api # The name of your Serverless Framework App
inputs: # The parameters to send to the "deploy" action of the component.
src: ./src
domain: api.my-app.com
There is nothing to install when using Serverless Components. They live in the cloud. When you run deploy, the configuration you specify in serverless.yml
will be sent to the Serverless Components Engine, along with the files or source code you specifiy in inputs
.
Other Notes:
-
You cannot use Serverless Components within an existing Serverless Framework project file (i.e. a
serverless.yml
file that containsfunctions
,events
,resources
andplugins
). -
You can only have 1 Serverless Component in
serverless.yml
. We encourage this because it's important to separate the resources in your Serverless Applications, rather than put all of them in 1 infrastructure stack.
Every Serverless Component can perform one or many Actions, which are functions that contain logic which the Component can do for you, such as:
- deploy - Deploy something onto cloud infrastructure.
- remove - Remove something from cloud infrastructure.
- test - Test some functionality provisioned by the Component, like an API endpoint.
- metrics - Get metrics about the Component's performance.
Components ship with their own unique Actions, though all have deploy and remove. One way to think about Actions is to consider Components as Javascript classes and Actions are the class methods.
You can run Component Actions via the Serverless Framework CLI or the Serverless Framework SDK.
All Actions accept parameters known as Inputs and return other parameters known as Outputs.
In serverless.yml
the inputs
property are merely Inputs that you wish to send to the deploy
Action of your Component.
Every Action has it' own Inputs and Outputs.
When a Component Action is finished running, it returns an outputs
object.
Outputs contain the most important information you need to know from a deployed Component Instance, like the URL of the API or website, or all of the API endpoints.
Outputs can be referenced easily in the inputs
of other Components. Just use this syntax:
# Simpler Syntax - References the same "stage" and "app"
${output:[instance].[output]}
# More Configurable Syntax - Customize the "stage" and "app"
${output:[stage]:[app]:[instance].[output]}
stage
- The stage that the referenced component instance was deployed to. It is thestage
property in that component instanceserverless.yml
file.app
- The app that the referenced component instance was deployed to. It is theapp
property in that component instanceserverelss.yml
file, which falls back to thename
property if you did not specify it.instance
- The name of the component instance you are referencing. It is thename
property in that component instanceserverless.yml
file.output
- One of the outputs of the component instance you are referencing. They are displayed in the CLI after deploying.
# Examples
${output:prod:ecommerce:products-api.url}
${output:prod:ecommerce:role.arn}
${output:prod:ecommerce:products-database.name}
You can deploy Components easily via the Serverless Framework with the $ serverless deploy
command.
$ serverless deploy
This command can be run in any directory containing a valid components serverless.yml
as shown above. You can also run serverless deploy
in any directory that contains multiple component directories, in which case it would deploy all these components in parallel whenever possible according to their output variable dependencies. If you'd like to make sure all these related components deploy to the same org, app & stage, you can create a serverless.yml
file at the parent level that includes these properties. The fullstack-app
template is a good example for all of this.
While Serverless Components deploy incredibly fast, please note that first deployments can often be 2x slower because creating cloud resources takes a lot longer than updating them. Also note that some resources take a few minutes to be availbale. For example, APIs and Website URLs may take 1-2 minutes before they are available.
Serverless Components automatically save their state remotely. This means you can easily push your Components to Github, Gitlab, Bitbucket, etc., and collaborate on them with others as long as the serverless.yml
contains an org
which your collaboraters are added to:
org: acme-team # Your collaboraters must be added at dashboard.serverless.com
app: ecommerce
component: my-component
name: rest-api
Further, your Component Instances can easily be deployed with CI/CD, as long as you make sure to include a SERVERLESS_ACCESS_KEY
environment variable.
You can add collaboraters and create access tokens in the Serverless Framework Dashboard.
Serverless Components use semantic versioning.
component: [email protected]
When you add a version, only that Component version is used. When you don't add a version, the Serverless Framework will use the latest version of that Component, if it exists. We recommend to always pin your Component to a version.
Upon deployment, the Serverless Framework looks for a .env
file in the current working directory, as well as the immediate parent directory. Components can find these credentials within the this.credentials
object. However, you must use the following Environment Variable keys:
AWS_ACCESS_KEY_ID=123456789
AWS_SECRET_ACCESS_KEY=123456789
Components could access these AWS credentials using this.credentials.aws
. This object would look like this:
{
accessKeyId: '123456789',
secretAccessKey: '123456789',
}
Note: For AWS, if no .env
file was found in the current working directory or immediate parent directory, the CLI will attempt to get the credentials from AWS's shared credentials file (typically at ~/.aws/credentials
) as a fallback according to your AWS_DEFAULT_PROFILE
or AWS_PROFILE
environment variables, just like how it works on the AWS SDK.
AWS_PROFILE=myprofile
The CLI will check AWS's shared credentials file (typically at ~/.aws/credentials
) for 'role_arn' and 'source_profile' configuration for provided profile
and assume that role using AWS STS API. AWS's shared credentials should look like this:
[mycompanyprofile]
aws_access_key_id = xxxxxxxxxxxxxxxxxxxx
aws_secret_access_key = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
[myprofile]
role_arn = arn:aws:iam::000000000000:role/MyOrganizationAccountAccessRole
source_profile = mycompanyprofile
Components could access AWS credentials using this.credentials.aws
with the addition of 'sessionToken' property. This object would look like this:
{
accessKeyId: '123456789',
secretAccessKey: '123456789',
sessionToken: '123456789AAAAAAAAAAAAAAAAAAAAAAAA',
}
Note: These credentials are temporary, by default they last 3600 seconds (60 minutes). This value can be configured via AWS_ROLE_SESSION_DURATION
environment variable. The minimum value is 900 (15 minutes) and the maximum is 43200 (12 hours).
# You can specify the path to the JSON credentials file that you downloaded from Google
GOOGLE_APPLICATION_CREDENTIALS=path/to/credentials/json/file
# Or you could just provide your project id, client email & private key
GOOGLE_PROJECT_ID=project-id-xxx
[email protected]
GOOGLE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgk..."
Components could access these google credentials using this.credentials.google
. This object would look like this:
{
applicationCredentials: 'path/to/credentials/json/file',
projectId: 'project-id-xxx',
clientEmail: '[email protected]',
privateKey: '-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgk...'
}
Serverless Components have a Stages concept, which enables you to deploy entirely separate Component Instances and their cloud resources per stage.
The dev
Stage is always used as the default stage. If you wish to change your stage, set it in serverless.yml
, like this:
org: my-org
app: my-app
component: [email protected]
name: my-component-instance
stage: prod # Enter the stage here
You can also specify a Stage within the SERVERLESS_STAGE
Environment Variable, which overrides the stage
set in serverless.yml
:
SERVERLESS_STAGE=prod
And, you can specify a Stage upon deployment via a CLI flag, which overrides anything set in serverless.yml
AND an Environment Variable, like this:
$ serverless deploy --stage prod
Again, the CLI flag overrides both a stage
in serverless.yml
and an Environment Variable. Whereas an Environment Variable can only override the stage
in serverless.yml
.
Lastly, you can set stage-specific environment variables using separate .env
files. Each file must be named in the following format: .env.STAGE
. For example, if you run in the prod stage, the environment variables in .env.prod
would be loaded, otherwise the default .env
file (without stage extension) would be loaded. You can also put the .env.STAGE
file in the immediate parent directory, in the case that you have a parent folder containing many Component Instances.
A practical usage of this is if you want to have a separate AWS account for each stage. In that case you would keep separate AWS credentials for each stage you are targeting. Then based on the stage you're deploying to, the correct credentials would be picked up.
You can use Variables within your Component Instances serverless.yml
to reference Environment Variables, values from within serverless.yml
and Outputs from other Serverless Component Instances that you've already deployed.
Here is a quick preview of possibilities:
org: acme
app: ecommerce
component: express
name: rest-api
stage: prod
inputs:
name: ${org}-${stage}-${app}-${name} # Results in "acme-prod-ecommerce-rest-api"
region: ${env:REGION} # Results in whatever your environment variable REGION= is set to.
roleArn: ${output:prod:my-app:role.arn} # Fetches an output from another component instance that is already deployed
roleArn: ${output:${stage}:${app}:role.arn} # You can combine variables too
You can reference your org
value in the inputs
of your YAML in serverless.yml
by using the ${org}
Variable, like this:
org: acme
app: ecommerce
component: express
name: rest-api
stage: prod
inputs:
name: ${org}-api # Results in "acme-api"
Note: If you didn't specify an org
, the default org
would be the first org you created when you first signed up. You can always overwrite the default org
or the one specified in serverless.yml
by passing the --org
option on deploy:
$ serverless deploy --org my-other-org
You can reference your stage
value in the inputs
of your YAML in serverless.yml
by using the ${stage}
Variable, like this:
org: acme
app: ecommerce
component: express
name: rest-api
stage: prod
inputs:
name: ${stage}-api # Results in "prod-api"
Note: If you didn't specify a stage
, the default stage would be dev
. You can always overwrite the default stage
or the one specified in serverless.yml
by passing the --stage
option on deploy:
$ serverless deploy --stage prod
You can reference your app
value in the inputs
of your YAML in serverless.yml
by using the ${app}
Variable, like this:
org: acme
app: ecommerce
component: express
name: rest-api
stage: prod
inputs:
name: ${app}-api # Results in "ecommerce-api"
Note: If you didn't specify an app, the default app name would be the instance name (the name
property in serverless.yml
). You can always overwrite the default app
or the one specified in serverless.yml
by passing the --app
option on deploy:
$ serverless deploy --app my-other-app
You can reference your name
value in the inputs
of your YAML in serverless.yml
by using the ${name}
Variable, like this:
org: acme
app: ecommerce
component: express
name: rest-api
stage: prod
inputs:
name: ${name} # Results in "rest-api"
You can reference Environment Variables (e.g. those that you defined in the .env
file or that you've set in your environment manually) directly in serverless.yml
by using the ${env}
Variable.
For example, if you want to reference the REGION
environment variable, you could do that with ${env:REGION}
.
component: express
org: acme
app: ecommerce
name: rest-api
stage: prod
inputs:
region: ${env:REGION}
Perhaps one of the most useful Variables is the ability to reference Outputs from other Component Instances that you have already deployed. This allows you to share configuration/data easily across as many Component Instances as you'd like.
If you want to reference an Output of another Component Instance, use the ${output:[app]:[stage]:[instance name].[output]}
syntax, like this:
component: express
org: acme
app: ecommerce
name: rest-api
stage: prod
inputs:
roleArn: ${output:[STAGE]:[APP]:[INSTANCE].arn} # Fetches an output from another component instance that is already deployed
You can access Outputs across any App, Instance, in an any Stage, within the same Org.
A useful feature of this is the ability to share resources easily, and even do so across environments. This is useful when developers want to deploy a Component Instance in their own personal Stage, but access shared resources within a common "development" Stage, like a database. This way, the developers on your team do not have to recreate the entire development stage to perform their feature work or bug fix, only the Component Instance that needs changes.
Problem: your environment does not have permission to access the public network and can access the public network only through a proxy, and a network failure is reported when sls deploy
is executed.
Solution: add the following configuration to the .env
file, it needs the version of Node.js >= 11.7.0
:
HTTP_PROXY=http://127.0.0.1:12345 # Your proxy
HTTPS_PROXY=http://127.0.0.1:12345 # Your proxy
See available Components
Publish a Component to the Serverless Registry.
--dev
- Publishes to the @dev
version of your Component, for testing purposes.
Initializes the specified package (component or template) locally to get you started quickly.
--dir
, -d
- Specify destination directory.
Deploys an Instance of a Component.
--debug
- Lists console.log()
statements left in your Component upon deploy
or any action.
Removes an Instance of a Component.
--debug
- Lists console.log()
statements left in your Component upon remove
or any action.
Fetches information of an Instance of a Component.
--debug
- Lists state
.
Starts DEV MODE, which watches the Component for changes, auto-deploys on changes, and (if supported by the Component) streams logs, errors and transactions to the terminal.
User can set and list secrets value as parameters by CLI with app and stage
serverless param set id=param age=12 [--app test] [--stage dev]
- User can set multiple parameters once, use
paramName=paramValue
- If user does not set app or stage, CLI will read from config file or use default values
serverless param list [--app test] [--stage dev]
- If user does not set app or stage, CLI will read from config file or use default values
- CLI will show the all parameters for current stage and app
Runs any component custom command, and passes inputs to it. The inputs you pass in the above syntax overwrite any inputs found in the serverless.yml
file.
Few examples:
# simple example
serverless test --inputs domain=serverless.com
# passing objects with JSON syntax
serverless invoke --inputs env='{"LANG": "en"}'
# passing arrays with comma separation
serverless backup --inputs userIds=foo,bar
If you want to build your own Serverless Component, there are 2 essential files you need to be aware of:
serverless.component.yml
- This contains the definition of your Serverless Component.serverless.js
- This contains your Serverless Component's code.
One of the most important things to note is that Serverless Components only run in the cloud and do not run locally. That means, to run and test your Component, you must publish it first (it takes only few seconds to publish). We're continuing to improve this workflow. Here's how to do it...
To declare a Serverless Component and make it available within the Serverless Registry, you must create a serverless.component.yml
file with the following properties:
# serverless.component.yml
name: express # Required. The name of the Component
version: 0.0.4 # Required. The version of the Component
author: eahefnawy # Required. The author of the Component
org: serverlessinc # Required. The Serverless Framework org which owns this Component
main: ./src # Required. The directory which contains the Component code
description: Deploys Serverless Express.js Apps # Optional. The description of the Component
keywords: aws, serverless, express # Optional. The keywords of the Component to make it easier to find at registry.serverless.com
repo: https://github.com/owner/project # Optional. The code repository of the Component
license: MIT # Optional. The license of the Component code
A serverless.js
file contains the Serverless Component's code.
To make a bare minimum Serverless Component, create a serverless.js
file, extend the Component class and add a deploy
method like this:
// serverless.js
const { Component } = require('@serverless/core');
class MyComponent extends Component {
async deploy(inputs = {}) {
return {};
} // The default functionality to run/provision/update your Component
}
module.exports = MyComponent;
Note: You do NOT need to install the @serverless/core
package via npm. This package is automatically available to you in the cloud environment.
deploy()
is always required. It is where the logic resides in order for your Component to make something. Whenever you run the $ serverless deploy
command, it's always calling the deploy()
method.
You can also add other methods to this class. A remove()
method is often the next logical choice, if you want your Serverless Component to remove the things it creates, via $ serverless remove
.
You can add as many methods as you want. This is interesting because it enables you to ship more automation with your Component, than logic that merely deploys and removes something.
It's still early days for Serverless Components, but we are starting to work on Components that ship with their own test()
function, or their own logs()
and metrics()
functions, or seed()
for establishing initial values in a database Component. Overall, there is a lot of opportunity here to deliver Components that are loaded with useful automation.
All methods other than the deploy()
method are optional. All methods take a single inputs
object, not individual arguments, and return a single outputs
object.
Here is what it looks like to add a remove
method, as well as a custom method.
// serverless.js
const { Component } = require('@serverless/core');
class MyComponent extends Component {
/*
* The default functionality to run/provision/update your Component
* You can run this function by running the "$ serverless deploy" command
*/
async deploy(inputs = {}) {
return {};
}
/*
* If your Component removes infrastructure, this is recommended.
* You can run this function by running "$ serverless remove"
*/
async remove(inputs = {}) {
return {};
}
/*
* If you want to ship your Component w/ extra functionality, put it in a method.
* You can run this function by running "$ serverless anything"
*/
async anything(inputs = {}) {
return {};
}
}
module.exports = MyComponent;
When inside a Component method, this
comes with utilities which you can use. Here is a guide to what's available to you within the context of a Component.
// serverless.js
const { Component } = require('@serverless/core');
class MyComponent extends Component {
async deploy(inputs = {}) {
// this features useful information
console.log(this);
// Common provider credentials are identified in the environment or .env file and added to this.context.credentials
// when you run "serverless deploy", then the credentials in .env will be used
// when you run "serverless deploy --stage prod", then the credentials in .env.prod will be used...etc
// if you don't have any .env files, then global aws credentials will be used
const dynamodb = new AWS.DynamoDB({ credentials: this.credentials.aws });
// You can easily create a random ID to name cloud infrastructure resources with using this utility.
const s3BucketName = `my-bucket-${this.resourceId()}`;
// This prevents name collisions.
// Components have built-in state storage.
// Here is how to save state to your Component:
this.state.name = 'myComponent';
// If you want to show a debug statement in the CLI, use console.log.
console.log('this is a debug statement');
// Return your outputs
return { url: websiteOutputs.url };
}
}
module.exports = MyComponent;
Every Serverless Component has Actions (which are merely functions, e.g. deploy, remove, metrics). Each Action accepts Inputs and returns Outputs. Serverless Components can optionally declare Types for the Inputs and Outputs of each Action. in their serverless.component.yml
, which make them easier to write and use.
Inputs & Output Types are recommended because they offer the following benefits:
- They validate an Action is supported by a Component before running it.
- They validate user Inputs before they are sent to a Component's Actions.
- They prevent Component authors from needing to write their own validation logic.
- They offer helpful errors to Component users when they enter invalid Inputs.
- They can automate documentation for your Component.
- They are needed for upcoming Serverless Framework Dashboard features that will enable visualizing Input and Output data special ways (e.g. form fields, charts, etc.).
Types are optionally declared in serverless.component.yml
files.
You must first declare the Actions the Component uses, like this:
name: express
version: 1.5.7
org: serverlessinc
description: Deploy a serverless Express.js application onto AWS Lambda and AWS HTTP API.
actions:
# deploy action
deploy:
# deploy action definition
definition: Deploy your Express.js application to AWS Lambda, AWS HTTP API and more.
inputs:
# An array of Types goes here.
outputs:
# An array of Types goes here.
Below is a full example, which also details all supported Types (Disclaimer: This combines documentation and a real example. Hopefully it's more helpful!).
name: express
version: 1.5.7
org: serverlessinc
description: Deploy a serverless Express.js application onto AWS Lambda and AWS HTTP API.
actions:
# deploy action
deploy:
# deploy action definition
definition: Deploy your Express.js application to AWS Lambda, AWS HTTP API and more.
inputs:
#
#
# Primitive Types
# These cover standard data types, like "string", "number", "object", etc.
#
#
# Type: string
name: # The name of the input/output
type: string # The type
# Optional
required: true # Defaults to required: false
default: my-app # The default value
description: The name of the AWS Lambda function. # A description of this parameter
min: 5 # Minimum number of characters
max: 64 # Maximum number of characters
regex: ^[a-z0-9-]*$ # A RegEx pattern to validate against.
allow: # The values that are allowed for this
- my-api
- my-backend
# Type: number
memory: # The name of the input/output
type: number # The type. These can be integers or decimals.
# Optional
required: true # Defaults to required: false
default: 2048 # The default value
description: The memory size of the AWS Lambda function. # A description of this parameter
min: 128 # Minimum number allowed
max: 3008 # Maximum number allowed
allow: # The values that are allowed for this
- 128
- 1024
- 2048
- 3008
# Type: boolean
delete: # The name of the input/output
type: boolean # The type.
# Optional
required: true # Defaults to required: false
description: Whether to delete this infrastructure resource when removed # A description of this parameter
default: true # The default value
# Type: object
vpcConfig: # The name of the input/output
type: object # The type
# Optional
required: true # Defaults to required: false
description: The VPC configuration for your AWS Lambda function # A description of this input
keys:
# Add more Types in here
securityGroupIds: # The name of the key
type: string
# Type: array
mappingTemplates: # The name of the input/output
type: array # The type
# Optional
required: true # Defaults to required: false
description: The mapping templates for your GraphQL endpoints. # A description of this input
min: 1 # Minimum array items
max: 10 # Max array items
items:
# Add more Types in here, that you wish to allow, without "name" properties because they are array items.
- type: string
min: 5
max: 13
- type: object
keys:
# Add more standard Types in here, with "name" properties because they are object properties.
- name: aws_lambda
type: string
default: # Default array items
- '12345678'
#
#
# Special Types
# These are special types, they cover handling source code, and more
#
#
# Type: src
# This Type specifies a folder containing code or general files you wish to upload upon deployment, which the Component may need to deploy a specific outcome. Before running the Component in the cloud, the Serverless Framework will first upload any files specified in `src`. Generally, you want to keep the package size of your serverless applications small (<5MB) in order to have the best performance in serverless compute services. Larger package sizes will also make deployments slower since the upload process is dependent on your internet connection bandwidth. Consider a tool to build and minify your code first. You can specify a build hook to run and a `dist` folder to upload, via the `src` property.
# This Type can either be a string containing a relative path to your source code, or an object.
src: # The name "src" is reserved for this Type. Your inputs can only have one of these.
type: src # The type
# Optional
required: true # Defaults to required: false
description: The source code of your application that will be uploaded to AWS Lambda. # A description of this parameter
src: # A relative file path to the directory which contains your source code and any scripts you wish to run via the "hook" property.
hook: # A script you wish to run before uploading your source code.
dist: # The directory containing your built source code which you wish to upload.
exclude: # An array of glob patterns of files/paths to exclude
- .env # exclude .env file in ./src
- '.git/**' # exclude .git folder and all subfolders and files inside it
- '**/*.log' # exclude all files with .log extension in any folder under the ./src
# Type: env
# This Type is for an object of key-value pairs meant to contain sensitive information. By using it, the Serverless Framework will treat this data more securely.
env: # The name "env" is reserved for this Special Type. Your params can only have one of these.
type: env # The type
# Optional
description: Environment variables to include in AWS Lambda # A description of this input
# Type: datetime
# This Type is an ISO8601 string that contains a datetime.
rangeStart: # The name of the input/output
type: datetime
# Optional
required: true # Defaults to required: false
description: The start date of your metrics timeframe. # A description of this input
# Type: url
# This Type is for a URL, often describing your root API URL or website URL.
url: # The name of the input/output
type: url
# Optional
required: true # Defaults to required: false
description: The url of your website. # A description of this input
# Type: api
# This Type is for an OpenAPI specification.
api: # The name of the input/output
type: api
# Optional
required: true # Defaults to required: false
description: The API from your Express.js app. # A description of this input
# Type: metrics
# This Type is for an array of supported Metrics widgets which can be rendered dynamically in GUIs.
metrics: # The name of the input/output
type: metrics
# Optional
required: true # Defaults to required: false
description: API metrics from your back-end. # A description of this input
outputs:
# Another array of Types goes here.
# remove action
remove:
# ... accepts config identical to the deploy action
If you use the metrics
Type in your Component Outputs, you must return an array that contains one or many of the following data structures.
Each data structure corresponds to a widget that can be rendered in the Serverless Framework Dashboard.
This is for displaying a bar chart. It can support multiple y data sets which cause the bar chart to stack.
In the dashboard, the stat
property of the first array is preferred.
{
// Type: Name and version of this chart type.
"type": "bar-v1",
// Title: Name of the chart
"title": "API Requests & Errors",
// xData: The values along the bottom of the chart. Must have the same quantity as yValues.
"xData": [
"2021-07-01T19:00:00.999Z",
"2021-07-01T20:00:00.999Z",
"2021-07-01T21:00:00.999Z",
"2021-07-01T22:00:00.999Z"
],
// yDataSets: An array of 1 or more items to include in order to stack the bar charts.
"yDataSets": [
{
"title": "API Requests",
// yData: An array of the values that correspond to the xData values
"yData": [3, 43, 31, 65],
// Color of bar chart. Must be a hex value.
"color": "#000000",
// Stat: A large number to show at the top. E.g., total api requests
"stat": 142,
// Stat Text: Shows next to the large number. E.g., ms, seconds, requests, etc. Default is null.
"statText": "requests",
},
{
"title": "API Errors",
// yData: An array of the values that correspond to the xData values
"yData": [2, 3, 1, 6],
// Color of bar chart. Must be a hex value.
"color": "#FF5733",
// Stat: A large number to show at the top. E.g., total api errors
"stat": 12,
// Stat Text: Shows next to the large number. E.g., ms, seconds, requests, etc. Default is null.
"statText": "errors",
}
]
}
This is for displaying a line chart. It can support multiple y data sets which cause multiple lines on the chart.
In the dashboard, the stat
property of the first array is preferred.
{
// Type: Name and version of this chart type.
"type": "line-v1",
// Title: Name of the chart
"title": "API Latency",
// xData: The values along the bottom of the chart. Must have the same quantity as yValues.
"xData": [
"2021-07-01T19:00:00.999Z",
"2021-07-01T20:00:00.999Z",
"2021-07-01T21:00:00.999Z",
"2021-07-01T22:00:00.999Z"
],
// yDataSets: An array of 1 or more items to include for each line.
"yDataSets": [
{
"title": "API P95 Latency",
// yData: An array of the values that correspond to the xData values
"yData": [3, 43, 31, 65],
// Color of bar chart. Must be a hex value.
"color": "#000000",
// Stat: A large number to show at the top. E.g., total api requests
"stat": 142,
// Stat Text: Shows next to the large number. E.g., ms, seconds, requests, etc. Default is null.
"statText": "requests",
},
{
"title": "API P99 Latency",
// yData: An array of the values that correspond to the xData values
"yData": [2, 3, 1, 6],
// Color of bar chart. Must be a hex value.
"color": "#FF5733",
// Stat: A large number to show at the top. E.g., total api errors
"stat": 12,
// Stat Text: Shows next to the large number. E.g., ms, seconds, requests, etc. Default is null.
"statText": "errors",
}
]
}
When working with a Component that requires source code (e.g. you are creating a Component that will run on AWS Lambda), if you make the src
one of your inputs, anything specified there will be automatically uploaded and made available within the Component environment.
Within your Component, the inputs.src
will point to a zip file of the source files within your environment. If you wish to unzip the source files, use this helpful utility method:
async deploy(inputs = {}) {
// Unzip the source files...
const sourceDirectory = await this.unzip(inputs.src)
}
Now, you are free to manipulate the source files. When finished, you may want to use this utility method to zip up the source files again because in some circumstances you will next want to upload the code to a compute service (e.g. AWS Lambda).
async deploy(inputs = {}) {
// Zip up the source files...
const zipPath = await this.zip(sourceDirectory)
}
If your Component runs code, and you want to enable streaming logs, errors and transactions for you Component via Serverless Dev Mode (serverless dev
), be sure to add the Serverless SDK into the deployed application/logic. We offer some helpful utility methods to make this possible:
// unzip source zip file
console.log(`Unzipping ${inputs.src}...`);
const sourceDirectory = await instance.unzip(inputs.src);
console.log(`Files unzipped into ${sourceDirectory}...`);
// add sdk to the source directory, add original handler
console.log(`Installing Serverless Framework SDK...`);
instance.state.handler = await instance.addSDK(sourceDirectory, '_express/handler.handler');
// zip the source directory with the shim and the sdk
console.log(`Zipping files...`);
const zipPath = await instance.zip(sourceDirectory);
console.log(`Files zipped into ${zipPath}...`);
After this, you'll likely want to upload the code to a compute service (e.g. AWS Lambda).
Serverless Components only run in the cloud and cannot be run locally. This presents some tremendous advantages to Component consumers, and we've added some workflow tricks to make the authoring workflow easier. Here they are...
When you have added or updated the code of your Serverless Component and you want to test the change, you will need to publish it first. Since you don't want to publish your changes to a proper version of your Component just for testing (because people may be using it), we allow for you to publish a "dev" version of your Component.
Simply run the following command to publish your Serverless Component to the "dev" version:
$ serverless publish --dev
You can test the "dev" version of your Component in serverless.yml
, by including a @dev
in your Component name, like this:
# serverless.yml
org: acme
app: fullstack
component: express@dev # Add "dev" as the version
name: rest-api
inputs:
src: ./src
Run your Component command to test your changes:
$ serverless deploy --debug
When writing a Component, we recomend to always use the --debug
flag, so that the Component's console.log()
statements are sent to the CLI. These are handy to use in Serverless Components, since they describe what the Component is doing. We recommend you add console.log()
statements to your Component wherever you think they are necessary.
class MyComponent extends Component {
async deploy(inputs) {
console.log(`Starting MyComponent.`);
console.log(`Creating resources.`);
console.log(`Waiting for resources to be provisioned.`);
console.log(`Finished MyComponent.`);
return {};
}
}
When you're ready to publish a new version for others to use, update the version in serverless.component.yml
, then run publish without the --dev
flag.
# serverless.component.yml
name: [email protected]
$ serverless publish
Serverless: Successfully publish [email protected]
Here are some development tips when it comes to writing Serverless Components:
We recommend starting with a focus on your desired outcome, rather than try to break things down into multiple smaller Components from the start. Trying to break things down into multiple Components most often ends up as a distraction. Create a higher level Component that solves your problem first. Use it. Learn from it. Then consider breaking things down into smaller Components if necessary. At the same time, high-level solutions are what Serverless Components are meant for. They are outcomes—with the lowest operational overhead.
Provisioning infrastructure safely and reliably can be quite complicated. However, Serverless Components have a powerful advantage over general infrastructure provisioning tools that seek to enable every possible option and combination (e.g. AWS Cloudformation, Terraform) — Serverless Components know the specific use-case they are trying to deliver.
One of the most important lessons we've learned about software development tools is that once you know the use-case or specific goal, you can create a much better tool.
Components know their use-case. You can use that knowledge to: 1) provision infrastructure more reliably, because you have a clear provisioning path and you can program around the pitfalls. 2) provision infrastructure more quickly 3) add use-case specific automation to your Component in the form of custom methods.
Serverless Components save remarkably little state. In fact, many powerful Components have less than 10 properties in their state objects.
Components rely on the state saved within the cloud services they use as the source of truth. This prevents drift issues that break infrastructure provisioning tools. It also opens up the possibility of working with existing resources, that were not originally managed by Serverless Components.
If you do need to store state, try to store it immediately after a successful operation.
// Do something
this.state.id = 'updated or new id';
// Do something else
this.state.url = 'updated or new url';
This way, if anything after that operation fails, your Serverless Component can pick up where it left off, when the end user tries to deploy it again.
We believe serverless infrastructure and architectures will empower more people to develop software than ever before.
Because of this, we're designing all of our projects to be as approachable as possible. Please try to use simple, vanilla Javascript. Additionally, to reduce security risks and general bloat, please try to use the least amount of NPM dependencies as possible.
Never surprise the user by deleting or fundamentally changing infrastructure within your Serverless Component, based on a configuration change in serverless.yml
.
For example, if a user is changing their region, NEVER remove their infrastructure in one region and automatically recreate it in the new region upon their next $ serverless deploy
.
Instead, throw an error with a warning about this:
$ serverless deploy
Error: Changing the region from us-east-1 to us-east-2 will remove your infrastructure. Please remove it manually, change the region, then re-deploy.
$
We have measured this user experience and so far 100% of the time the user will remove their existing Component Instance and deploy another one. This works extremely well.
We write integration tests in the tests/integration.tests.js
file in each component repo. We run these tests on every push/merge to master with Github Actions. We recommend you do the same. As an example, here are the tests for the website component:
Running these integration tests will most likely require AWS keys, which are stored as Github Secrets. So you'll most likely need write access to the repo to accomplish this.
A serverless.yml
file can only hold 1 Component at this time. However, that does not mean you cannot deploy/remove multiple Components at the same time.
Simply navigate to a parent directory, and run serverless deploy
to deploy any serverless.yml
files in immediate subfolders. When this happens, the Serverless Framework will quickly create a graph based on the references your Component apps are making to eachother. Depending on those references, it will prioritize what needs to be deployed first, otherwise its default is to deploy things in parallel. This also works for serverless remove
.
For context, here is why we designed serverless.yml
to only hold 1 Component at a time:
-
We have a lot of advanced automation and other features in the works for Components that push the limits of how we think about infrastructure-as-code. Delivering those features is harder if
serverless.yml
contains multiple Components. -
Many of our support requests come from users who deploy a lot of critical infrastructure together, and end up accidentally breaking that critical infrastructure, often while intending to push updates to one specific area. In response to this, we wanted to make sure there was an easy way to deploy things separately first, so that developers can deploy more safely. Generally, try to keep the things you deploy frequently (e.g. code, functions, APIs, etc.), separate from critical things that you deploy infrequently (e.g. VPCs, databases, S3 buckets). We get that it's convenient to deploy everything together (which is why we still enabled this via the method above), just be careful out there!
Components run in the cloud. Here's what that means and why it's important...
We've been working on the Serverless Framework for 5 years now. During that time, there have been many ways we've wanted to better solve user problems, improve the experience and innovate—but we've been limited by the project's design (e.g. requires local installation, hard to push updates, lack of error diagnostics, dealing with user environment quirks, etc.).
Over a year ago, we whiteboarded several groundbreaking ways we can push the boundaries of serverless dev tools (and infrastructure as code in general), and realized the only way to make that happen was to move the majority of work to the cloud.
Now, when you deploy, or perform any other Action of a Component, that happens in our "Components Engine", which we've spent 1.5+ years building. For clarity, this means your source code, environment variables and credentials are passed through the Components Engine.
This is a complete change in how Serverless Framework traditionally worked. However, this is no different from how most build engines, CI/CD products, and cloud services work, as well as AWS CloudFormation, which Serverless Framework traditionally used. The "Components Engine" is a managed service, like AWS CloudFormation, CircleCI, Github, Github Actions, Hosted Gitlab, Terraform Cloud, etc.
As of today, the Components Engine helped enable: The fastest infrastructure deployments possible, streaming logs to your CLI, streaming metrics to the Dashboard, remote state storage and sharing, secrets injection, configuration validation, and so much more. Please note, this is only 25% of our vision for this effort. Otherwise known as the table-stakes features. The real thought-provoking and groundbreaking developer productivity features are coming next...
Part of these features will enable greater security features than we've ever had in Serverless Framework. Features that involve making it easier to reduce the scope of your credentials, analyze/block everything passing through the Engine, rollback unsafe deployments, etc.