Deploy AWS Amplify Applications

The aws:amplify/app:App resource, part of the Pulumi AWS provider, defines an Amplify app that connects to a Git repository, builds frontend code, and serves it through AWS infrastructure. This guide focuses on four capabilities: repository connection and authentication, build specifications and environment configuration, branch management and preview environments, and URL routing and security headers.

Amplify apps connect to Git repositories and may reference IAM roles for build permissions. The examples are intentionally small. Combine them with your own repository URLs, authentication tokens, and IAM configuration.

Deploy a frontend app with build configuration

Most deployments connect a Git repository and define how to build and serve the application.

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

const example = new aws.amplify.App("example", {
    name: "example",
    repository: "https://github.com/example/app",
    buildSpec: `version: 0.1
frontend:
  phases:
    preBuild:
      commands:
        - yarn install
    build:
      commands:
        - yarn run build
  artifacts:
    baseDirectory: build
    files:
      - '**/*'
  cache:
    paths:
      - node_modules/**/*
`,
    customRules: [{
        source: "/<*>",
        status: "404",
        target: "/index.html",
    }],
    environmentVariables: {
        ENV: "test",
    },
});
import pulumi
import pulumi_aws as aws

example = aws.amplify.App("example",
    name="example",
    repository="https://github.com/example/app",
    build_spec="""version: 0.1
frontend:
  phases:
    preBuild:
      commands:
        - yarn install
    build:
      commands:
        - yarn run build
  artifacts:
    baseDirectory: build
    files:
      - '**/*'
  cache:
    paths:
      - node_modules/**/*
""",
    custom_rules=[{
        "source": "/<*>",
        "status": "404",
        "target": "/index.html",
    }],
    environment_variables={
        "ENV": "test",
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := amplify.NewApp(ctx, "example", &amplify.AppArgs{
			Name:       pulumi.String("example"),
			Repository: pulumi.String("https://github.com/example/app"),
			BuildSpec: pulumi.String(`version: 0.1
frontend:
  phases:
    preBuild:
      commands:
        - yarn install
    build:
      commands:
        - yarn run build
  artifacts:
    baseDirectory: build
    files:
      - '**/*'
  cache:
    paths:
      - node_modules/**/*
`),
			CustomRules: amplify.AppCustomRuleArray{
				&amplify.AppCustomRuleArgs{
					Source: pulumi.String("/<*>"),
					Status: pulumi.String("404"),
					Target: pulumi.String("/index.html"),
				},
			},
			EnvironmentVariables: pulumi.StringMap{
				"ENV": pulumi.String("test"),
			},
		})
		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.Amplify.App("example", new()
    {
        Name = "example",
        Repository = "https://github.com/example/app",
        BuildSpec = @"version: 0.1
frontend:
  phases:
    preBuild:
      commands:
        - yarn install
    build:
      commands:
        - yarn run build
  artifacts:
    baseDirectory: build
    files:
      - '**/*'
  cache:
    paths:
      - node_modules/**/*
",
        CustomRules = new[]
        {
            new Aws.Amplify.Inputs.AppCustomRuleArgs
            {
                Source = "/<*>",
                Status = "404",
                Target = "/index.html",
            },
        },
        EnvironmentVariables = 
        {
            { "ENV", "test" },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.amplify.App;
import com.pulumi.aws.amplify.AppArgs;
import com.pulumi.aws.amplify.inputs.AppCustomRuleArgs;
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 App("example", AppArgs.builder()
            .name("example")
            .repository("https://github.com/example/app")
            .buildSpec("""
version: 0.1
frontend:
  phases:
    preBuild:
      commands:
        - yarn install
    build:
      commands:
        - yarn run build
  artifacts:
    baseDirectory: build
    files:
      - '**/*'
  cache:
    paths:
      - node_modules/**/*
            """)
            .customRules(AppCustomRuleArgs.builder()
                .source("/<*>")
                .status("404")
                .target("/index.html")
                .build())
            .environmentVariables(Map.of("ENV", "test"))
            .build());

    }
}
resources:
  example:
    type: aws:amplify:App
    properties:
      name: example
      repository: https://github.com/example/app
      buildSpec: |
        version: 0.1
        frontend:
          phases:
            preBuild:
              commands:
                - yarn install
            build:
              commands:
                - yarn run build
          artifacts:
            baseDirectory: build
            files:
              - '**/*'
          cache:
            paths:
              - node_modules/**/*        
      customRules:
        - source: /<*>
          status: '404'
          target: /index.html
      environmentVariables:
        ENV: test

The buildSpec property defines the build process in YAML format: dependency installation (preBuild), build commands, output artifacts, and caching. The customRules array handles client-side routing by rewriting 404s to index.html. Environment variables pass configuration to the build process.

Authenticate with GitHub using access tokens

Private repositories require authentication so Amplify can clone code and set up webhooks.

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

const example = new aws.amplify.App("example", {
    name: "example",
    repository: "https://github.com/example/app",
    accessToken: "...",
});
import pulumi
import pulumi_aws as aws

example = aws.amplify.App("example",
    name="example",
    repository="https://github.com/example/app",
    access_token="...")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := amplify.NewApp(ctx, "example", &amplify.AppArgs{
			Name:        pulumi.String("example"),
			Repository:  pulumi.String("https://github.com/example/app"),
			AccessToken: pulumi.String("..."),
		})
		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.Amplify.App("example", new()
    {
        Name = "example",
        Repository = "https://github.com/example/app",
        AccessToken = "...",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.amplify.App;
import com.pulumi.aws.amplify.AppArgs;
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 App("example", AppArgs.builder()
            .name("example")
            .repository("https://github.com/example/app")
            .accessToken("...")
            .build());

    }
}
resources:
  example:
    type: aws:amplify:App
    properties:
      name: example
      repository: https://github.com/example/app
      accessToken: '...'

The accessToken property accepts a GitHub personal access token with repository permissions. Amplify uses this token to create webhooks for automatic deployments and read-only deploy keys. The token is not stored after initial setup, so you can remove it from your configuration after the first apply.

Enable automatic branch deployments

Teams working with feature branches often want preview environments created automatically when new branches are pushed.

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

const example = new aws.amplify.App("example", {
    name: "example",
    enableAutoBranchCreation: true,
    autoBranchCreationPatterns: [
        "*",
        "*/**",
    ],
    autoBranchCreationConfig: {
        enableAutoBuild: true,
    },
});
import pulumi
import pulumi_aws as aws

example = aws.amplify.App("example",
    name="example",
    enable_auto_branch_creation=True,
    auto_branch_creation_patterns=[
        "*",
        "*/**",
    ],
    auto_branch_creation_config={
        "enable_auto_build": True,
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := amplify.NewApp(ctx, "example", &amplify.AppArgs{
			Name:                     pulumi.String("example"),
			EnableAutoBranchCreation: pulumi.Bool(true),
			AutoBranchCreationPatterns: pulumi.StringArray{
				pulumi.String("*"),
				pulumi.String("*/**"),
			},
			AutoBranchCreationConfig: &amplify.AppAutoBranchCreationConfigArgs{
				EnableAutoBuild: pulumi.Bool(true),
			},
		})
		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.Amplify.App("example", new()
    {
        Name = "example",
        EnableAutoBranchCreation = true,
        AutoBranchCreationPatterns = new[]
        {
            "*",
            "*/**",
        },
        AutoBranchCreationConfig = new Aws.Amplify.Inputs.AppAutoBranchCreationConfigArgs
        {
            EnableAutoBuild = true,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.amplify.App;
import com.pulumi.aws.amplify.AppArgs;
import com.pulumi.aws.amplify.inputs.AppAutoBranchCreationConfigArgs;
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 App("example", AppArgs.builder()
            .name("example")
            .enableAutoBranchCreation(true)
            .autoBranchCreationPatterns(            
                "*",
                "*/**")
            .autoBranchCreationConfig(AppAutoBranchCreationConfigArgs.builder()
                .enableAutoBuild(true)
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:amplify:App
    properties:
      name: example
      enableAutoBranchCreation: true # The default patterns added by the Amplify Console.
      autoBranchCreationPatterns:
        - '*'
        - '*/**'
      autoBranchCreationConfig:
        enableAutoBuild: true

The enableAutoBranchCreation property activates automatic branch detection. The autoBranchCreationPatterns array defines glob patterns that match branch names; * and */** match all branches. The autoBranchCreationConfig block controls settings for auto-created branches, like enabling automatic builds.

Protect preview environments with HTTP basic auth

Preview deployments often need password protection before features are ready for release.

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

const example = new aws.amplify.App("example", {
    name: "example",
    enableBasicAuth: true,
    basicAuthCredentials: std.base64encode({
        input: "username1:password1",
    }).then(invoke => invoke.result),
});
import pulumi
import pulumi_aws as aws
import pulumi_std as std

example = aws.amplify.App("example",
    name="example",
    enable_basic_auth=True,
    basic_auth_credentials=std.base64encode(input="username1:password1").result)
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		invokeBase64encode, err := std.Base64encode(ctx, &std.Base64encodeArgs{
			Input: "username1:password1",
		}, nil)
		if err != nil {
			return err
		}
		_, err = amplify.NewApp(ctx, "example", &amplify.AppArgs{
			Name:                 pulumi.String("example"),
			EnableBasicAuth:      pulumi.Bool(true),
			BasicAuthCredentials: pulumi.String(invokeBase64encode.Result),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
using Std = Pulumi.Std;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.Amplify.App("example", new()
    {
        Name = "example",
        EnableBasicAuth = true,
        BasicAuthCredentials = Std.Base64encode.Invoke(new()
        {
            Input = "username1:password1",
        }).Apply(invoke => invoke.Result),
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.amplify.App;
import com.pulumi.aws.amplify.AppArgs;
import com.pulumi.std.StdFunctions;
import com.pulumi.std.inputs.Base64encodeArgs;
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 App("example", AppArgs.builder()
            .name("example")
            .enableBasicAuth(true)
            .basicAuthCredentials(StdFunctions.base64encode(Base64encodeArgs.builder()
                .input("username1:password1")
                .build()).result())
            .build());

    }
}
resources:
  example:
    type: aws:amplify:App
    properties:
      name: example
      enableBasicAuth: true
      basicAuthCredentials:
        fn::invoke:
          function: std:base64encode
          arguments:
            input: username1:password1
          return: result

The enableBasicAuth property activates HTTP basic authentication across all branches. The basicAuthCredentials property accepts base64-encoded credentials in “username:password” format. This applies app-wide; individual branches can override these settings.

Configure URL routing and API proxying

Single-page applications need URL rewriting for client-side routing, and many apps proxy API requests to avoid CORS issues.

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

const example = new aws.amplify.App("example", {
    name: "example",
    customRules: [
        {
            source: "/api/<*>",
            status: "200",
            target: "https://api.example.com/api/<*>",
        },
        {
            source: "</^[^.]+$|\\.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|ttf|map|json)$)([^.]+$)/>",
            status: "200",
            target: "/index.html",
        },
    ],
});
import pulumi
import pulumi_aws as aws

example = aws.amplify.App("example",
    name="example",
    custom_rules=[
        {
            "source": "/api/<*>",
            "status": "200",
            "target": "https://api.example.com/api/<*>",
        },
        {
            "source": "</^[^.]+$|\\.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|ttf|map|json)$)([^.]+$)/>",
            "status": "200",
            "target": "/index.html",
        },
    ])
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := amplify.NewApp(ctx, "example", &amplify.AppArgs{
			Name: pulumi.String("example"),
			CustomRules: amplify.AppCustomRuleArray{
				&amplify.AppCustomRuleArgs{
					Source: pulumi.String("/api/<*>"),
					Status: pulumi.String("200"),
					Target: pulumi.String("https://api.example.com/api/<*>"),
				},
				&amplify.AppCustomRuleArgs{
					Source: pulumi.String("</^[^.]+$|\\.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|ttf|map|json)$)([^.]+$)/>"),
					Status: pulumi.String("200"),
					Target: pulumi.String("/index.html"),
				},
			},
		})
		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.Amplify.App("example", new()
    {
        Name = "example",
        CustomRules = new[]
        {
            new Aws.Amplify.Inputs.AppCustomRuleArgs
            {
                Source = "/api/<*>",
                Status = "200",
                Target = "https://api.example.com/api/<*>",
            },
            new Aws.Amplify.Inputs.AppCustomRuleArgs
            {
                Source = "</^[^.]+$|\\.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|ttf|map|json)$)([^.]+$)/>",
                Status = "200",
                Target = "/index.html",
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.amplify.App;
import com.pulumi.aws.amplify.AppArgs;
import com.pulumi.aws.amplify.inputs.AppCustomRuleArgs;
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 App("example", AppArgs.builder()
            .name("example")
            .customRules(            
                AppCustomRuleArgs.builder()
                    .source("/api/<*>")
                    .status("200")
                    .target("https://api.example.com/api/<*>")
                    .build(),
                AppCustomRuleArgs.builder()
                    .source("</^[^.]+$|\\.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|ttf|map|json)$)([^.]+$)/>")
                    .status("200")
                    .target("/index.html")
                    .build())
            .build());

    }
}
resources:
  example:
    type: aws:amplify:App
    properties:
      name: example
      customRules:
        - source: /api/<*>
          status: '200'
          target: https://api.example.com/api/<*>
        - source: </^[^.]+$|\.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|ttf|map|json)$)([^.]+$)/>
          status: '200'
          target: /index.html

The customRules array defines URL rewrites and redirects. Each rule has a source pattern, target URL, and HTTP status code. The first rule proxies API requests to an external endpoint. The second rule uses a regex pattern to rewrite all non-asset requests to index.html, enabling client-side routing.

Specify a custom build container image

Some projects require specific Node.js versions or build tools not in Amplify’s default images.

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

const example = new aws.amplify.App("example", {
    name: "example",
    environmentVariables: {
        _CUSTOM_IMAGE: "node:16",
    },
});
import pulumi
import pulumi_aws as aws

example = aws.amplify.App("example",
    name="example",
    environment_variables={
        "_CUSTOM_IMAGE": "node:16",
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := amplify.NewApp(ctx, "example", &amplify.AppArgs{
			Name: pulumi.String("example"),
			EnvironmentVariables: pulumi.StringMap{
				"_CUSTOM_IMAGE": pulumi.String("node:16"),
			},
		})
		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.Amplify.App("example", new()
    {
        Name = "example",
        EnvironmentVariables = 
        {
            { "_CUSTOM_IMAGE", "node:16" },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.amplify.App;
import com.pulumi.aws.amplify.AppArgs;
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 App("example", AppArgs.builder()
            .name("example")
            .environmentVariables(Map.of("_CUSTOM_IMAGE", "node:16"))
            .build());

    }
}
resources:
  example:
    type: aws:amplify:App
    properties:
      name: example
      environmentVariables:
        _CUSTOM_IMAGE: node:16

The _CUSTOM_IMAGE environment variable tells Amplify which Docker image to use for builds. Set it to any public Docker image, like specific Node.js versions from Docker Hub. This overrides Amplify’s default build environment.

Add security headers to all responses

Production applications need security headers to protect against common web vulnerabilities.

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

const example = new aws.amplify.App("example", {
    name: "example",
    customHeaders: `customHeaders:
  - pattern: '**'
    headers:
      - key: 'Strict-Transport-Security'
        value: 'max-age=31536000; includeSubDomains'
      - key: 'X-Frame-Options'
        value: 'SAMEORIGIN'
      - key: 'X-XSS-Protection'
        value: '1; mode=block'
      - key: 'X-Content-Type-Options'
        value: 'nosniff'
      - key: 'Content-Security-Policy'
        value: \\"default-src 'self'\\"
`,
});
import pulumi
import pulumi_aws as aws

example = aws.amplify.App("example",
    name="example",
    custom_headers="""customHeaders:
  - pattern: '**'
    headers:
      - key: 'Strict-Transport-Security'
        value: 'max-age=31536000; includeSubDomains'
      - key: 'X-Frame-Options'
        value: 'SAMEORIGIN'
      - key: 'X-XSS-Protection'
        value: '1; mode=block'
      - key: 'X-Content-Type-Options'
        value: 'nosniff'
      - key: 'Content-Security-Policy'
        value: \"default-src 'self'\"
""")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := amplify.NewApp(ctx, "example", &amplify.AppArgs{
			Name: pulumi.String("example"),
			CustomHeaders: pulumi.String(`customHeaders:
  - pattern: '**'
    headers:
      - key: 'Strict-Transport-Security'
        value: 'max-age=31536000; includeSubDomains'
      - key: 'X-Frame-Options'
        value: 'SAMEORIGIN'
      - key: 'X-XSS-Protection'
        value: '1; mode=block'
      - key: 'X-Content-Type-Options'
        value: 'nosniff'
      - key: 'Content-Security-Policy'
        value: \"default-src 'self'\"
`),
		})
		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.Amplify.App("example", new()
    {
        Name = "example",
        CustomHeaders = @"customHeaders:
  - pattern: '**'
    headers:
      - key: 'Strict-Transport-Security'
        value: 'max-age=31536000; includeSubDomains'
      - key: 'X-Frame-Options'
        value: 'SAMEORIGIN'
      - key: 'X-XSS-Protection'
        value: '1; mode=block'
      - key: 'X-Content-Type-Options'
        value: 'nosniff'
      - key: 'Content-Security-Policy'
        value: \""default-src 'self'\""
",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.amplify.App;
import com.pulumi.aws.amplify.AppArgs;
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 App("example", AppArgs.builder()
            .name("example")
            .customHeaders("""
customHeaders:
  - pattern: '**'
    headers:
      - key: 'Strict-Transport-Security'
        value: 'max-age=31536000; includeSubDomains'
      - key: 'X-Frame-Options'
        value: 'SAMEORIGIN'
      - key: 'X-XSS-Protection'
        value: '1; mode=block'
      - key: 'X-Content-Type-Options'
        value: 'nosniff'
      - key: 'Content-Security-Policy'
        value: \"default-src 'self'\"
            """)
            .build());

    }
}
resources:
  example:
    type: aws:amplify:App
    properties:
      name: example
      customHeaders: |
        customHeaders:
          - pattern: '**'
            headers:
              - key: 'Strict-Transport-Security'
                value: 'max-age=31536000; includeSubDomains'
              - key: 'X-Frame-Options'
                value: 'SAMEORIGIN'
              - key: 'X-XSS-Protection'
                value: '1; mode=block'
              - key: 'X-Content-Type-Options'
                value: 'nosniff'
              - key: 'Content-Security-Policy'
                value: \"default-src 'self'\"        

The customHeaders property accepts YAML-formatted header configuration. The pattern field uses glob syntax to match routes; ** matches all paths. Each header has a key and value. These headers apply to all responses, adding protections like HSTS, frame options, and Content Security Policy.

Increase build instance compute capacity

Large applications with long build times may need more powerful build instances.

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

const example = new aws.amplify.App("example", {
    name: "example",
    jobConfig: {
        buildComputeType: "STANDARD_8GB",
    },
});
import pulumi
import pulumi_aws as aws

example = aws.amplify.App("example",
    name="example",
    job_config={
        "build_compute_type": "STANDARD_8GB",
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := amplify.NewApp(ctx, "example", &amplify.AppArgs{
			Name: pulumi.String("example"),
			JobConfig: &amplify.AppJobConfigArgs{
				BuildComputeType: pulumi.String("STANDARD_8GB"),
			},
		})
		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.Amplify.App("example", new()
    {
        Name = "example",
        JobConfig = new Aws.Amplify.Inputs.AppJobConfigArgs
        {
            BuildComputeType = "STANDARD_8GB",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.amplify.App;
import com.pulumi.aws.amplify.AppArgs;
import com.pulumi.aws.amplify.inputs.AppJobConfigArgs;
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 App("example", AppArgs.builder()
            .name("example")
            .jobConfig(AppJobConfigArgs.builder()
                .buildComputeType("STANDARD_8GB")
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:amplify:App
    properties:
      name: example
      jobConfig:
        buildComputeType: STANDARD_8GB

The jobConfig block controls build instance size. The buildComputeType property accepts values like STANDARD_8GB for larger instances. This speeds up builds for memory-intensive operations or large dependency installations.

Beyond these examples

These snippets focus on specific Amplify app features: repository connection and build configuration, branch management and preview environments, and routing, security, and build customization. They’re intentionally minimal rather than full hosting configurations.

The examples may reference pre-existing infrastructure such as Git repositories, GitHub personal access tokens for private repos, and IAM service roles for some configurations. They focus on configuring the app rather than provisioning everything around it.

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

  • IAM service roles (iamServiceRoleArn, computeRoleArn)
  • Cache configuration (cacheConfig)
  • Branch-specific settings and domain management
  • Monorepo configuration and build artifact paths

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

Let's deploy AWS Amplify Applications

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Authentication & Repository Setup
Why am I getting 'BadRequestException: You should at least provide one valid token'?
This error occurs when creating or updating an Amplify app with a repository but without authentication. Set accessToken (for GitHub) or oauthToken (for other systems) to authenticate. For GitHub, create a personal access token with write access to your repository.
What happens to my access token after creating the app?
Access tokens are not stored by AWS after initial setup. Once you’ve applied your Pulumi configuration, you can safely remove the accessToken or oauthToken from your code and delete the token.
Can I import an existing Amplify app without providing an access token?
Yes, if the app was created through the Amplify Console using OAuth authentication, you can omit accessToken when importing the resource.
Branch Management
How do I set up automatic branch creation for feature branches?
Set enableAutoBranchCreation to true and configure autoBranchCreationPatterns with glob patterns like ["*", "*/**"]. Use autoBranchCreationConfig to control settings like enableAutoBuild for new branches.
What's the difference between enableBranchAutoBuild and enableBranchAutoDeletion?
enableBranchAutoBuild automatically builds branches when code is pushed. enableBranchAutoDeletion automatically disconnects branches in Amplify Console when you delete them from your Git repository.
Routing & Redirects
How do I handle 404 errors for single-page applications?
Use customRules to redirect requests to your SPA’s entry point. Set source to "/<*>", status to "404" (or "200"), and target to "/index.html" to route all non-file requests to your app.
How do I set up API proxying or complex redirect rules?
Use customRules with regex patterns. For example, proxy API requests with source: "/api/<*>", status: "200", target: "https://api.example.com/api/<*>", or use regex patterns to match specific file types.
Security & Access Control
How do I enable basic authentication for my Amplify app?
Set enableBasicAuth to true and provide base64-encoded credentials in basicAuthCredentials. Use base64encode("username:password") to encode your credentials. This applies to all branches.
How do I add security headers like HSTS or CSP to my app?
Configure customHeaders with a YAML string specifying patterns and headers. You can set headers like Strict-Transport-Security, Content-Security-Policy, X-Frame-Options, and X-Content-Type-Options.
Build Configuration
Can I use a custom Docker image for builds?
Yes, set the _CUSTOM_IMAGE environment variable in environmentVariables to specify a Docker image like "node:16".
How do I configure the build instance size?
Use jobConfig with buildComputeType to specify the compute type, such as "STANDARD_8GB" for larger builds.
What's the difference between WEB and WEB_COMPUTE platforms?
WEB (default) is for static sites and client-side apps. WEB_COMPUTE is for server-side rendering (SSR) applications that require compute resources at runtime.

Using a different cloud?

Explore serverless guides for other cloud providers: