App & Context
Every Anvil program starts the same way, in every language.
TypeScript programs start with new App(). Python programs call anvil.App(run=...).
Go programs call anvil.Run() with an AppConfig. In every case, a run callback receives a Context that carries the information every component needs to deploy correctly.
App configuration
Everything except run is optional. With no config, Anvil deploys to the stage's region from anvil.yaml using your environment's AWS credentials, and keeps the last 3 deploys' state.
import { App } from '@anvil-cloud/sdk';
import * as anvil from '@anvil-cloud/sdk';
export default new App({
providers: {
aws: { region: 'ap-southeast-2' },
'aws.us': { region: 'us-east-1' },
},
defaults: {
tags: { team: 'platform' },
state: { retainVersions: 3, compressState: true },
},
compliance: { frameworks: ['soc2', 'cis'], schedule: 'daily' },
run(ctx) {
new anvil.aws.Bucket('logs', { /* ... */ });
new anvil.aws.Bucket('logs-us', { /* ... */ }, { provider: ctx.providers['aws.us'] });
},
});import anvil_cloud as anvil
def infra(ctx: anvil.Context):
anvil.aws.Bucket("logs")
anvil.aws.Bucket("logs-us", opts=anvil.ResourceOptions(provider=ctx.provider("aws.us")))
anvil.App(
aws_providers={
"aws": anvil.AwsProviderConfig(region="ap-southeast-2"),
"aws.us": anvil.AwsProviderConfig(region="us-east-1"),
},
defaults=anvil.DefaultsConfig(
tags={"team": "platform"},
state=anvil.StateConfig(retain_versions=3, compress_state=True),
),
compliance=anvil.ComplianceConfig(frameworks=["soc2", "cis"], schedule="daily"),
run=infra,
)compress := true
anvil.Run(anvil.AppConfig{
AwsProviders: map[string]*anvil.AwsProviderConfig{
"aws": {Region: "ap-southeast-2"},
"aws.us": {Region: "us-east-1"},
},
Defaults: &anvil.DefaultsConfig{
Tags: map[string]string{"team": "platform"},
State: &anvil.StateConfig{RetainVersions: 3, CompressState: &compress},
},
Compliance: &anvil.ComplianceConfig{Frameworks: []string{"soc2", "cis"}, Schedule: "daily"},
Run: func(ctx *anvil.Context) error {
_, err := anvilaws.NewBucket(ctx.PulumiCtx(), "logs-us", &anvilaws.BucketArgs{}, ctx.Provider("aws.us"))
return err
},
})Names below are TypeScript (camelCase). In Python use snake_case (retainVersions → retain_versions); in Go use PascalCase (RetainVersions).
run requiredfunction Your infrastructure. Called with a Context (see below) once providers are set up.
providers map<string, provider config> Configuration for the cloud providers Anvil deploys with: which region, account and credentials to use. See Providers below. Python and Go split these into aws_providers / gcp_providers (AwsProviders / GcpProviders).
defaults object (DefaultsConfig) Settings applied to the whole app: tags on every resource, and how the stage's state is stored.
compliance object (ComplianceConfig) Scheduled compliance scans of the deployed resources. See Compliance scanning.
Providers
A provider is what Anvil uses to talk to a cloud: it holds the region, the account and the credentials every resource is created with. Anvil uses Pulumi's AWS and GCP providers, which are built on the official Terraform providers, so provider settings mean the same thing as they do in Pulumi or Terraform.
aws/gcpconfigure the default provider for that cloud. Every resource uses it unless told otherwise. With noawsentry, Anvil uses the stage's region fromanvil.yamland your environment's credentials, as the AWS CLI finds them.aws.<name>/gcp.<name>add extra named providers, for example another region or account. Pass one to a resource fromctx.providers(TypeScript),ctx.provider(name)(Python) orctx.Provider(name)(Go), as in the example above.
Anvil supports the settings most apps need: region, credentials or profile, and account, project or role. It adds
your defaults.tags to every provider itself. Each SDK's types list the exact settings available.
defaults
tags map<string, string> Tags added to every taggable resource (labels on GCP), along with stage and project. Your tags override those two, and a resource's own tags override these. Applies to raw Pulumi resources too, unless you give one its own provider. In Go, pass ctx.Provider("aws") to each resource to get them.
state object (StateConfig) How the stage's Pulumi state is stored. See the fields below and the State guide.
defaults.state
retainVersions integer How many deploys' state is kept, counting the latest: 2 keeps the latest deploy and the one before, 3 also keeps the deploy before that. Older deploys' state is deleted after each deploy. Counts deploys, not saves. Default: 3. Min 2, max 101.
compressState boolean Save state gzipped, which makes every save during a deploy much smaller and faster. Switching either way is safe: existing state is read in either format. Default: true.
The State guide explains where state lives, what's kept, and how to recover from a stuck or interrupted deploy.
compliance
frameworks requiredstring[] Frameworks to scan against, e.g. ["soc2", "iso27001", "cis"]. No default.
schedule string | object "daily", "weekly", "none", or { cron, timezone? }. Default: "daily".
retention string How long results are kept: 30d, 90d, 180d, 1y, 2y or 7y. Default: 1y.
scanOnDeploy boolean Also start a scan after each successful deploy. Default: false.
The first deploy with compliance set creates a scanner shared by every Anvil app in the account and
region. See Compliance scanning for frameworks, results and costs.
Context
| Member | Description |
|---|---|
ctx.stage | Current deployment stage. Defaults to your OS username for dev isolation. |
ctx.project | Project name, read from anvil.yaml. |
ctx.export(name, value) | Exports a stack output. |
ctx.providers | Named cloud providers, for multi-region / multi-account setups. |
ctx.ref(id) | References a resource declared elsewhere in the program — including later (TypeScript and Python only). |
Forward references
Normally you reference a resource through the variable it's assigned to, which means it must
be declared first. ctx.ref(id) lets you reference a resource by its logical name —
even one declared later in the program:
import { App } from '@anvil-cloud/sdk';
import * as anvil from '@anvil-cloud/sdk';
export default new App({
run(ctx) {
const fn = new anvil.aws.Lambda('processor', {
runtime: 'nodejs24.x',
handler: 'functions/processor/index.handler',
environment: {
// forward reference — `db` is declared below
DSQL_ENDPOINT: ctx.ref<anvil.aws.DSQL>('db').endpoint,
},
});
const db = new anvil.aws.DSQL('db', { /* ... */ });
},
});def infra(ctx: anvil.Context):
fn = anvil.aws.Lambda("processor",
runtime=LambdaRuntime.NODEJS24_X,
handler="functions/processor/index.handler",
environment={
# forward reference — `db` is declared below
"DSQL_ENDPOINT": ctx.ref("db").endpoint,
},
)
db = anvil.aws.DSQL("db", schemas=[...])
anvil.App(run=infra)anvil.Run(anvil.AppConfig{
Run: func(ctx *anvil.Context) error {
// Go does not yet support forward references (ctx.Ref) —
// declare resources in dependency order.
db, err := anvilaws.NewDSQL(ctx.PulumiCtx(), "db", nil)
if err != nil {
return err
}
_, err = anvilaws.NewLambda(ctx.PulumiCtx(), "processor", &anvilaws.LambdaArgs{
Runtime: anvilaws.LambdaRuntime_Nodejs24_x,
Handler: pulumi.String("functions/processor/index.handler"),
})
return err
},
})ctx.ref('db').endpoint resolves to the same output as db.endpoint —
they're interchangeable. This is an escape hatch for cases where declaration order is awkward;
most code references resources directly. See Forward References for how it works, how to avoid cycles, and its limits.