Skip to content

Support setting GSI ProjectionType & nonKeyAttributes in defineData() #604

@mabibby

Description

@mabibby

Support setting GSI ProjectionType & nonKeyAttributes in defineData()

Describe the bug / limitation

defineData() lets us declare GSIs via .secondaryIndexes(…), but there is no way to set projectionType (KEYS_ONLY | INCLUDE | ALL) or provide nonKeyAttributes.

Because Amplify deploys the table as a Custom::AmplifyDynamoDBTable resource, neither CDK overrides nor CloudFormation transforms can patch the index afterwards. We currently run a post‑deploy CLI script that creates each GSI with the correct projection.

Why it matters

Write‑time cost & latency – every additional attribute written to an ALL‑projected GSI consumes extra write‑capacity and increases replication latency.

Storage cost – our single‑table design has five GSIs; projecting all attributes multiplies storage five‑fold.

Payload, object‑count & pagination limits –

1 MB per GraphQL response – AppSync caps a single resolver payload at 1 MB.  (docs.aws.amazon.com, docs.aws.amazon.com)

1,000 items per list – The $util.list helper and AppSync’s List/Sync utilities hard‑limit a response to 1,000 objects; whichever ceiling (bytes or count) is hit first ends the page.  (docs.aws.amazon.com, docs.aws.amazon.com)
Bloated projections mean fewer objects fit into the same limits, harming throughput and UX.

Desired behaviour / API proposal

const schema = a.schema({
Order: a.model({
pk: a.id().required(),
sk: a.string().required(),
status: a.string(),
customerId: a.string(),
}).secondaryIndexes((index) => [
index('status')
.projection('KEYS_ONLY'), // new
index(['customerId', 'status'])
.projection('INCLUDE', ['total', 'createdAt']) // new
])
});

projection(type: 'KEYS_ONLY' | 'INCLUDE' | 'ALL', nonKeyAttrs?: string[])

If omitted, keep today’s default of ALL to avoid breaking existing apps.

Workarounds tried

Post‑deploy CLI script (described above) – brittle and slow.

CDK addGlobalSecondaryIndex – blocked because the underlying resource is Custom::AmplifyDynamoDBTable.

Custom AppSync resolver – we created an AppSync JS resolver that targets the manually‑recreated GSI (by setting index in the request mapping) so application GraphQL calls still work, but this is extra boilerplate and opaque to Amplify.

Checked existing issues – #2945 requests the same feature; this issue adds further business‑impact detail.  (github.com)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions