Grants
How Anvil wires permissions between resources.
Instead of writing IAM policies by hand, you call a grant* method on a resource (or
lists the same actions in a Lambda's permissions in Go) and Anvil creates the scoped IAM role policy for you. Each
resource type exposes the specific grants that make sense for it — there's no single generic .grant() — for example Bucket has grantRead, grantWrite, grantReadWrite, grantDelete, and grantFullAccess.
import { App } from '@anvil-cloud/sdk';
import * as anvil from '@anvil-cloud/sdk';
export default new App({
run(ctx) {
const bucket = new anvil.aws.Bucket('uploads');
const fn = new anvil.aws.Lambda('processor', {
runtime: 'nodejs24.x',
handler: 'functions/processor/index.handler',
environment: {
BUCKET_NAME: bucket.bucketName,
},
});
// Scopes the IAM policy to GetObject/ListBucket on uploads/* only.
bucket.grantRead(fn, ['uploads/*']);
},
});def infra(ctx: anvil.Context):
bucket = anvil.aws.Bucket("uploads")
fn = anvil.aws.Lambda("processor",
runtime="nodejs24.x",
handler="functions/processor/index.handler",
environment={"BUCKET_NAME": bucket.bucket_name},
)
# Scopes the IAM policy to GetObject/ListBucket on uploads/* only.
bucket.grant_read(fn, paths=["uploads/*"])
anvil.App(run=infra)anvil.Run(anvil.AppConfig{
Run: func(ctx *anvil.Context) error {
bucket, err := anvilaws.NewBucket(ctx.PulumiCtx(), "uploads", nil)
if err != nil {
return err
}
// Go has no grant methods yet: the same actions as grantRead(fn, ['uploads/*']).
_, err = anvilaws.NewLambda(ctx.PulumiCtx(), "processor", &anvilaws.LambdaArgs{
Runtime: anvilaws.LambdaRuntime_Nodejs24_x,
Handler: pulumi.String("functions/processor/index.handler"),
Environment: pulumi.StringMap{"BUCKET_NAME": bucket.BucketName},
Permissions: anvilaws.LambdaPermissionArray{
anvilaws.LambdaPermissionArgs{
Actions: pulumi.ToStringArray([]string{"s3:GetObject"}),
Resource: bucket.Arn,
Path: pulumi.String("uploads"),
},
anvilaws.LambdaPermissionArgs{
Actions: pulumi.ToStringArray([]string{"s3:ListBucket"}),
Resource: bucket.Arn,
},
},
})
return err
},
})Grants only create the IAM policy — they do not inject environment variables.
Pass whatever the Lambda needs (bucket.bucketName, table.tableName, db.endpoint, ...) through the compute resource's own environment argument, as shown above.
What Anvil does under the hood
- Builds the resource ARNs to grant against — optionally scoped to specific paths/prefixes (e.g.
uploads/*) rather than the whole resource. - Creates one IAM role policy on the target's execution role, scoped to exactly the actions that grant method implies.
- No manual ARN wiring, no forgotten permissions, no overly broad
*policies by default.
What each component exposes
| Component | Grant methods |
|---|---|
| Bucket | grantRead, grantWrite, grantReadWrite, grantDelete, grantFullAccess |
| DynamoDB | grantRead, grantWrite, grantReadWrite, grantDelete (each takes optional indexes) |
| Queue | grantSendMessage, grantConsumeMessages, grantFullAccess |
| EventBus | grantPutEvents |
| Lambda | grantInvoke |
| DSQL | grantConnect(target, { schemas: [{ schema, roleName }] }) — see how it works |
In Go, there's no per-resource grant* method yet. List the same AWS IAM actions in
the Lambda's permissions, as shown above; each component's Overview lists the exact
actions its grants add. DSQL connect grants in Go are the one exception: construct anvilaws.NewDSQLConnect directly, as shown on the DSQLConnect page.