콘텐츠로 이동

TypeScript DynamoDB

이 생성기는 Amazon DynamoDB를 기반으로 하는 새로운 TypeScript DynamoDB 프로젝트를 생성하며, 타입 안전 엔티티 모델링을 위해 ElectroDB를 사용합니다. AWS CDK 또는 Terraform을 사용하여 DynamoDB 테이블을 프로비저닝하고 관리하는 데 필요한 애플리케이션 코드와 인프라를 생성하며, 단일 테이블 설계 지원과 DynamoDB Local을 통한 로컬 개발 환경을 내장하고 있습니다.

TypeScript DynamoDB 프로젝트 생성하기

섹션 제목: “TypeScript DynamoDB 프로젝트 생성하기”

이 제너레이터 실행@aws/nx-plugin:ts#dynamodb

pnpm nx g @aws/nx-plugin:ts#dynamodb
명령 구성하기8

필수

제너레이터 옵션8 옵션
name필수string

생성할 DynamoDB 프로젝트의 이름

directorystring기본값: packages

프로젝트를 저장할 디렉토리입니다.

frameworkenum기본값: electrodb

DynamoDB 엔티티에 사용할 프레임워크입니다.

electrodb
infraenum기본값: dynamodb

DynamoDB 테이블을 위해 프로비저닝할 인프라입니다.

dynamodbnone
iacenum기본값: inherit

선호하는 IaC 공급자입니다. 기본적으로 초기 선택에서 상속됩니다.

inheritcdkterraform
subDirectorystring

프로젝트가 배치되는 하위 디렉토리입니다. 기본값은 프로젝트 이름입니다.

tableNamestring

DynamoDB 테이블 이름입니다. 지정하지 않으면 자동으로 생성됩니다.

preferInstallDependenciesboolean기본값: true

생성기 실행 후 의존성 설치를 선호할지 여부입니다. 여러 생성기를 일괄 실행할 때 설치를 연기하려면 false로 설정하세요 (후속 생성기가 Nx 프로젝트 그래프를 계산할 수 있도록 필요한 경우 설치는 여전히 실행됩니다). 마지막에 한 번만 설치하세요.

생성기는 <directory>/<name> 디렉토리에 다음과 같은 프로젝트 구조를 생성합니다:

  • 디렉터리src
    • index.ts Project entry point and exports
    • client.ts DynamoDB client singleton and table name resolution
    • 디렉터리entities
      • example.ts Example ElectroDB entity definition
      • index.ts Entity exports
  • config.json Table configuration including GSI definitions and local development settings
  • package.json Project manifest defining the project’s package name and dependencies
  • project.json Project configuration and build targets

로컬 개발 스크립트는 모든 DynamoDB 프로젝트(TypeScript 및 Python 모두)에서 공유되며 다음 위치에 한 번 생성됩니다:

  • 디렉터리packages/common/scripts/src/dynamodb
    • create-local-table.ts Creates the DynamoDB table in the local DynamoDB Local instance
    • pull-image.ts Pulls the DynamoDB Local image
    • start-container.ts Starts the DynamoDB Local container

이 생성기는 선택한 iac를 기반으로 코드형 인프라를 제공하므로, 관련 CDK constructs 또는 Terraform 모듈을 포함하는 packages/common에 프로젝트를 생성합니다.

공통 코드형 인프라 프로젝트는 다음과 같이 구성됩니다:

  • 디렉터리packages/common/constructs
    • 디렉터리src
      • 디렉터리app/ 프로젝트/생성기에 특정한 인프라를 위한 Constructs
      • 디렉터리core/ app의 constructs에서 재사용되는 일반 constructs
      • index.ts app에서 constructs를 내보내는 진입점
    • project.json 프로젝트 빌드 타겟 및 구성
  • 디렉터리packages/common/constructs/src
    • 디렉터리app
      • 디렉터리dynamodb
        • <name>.ts 테이블에 특정한 인프라
    • 디렉터리core
      • dynamodb.ts 범용 DynamoDB 테이블 구성

배포된 프로젝트는 테이블 자체를 프로비저닝하며, 연결된 모든 프로젝트가 이를 읽고 씁니다:

Loading the diagram…

생성기는 DynamoDB Local 인스턴스를 시작하고 테이블을 생성하는 dev 타겟을 구성합니다. 프로젝트의 dev 타겟을 사용하세요:

Terminal window
pnpm nx dev <project-name>

이것은 자동으로:

  1. DynamoDB Local 이미지를 가져옵니다 (pull-image 타겟)
  2. 컨테이너를 시작합니다
  3. config.json에 정의된 인덱스로 로컬 테이블을 생성합니다

생성된 프로젝트는 단일 DynamoDB 테이블에서 타입 안전 엔티티 모델링을 위해 ElectroDB를 사용하며, DynamoDB의 단일 테이블 설계를 따릅니다. 생성된 예제 엔티티를 시작점으로 사용하여 src/entities/ 아래에 엔티티 파일을 추가하거나 업데이트하세요.

엔티티 정의 예제:

packages/my-table/src/entities/example.ts
import { Entity } from 'electrodb';
import { getDynamoDBClient, resolveTableName } from '../client.js';
export const createExampleEntity = async () =>
new Entity(
{
model: {
entity: 'example',
version: '1',
service: 'MyTable',
},
attributes: {
id: {
type: 'string',
required: true,
},
createdAt: {
type: 'string',
required: true,
default: () => new Date().toISOString(),
readOnly: true,
},
updatedAt: {
type: 'string',
required: true,
default: () => new Date().toISOString(),
watch: '*',
set: () => new Date().toISOString(),
},
},
indexes: {
primary: {
pk: {
field: 'pk',
composite: ['id'],
},
sk: {
field: 'sk',
composite: [],
},
},
},
},
{ client: getDynamoDBClient(), table: await resolveTableName() },
);

자세한 내용은 ElectroDB 엔티티 문서를 참조하세요.

생성된 src/client.ts는 두 가지 주요 유틸리티를 내보냅니다:

  • getDynamoDBClient() — 캐시된 싱글톤 DynamoDBClient를 반환합니다. LOCAL_DEV=true일 때는 로컬 DynamoDB Local 인스턴스에 연결하고, 그렇지 않으면 기본 자격 증명 체인을 사용하여 AWS 클라이언트를 생성합니다.
  • resolveTableName() — DynamoDB 테이블 이름을 반환합니다. LOCAL_DEV=true일 때는 로컬 테이블 이름 상수를 반환하고, 그렇지 않으면 RUNTIME_CONFIG_APP_ID 환경 변수를 사용하여 AWS AppConfig에서 이름을 가져와 후속 호출을 위해 캐시합니다.

dev를 중지하면 (예: Ctrl+C로) DynamoDB Local 컨테이너가 자동으로 제거되지만, 명명된 볼륨은 보존되므로 재시작 시에도 데이터가 유지됩니다.

GSI는 프로젝트 루트의 config.json에서 tableConfig.globalSecondaryIndexes 키 아래에 정의됩니다. GSI 키에 대한 단일 테이블 설계 명명 규칙을 따라 각 GSI에 대한 항목을 추가하세요:

config.json
{
...
"tableConfig": {
"globalSecondaryIndexes": [
{
"indexName": "gsi1pk-gsi1sk-index",
"partitionKey": "gsi1pk",
"sortKey": "gsi1sk"
},
{
"indexName": "gsi2pk-gsi2sk-index",
"partitionKey": "gsi2pk",
"sortKey": "gsi2sk"
}
]
}
}

sortKey 필드는 해시 키만 사용하는 GSI의 경우 선택 사항입니다.

이 구성 파일은 모든 소비자가 읽는 단일 진실 공급원입니다:

  • 로컬 개발devconfig.json을 읽고 GSI 목록과 일치하도록 로컬 테이블을 생성하거나 업데이트합니다
  • CDK — 구성체는 합성 시점에 config.json을 읽으므로 GSI 변경 사항이 다음 cdk deploy에 반영됩니다
  • Terraform — 모듈은 plan/apply 시점에 config.json을 읽습니다

모든 TypeScript 프로젝트에서 DynamoDB 패키지에서 엔티티 팩토리를 가져와 직접 사용할 수 있습니다:

import { createExampleEntity } from '@my-scope/my-table';
const entity = await createExampleEntity();
const result = await entity.query.primary({ id: '123' }).go();

내부적으로 createExampleEntity()resolveTableName()을 호출하여 런타임에 AWS AppConfig에서 테이블 이름을 가져옵니다.

DynamoDB 생성기는 선택한 iac에 따라 CDK 또는 Terraform 인프라를 생성합니다.

CDK 구성은 common/constructs에 생성됩니다. 사용 예시:

packages/infra/src/stacks/application-stack.ts
import { MyTable } from '@my-scope/common-constructs';
export class ApplicationStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
const table = new MyTable(this, 'Table');
}
}

다음과 같은 DynamoDB 테이블을 프로비저닝합니다:

  • pk (파티션 키)와 sk (정렬 키), 둘 다 String 타입
  • config.json에 정의된 Global Secondary Indexes
  • 온디맨드 (PAY_PER_REQUEST) 과금
  • 자동 키 로테이션이 활성화된 고객 관리형 KMS 암호화
  • 특정 시점 복구 활성화
  • 삭제 보호 활성화
  • AWS AppConfig의 dynamodb 네임스페이스 아래 Runtime Config에 등록된 테이블 이름

테이블은 두 개의 독립적인 가드로 보호되므로, 둘 중 하나만 끄는 것으로는 데이터를 삭제할 수 없습니다:

  • deletionProtection, DynamoDB에 의해 적용됩니다.
  • RemovalPolicy.RETAIN, CloudFormation에 의해 적용되며, 스택에서 제거될 때 테이블을 그대로 유지합니다.

단기 개발 또는 프리뷰 스택과 같이 테이블 삭제가 예상되는 환경에서는 보호를 비활성화하세요.

packages/infra/src/stacks/application-stack.ts
import { RemovalPolicy } from 'aws-cdk-lib';
import { MyTable } from '@my-scope/common-constructs';
const table = new MyTable(this, 'Table', {
deletionProtection: false,
removalPolicy: RemovalPolicy.DESTROY,
});

테이블은 기본적으로 온디맨드 (PAY_PER_REQUEST) 과금을 사용합니다. 예측 가능한 고처리량 워크로드의 경우 프로비저닝된 용량으로 전환하세요.

packages/infra/src/stacks/application-stack.ts
import { BillingMode } from 'aws-cdk-lib/aws-dynamodb';
import { MyTable } from '@my-scope/common-constructs';
const table = new MyTable(this, 'Table', {
billingMode: BillingMode.PROVISIONED,
readCapacity: 5,
writeCapacity: 5,
});

특정 시점 복구는 기본적으로 활성화되어 있으며, 지난 35일 동안의 임의 시점으로 테이블을 복원할 수 있습니다.

packages/infra/src/stacks/application-stack.ts
import { MyTable } from '@my-scope/common-constructs';
const table = new MyTable(this, 'Table', {
pointInTimeRecoverySpecification: { pointInTimeRecoveryEnabled: false },
});

테이블은 기본적으로 고객 관리형 KMS 키로 암호화되며, 자동으로 생성됩니다. 암호화를 다르게 관리하는 경우 AWS 관리형 키, AWS 소유 키로 전환하거나 자체 KMS 키를 가져올 수 있습니다.

AWS가 대신 관리하는 공유 aws/dynamodb KMS 키를 사용합니다. 계정의 KMS 콘솔에서 볼 수 있고 요청당 과금되지만, 생성, 로테이션 또는 삭제할 키가 없습니다.

packages/infra/src/stacks/application-stack.ts
import { TableEncryption } from 'aws-cdk-lib/aws-dynamodb';
import { MyTable } from '@my-scope/common-constructs';
const table = new MyTable(this, 'Table', {
encryption: TableEncryption.AWS_MANAGED,
});

AWS가 완전히 소유하고 관리하는 키를 사용합니다 — 무료이며, 계정에 키가 전혀 표시되지 않습니다. 규정 준수 이유로 고객 또는 계정에 표시되는 키가 필요하지 않은 경우 가장 간단한 옵션입니다.

packages/infra/src/stacks/application-stack.ts
import { TableEncryption } from 'aws-cdk-lib/aws-dynamodb';
import { MyTable } from '@my-scope/common-constructs';
const table = new MyTable(this, 'Table', {
encryption: TableEncryption.DEFAULT,
});
iac = terraform

이미 배포된 테이블에서 단일 terraform applyencryptionCUSTOMER_MANAGED에서 (AWS_MANAGED 또는 DEFAULT로) 변경하면 실패합니다: Terraform이 테이블을 업데이트하기 전에 고객 관리형 키를 삭제하고, DynamoDB는 키가 이미 삭제 대기 중이기 때문에 업데이트를 거부합니다.

먼저 AWS CLI를 통해 테이블의 암호화를 직접 업데이트한 다음 Terraform이 따라잡고 고아가 된 키를 정리하도록 하여 이 문제를 해결하세요:

터미널 창
# For AWS_MANAGED:
aws dynamodb update-table --table-name <table-name> \
--sse-specification Enabled=true,SSEType=KMS,KMSMasterKeyId=alias/aws/dynamodb
# For DEFAULT:
aws dynamodb update-table --table-name <table-name> --sse-specification Enabled=false
# Then wait for this to report ENABLED (or for SSEDescription to disappear, for DEFAULT):
aws dynamodb describe-table --table-name <table-name> --query Table.SSEDescription.Status

그런 다음 Terraform 구성에서 encryption을 업데이트하고 평소처럼 terraform apply를 실행하세요 — 이제 Terraform은 이미 사용되지 않는 키만 삭제하면 되며, 더 이상 의존하는 것이 없습니다.

자동으로 생성되는 대신 기존 고객 관리형 키를 제공합니다. 키는 자체 키 정책에서 DynamoDB 서비스에 필요한 권한을 이미 부여해야 합니다.

packages/infra/src/stacks/application-stack.ts
import { Key } from 'aws-cdk-lib/aws-kms';
import { MyTable } from '@my-scope/common-constructs';
const key = Key.fromKeyArn(this, 'Key', 'arn:aws:kms:us-east-1:111111111111:key/my-key-id');
const table = new MyTable(this, 'Table', {
encryptionKey: key,
});

테이블이 자체 고객 관리형 KMS 키를 생성하는 경우(기본값이며, 자체 키를 제공하지 않은 경우에만 해당), 해당 키는 기본적으로 자동 키 로테이션이 활성화됩니다. 보안 정책이 외부에서 로테이션을 관리하는 경우 비활성화하세요.

packages/infra/src/stacks/application-stack.ts
import { MyTable } from '@my-scope/common-constructs';
const table = new MyTable(this, 'Table', {
enableKeyRotation: false,
});

connection 생성기를 사용하여 이 프로젝트를 워크스페이스의 다른 프로젝트와 통합하세요. 다음 연결은 이 프로젝트와 관련이 있습니다:

tRPCAmazon DynamoDB
tRPC API to TypeScript DynamoDBtRPC API를 DynamoDB 테이블에 연결하기
SmithyAmazon DynamoDB
Smithy API to TypeScript DynamoDBSmithy API를 DynamoDB 테이블에 연결하기
Strands AgentsTypeScriptAmazon DynamoDB
TypeScript Agent to TypeScript DynamoDBTypeScript Agent를 DynamoDB 테이블에 연결하기
Model Context ProtocolAmazon DynamoDB
MCP Server to TypeScript DynamoDBTypeScript MCP Server를 DynamoDB 테이블에 연결하기