Name:
interface
Value:
Extend your Amplify Gen 2 app with AWS Blocks — self-contained backend capabilities you compose into your existing backend.
Gen1 DocsLegacy

Page updated Sep 28, 2026

Connect to existing AWS resources

Amplify client libraries can be used independently without the Amplify backend workflow. If you've provisioned AWS resources with CDK, Terraform, CloudFormation, or the AWS Console, you can connect Amplify libraries directly to those resources.

This means you can adopt Amplify's client libraries for authentication, data, storage, and more, while keeping full control over your infrastructure.

When to use this approach

  • You already have AWS resources provisioned with CDK, Terraform, or CloudFormation
  • You want to use Amplify client libraries without adopting the Amplify backend (ampx) workflow
  • You need to connect to shared infrastructure managed by a platform team
  • You want programmatic control over configuration for testing or environment switching

How it works

The default path is a generated amplify_outputs.json file that you hand to Amplify.configure():

import { Amplify } from 'aws-amplify';
import outputs from './amplify_outputs.json';
Amplify.configure(outputs);

When you own the infrastructure there is no generated file, so you provide the configuration yourself. There are three ways to do that:

createConfigurationBuilder, exported from aws-amplify, assembles a ResourcesConfig step by step. Every method returns the builder, and build() produces a frozen ResourcesConfig that Amplify.configure() accepts:

import { Amplify, createAmplifyContext, createConfigurationBuilder } from 'aws-amplify';
const config = createConfigurationBuilder()
.auth({
Cognito: {
userPoolId: 'us-east-1_abc123',
userPoolClientId: 'abcdef123456'
}
})
.storage({ S3: { bucket: 'my-app-bucket', region: 'us-east-1' } })
.build();
Amplify.configure(config);
// or
const ctx = createAmplifyContext(config);
MethodDescription
from(seed)Merges an existing configuration in. Accepts anything Amplify.configure() accepts: a ResourcesConfig, a legacy aws-exports object, amplify_outputs.json, or another builder. Can be called repeatedly to accumulate, and is also available as createConfigurationBuilder({ from }).
add(category, value)Adds a category, replacing it entirely if already present.
patch(category, partial)Deep-merges a partial into a category, keeping nested values you don't mention. Creates the category if it doesn't exist.
auth(), api(), storage(), analytics(), geo(), notifications(), interactions(), predictions()Shorthands for add() with that category: .auth(config) is .add('Auth', config).
build()Returns the finished, frozen ResourcesConfig.

Configure part of a configuration. patch() deep-merges into a category, so you can change one nested value and leave the rest of it alone. This is the difference between the two write methods: add('Auth', …) (and its auth() shorthand) discards whatever Auth held, while patch() keeps it.

const config = createConfigurationBuilder({ from: outputs })
// Everything else under Auth.Cognito survives
.patch('Auth', { Cognito: { userPoolId: 'us-east-1_dev123' } })
// Add or overwrite a category outright, whether or not the outputs file carries it
.add('Storage', { S3: { bucket: 'my-platform-bucket', region: 'us-east-1' } })
.build();

Extend a base builder. A builder is itself a valid seed, so one shared base can produce environment-specific configurations without being mutated:

// Owned by your platform team, never passed to configure() directly
const base = createConfigurationBuilder({ from: outputs });
const dev = createConfigurationBuilder({ from: base })
.patch('Auth', { Cognito: { userPoolId: 'us-east-1_dev123' } })
.build();
const prod = createConfigurationBuilder({ from: base })
.patch('Auth', { Cognito: { userPoolId: 'us-east-1_prod789' } })
.build();

Write generators. Because build() returns a plain object, a function that closes over the shared base turns a single varying value into a whole configuration:

const withUserPool = (userPoolId: string) =>
createConfigurationBuilder({ from: base })
.patch('Auth', { Cognito: { userPoolId } })
.build();
Amplify.configure(withUserPool('us-east-1_dev123'));

Pass a ResourcesConfig object straight to Amplify.configure(). Nothing is merged for you, so every call states the complete configuration:

import { Amplify } from 'aws-amplify';
Amplify.configure({
Auth: {
Cognito: {
userPoolId: 'us-east-1_abc123',
userPoolClientId: 'abcdef123456',
identityPoolId: 'us-east-1:11111111-2222-3333-4444-555555555555',
loginWith: {
email: true
}
}
},
Storage: {
S3: {
bucket: 'my-app-bucket',
region: 'us-east-1'
}
}
});

This is the most direct option when your app has exactly one configuration and it never varies at runtime.

Keep the configuration in a file of your own and import it, the way a generated amplify_outputs.json is imported. Amplify only cares about the shape, so the file name is yours to choose. See the full amplify_outputs.json specification for every supported field:

my_resources.json
{
"version": "1.5",
"auth": {
"aws_region": "us-east-1",
"user_pool_id": "us-east-1_abc123",
"user_pool_client_id": "abcdef123456"
},
"storage": {
"aws_region": "us-east-1",
"bucket_name": "my-app-bucket"
}
}
import { Amplify, createAmplifyContext } from 'aws-amplify';
import resources from './my_resources.json';
Amplify.configure(resources);
// or
const ctx = createAmplifyContext(resources);

Because the file is checked in as data, this option keeps the configuration out of your application code while still letting you hold several of them: one file per environment, each imported where it is needed.

The built ResourcesConfig is a plain object either way, so it works anywhere a configuration is accepted: pass it to Amplify.configure() to set it globally, or to createAmplifyContext() to create an isolated local context instead of touching global state.

Configure Auth (Amazon Cognito)

Connect to an existing Cognito User Pool and Identity Pool.

import { Amplify, createAmplifyContext, createConfigurationBuilder } from 'aws-amplify';
const config = createConfigurationBuilder()
.auth({
Cognito: {
userPoolId: 'us-east-1_abc123',
userPoolClientId: 'abcdef123456',
identityPoolId: 'us-east-1:11111111-2222-3333-4444-555555555555',
loginWith: {
email: true
},
signUpVerificationMethod: 'code',
userAttributes: {
email: { required: true }
},
allowGuestAccess: true,
passwordFormat: {
minLength: 8,
requireLowercase: true,
requireUppercase: true,
requireNumbers: true,
requireSpecialCharacters: true
}
}
})
.build();
Amplify.configure(config);
// or
const ctx = createAmplifyContext(config);
import { Amplify } from 'aws-amplify';
Amplify.configure({
Auth: {
Cognito: {
userPoolId: 'us-east-1_abc123',
userPoolClientId: 'abcdef123456',
identityPoolId: 'us-east-1:11111111-2222-3333-4444-555555555555',
loginWith: {
email: true
},
signUpVerificationMethod: 'code',
userAttributes: {
email: { required: true }
},
allowGuestAccess: true,
passwordFormat: {
minLength: 8,
requireLowercase: true,
requireUppercase: true,
requireNumbers: true,
requireSpecialCharacters: true
}
}
}
});

Auth required fields

Fields of ResourcesConfig['Auth'], the object both tabs above build:

FieldRequiredDescription
Cognito.userPoolIdWith a user poolCognito User Pool ID
Cognito.userPoolClientIdWith a user poolCognito app client ID
Cognito.identityPoolIdWith an identity poolCognito Identity Pool ID, needed for guest access and for IAM-signed requests

There is no region field: the region is read from the user pool and identity pool IDs. Cognito accepts the user pool fields, the identity pool fields, or both, so an identity-pool-only configuration cannot carry userPoolId.

Every other field is optional. See AuthConfig for the full type.

Configure Data (AWS AppSync)

Connect to an existing AppSync GraphQL API.

import { Amplify, createAmplifyContext, createConfigurationBuilder } from 'aws-amplify';
const config = createConfigurationBuilder()
.api({
GraphQL: {
endpoint:
'https://abc123.appsync-api.us-east-1.amazonaws.com/graphql',
region: 'us-east-1',
apiKey: 'da2-abcdefghijklmno',
defaultAuthMode: 'apiKey'
}
})
.build();
Amplify.configure(config);
// or
const ctx = createAmplifyContext(config);
import { Amplify } from 'aws-amplify';
Amplify.configure({
API: {
GraphQL: {
endpoint:
'https://abc123.appsync-api.us-east-1.amazonaws.com/graphql',
region: 'us-east-1',
apiKey: 'da2-abcdefghijklmno',
defaultAuthMode: 'apiKey'
}
}
});

In a ResourcesConfig object the AppSync API lives under API.GraphQL, and defaultAuthMode takes the client-side value, one of apiKey, userPool, identityPool, oidc, lambda, or none, rather than the API_KEY style used in amplify_outputs.json.

Data required fields

Fields of ResourcesConfig['API'], the object both tabs above build:

FieldRequiredDescription
GraphQL.endpointYesAppSync GraphQL endpoint URL
GraphQL.defaultAuthModeYesapiKey, userPool, identityPool, oidc, lambda, or none. iam is the deprecated spelling of identityPool
GraphQL.apiKeyWith apiKey authAppSync API key
GraphQL.regionWith identityPool authRegion used to sign the request

Every other field is optional. See APIConfig for the full type.

Configure Storage (Amazon S3)

Connect to an existing S3 bucket.

import { Amplify, createAmplifyContext, createConfigurationBuilder } from 'aws-amplify';
const config = createConfigurationBuilder()
.auth({
Cognito: {
userPoolId: 'us-east-1_abc123',
userPoolClientId: 'abcdef123456',
identityPoolId: 'us-east-1:11111111-2222-3333-4444-555555555555'
}
})
.storage({ S3: { bucket: 'my-app-bucket', region: 'us-east-1' } })
.build();
Amplify.configure(config);
// or
const ctx = createAmplifyContext(config);
import { Amplify } from 'aws-amplify';
Amplify.configure({
Auth: {
Cognito: {
userPoolId: 'us-east-1_abc123',
userPoolClientId: 'abcdef123456',
identityPoolId: 'us-east-1:11111111-2222-3333-4444-555555555555'
}
},
Storage: {
S3: {
bucket: 'my-app-bucket',
region: 'us-east-1'
}
}
});

Multiple buckets

const config = createConfigurationBuilder()
.storage({
S3: {
bucket: 'primary-bucket',
region: 'us-east-1',
buckets: {
media: { bucketName: 'my-media-bucket', region: 'us-east-1' },
logs: { bucketName: 'my-logs-bucket', region: 'us-west-2' }
}
}
})
.build();
Amplify.configure({
Storage: {
S3: {
bucket: 'primary-bucket',
region: 'us-east-1',
buckets: {
media: { bucketName: 'my-media-bucket', region: 'us-east-1' },
logs: { bucketName: 'my-logs-bucket', region: 'us-west-2' }
}
}
}
});

Storage requires Auth (Cognito Identity Pool) for authorization. Always configure Auth alongside Storage.

Storage required fields

Fields of ResourcesConfig['Storage'], the object both tabs above build:

FieldRequiredDescription
S3.bucketFor the default bucketBucket used by calls that do not name one
S3.regionFor the default bucketRegion of that bucket
S3.buckets[name].bucketName, S3.buckets[name].regionWith additional bucketsEach extra bucket is keyed by the friendly name you pass to the Storage APIs

Every other field is optional. See StorageConfig for the full type.

Configure Analytics (Amazon Pinpoint)

Connect to an existing Pinpoint application.

import { Amplify, createAmplifyContext, createConfigurationBuilder } from 'aws-amplify';
const config = createConfigurationBuilder()
.analytics({
Pinpoint: {
appId: 'abc123def456',
region: 'us-east-1'
}
})
.build();
Amplify.configure(config);
// or
const ctx = createAmplifyContext(config);
import { Amplify } from 'aws-amplify';
Amplify.configure({
Analytics: {
Pinpoint: {
appId: 'abc123def456',
region: 'us-east-1'
}
}
});

Analytics required fields

Fields of ResourcesConfig['Analytics'], the object both tabs above build:

FieldRequiredDescription
Pinpoint.appIdYesPinpoint application (project) ID
Pinpoint.regionYesRegion of the Pinpoint project

Every other field is optional. See AnalyticsConfig for the full type.

Configure Geo (Amazon Location Service)

Connect to existing Location Service resources.

import { Amplify, createAmplifyContext, createConfigurationBuilder } from 'aws-amplify';
const config = createConfigurationBuilder()
.geo({
LocationService: {
region: 'us-east-1',
maps: {
items: { myMap: { style: 'VectorEsriStreets' } },
default: 'myMap'
},
searchIndices: {
items: ['myPlaceIndex'],
default: 'myPlaceIndex'
},
geofenceCollections: {
items: ['myGeofenceCollection'],
default: 'myGeofenceCollection'
}
}
})
.build();
Amplify.configure(config);
// or
const ctx = createAmplifyContext(config);
import { Amplify } from 'aws-amplify';
Amplify.configure({
Geo: {
LocationService: {
region: 'us-east-1',
maps: {
items: { myMap: { style: 'VectorEsriStreets' } },
default: 'myMap'
},
searchIndices: {
items: ['myPlaceIndex'],
default: 'myPlaceIndex'
},
geofenceCollections: {
items: ['myGeofenceCollection'],
default: 'myGeofenceCollection'
}
}
}
});

Geo required fields

Fields of ResourcesConfig['Geo'], the object both tabs above build:

FieldRequiredDescription
LocationService.regionYesRegion of the Location Service resources
LocationService.maps.items, LocationService.maps.defaultWith mapsMaps keyed by name, plus the default map name
LocationService.searchIndices.items, LocationService.searchIndices.defaultWith searchIndicesPlace index names, plus the default index
LocationService.geofenceCollections.items, LocationService.geofenceCollections.defaultWith geofenceCollectionsCollection names, plus the default collection

Every other field is optional. See GeoConfig for the full type.

Each resource group is optional on its own, but configure the ones your app actually calls: the Geo APIs need a default for the resource type they use.

Configure Notifications (Push)

Connect to an existing Pinpoint application for push notifications.

import { Amplify, createAmplifyContext, createConfigurationBuilder } from 'aws-amplify';
const config = createConfigurationBuilder()
.notifications({
PushNotification: {
Pinpoint: { appId: 'abc123def456', region: 'us-east-1' }
},
InAppMessaging: {
Pinpoint: { appId: 'abc123def456', region: 'us-east-1' }
}
})
.build();
Amplify.configure(config);
// or
const ctx = createAmplifyContext(config);
import { Amplify } from 'aws-amplify';
Amplify.configure({
Notifications: {
PushNotification: {
Pinpoint: { appId: 'abc123def456', region: 'us-east-1' }
},
InAppMessaging: {
Pinpoint: { appId: 'abc123def456', region: 'us-east-1' }
}
}
});

Notifications required fields

Fields of ResourcesConfig['Notifications'], the object both tabs above build. At least one of PushNotification and InAppMessaging must be present:

FieldRequiredDescription
PushNotification.Pinpoint.appId, PushNotification.Pinpoint.regionFor Pinpoint pushPinpoint project backing push device registration
PushNotification.CustomerProfiles.endpoint, PushNotification.CustomerProfiles.regionFor Amazon Connect pushAmazon Connect Customer Profiles endpoint backing push device registration
InAppMessaging.Pinpoint.appId, InAppMessaging.Pinpoint.regionFor in-app messagingPinpoint project backing in-app messages

Every other field is optional. See NotificationsConfig for the full type.

In a ResourcesConfig object there is no channels list: which channels are active follows from the providers you configure, PushNotification and InAppMessaging. The amazon_connect block in amplify_outputs.json becomes Notifications.PushNotification.CustomerProfiles with endpoint and region.

Multi-category configuration

You can configure multiple services together. This example sets up Auth, Data, and Storage in a single configuration.

import { Amplify, createAmplifyContext, createConfigurationBuilder } from 'aws-amplify';
const config = createConfigurationBuilder()
.auth({
Cognito: {
userPoolId: 'us-east-1_abc123',
userPoolClientId: 'abcdef123456',
identityPoolId: 'us-east-1:11111111-2222-3333-4444-555555555555'
}
})
.api({
GraphQL: {
endpoint:
'https://abc123.appsync-api.us-east-1.amazonaws.com/graphql',
region: 'us-east-1',
defaultAuthMode: 'userPool'
}
})
.storage({ S3: { bucket: 'my-app-bucket', region: 'us-east-1' } })
.build();
Amplify.configure(config);
// or
const ctx = createAmplifyContext(config);

Chaining also means a category can come from somewhere else entirely: seed the builder with a shared configuration and add only what this app owns.

import { Amplify } from 'aws-amplify';
Amplify.configure({
Auth: {
Cognito: {
userPoolId: 'us-east-1_abc123',
userPoolClientId: 'abcdef123456',
identityPoolId: 'us-east-1:11111111-2222-3333-4444-555555555555'
}
},
API: {
GraphQL: {
endpoint:
'https://abc123.appsync-api.us-east-1.amazonaws.com/graphql',
region: 'us-east-1',
defaultAuthMode: 'userPool'
}
},
Storage: {
S3: {
bucket: 'my-app-bucket',
region: 'us-east-1'
}
}
});

Environment-specific configuration

Keep one configuration per environment and select it at startup. With the builder, derive each one from a shared base so only the differing fields are restated. The generator pattern from How it works applies directly:

import { Amplify, createConfigurationBuilder } from 'aws-amplify';
import outputs from './amplify_outputs.json';
const base = createConfigurationBuilder({ from: outputs });
const withUserPool = (userPoolId: string) =>
createConfigurationBuilder({ from: base })
.patch('Auth', { Cognito: { userPoolId } })
.build();
const configs = {
dev: withUserPool('us-east-1_dev123'),
prod: withUserPool('us-east-1_prod789')
};
Amplify.configure(configs[selectedEnvironment]);

If the environments share nothing, keep a separate outputs file per environment instead:

import devOutputs from './amplify_outputs.dev.json';
import prodOutputs from './amplify_outputs.prod.json';
const outputs = process.env.NODE_ENV === 'production' ? prodOutputs : devOutputs;
Amplify.configure(outputs);

Several environments at the same time

Amplify.configure() sets one process-wide configuration, so selecting an environment this way means the whole app moves with it. To keep more than one environment live at once, pass each configuration to createAmplifyContext() instead of to configure(), then hand the resulting context to the category APIs:

import { createAmplifyContext } from 'aws-amplify';
const environments = {
dev: createAmplifyContext(withUserPool('us-east-1_dev123')),
prod: createAmplifyContext(withUserPool('us-east-1_prod789'))
};

See Local context for what a context isolates, how to use one, and why it is a client-side API.

amplify_outputs.json schema reference

For the full schema of all supported configuration fields, see the amplify_outputs.json reference.