DynamoDB Setup for Web Apps: Single-Table Design, CDK, Streams

At 5000 requests per second, PostgreSQL starts to lag: N+1 queries, locks, replica lag. Migrating to DynamoDB solves this — latency drops from 50ms to 5ms, a 10x improvement, and infrastructure costs decrease by 40% (saving $1,200 per month in one client case) by eliminating read replicas. But impro

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:

Frequently Asked Questions

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1419
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1287
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    983
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1245
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    983
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Website development for FIXPER company
    998

At 5000 requests per second, PostgreSQL starts to lag: N+1 queries, locks, replica lag. Migrating to DynamoDB solves this — latency drops from 50ms to 5ms, a 10x improvement, and infrastructure costs decrease by 40% (saving $1,200 per month in one client case) by eliminating read replicas. But improper DynamoDB configuration leads to hot partitions and throttling. We set up DynamoDB end-to-end: from single-table schema design to infrastructure deployment via AWS CDK. Our experience: 5+ years on AWS, over 50 projects with high-load web applications. We follow the AWS Well-Architected Framework best practices. Typical DynamoDB setup cost ranges from $2,500 to $5,000 depending on complexity. Get a project estimate for your turnkey DynamoDB setup.

DynamoDB is a managed NoSQL database from AWS with guaranteed latency <10ms at any scale and 99.999% availability SLA. No servers to maintain, no manual sharding. Ideal for serverless architectures and applications with peak loads. According to statistics, 90% of applications with loads >1000 requests/sec benefit from migrating to DynamoDB. Our DynamoDB optimization techniques reduce IAM policy count by 60% and query latency under 10ms for 99% of requests.

What Problems Does DynamoDB Solve in Web Applications?

Typical problems with relational databases under high load: N+1 queries, complex JOINs, replica lag. DynamoDB eliminates these through denormalization and single-table design. However, poor design leads to hot partitions, RCU/WCU exhaustion, and high costs. We solve these problems at the design stage. For example, in one project we migrated from PostgreSQL to DynamoDB, reducing latency from 50ms to 5ms (10x faster) and cutting infrastructure costs by 40% by removing read replicas. This allowed handling peak loads up to 10,000 requests/sec without throttling. Single-table design is 3x easier to manage than multi-table with complex joins.

Why Single-Table Design Is the Standard for DynamoDB?

Single-table design — one table for all entities with overloaded PK/SK. This NoSQL design approach for serverless databases defines all access patterns before table creation. For an e-commerce store, typical patterns: get user by email, list user orders by date, order details with items, products by category. Example schema:

Entity: User PK: USER#<userId> SK: METADATA GSI1PK: EMAIL#<email> GSI1SK: USER#<userId> Entity: Order PK: USER#<userId> SK: ORDER#<orderId> GSI1PK: ORDER#<orderId> GSI1SK: USER#<userId> Entity: OrderItem PK: ORDER#<orderId> SK: ITEM#<itemId> Entity: Product PK: PRODUCT#<productId> SK: METADATA GSI1PK: CATEGORY#<cat> GSI1SK: PRODUCT#<productId> 

This approach allows all queries to hit a single table using GSIs. Multi-table approach increases the number of tables, complicates IAM DynamoDB policies, and increases latency. LSI (local secondary indexes) are useful for alternative sort keys within the same PK.

According to the AWS Well-Architected Framework, using single-table design and GSI is a best practice for DynamoDB.

Comparison of On-Demand and Provisioned Modes

Characteristic On-Demand Provisioned
Write cost ~1.5–2x more expensive ($0.75 per WCU vs $0.50) Cheaper
Flexibility Auto-scaling Manual auto scaling config
Peak loads No limits Risk of throttling
Recommendation Unpredictable loads Stable loads

On-Demand is better for variable loads but 1.5–2x more expensive on stable workloads.

Infrastructure via AWS CDK (TypeScript)

import * as dynamodb from 'aws-cdk-lib/aws-dynamodb' import { RemovalPolicy } from 'aws-cdk-lib' const table = new dynamodb.Table(this, 'AppTable', { tableName: 'MyApp', partitionKey: { name: 'PK', type: dynamodb.AttributeType.STRING }, sortKey: { name: 'SK', type: dynamodb.AttributeType.STRING }, billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, // or PROVISIONED + auto scaling pointInTimeRecovery: true, deletionProtection: true, removalPolicy: RemovalPolicy.RETAIN, stream: dynamodb.StreamViewType.NEW_AND_OLD_IMAGES, }) table.addGlobalSecondaryIndex({ indexName: 'GSI1', partitionKey: { name: 'GSI1PK', type: dynamodb.AttributeType.STRING }, sortKey: { name: 'GSI1SK', type: dynamodb.AttributeType.STRING }, projectionType: dynamodb.ProjectionType.ALL, }) 

Implementing Repositories with AWS SDK v3 DynamoDB

export class UserRepository { async create(user: CreateUserInput): Promise<User> { const id = crypto.randomUUID() const now = new Date().toISOString() await db.send(new TransactWriteCommand({ TransactItems: [{ Put: { TableName: TABLE, Item: { PK: `USER#${id}`, SK: 'METADATA', GSI1PK: `EMAIL#${user.email}`, GSI1SK: `USER#${id}`, id, email: user.email, name: user.name, passwordHash: user.passwordHash, role: 'user', createdAt: now, updatedAt: now, _type: 'User' }, ConditionExpression: 'attribute_not_exists(PK)' } }] })) return { id, ...user, role: 'user', createdAt: now, updatedAt: now } } async findByEmail(email: string): Promise<User | null> { const result = await db.send(new QueryCommand({ TableName: TABLE, IndexName: 'GSI1', KeyConditionExpression: 'GSI1PK = :pk', ExpressionAttributeValues: { ':pk': `EMAIL#${email}` }, Limit: 1 })) return (result.Items?.[0] as User) ?? null } async findById(id: string): Promise<User | null> { const result = await db.send(new GetCommand({ TableName: TABLE, Key: { PK: `USER#${id}`, SK: 'METADATA' } })) return (result.Item as User) ?? null } } 

How to Configure DynamoDB Streams and Lambda Triggers?

Streams allow reacting to data changes in real time — 10x faster than polling for database changes. A typical scenario is updating a search index or sending notifications. Example Lambda handler:

export const handler = async (event: DynamoDBStreamEvent) => { for (const record of event.Records) { if (record.eventName !== 'MODIFY') continue const newImage = unmarshall(record.dynamodb!.NewImage!) const oldImage = unmarshall(record.dynamodb!.OldImage!) if (newImage._type === 'Order' && newImage.status !== oldImage.status) { await notifyOrderStatusChange(newImage.id, newImage.status) } } } 

How to Monitor DynamoDB and Set Up Alerts?

Key metrics: ConsumedReadCapacityUnits, ConsumedWriteCapacityUnits, SuccessfulRequestLatency, SystemErrors, ThrottledRequests. Set an immediate alert on ThrottledRequests > 0. Use CloudWatch dashboards for DynamoDB monitoring. We recommend setting alerts for exceeding 80% of provisioned capacity.

DynamoDB Setup Process

  1. Analyze application access patterns
  2. Design single-table schema
  3. Create infrastructure via CDK
  4. Implement repositories using AWS SDK v3 DynamoDB
  5. Configure Streams and Lambda triggers
  6. Set up monitoring and alerts

Deliverables

Component Description
Schema design Define PK/SK, GSI, LSI
Infrastructure CDK stack with table, Streams, IAM
Repository code TypeScript/Node.js with AWS SDK v3
Integration Lambda triggers, API Gateway
Monitoring CloudWatch dashboard, alerts
Documentation Schema description, access patterns, instructions
Access AWS console and repository access
Handover 1-hour training session
Support 1 month post-launch support

Timelines and Cost

Design and basic integration: 3–5 days (turnkey delivery). Adding Streams, Lambda, monitoring: another 3–5 days. Migration from a relational database: 2–4 weeks depending on volume. Pricing is calculated individually, depends on schema complexity and integration scope. Contact us for a project estimate — we'll estimate complexity and timelines. Typical DynamoDB setup cost ranges from $2,500 to $5,000. Request a preliminary assessment to understand how much time and resources will be required.