Configure AWS S3 Bucket Metrics

The aws:s3/bucketMetric:BucketMetric resource, part of the Pulumi AWS provider, defines CloudWatch metrics configurations that track request and data transfer activity for S3 buckets. This guide focuses on three capabilities: bucket-wide metrics, prefix and tag filtering, and Access Point filtering.

Metrics configurations reference existing S3 buckets and optionally Access Points. The examples are intentionally small. Combine them with your own bucket infrastructure and monitoring dashboards.

Track metrics for all objects in a bucket

CloudWatch metrics for S3 provide visibility into request rates, data transfer, and error counts across the entire bucket.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.s3.Bucket("example", {bucket: "example"});
const example_entire_bucket = new aws.s3.BucketMetric("example-entire-bucket", {
    bucket: example.id,
    name: "EntireBucket",
});
import pulumi
import pulumi_aws as aws

example = aws.s3.Bucket("example", bucket="example")
example_entire_bucket = aws.s3.BucketMetric("example-entire-bucket",
    bucket=example.id,
    name="EntireBucket")
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/s3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		example, err := s3.NewBucket(ctx, "example", &s3.BucketArgs{
			Bucket: pulumi.String("example"),
		})
		if err != nil {
			return err
		}
		_, err = s3.NewBucketMetric(ctx, "example-entire-bucket", &s3.BucketMetricArgs{
			Bucket: example.ID(),
			Name:   pulumi.String("EntireBucket"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.S3.Bucket("example", new()
    {
        BucketName = "example",
    });

    var example_entire_bucket = new Aws.S3.BucketMetric("example-entire-bucket", new()
    {
        Bucket = example.Id,
        Name = "EntireBucket",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.s3.Bucket;
import com.pulumi.aws.s3.BucketArgs;
import com.pulumi.aws.s3.BucketMetric;
import com.pulumi.aws.s3.BucketMetricArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new Bucket("example", BucketArgs.builder()
            .bucket("example")
            .build());

        var example_entire_bucket = new BucketMetric("example-entire-bucket", BucketMetricArgs.builder()
            .bucket(example.id())
            .name("EntireBucket")
            .build());

    }
}
resources:
  example:
    type: aws:s3:Bucket
    properties:
      bucket: example
  example-entire-bucket:
    type: aws:s3:BucketMetric
    properties:
      bucket: ${example.id}
      name: EntireBucket

The bucket property references the S3 bucket to monitor. The name property creates a unique identifier for this metrics configuration (up to 64 characters). Without a filter, CloudWatch tracks all objects in the bucket.

Track metrics for objects matching prefix and tags

Large buckets often contain multiple workloads. Filtered metrics let you monitor specific subsets by path and metadata.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.s3.Bucket("example", {bucket: "example"});
const example_filtered = new aws.s3.BucketMetric("example-filtered", {
    bucket: example.id,
    name: "ImportantBlueDocuments",
    filter: {
        prefix: "documents/",
        tags: {
            priority: "high",
            "class": "blue",
        },
    },
});
import pulumi
import pulumi_aws as aws

example = aws.s3.Bucket("example", bucket="example")
example_filtered = aws.s3.BucketMetric("example-filtered",
    bucket=example.id,
    name="ImportantBlueDocuments",
    filter={
        "prefix": "documents/",
        "tags": {
            "priority": "high",
            "class": "blue",
        },
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/s3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		example, err := s3.NewBucket(ctx, "example", &s3.BucketArgs{
			Bucket: pulumi.String("example"),
		})
		if err != nil {
			return err
		}
		_, err = s3.NewBucketMetric(ctx, "example-filtered", &s3.BucketMetricArgs{
			Bucket: example.ID(),
			Name:   pulumi.String("ImportantBlueDocuments"),
			Filter: &s3.BucketMetricFilterArgs{
				Prefix: pulumi.String("documents/"),
				Tags: pulumi.StringMap{
					"priority": pulumi.String("high"),
					"class":    pulumi.String("blue"),
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.S3.Bucket("example", new()
    {
        BucketName = "example",
    });

    var example_filtered = new Aws.S3.BucketMetric("example-filtered", new()
    {
        Bucket = example.Id,
        Name = "ImportantBlueDocuments",
        Filter = new Aws.S3.Inputs.BucketMetricFilterArgs
        {
            Prefix = "documents/",
            Tags = 
            {
                { "priority", "high" },
                { "class", "blue" },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.s3.Bucket;
import com.pulumi.aws.s3.BucketArgs;
import com.pulumi.aws.s3.BucketMetric;
import com.pulumi.aws.s3.BucketMetricArgs;
import com.pulumi.aws.s3.inputs.BucketMetricFilterArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new Bucket("example", BucketArgs.builder()
            .bucket("example")
            .build());

        var example_filtered = new BucketMetric("example-filtered", BucketMetricArgs.builder()
            .bucket(example.id())
            .name("ImportantBlueDocuments")
            .filter(BucketMetricFilterArgs.builder()
                .prefix("documents/")
                .tags(Map.ofEntries(
                    Map.entry("priority", "high"),
                    Map.entry("class", "blue")
                ))
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:s3:Bucket
    properties:
      bucket: example
  example-filtered:
    type: aws:s3:BucketMetric
    properties:
      bucket: ${example.id}
      name: ImportantBlueDocuments
      filter:
        prefix: documents/
        tags:
          priority: high
          class: blue

The filter property narrows metrics to objects matching criteria. The prefix limits tracking to objects under a specific path. The tags property further filters by object metadata, requiring both conditions to match. This configuration tracks only high-priority blue documents in the documents/ path.

Track metrics for objects accessed through an Access Point

S3 Access Points provide named network endpoints with specific permissions. Metrics filtered by Access Point show activity through that endpoint.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.s3.Bucket("example", {bucket: "example"});
const example_access_point = new aws.s3.AccessPoint("example-access-point", {
    bucket: example.id,
    name: "example-access-point",
});
const example_filtered = new aws.s3.BucketMetric("example-filtered", {
    bucket: example.id,
    name: "ImportantBlueDocuments",
    filter: {
        accessPoint: example_access_point.arn,
        tags: {
            priority: "high",
            "class": "blue",
        },
    },
});
import pulumi
import pulumi_aws as aws

example = aws.s3.Bucket("example", bucket="example")
example_access_point = aws.s3.AccessPoint("example-access-point",
    bucket=example.id,
    name="example-access-point")
example_filtered = aws.s3.BucketMetric("example-filtered",
    bucket=example.id,
    name="ImportantBlueDocuments",
    filter={
        "access_point": example_access_point.arn,
        "tags": {
            "priority": "high",
            "class": "blue",
        },
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/s3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		example, err := s3.NewBucket(ctx, "example", &s3.BucketArgs{
			Bucket: pulumi.String("example"),
		})
		if err != nil {
			return err
		}
		example_access_point, err := s3.NewAccessPoint(ctx, "example-access-point", &s3.AccessPointArgs{
			Bucket: example.ID(),
			Name:   pulumi.String("example-access-point"),
		})
		if err != nil {
			return err
		}
		_, err = s3.NewBucketMetric(ctx, "example-filtered", &s3.BucketMetricArgs{
			Bucket: example.ID(),
			Name:   pulumi.String("ImportantBlueDocuments"),
			Filter: &s3.BucketMetricFilterArgs{
				AccessPoint: example_access_point.Arn,
				Tags: pulumi.StringMap{
					"priority": pulumi.String("high"),
					"class":    pulumi.String("blue"),
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.S3.Bucket("example", new()
    {
        BucketName = "example",
    });

    var example_access_point = new Aws.S3.AccessPoint("example-access-point", new()
    {
        Bucket = example.Id,
        Name = "example-access-point",
    });

    var example_filtered = new Aws.S3.BucketMetric("example-filtered", new()
    {
        Bucket = example.Id,
        Name = "ImportantBlueDocuments",
        Filter = new Aws.S3.Inputs.BucketMetricFilterArgs
        {
            AccessPoint = example_access_point.Arn,
            Tags = 
            {
                { "priority", "high" },
                { "class", "blue" },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.s3.Bucket;
import com.pulumi.aws.s3.BucketArgs;
import com.pulumi.aws.s3.AccessPoint;
import com.pulumi.aws.s3.AccessPointArgs;
import com.pulumi.aws.s3.BucketMetric;
import com.pulumi.aws.s3.BucketMetricArgs;
import com.pulumi.aws.s3.inputs.BucketMetricFilterArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new Bucket("example", BucketArgs.builder()
            .bucket("example")
            .build());

        var example_access_point = new AccessPoint("example-access-point", AccessPointArgs.builder()
            .bucket(example.id())
            .name("example-access-point")
            .build());

        var example_filtered = new BucketMetric("example-filtered", BucketMetricArgs.builder()
            .bucket(example.id())
            .name("ImportantBlueDocuments")
            .filter(BucketMetricFilterArgs.builder()
                .accessPoint(example_access_point.arn())
                .tags(Map.ofEntries(
                    Map.entry("priority", "high"),
                    Map.entry("class", "blue")
                ))
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:s3:Bucket
    properties:
      bucket: example
  example-access-point:
    type: aws:s3:AccessPoint
    properties:
      bucket: ${example.id}
      name: example-access-point
  example-filtered:
    type: aws:s3:BucketMetric
    properties:
      bucket: ${example.id}
      name: ImportantBlueDocuments
      filter:
        accessPoint: ${["example-access-point"].arn}
        tags:
          priority: high
          class: blue

The filter.accessPoint property tracks requests through a specific Access Point by ARN. This isolates metrics for traffic using that endpoint’s permissions and policies, separate from direct bucket access or other Access Points.

Beyond these examples

These snippets focus on specific metrics configuration features: bucket-wide and filtered metrics, prefix and tag-based filtering, and Access Point filtering. They’re intentionally minimal rather than full monitoring solutions.

The examples reference pre-existing infrastructure such as S3 buckets and Access Points (for Access Point filtering). They focus on configuring metrics rather than provisioning the underlying storage.

To keep things focused, common metrics patterns are omitted, including:

  • Multiple metrics configurations per bucket
  • Region-specific configuration (region property)
  • Metrics configuration lifecycle management

These omissions are intentional: the goal is to illustrate how each metrics feature is wired, not provide drop-in monitoring modules. See the S3 BucketMetric resource reference for all available configuration options.

Let's configure AWS S3 Bucket Metrics

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Configuration & Setup
What's a bucket metric configuration?
A bucket metric configuration enables CloudWatch request metrics for an S3 bucket, allowing you to monitor storage and request patterns.
How do I monitor my entire bucket vs specific objects?
Omit the filter property to monitor the entire bucket. To monitor specific objects, add a filter with prefix, tags, or both.
Filtering & Scope
What filtering options are available for metrics?
You can filter by prefix (object key prefix), tags (object tags), accessPoint (Access Point ARN), or a logical AND of prefix and tags.
Can I filter metrics by S3 Access Point?
Yes, use the accessPoint field in the filter with the Access Point ARN, optionally combined with tags.
Limitations & Constraints
Can I use this with S3 directory buckets?
No, this resource cannot be used with S3 directory buckets. Use standard S3 buckets only.
What properties can't I change after creation?
The bucket and name properties are immutable. Changing either requires replacing the resource.
What's the maximum length for the metric configuration name?
The name must be 64 characters or less.

Using a different cloud?

Explore monitoring guides for other cloud providers: