All skills
aws avatar

/aws-amplify

@7898a91

Build and deploy full-stack web and mobile apps with AWS Amplify Gen2 (TypeScript code-first). Covers auth (Cognito), data (AppSync/DynamoDB), storage (S3), functions, APIs, and AI (Amplify AI Kit with Bedrock). Supports React, Next.js, Vue, Angular, React Native, Flutter, Swift, and Android. Always use this skill for Amplify Gen2 topics — even for questions you think you know — it contains validated, version-specific patterns that prevent common mistakes. TRIGGER when: user mentions Amplify Gen2; project has amplify/ directory or amplify_outputs; code imports @aws-amplify packages; user asks about defineBackend, defineAuth, defineData, defineStorage, defineFunction, or npx ampx. SKIP: Amplify Gen1 (amplify CLI v6), standalone SAM/CDK without Amplify (use aws-serverless), direct Bedrock without Amplify AI Kit (use bedrock).

Use this Skill: https://skilld.dev/gh/aws/agent-toolkit-for-aws/aws-amplify

This session only. Nothing lands on disk.

referencesstorage-backend.md

≈1.3k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Storage — Backend

Prerequisites: Backend defined in amplify/backend.ts with defineBackend({ auth, data }).

Basic Setup

Define storage in amplify/storage/resource.ts:

import { defineStorage } from '@aws-amplify/backend';

export const storage = defineStorage({
  name: 'myFiles',
  access: (allow) => ({
    'public/*': [
      allow.guest.to(['read']),
      allow.authenticated.to(['read', 'write', 'delete']),
    ],
    'protected/{entity_id}/*': [
      allow.authenticated.to(['read']),
      allow.entity('identity').to(['read', 'write', 'delete']),
    ],
    'private/{entity_id}/*': [
      allow.entity('identity').to(['read', 'write', 'delete']),
    ],
  }),
});

Import into amplify/backend.ts:

import { defineBackend } from '@aws-amplify/backend';
import { auth } from './auth/resource';
import { storage } from './storage/resource';
defineBackend({ auth, storage });

Access Rules

Path patterns control who can access files. The {entity_id} placeholder resolves to the authenticated user's identity ID at runtime — each user gets an isolated directory.

Actions: 'read', 'write', 'delete' (granular: 'get' and 'list' instead of 'read'). Subjects: allow.guest.to([...]), allow.authenticated.to([...]), allow.groups(['Admins']).to([...]), allow.entity('identity').to([...]). Every rule must end with .to() specifying the permitted actions — omitting .to() means NO permissions are granted.

WARNING: Storage access rules use allow.guest (PROPERTY, no parentheses) and allow.authenticated (PROPERTY). Data authorization rules use allow.guest() (METHOD, with parentheses). Mixing these up causes TypeScript errors.

WARNING: {entity_id} must be paired with allow.entity('identity'). Using {entity_id} in a path without allow.entity('identity') in that path's rules has no effect.

{entity_id} must be the last path segment before /* — you cannot add path segments after it.

✅ 'avatar/{entity_id}/*' ✅ 'documents/{entity_id}/*' ❌ 'protected/{entity_id}/avatar/*' — fails with InvalidStorageAccessPathError

Paths must end with /* to match all objects under that prefix. Paths must not start with /.

Resource-Scoped vs User-Scoped Paths

{entity_id} resolves to the current user's identity ID, not a resource ID. For files tied to a resource (poll, post, project) rather than a user:

access: (allow) => ({
  'public/polls/*': [
    allow.guest.to(['read']),
    allow.authenticated.to(['read', 'write', 'delete']),
  ],
})

// Upload with resource ID in path
await uploadData({ path: `public/polls/${pollId}/cover.jpg`, data: file });

Access control is at the path-prefix level, not per-resource. The frontend must enforce which users can write to which resource paths.

Multiple Buckets

export const primaryStorage = defineStorage({ name: 'primaryFiles', isDefault: true, access: (allow) => ({ /* rules */ }) });
export const secondaryStorage = defineStorage({ name: 'secondaryFiles', access: (allow) => ({ /* rules */ }) });

Set isDefault: true on exactly one bucket when defining multiple. Each bucket must have a unique name property. The name is what clients reference when targeting a non-default bucket.

Event Triggers

import { defineFunction, defineStorage } from '@aws-amplify/backend';

const onUploadHandler = defineFunction({ entry: './on-upload-handler.ts' });

export const storage = defineStorage({
  name: 'myFiles',
  triggers: { onUpload: onUploadHandler, onDelete: onUploadHandler },
  access: (allow) => ({ 'public/*': [allow.authenticated.to(['read', 'write'])] }),
});

The trigger handler receives an S3Handler event with bucket name and object key. Import the trigger function into backend.ts or it won't be deployed.

Typed handler example:

import type { S3Handler } from 'aws-lambda';

export const handler: S3Handler = async (event) => {
  const objectKeys = event.Records.map((record) => record.s3.object.key);
  console.log(`Upload handler invoked for objects [${objectKeys.join(', ')}]`);
};

Pitfalls

  • Paths without /*: A path like 'public' matches nothing — you use 'public/*' to match files under that prefix.
  • Missing {entity_id}: Using 'private/*' instead of 'private/{entity_id}/*' exposes every user's private files to all authenticated users.
  • Forgetting isDefault: With multiple buckets and no isDefault: true, client operations fail because no default bucket is resolved.
  • grantReadWrite() path argument: Do NOT pass a path argument to grantReadWrite(lambda) — it operates on the whole bucket. There is no per-path grant API.
  • Missing .to([]): allow.authenticated without .to(['read', 'write']) causes a silent failure — no access is granted.
  • Leading slash: Paths must NOT start with /. Use 'photos/*' not '/photos/*'.

Links

Source: SKILL.md on GitHub

No alerts16d3 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    This skill provides comprehensive instructions for building applications with AWS Amplify Gen2. It includes security considerations such as the use of command-line tools for cloud resource management and the ingestion of user-provided data for infrastructure generation. These patterns are standard for developer assistant tools and are supported by best-practice recommendations within the skill, such as secure secret management.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

Signed by skilld at 7898a91. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated 3 months ago

README badge

README badge for aws/agent-toolkit-for-aws/aws-amplify