Overview
StorageFactory creates S3 bucket resources with type-safe configurations. Every bucket comes from the single S3Bucket class. Different property combinations control the behaviour (private, website hosting, public read access).
For databases (Aurora, RDS, DynamoDB), use the DatabaseFactory instead.
Basic Usage
Bucket Configurations
Private Bucket (Default)
Standard bucket with no public access. Best for application assets, uploads and caches:App.getApp(name, { backup: { tier: "resilient" } }) (or "enterprise") is versioned by default, with a 30-day noncurrent-version expiry rule. A standard application, or one with no backup tier, leaves versioning off. Set versioned to override the tier in either direction, or backupVaultTier to give one bucket a different tier from the application.
Features:
- Private by default (block public access set to BLOCK_ALL)
- Versioning driven by the backup tier
- Optional encryption (AES256 or KMS)
Website Hosting Bucket
Configure a bucket for static website hosting with thewebsiteHosting property:
- Static website hosting enabled
- Configurable index and error documents (
errorDocumentdefaults toerror.html) - CORS support
Public Read Access Bucket
Grant public read access to all objects with thepublicReadAccess property:
- All objects publicly readable through a bucket policy
- Best for CDN origin buckets
- Optional versioning and encryption
Removal Policy
removalPolicy decides whether a bucket survives stack teardown. It is the highest-consequence property on the factory.
DESTROY bucket carries the fjall:sdk-pre-empty tag, so fjall destroy empties it before CloudFormation deletes the stack. Without that tag, a non-empty bucket blocks the delete.
Configuration Parameters
Common Patterns
Media Uploads
Store user-uploaded media. Aresilient or enterprise application versions the bucket through its tier. versioned: true pins versioning on whatever the application tier is:
Static Assets with Deployment
Upload static assets during CDK deployment:ISR Cache Bucket
Cache bucket for Next.js ISR:Website with CORS
Website bucket with CORS for API requests:allowedMethods accepts GET, PUT, POST, DELETE and HEAD. Any other value fails synth.
CDN Origin Bucket
Place a bucket in the CDN stack to avoid circular dependencies:KMS Encryption
bucketKeyEnabled: false to opt out. Omitting kmsKeyArn falls back to the AWS-managed key and raises a synth warning.
Bucket Policy Statements
Append statements to the bucket’s resource policy. Principals are either"*" or an IAM ARN:
Deploying Assets After Construction
The constructordeployment property uploads assets but cannot invalidate a CloudFront cache, because the distribution does not exist yet when the bucket is built. Call deployAssets(config, distribution?) after the CDN to get both:
/* after upload, so new assets serve immediately instead of waiting out the cache TTL.
A bucket deploys one asset set. Calling deployAssets when a deployment already exists (from the constructor deployment property or a prior call) throws rather than stacking a second BucketDeployment whose prune semantics would fight the first.
Accessing Bucket Information
<stackName><id>BucketArn and <stackName><id>BucketName.
Connecting to Compute Resources
Pass the storage construct in a compute resource’sconnections array. Fjall grants the IAM policy. Storage connections default to readWrite:
connections sits on the service, not on the compute props. On Lambda it sits at the top level.
connections handles IAM only. Pass the bucket name through environment when the application code needs it at runtime.
Granting Access
Grant access directly to any IAM grantable whenconnections is not the right fit:
grantPublicAccess writes a bucket policy, so it works only on a bucket created with publicReadAccess: true or websiteHosting. A private bucket blocks public policies.
Event Notifications
Security
Every bucket gets these without configuration:- TLS-only access: a deny statement rejects non-HTTPS requests
- Encryption: SSE-S3 applies by default. Set
encryptionto pin AES256 or KMS - Multipart hygiene: incomplete multipart uploads abort after 7 days, so abandoned parts stop accruing storage cost
- IAM policies: least-privilege grants from
connectionsand thegrant*methods
Block Public Access
A private bucket assertsBLOCK_ALL in the template rather than relying on the account default, so a manually loosened bucket is healed on the next deploy.
Setting publicReadAccess: true or websiteHosting opens the two policy halves (blockPublicPolicy and restrictPublicBuckets off) and keeps the two ACL halves closed (blockPublicAcls and ignorePublicAcls on). Public access is bucket-policy-based, because ACLs are disabled on modern buckets.
Best Practices
- Keep buckets private by default - Set
publicReadAccessorwebsiteHostingonly when a public endpoint is the requirement - Choose a backup tier that matches the data’s recovery needs - Override
versionedorbackupVaultTieronly for a single-bucket exception - Set
removalPolicy: "RETAIN"on any non-production bucket holding data you cannot re-create - Use KMS encryption for regulated or customer-sensitive data, and leave
bucketKeyEnabledon - Use
deploymentordeployAssetsfor static assets instead of a manual S3 sync - Set
stackPlacementto"cdn"when the bucket is a CloudFront origin
Next Steps
CDN Factory
Front a bucket with CloudFront
Compute Factory
Deploy Lambda and ECS compute resources
Database Factory
Create Aurora, RDS and DynamoDB databases
Static Site Pattern
Deploy a static site with bucket, CDN and DNS