Components
Components are the building blocks of your app.
Every SST app is made up of components. Components in turn create one or more pieces of low level infrastructure. Components wrap these up into logical units that represent the high level concepts of your app.
For example, sst.aws.Function
lets you add a Lambda function to your app, while sst.aws.Nextjs
lets you deploy your Next.js app.
SST’s components use Pulumi behind the scenes to create the low level infrastructure. These are generated from Terraform modules. SST allows you to customize how these are created.
You can also use any Pulumi component in your SST app. This is useful if you want to create infrastructure that SST doesn’t support yet.
Providers
There are two types of components in your app.
- Native SST components, namespaced under
sst.*
- And Pulumi components, namespaced under
<provider>.*
A provider is the infrastructure service that the component is deployed to. SST’s components currently deploy to two providers.
-
AWS
These components are namespaced under
sst.aws.*
. Internally they use Pulumi’s AWS Classic provider. -
Cloudflare
These components are namespaced under
sst.cloudflare.*
. Internally they use Pulumi’s Cloudflare provider.
Learn more about providers.
Constructor
To add a component to your app, you create an instance of it by passing in a couple of args. For example, here’s the signature of the Function component.
Each component takes the following:
name
: The name of the component. This needs to be unique across your entire app.args
: An object of properties that allows you to configure the component.opts?
: An optional object of properties that allows you to configure this component in Pulumi.
Here’s an example of creating a Function
component:
Name
There are two guidelines to follow when naming your components:
-
Component names are global across your entire app.
-
Use PascalCase for the component name. For example,
MyFunction
instead ofmyFunction
ormy_function
.
These make it possible to link resources together in your SST app.
Args
Each component takes a set of args that allow you to configure it. These args are specific to each component. For example, the Function component takes FunctionArgs
.
Most of these args are optional, meaning that most components need very little configuration to get started. Typically, the most common configuration options are lifted to the top-level. To further configure the component, you’ll need to use the transform
prop.
Args usually take primitive types. However, they also take a special version of a primitive type. It’ll look something like Input<string>
. We’ll look at this in detail below.
Transform
Most components take a transform
prop as a part of their constructor or methods. It’s an object that takes callbacks that allow you to transform how that component’s infrastructure is created.
For example, here’s what the transform
prop looks like for the Function component:
function
: A callback to transform the underlying Lambda functionlogGroup
: A callback to transform the Lambda’s LogGroup resourcerole
: A callback to transform the role that the Lambda function assumes
The type for these callbacks is similar. Here’s what the role
callback looks like:
So this takes either a RoleArgs
object or a function that takes RoleArgs
. Where RoleArgs is the props for the role that’s passed to Pulumi.
This allows you to either:
-
Pass in your own
RoleArgs
object.This is merged with the original
RoleArgs
that were going to be passed to the component. -
Or, pass in a callback that takes the current
RoleArgs
and mutates it.
$transform
Similar to the component transform, we have the global $transform
. This allows you to transform how a component of a given type is created.
For example, to set a default runtime for all function components.
Here, args
and opts
are what you’d pass to the Function
component. Recall the
signature of the Function
component:
Read more about the global $transform
.
Properties
An instance of a component exposes a set of properties. For example, the Function
component exposes the following properties — arn
, name
, url
, and nodes
.
These can be used to output info about your app or can be used as args for other components.
These are typically primitive types. However, they can also be a special version of a primitive type. It’ll look something like Output<string>
. We’ll look at this in detail below.
Links
Some of these properties are also made available via resource linking. This allows you to access them in your functions and frontends in a typesafe way.
For example, a Function exposes its name
through its links.
Nodes
The nodes
property that a component exposes gives you access to the underlying infrastructure. This is an object that contains references to the underlying Pulumi components that are created.
For example, the Function
component exposes the following nodes — function
, logGroup
, and role
.
Outputs
The properties of a component are typically of a special type that looks something like, Output<primitive>
.
These are values that are not available yet and will be resolved as the deploy progresses. However, these outputs can be used as args in other components.
This makes it so that parts of your app are not blocked and all your resources are deployed as concurrently as possible.
For example, let’s create a function with a url.
Here, myFunction.url
is of type Output<string>
. We want to use this function url as a route in our router.
The route arg takes Input<string>
, which means it can take a string or an output. This creates a dependency internally. So the router will be deployed after the function has been. However, other components that are not dependent on this function can be deployed concurrently.
You can learn more about Input and Output types on the Pulumi docs.
Apply
Since outputs are values that are yet to be resolved, you cannot use them in regular operations. You’ll need to resolve them first.
For example, let’s take the function url from above. We cannot do the following.
This is because the value of the output is not known at the time of this operation. We’ll need to resolve it.
The easiest way to work with an output is using .apply
. It’ll allow you to apply an operation on the output and return a new output.
In this case, newUrl
is also an Output<string>
.
Helpers
To make it a little easier to work with outputs, we have the following global helper functions.
$concat
This let’s you do.
Instead of the apply.
Learn more about $concat
.
$interpolate
This let’s you do.
Instead of the apply.
Learn more about $interpolate
.
$jsonParse
This is for outputs that are JSON strings. So instead of doing this.
You can.
Learn more about $jsonParse
.
$jsonStringify
Similarly, for outputs that are JSON objects. Instead of doing a stringify after an apply.
You can.
Learn more about $jsonStringify
.
$resolve
And finally when you are working with a list of outputs and you want to resolve them all together.
Learn more about $resolve
.