Skip to content
GitHub Discord

Bucket

The Bucket component lets you add an AWS S3 Bucket to your app.

Minimal example

sst.config.ts
const bucket = new sst.aws.Bucket("MyBucket");

Public read access

Enable public read access for all the files in the bucket. Useful for hosting public files.

sst.config.ts
new sst.aws.Bucket("MyBucket", {
access: "public"
});

Add a subscriber

sst.config.ts
bucket.notify({
notifications: [
{
name: "MySubscriber",
function: "src/subscriber.handler"
}
]
});

You can link the bucket to other resources, like a function or your Next.js app.

sst.config.ts
new sst.aws.Nextjs("MyWeb", {
link: [bucket]
});

Once linked, you can generate a pre-signed URL to upload files in your app.

app/page.tsx
import { Resource } from "sst";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
const command = new PutObjectCommand({
Key: "file.txt",
Bucket: Resource.MyBucket.name
});
await getSignedUrl(new S3Client({}), command);

Constructor

new Bucket(name, args?, opts?)

Parameters

BucketArgs

access?

Type Input<“public” | “cloudfront”>

Enable public read access for all the files in the bucket. By default, no access is granted.

This adds a statement to the bucket policy that either allows public access or just cloudfront access. With cloudfront, only CloudFront distributions in the same AWS account can read the bucket.

{
access: "public"
}

To let the distributions of another AWS account read a cloudfront bucket, add a statement with the policy option. In the GovCloud and China partitions, start the ARN with arn:aws-us-gov: or arn:aws-cn: instead of arn:aws:.

{
access: "cloudfront",
policy: [
{
effect: "allow",
principals: [{ type: "service", identifiers: ["cloudfront.amazonaws.com"] }],
actions: ["s3:GetObject"],
paths: ["*"],
conditions: [
{
test: "StringLike",
variable: "aws:SourceArn",
values: ["arn:aws:cloudfront::OTHER_ACCOUNT_ID:distribution/*"]
}
]
}
]
}

cors?

Type Input<false | Object>

Default true

The CORS configuration for the bucket. Defaults to true, which is the same as:

{
cors: {
allowHeaders: ["*"],
allowOrigins: ["*"],
allowMethods: ["DELETE", "GET", "HEAD", "POST", "PUT"],
exposeHeaders: ["ETag"],
maxAge: "0 seconds"
}
}

cors.allowHeaders?

Type Input<Input<string>[]>

Default [”*”]

The HTTP headers that origins can include in requests to the bucket.

{
cors: {
allowHeaders: ["date", "keep-alive", "x-custom-header"]
}
}

cors.allowMethods?

Type Input<Input<“GET” | “POST” | “PUT” | “DELETE” | “HEAD”>[]>

Default [“DELETE” | “GET” | “HEAD” | “POST” | “PUT”]

The HTTP methods that are allowed when calling the bucket.

{
cors: {
allowMethods: ["GET", "POST", "DELETE"]
}
}

cors.allowOrigins?

Type Input<Input<string>[]>

Default [”*”]

The origins that can access the bucket.

{
cors: {
allowOrigins: ["https://www.example.com", "http://localhost:60905"]
}
}

Or the wildcard for all origins.

{
cors: {
allowOrigins: ["*"]
}
}

cors.exposeHeaders?

Type Input<Input<string>[]>

Default [“ETag”]

The HTTP headers you want to expose to an origin that calls the bucket.

{
cors: {
exposeHeaders: ["date", "keep-alive", "x-custom-header"]
}
}

cors.maxAge?

Type Input<“${number} minute” | “${number} minutes” | “${number} hour” | “${number} hours” | “${number} second” | “${number} seconds” | “${number} day” | “${number} days”>

Default “0 seconds”

The maximum amount of time the browser can cache results of a preflight request. By default the browser doesn’t cache the results. The maximum value is 86400 seconds or 1 day.

{
cors: {
maxAge: "1 day"
}
}

enforceHttps?

Type Input<boolean>

Default true

Enforce HTTPS for all requests to the bucket.

By default, the bucket policy will automatically block any HTTP requests. This is done using the aws:SecureTransport condition key.

{
enforceHttps: false
}

lifecycle?

Type Input<Input<Object>[]>

The lifecycle configuration for the bucket.

Delete objects in the “/tmp” directory after 30 days.

{
lifecycle: [
{
prefix: "/tmp",
expiresIn: "30 days"
}
]
}

Use stable IDs to preserve rule identity when reordering.

{
lifecycle: [
{
id: "expire-tmp-files",
prefix: "/tmp",
expiresIn: "7 days"
},
{
id: "archive-old-logs",
prefix: "/logs",
expiresIn: "90 days"
}
]
}

lifecycle[].enabled?

Type Input<boolean>

Default true

Whether the lifecycle rule is enabled.

{
enabled: true
}

lifecycle[].expiresAt?

Type Input<string>

Date after which the objects in the bucket should expire. Defaults to midnight UTC time.

{
expiresAt: "2023-08-22"
}

lifecycle[].expiresIn?

Type Input<“${number} day” | “${number} days”>

Days after which the objects in the bucket should expire.

{
expiresIn: "30 days"
}

lifecycle[].id?

Type Input<string>

The unique identifier for the lifecycle rule.

This ID must be unique across all lifecycle rules in the bucket and cannot exceed 255 characters. Whitespace-only values are not allowed.

If not provided, SST will generate a unique ID based on the bucket component name and rule index.

Use stable IDs to ensure rule identity is preserved when reordering rules.

{
id: "expire-tmp-files",
prefix: "/tmp",
expiresIn: "7 days"
}

lifecycle[].prefix?

Type Input<string>

An S3 object key prefix that the lifecycle rule applies to.

Applies to all the objects in the images/ folder.

{
prefix: "images/"
}

policy?

Type Input<Input<Object>[]>

Configure the policy for the bucket.

Restrict Access to Specific IP Addresses

{
policy: [{
actions: ["s3:*"],
principals: "*",
conditions: [
{
test: "IpAddress",
variable: "aws:SourceIp",
values: ["10.0.0.0/16"]
}
]
}]
}

Allow Specific IAM User Access

{
policy: [{
actions: ["s3:*"],
principals: [{
type: "aws",
identifiers: ["arn:aws:iam::123456789012:user/specific-user"]
}],
}]
}

Cross-Account Access

{
policy: [{
actions: ["s3:GetObject", "s3:ListBucket"],
principals: [{
type: "aws",
identifiers: ["123456789012"]
}],
}]
}

policy[].actions

Type Input<Input<string>[]>

The IAM actions that can be performed.

{
actions: ["s3:*"]
}

policy[].conditions?

Type Input<Input<Object>[]>

Configure specific conditions for when the policy is in effect.

{
conditions: [
{
test: "StringEquals",
variable: "s3:x-amz-server-side-encryption",
values: ["AES256"]
}
]
}
policy[].conditions[].test

Type Input<string>

Name of the IAM condition operator to evaluate.

policy[].conditions[].values

Type Input<Input<string>[]>

The values to evaluate the condition against. If multiple values are provided, the condition matches if at least one of them applies. That is, AWS evaluates multiple values as though using an “OR” boolean operation.

policy[].conditions[].variable

Type Input<string>

Name of a Context Variable to apply the condition to. Context variables may either be standard AWS variables starting with aws: or service-specific variables prefixed with the service name.

policy[].effect?

Type Input<“allow” | “deny”>

Default “allow”

Configures whether the permission is allowed or denied.

{
effect: "deny"
}

policy[].paths?

Type Input<Input<string>[]>

Default ["", ”*”]

The S3 file paths that the policy is applied to. The paths are specified using the S3 path format. The bucket arn will be prepended to the paths when constructing the policy.

Apply the policy to the bucket itself.

{
paths: [""]
}

Apply to all files in the bucket.

{
paths: ["*"]
}

Apply to all files in the images/ folder.

{
paths: ["images/*"]
}

policy[].principals

Type Input<“*” | Input<Object>[]>

The principals that can perform the actions.

Allow anyone to perform the actions.

{
principals: "*"
}

Allow anyone within an AWS account.

{
principals: [{ type: "aws", identifiers: ["123456789012"] }]
}

Allow specific IAM roles.

{
principals: [{
type: "aws",
identifiers: [
"arn:aws:iam::123456789012:role/MyRole",
"arn:aws:iam::123456789012:role/MyOtherRole"
]
}]
}

Allow AWS CloudFront.

{
principals: [{ type: "service", identifiers: ["cloudfront.amazonaws.com"] }]
}

Allow OIDC federated users.

{
principals: [{
type: "federated",
identifiers: ["accounts.google.com"]
}]
}

Allow SAML federated users.

{
principals: [{
type: "federated",
identifiers: ["arn:aws:iam::123456789012:saml-provider/provider-name"]
}]
}

Allow Canonical User IDs.

{
principals: [{
type: "canonical",
identifiers: ["79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be"]
}]
}

Allow specific IAM users.

policy[].principals[].identifiers

Type Input<Input<string>[]>

policy[].principals[].type

Type Input<“aws” | “service” | “federated” | “canonical”>

transform?

Type Object

Transform how this component creates its underlying resources.

transform.bucket?

Type BucketArgs | (args: BucketArgs, opts: ComponentResourceOptions, name: string) => void

Transform the S3 Bucket resource.

transform.cors?

Type BucketCorsConfigurationArgs | (args: BucketCorsConfigurationArgs, opts: ComponentResourceOptions, name: string) => void

Transform the S3 Bucket CORS configuration resource.

transform.lifecycle?

Type BucketLifecycleConfigurationArgs | (args: BucketLifecycleConfigurationArgs, opts: ComponentResourceOptions, name: string) => void

Transform the S3 Bucket lifecycle resource.

transform.policy?

Type BucketPolicyArgs | (args: BucketPolicyArgs, opts: ComponentResourceOptions, name: string) => void

Transform the S3 Bucket Policy resource.

transform.publicAccessBlock?

Type false | BucketPublicAccessBlockArgs | (args: BucketPublicAccessBlockArgs, opts: ComponentResourceOptions, name: string) => void

Transform the public access block resource that’s attached to the Bucket.

Returns false if the public access block resource should not be created.

transform.versioning?

Type BucketVersioningArgs | (args: BucketVersioningArgs, opts: ComponentResourceOptions, name: string) => void

Transform the S3 Bucket versioning resource.

versioning?

Type Input<boolean>

Default false

Enable versioning for the bucket.

Bucket versioning enables you to store multiple versions of an object, protecting against accidental deletion or overwriting.

{
versioning: true
}

Properties

arn

Type Output<string>

The ARN of the S3 Bucket.

domain

Type Output<string>

The domain name of the bucket. Has the format ${bucketName}.s3.amazonaws.com.

name

Type Output<string>

The generated name of the S3 Bucket.

nodes

Type Object

The underlying resources this component creates.

nodes.bucket

Type Output<Bucket>

The Amazon S3 bucket.

SDK

Use the SDK in your runtime to interact with your infrastructure.


This is accessible through the Resource object in the SDK.

  • name string

    The generated name of the S3 Bucket.

Methods

notify

notify(args)

Parameters

Returns BucketNotification

Subscribe to event notifications from this bucket. You can subscribe to these notifications with a function, a queue, or a topic.

For exmaple, to notify a function:

sst.config.ts
bucket.notify({
notifications: [
{
name: "MySubscriber",
function: "src/subscriber.handler"
}
]
});

Or let’s say you have a queue.

sst.config.ts
const myQueue = new sst.aws.Queue("MyQueue");

You can notify it by passing in the queue.

sst.config.ts
bucket.notify({
notifications: [
{
name: "MySubscriber",
queue: myQueue
}
]
});

Or let’s say you have a topic.

sst.config.ts
const myTopic = new sst.aws.SnsTopic("MyTopic");

You can notify it by passing in the topic.

sst.config.ts
bucket.notify({
notifications: [
{
name: "MySubscriber",
topic: myTopic
}
]
});

Or enable EventBridge notifications for this bucket. This publishes S3 events to the account’s default EventBridge bus.

sst.config.ts
bucket.notify({
eventBridge: true
});

You can also set it to only send notifications for specific S3 events.

bucket.notify({
notifications: [
{
name: "MySubscriber",
function: "src/subscriber.handler",
events: ["s3:ObjectCreated:*", "s3:ObjectRemoved:*"]
}
]
});

And you can add filters to be only notified from specific files in the bucket.

bucket.notify({
notifications: [
{
name: "MySubscriber",
function: "src/subscriber.handler",
filterPrefix: "images/"
}
]
});

static get

Bucket.get(name, bucketName, opts?)

Parameters

  • name string

    The name of the component.
  • bucketName string

    The name of the existing S3 Bucket.
  • opts? ComponentResourceOptions

    Resource options.

Returns Bucket

Reference an existing bucket with the given bucket name. This is useful when you create a bucket in one stage and want to share it in another stage. It avoids having to create a new bucket in the other stage.

Imagine you create a bucket in the dev stage. And in your personal stage frank, instead of creating a new bucket, you want to share the bucket from dev.

sst.config.ts
const bucket = $app.stage === "frank"
? sst.aws.Bucket.get("MyBucket", "app-dev-mybucket-12345678")
: new sst.aws.Bucket("MyBucket");

Here app-dev-mybucket-12345678 is the auto-generated bucket name for the bucket created in the dev stage. You can find this by outputting the bucket name in the dev stage.

sst.config.ts
return {
bucket: bucket.name
};

static subscribeEventBridge

Bucket.subscribeEventBridge(name, bucketName, subscriber, args?)

Parameters

  • name string

    The name of the subscription.
  • bucketName Input<string>

    The name of the S3 bucket to subscribe to.
  • subscriber Input<string | FunctionArgs | “arn:aws:lambda:${string}” | Function | Workflow>

    The function that’ll be notified.
  • args? BucketEventBridgeSubscriberArgs

    Configure the subscription.

Returns Output<BusLambdaSubscriber>

Subscribe to S3 EventBridge notifications from a bucket with a function. The bucket is given by name, so it can be one that SST doesn’t manage.

This creates an EventBridge rule on the account’s default bus, and a target for it, only. The rule matches the events of that one bucket. The bucket has to publish to EventBridge for it to receive anything: for a bucket in your app, that’s notify({ eventBridge: true }); for any other bucket, turn it on there.

sst.config.ts
sst.aws.Bucket.subscribeEventBridge("Uploads", "my-bucket", "src/subscriber.handler", {
pattern: {
detailType: ["Object Created"],
detail: {
object: {
key: [{ prefix: "uploads/" }]
}
}
}
});

BucketEventBridgeSubscriberArgs

enabled?

Type Input<boolean>

Default true

Configures whether the subscriber is enabled. When disabled, the EventBridge rule is still created, but it won’t receive events.

{
enabled: false
}

pattern?

Type Input<Object>

Filter the S3 events that’ll be processed by the subscriber. The source and bucket name are automatically added to the EventBridge pattern.

pattern.detail?

Type Record<string, any>

An object of detail values to match.

{
detail: {
object: {
key: [{ prefix: "images/" }]
}
}
}

pattern.detailType?

Type Input<Input<string>[]>

A list of detail-type values to match against. These are the names of the S3 events: Object Created, Object Deleted, Object Restore Initiated, Object Restore Completed, Object Restore Expired, Object Tags Added, Object Tags Deleted, Object ACL Updated, Object Storage Class Changed, Object Access Tier Changed and Async Copy Completion. Leave it out to match all of them.

{
detailType: ["Object Created"]
}

transform?

Type Object

Transform how this subscription creates its underlying resources.

transform.rule?

Type EventRuleArgs | (args: EventRuleArgs, opts: ComponentResourceOptions, name: string) => void

Transform the EventBus rule resource.

transform.target?

Type EventTargetArgs | (args: EventTargetArgs, opts: ComponentResourceOptions, name: string) => void

Transform the EventBus target resource.

BucketNotificationsArgs

eventBridge?

Type Input<boolean>

Default false

Enable EventBridge notifications for this bucket. This publishes every S3 event of the bucket to the account’s default EventBridge bus. It doesn’t send them anywhere by itself: add rules with Bucket.subscribeEventBridge, or your own rules on the default bus, to react to them.

S3 keeps a single notification configuration for each bucket. To use EventBridge together with the queue, topic and function notifications below, set it in the same notify call. Calling notify again would replace what was set before, so it isn’t allowed.

Set it to false to turn EventBridge notifications off.

{
eventBridge: true,
notifications: [
{
name: "MySubscriber",
queue: myQueue
}
]
}

notifications?

Type Input<Input<Object>[]>

A list of subscribers that’ll be notified when events happen in the bucket. Leave it out if the bucket only uses eventBridge.

notifications[].events?

Type Input<Input<“s3:ObjectCreated:*” | “s3:ObjectCreated:Put” | “s3:ObjectCreated:Post” | “s3:ObjectCreated:Copy” | “s3:ObjectCreated:CompleteMultipartUpload” | “s3:ObjectRemoved:*” | “s3:ObjectRemoved:Delete” | “s3:ObjectRemoved:DeleteMarkerCreated” | “s3:ObjectRestore:*” | “s3:ObjectRestore:Post” | “s3:ObjectRestore:Completed” | “s3:ObjectRestore:Delete” | “s3:ReducedRedundancyLostObject” | “s3:Replication:*” | “s3:Replication:OperationFailedReplication” | “s3:Replication:OperationMissedThreshold” | “s3:Replication:OperationReplicatedAfterThreshold” | “s3:Replication:OperationNotTracked” | “s3:LifecycleExpiration:*” | “s3:LifecycleExpiration:Delete” | “s3:LifecycleExpiration:DeleteMarkerCreated” | “s3:LifecycleTransition” | “s3:IntelligentTiering” | “s3:ObjectTagging:*” | “s3:ObjectTagging:Put” | “s3:ObjectTagging:Delete” | “s3:ObjectAcl:Put”>[]>

Default All S3 events

A list of S3 event types that’ll trigger a notification.

{
events: ["s3:ObjectCreated:*", "s3:ObjectRemoved:*"]
}

notifications[].filterPrefix?

Type Input<string>

An S3 object key prefix that will trigger a notification.

To be notified for all the objects in the images/ folder.

{
filterPrefix: "images/"
}

notifications[].filterSuffix?

Type Input<string>

An S3 object key suffix that will trigger the notification.

To be notified for all the objects with the .jpg suffix.

{
filterSuffix: ".jpg"
}

notifications[].function?

Type Input<string | FunctionArgs | “arn:aws:lambda:${string}”>

The function that’ll be notified.

{
name: "MySubscriber",
function: "src/subscriber.handler"
}

Customize the subscriber function. The link ensures the subscriber can access the bucket through the SDK.

{
name: "MySubscriber",
function: {
handler: "src/subscriber.handler",
timeout: "60 seconds",
link: [bucket]
}
}

Or pass in the ARN of an existing Lambda function.

{
name: "MySubscriber",
function: "arn:aws:lambda:us-east-1:123456789012:function:my-function"
}

notifications[].name

Type Input<string>

The name of the subscriber.

notifications[].queue?

Type Input<string | Queue>

The Queue that’ll be notified.

For example, let’s say you have a queue.

sst.config.ts
const myQueue = new sst.aws.Queue("MyQueue");

You can subscribe to this bucket with it.

{
name: "MySubscriber",
queue: myQueue
}

Or pass in the ARN of an existing SQS queue.

{
name: "MySubscriber",
queue: "arn:aws:sqs:us-east-1:123456789012:my-queue"
}

notifications[].topic?

Type Input<string | SnsTopic>

The SNS topic that’ll be notified.

For example, let’s say you have a topic.

sst.config.ts
const myTopic = new sst.aws.SnsTopic("MyTopic");

You can subscribe to this bucket with it.

{
name: "MySubscriber",
topic: myTopic
}

Or pass in the ARN of an existing SNS topic.

{
name: "MySubscriber",
topic: "arn:aws:sns:us-east-1:123456789012:my-topic"
}

transform?

Type Object

Transform how this notification creates its underlying resources.

transform.notification?

Type BucketNotificationArgs | (args: BucketNotificationArgs, opts: ComponentResourceOptions, name: string) => void

Transform the S3 Bucket Notification resource.