DSQL

Serverless Postgres on Aurora DSQL. IAM auth over TLS, schemas and roles declared in code, and optional multi-region clusters.

Database · anvil:aws:DSQL

A side-effect resource with no outputs — it runs AWS IAM GRANT for the given database roles against the given IAM identity. You rarely construct it directly: calling .grant() on a DSQL component creates it for you.

Minimal

The smallest config that deploys.

import { App } from '@anvil-cloud/sdk';
import * as anvil from '@anvil-cloud/sdk';

export default new App({
  run(ctx) {
    const db = new anvil.aws.DSQL('db', {
      schemas: [{ name: 'app', roles: [{ name: 'app_rw', grants: ['SELECT', 'INSERT', 'UPDATE'] }] }],
    });

    const fn = new anvil.aws.Lambda('processor', {
      runtime: 'nodejs24.x',
      handler: 'functions/processor/index.handler',
    });

    // The same as db.grantConnect(fn, { schemas: [{ schema: 'app', roleName: 'app_rw' }] }).
    // targetRoleArn can be any IAM role, e.g. an ECS task role.
    new anvil.aws.DSQLConnect('processor-connect', {
      clusterArns: db.clusterArns,
      targetRoleArn: fn.roleArn,
      targetName: 'processor',
      dbRoles: ['app_rw'],
      declaredRoles: db.declaredRoles,
      rolesTableName: db.rolesTableName,
    });
  },
});
import anvil_cloud as anvil

def infra(ctx: anvil.Context):
    db = anvil.aws.DSQL("db",
        schemas=[{"name": "app", "roles": [{"name": "app_rw", "grants": ["SELECT", "INSERT", "UPDATE"]}]}],
    )

    fn = anvil.aws.Lambda("processor",
        runtime="nodejs24.x",
        handler="functions/processor/index.handler",
    )

    # The same as db.grant_connect(fn, schemas=[{"schema": "app", "role_name": "app_rw"}]).
    # target_role_arn can be any IAM role, e.g. an ECS task role.
    anvil.aws.DSQLConnect("processor-connect",
        cluster_arns=db.cluster_arns,
        target_role_arn=fn.role_arn,
        target_name="processor",
        db_roles=["app_rw"],
        declared_roles=db.declared_roles,
        roles_table_name=db.roles_table_name,
    )

anvil.App(run=infra)
package main

import (
    "github.com/anvil-cloud/anvil/sdk/go/anvil"
    anvilaws "github.com/anvil-cloud/anvil/sdk/go/anvil/aws"
    "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
    anvil.Run(anvil.AppConfig{
        Run: func(ctx *anvil.Context) error {
            db, err := anvilaws.NewDSQL(ctx.PulumiCtx(), "db", &anvilaws.DSQLArgs{
                Schemas: anvilaws.DSQLSchemaArray{
                    anvilaws.DSQLSchemaArgs{
                        Name: pulumi.String("app"),
                        Roles: anvilaws.DSQLRoleArray{
                            anvilaws.DSQLRoleArgs{
                                Name:   pulumi.String("app_rw"),
                                Grants: anvilaws.DSQLGrantArray{anvilaws.DSQLGrant("SELECT"), anvilaws.DSQLGrant("INSERT"), anvilaws.DSQLGrant("UPDATE")},
                            },
                        },
                    },
                },
            })
            if err != nil {
                return err
            }

            fn, err := anvilaws.NewLambda(ctx.PulumiCtx(), "processor", &anvilaws.LambdaArgs{
                Runtime: anvilaws.LambdaRuntime_Nodejs24_x,
                Handler: pulumi.String("functions/processor/index.handler"),
            })
            if err != nil {
                return err
            }

            // Go has no grantConnect yet, so this is how Go grants connect access.
            // TargetRoleArn can be any IAM role, e.g. an ECS task role.
            _, err = anvilaws.NewDSQLConnect(ctx.PulumiCtx(), "processor-connect", &anvilaws.DSQLConnectArgs{
                ClusterArns:    db.ClusterArns,
                TargetRoleArn:  fn.RoleArn,
                TargetName:     pulumi.String("processor"),
                DbRoles:        pulumi.StringArray{pulumi.String("app_rw")},
                DeclaredRoles:  db.DeclaredRoles,
                RolesTableName: db.RolesTableName,
            })
            return err
        },
    })
}

Arguments

Names below are TypeScript (camelCase). In Python use snake_case (e.g. dataClassification → data_classification); in Go use PascalCase on the Args struct (e.g. DataClassification).

clusterArns required
map<string, string>

Map of region to cluster ARN from the DSQL component. Used to scope the dsql:DbConnect IAM policy.

targetRoleArn required
string

IAM execution role ARN of the compute resource (Lambda, ECS task, etc.) that will connect to the cluster.

targetName required
string

Logical name of the compute resource. Used for naming child resources.

dbRoles
array

Postgres database role names to map this IAM identity to. One mapping is created per role; the bootstrap Lambda runs AWS IAM GRANT "<role>" TO the target for each. The compute connects as whichever role it chooses at runtime. Each must be declared in the DSQL component's schemas.

declaredRoles
map<string, string>

Pass dsql.declaredRoles from the DSQL component. Required with dbRoles: a role that isn't declared there fails the deploy.

dbRoleSchemas
map<string, string>

Maps a role in dbRoles to the schema you expect it in. Optional; a role declared in another schema fails the deploy. grantConnect fills it in for you.

rolesTableName
string

DynamoDB table name for role bootstrap. Pass dsql.rolesTableName from the DSQL component. Optional — omit when roles are not configured.

Attributes

Outputs available once the resource is deployed.

This component has no attributes.