# DirectS3Read

The DirectS3Read configuration for an S3 Files filesystem mount.

Direct reads let Lambda read objects straight from the backing S3 bucket for
higher throughput, instead of routing every read through the file system mount.

Create one with a factory method:

- `DirectS3Read.enabled(bucket)` — turn direct reads on and grant the execution
  role read access to `bucket`.
- `DirectS3Read.enabledWithoutGrant()` — turn direct reads on but add no S3
  permissions; grant read access to the execution role yourself.
- `DirectS3Read.auto()` — let the service decide based on the function's memory.
- `DirectS3Read.disabled()` — always read through the mount.

- Source: [`aws-lambda/lib/filesystem.ts`](https://github.com/aws/aws-cdk/blob/v2.274.0/packages/aws-cdk-lib/aws-lambda/lib/filesystem.ts#L26)
- Type last changed: v2.270.0 · 17 Sep 2026

## Example

```ts
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as s3files from 'aws-cdk-lib/aws-s3files';

const vpc = new ec2.Vpc(this, 'Vpc');

// Versioning is required — S3 Files relies on object versions for consistency.
const bucket = new s3.Bucket(this, 'Bucket', { versioned: true });

// S3 Files assumes this role to sync data between S3 and the file system.
const role = new iam.Role(this, 'S3FilesRole', {
  assumedBy: new iam.ServicePrincipal('elasticfilesystem.amazonaws.com'),
});

// S3 permissions: read/write access to the bucket and objects
role.addToPolicy(new iam.PolicyStatement({
  actions: ['s3:ListBucket*'],
  resources: [bucket.bucketArn],
}));
role.addToPolicy(new iam.PolicyStatement({
  actions: ['s3:AbortMultipartUpload', 's3:DeleteObject', 's3:GetObject*', 's3:List*', 's3:PutObject*'],
  resources: [bucket.arnForObjects('*')],
}));

// EventBridge permissions: S3 Files creates rules prefixed "DO-NOT-DELETE-S3-Files"
// to detect S3 object changes and trigger data synchronization.
role.addToPolicy(new iam.PolicyStatement({
  actions: [
    'events:DeleteRule', 'events:DisableRule', 'events:EnableRule',
    'events:PutRule', 'events:PutTargets', 'events:RemoveTargets',
  ],
  resources: [`arn:${cdk.Aws.PARTITION}:events:*:*:rule/DO-NOT-DELETE-S3-Files*`],
  conditions: { StringEquals: { 'events:ManagedBy': 'elasticfilesystem.amazonaws.com' } },
}));
role.addToPolicy(new iam.PolicyStatement({
  actions: ['events:DescribeRule', 'events:ListRuleNamesByTarget', 'events:ListRules', 'events:ListTargetsByRule'],
  resources: [`arn:${cdk.Aws.PARTITION}:events:*:*:rule/*`],
}));

const fileSystem = new s3files.CfnFileSystem(this, 'S3FilesFs', {
  bucket: bucket.bucketArn,
  roleArn: role.roleArn,
});

const sg = new ec2.SecurityGroup(this, 'MountTargetSG', { vpc });

// Create a mount target in each private subnet so Lambda can reach the file system via NFS.
vpc.privateSubnets.forEach((subnet, i) =>
  new s3files.CfnMountTarget(this, `MountTarget${i}`, {
    fileSystemId: fileSystem.attrFileSystemId,
    subnetId: subnet.subnetId,
    securityGroups: [sg.securityGroupId],
  }),
);

// The access point defines the POSIX identity and root path Lambda uses on the file system.
const accessPoint = new s3files.CfnAccessPoint(this, 'AccessPoint', {
  fileSystemId: fileSystem.attrFileSystemId,
  rootDirectory: {
    path: '/export/lambda',
    creationPermissions: { ownerGid: '1001', ownerUid: '1001', permissions: '750' },
  },
  posixUser: { gid: '1001', uid: '1001' },
});

const fn = new lambda.Function(this, 'MyFunction', {
  runtime: lambda.Runtime.NODEJS_LATEST,
  handler: 'index.handler',
  code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')),
  vpc,
  filesystem: lambda.FileSystem.fromS3FilesAccessPoint(accessPoint, '/mnt/s3files', {
    // Enables direct reads and grants s3:GetObject/s3:GetObjectVersion on the bucket to the execution role.
    directS3Read: lambda.DirectS3Read.enabled(bucket),
  }),
});
```

## Methods

- `auto(): DirectS3Read // chainable` (static) — Let the service decide whether to use direct S3 read based on the function's memory configuration: direct reads are active for functions with 512 MB or more of memory.

  No S3 read permissions are added; the execution role must already hold them for a
  service-initiated direct read to succeed, otherwise reads fall back to the mount.

- `disabled(): DirectS3Read // chainable` (static) — Disable direct S3 read;

  all reads are routed through the S3 Files file system's
  high-performance storage.

- `enabled(bucket: IBucket): DirectS3Read // chainable` (static) — Enable direct S3 reads, bypassing the mount for higher throughput, and grant the function's execution role `s3:GetObject` and `s3:GetObjectVersion` on the bucket's objects so that direct reads can succeed.

  Unlike `auto()`, this enables direct reads regardless of the function's memory size,
  including functions with less than 512 MB of memory.

  If the bucket is encrypted with a customer-managed KMS key, also grant the execution
  role `kms:Decrypt` on that key yourself.

  **Parameters**

  - `bucket` — the S3 bucket backing the S3 Files file system.

- `enabledWithoutGrant(): DirectS3Read // chainable` (static) — Enable direct S3 reads, bypassing the mount for higher throughput, without adding any S3 read permissions.

  Like `enabled()`, this enables direct reads regardless of the function's memory size,
  including functions with less than 512 MB of memory.

  Use this when the execution role already has `s3:GetObject`/`s3:GetObjectVersion` on the
  backing bucket (for example through a managed policy or a bucket policy). You are
  responsible for granting those permissions; without them, direct reads silently fall
  back to reading through the file system.
