Skip to main content

Overview

The StorageFactory creates S3 bucket resources with type-safe configurations. All buckets use the single S3Bucket class, with different property combinations controlling behaviour (private, website hosting, public read access).
For databases (Aurora, RDS, DynamoDB), use the DatabaseFactory instead.

Basic Usage

import { App, StorageFactory } from "@fjall/components-infrastructure";

const app = App.getApp("myapp");

const assets = app.addStorage(StorageFactory.build("Assets", {}));

Bucket Configurations

Private Bucket (Default)

Standard bucket with no public access. Best for application assets, uploads, and caches:
const assets = app.addStorage(
  StorageFactory.build("Assets", {
    versioned: true,
    encryption: "AES256",
  }),
);
Features:
  • Private by default (no public access)
  • Optional versioning
  • Optional encryption (AES256 or KMS)

Website Hosting Bucket

Configure a bucket for static website hosting using the websiteHosting property:
const site = app.addStorage(
  StorageFactory.build("StaticSite", {
    websiteHosting: {
      indexDocument: "index.html",
      errorDocument: "404.html",
    },
  }),
);
Features:
  • Static website hosting enabled
  • Configurable index and error documents
  • CORS support

Public Read Access Bucket

Enable public read access for all objects using the publicReadAccess property:
const publicAssets = app.addStorage(
  StorageFactory.build("PublicAssets", {
    publicReadAccess: true,
  }),
);
Features:
  • All objects publicly readable
  • Best for CDN origin buckets
  • Optional versioning and encryption

Configuration Parameters

ParameterTypeDescriptionDefault
versionedbooleanEnable versioningfalse
encryption"AES256" | "KMS"Encryption typeNone
kmsKeyArnstringKMS key ARN (if using KMS encryption)-
publicReadAccessbooleanAllow public read accessfalse
websiteHostingobjectWebsite hosting configuration-
websiteHosting.indexDocumentstringIndex document name"index.html"
websiteHosting.errorDocumentstringError document name-
corsarrayCORS rules-
stackPlacement"storage" | "cdn" | "compute"Which CDK stack to place the bucket in"storage"
backupVaultTierBackupTierAWS Backup tier (standard, resilient, enterprise)-
deploymentobjectAuto-deploy files from local path-

Common Patterns

Media Uploads

Store user-uploaded media with versioning:
const media = app.addStorage(
  StorageFactory.build("Media", {
    versioned: true,
    encryption: "AES256",
  }),
);

Static Assets with Deployment

Auto-deploy static assets during CDK deployment:
const assets = app.addStorage(
  StorageFactory.build("Assets", {
    deployment: {
      source: "./public/assets",
      prune: true,
      cacheControl: {
        maxAge: 31536000, // 1 year
        immutable: true,
      },
    },
  }),
);

ISR Cache Bucket

Cache bucket for Next.js ISR:
const cache = app.addStorage(StorageFactory.build("Cache", {}));

Website with CORS

Website bucket with CORS for API requests:
const site = app.addStorage(
  StorageFactory.build("Website", {
    websiteHosting: {
      indexDocument: "index.html",
      errorDocument: "error.html",
    },
    cors: [
      {
        allowedOrigins: ["https://api.example.com"],
        allowedMethods: ["GET", "HEAD"],
      },
    ],
  }),
);

CDN Origin Bucket

Place a bucket in the CDN stack to avoid circular dependencies:
const cdnAssets = app.addStorage(
  StorageFactory.build("CDNAssets", {
    stackPlacement: "cdn",
    encryption: "AES256",
  }),
);

KMS Encryption

const encrypted = app.addStorage(
  StorageFactory.build("Secure", {
    encryption: "KMS",
    kmsKeyArn: "arn:aws:kms:ap-southeast-2:123456789:key/abc-123",
  }),
);

Accessing Bucket Information

const storage = app.addStorage(StorageFactory.build("Assets", {}));

// Get bucket information
const name = storage.getBucketName();
const arn = storage.getBucketArn();
const domainName = storage.getBucketDomainName();

Connecting to Compute Resources

const assets = app.addStorage(StorageFactory.build("Assets", {}));

// Lambda with S3 access
const api = app.addCompute(
  ComputeFactory.build("Api", {
    type: "lambda",
    deployment: "code",
    handler: "api.handler",
  }),
);

// ECS with S3 access via environment variables
const service = app.addCompute(
  ComputeFactory.build("Service", {
    type: "ecs",
    services: [
      {
        name: "web",
        capacityProvider: "FARGATE",
        containers: [
          {
            port: 3000,
            environment: {
              ASSETS_BUCKET: assets.getBucketName(),
            },
          },
        ],
      },
    ],
  }),
);

Granting Access

const storage = app.addStorage(StorageFactory.build("Assets", {}));

// Grant read access
storage.grantRead(lambdaFunction);

// Grant write access
storage.grantWrite(lambdaFunction);

// Grant read/write access
storage.grantReadWrite(lambdaFunction);

// Grant public access to specific prefix
storage.grantPublicAccess("public/*");

Security

Automatic Security Features

  • Private by default: No public access unless explicitly configured
  • Encryption options: S3-managed (AES256) or customer-managed KMS keys
  • Block public access: Enabled by default on private buckets
  • IAM policies: Automatic least-privilege policies

Event Notifications

import { EventType } from "aws-cdk-lib/aws-s3";

const storage = app.addStorage(StorageFactory.build("Uploads", {}));

// Notify Lambda when objects are created
storage.addObjectCreatedNotification(lambdaDestination, {
  prefix: "uploads/",
  suffix: ".jpg",
});

// Custom event notification
storage.addEventNotification(EventType.OBJECT_REMOVED, sqsDestination, {
  prefix: "temp/",
});

Best Practices

  1. Keep buckets private by default - Only enable publicReadAccess or websiteHosting when needed
  2. Enable versioning for important data that may need recovery
  3. Use encryption for sensitive data
  4. Use deployment config for static assets instead of manual S3 sync
  5. Set stackPlacement to "cdn" when the bucket is used as a CloudFront origin

Next Steps

Database Factory

Create Aurora, RDS, and DynamoDB databases

Compute Factory

Deploy Lambda and ECS compute resources

Network Factory

Configure VPC and networking

Payload Pattern

Full-stack Payload CMS deployment