logo
▼
Projects
Collaborations
Resources
Our Partners
Our Community
Projects
Collaborations
Resources
Our Partners
Our Community
Account
Sign InJoin UsHelp & Support

The Cometbid
Technology Foundation

Empowering innovation through open-source collaboration. TCTF supports developers, organizations, and communities worldwide in building the future of technology with transparent, vendor-neutral governance and world-class open-source projects.


Follow Us

Our Community

  • About Us
  • Upcoming Events
  • Projects
  • Collaborations
  • Membership
  • TCTF Training
  • Corporate Sponsorship

Learn

  • FAQ
  • TCTF Incubator Programs
  • Brand Guidelines
  • Logo Specifications

Legal

  • Privacy Policy
  • Terms of Use
  • Compliance
  • Code of Conduct
  • Contribution Guidelines
  • Legal & Trademark
  • Manage Cookies

More

  • Report a Vulnerability
  • Report Bugs
  • Mailing Lists
  • Contact Us
  • Support
  • Support Tickets
  • TCTF Social Network

Subscribe to our Newsletter

Caching Strategies for Serverless: From In-Memory to DynamoDB-Backed TTL Caches
Framework Deep DivesFramework Series #5

Caching Strategies for Serverless: From In-Memory to DynamoDB-Backed TTL Caches

Part 1 of the caching series — how we built a pluggable cache layer for TCTF with DynamoDB TTL caching, in-memory caching for Lambda warm starts, cache monitoring with health checks, and the interface that makes storage backends swappable.

June 20, 2026· 12 min read
TCTF Editorials
TCTF Newsletter
Home›Newsletter›Caching Strategies for Serverless: From In-Memo...

In This Edition

  • The Serverless Caching Challenge
  • The CacheService: One API, Multiple Backends
  • DynamoDB Cache: Zero Extra Infrastructure
  • In-Memory Cache: Fast but Volatile
  • TTL: The Serverless Cache Invalidation Strategy
  • Cache Monitoring and Health Checks
  • Choosing the Right Backend
3Storage Backends
DynamoDBDefault Backend
AutomaticTTL Expiration
YesBatch Operations
Built-inHealth Checks
DynamoDBZero Extra Infra

Caching in serverless does not work the way it does in traditional applications. There is no long-lived process holding state between requests. Lambda functions are ephemeral — they start, handle a request, and may never be reused. That means any cache you build must live outside the function. It must clean up after itself. And it must be fast enough that caching does not cost more than the operation it replaces. This article is Part 1 of a two-part series. It covers the caching architecture we built for TCTF: a pluggable CacheService backed by DynamoDB TTL caching (the default), an in-memory cache for Lambda warm starts, and a monitoring layer for resilience. Part 2 covers ElastiCache Redis for sub-millisecond caching on hot paths.

Ephemeral cloud infrastructure representing the transient nature of serverless compute
Fig. 1 — Ephemeral cloud infrastructure representing the transient nature of serverless compute

01The Serverless Caching Challenge

In traditional applications, caching is simple. You run a Redis instance, your application server connects to it, and cached data stays available as long as the process runs.

Serverless removes that guarantee. A Lambda function handles a request, and the next request may land on a completely different instance. In-memory state is gone. Connection pools are gone. Any data stored in the process disappears with it.

This creates three hard requirements for a serverless cache:

1. The cache must be external — stored in a service accessible from any Lambda instance. 2. The cache must handle TTL automatically — expired entries must be cleaned up without a background worker. 3. The cache must be fast enough that the caching overhead does not exceed the cost of the original operation.

For TCTF, there was a fourth requirement: the cache must be pluggable. We run 34 services. Some need durability (geolocation data that costs real money to fetch). Some need speed (session lookups on every request). Some need simplicity (configuration data that changes once a week). No single cache backend satisfies all of them.

🎯

Four requirements: external storage, automatic TTL, low overhead, and pluggable backends. No single cache backend satisfies all 34 services.

02The CacheService: One API, Multiple Backends

The CacheService is the single entry point for all caching operations. It exposes a consistent API that works identically regardless of which storage backend is active.

Here is what the API surface looks like in practice:

import { CacheService } from '@tctf/cache';

const cache = CacheService.getInstance();

// Single item operations
await cache.set('user:123:profile', userData, 3600); // TTL in seconds
const profile = await cache.get<UserProfile>('user:123:profile');

// Batch operations — useful when you need multiple keys in one handler
const keys = ['config:feature-flags', 'config:rate-limits', 'config:thresholds'];
const configs = await cache.getMany<AppConfig>(keys);

await cache.setMany([
  { key: 'geo:8.8.8.8', value: geoResult, ttl: 86400 },
  { key: 'geo:1.1.1.1', value: geoResult2, ttl: 86400 },
]);

// TTL management
await cache.expire('session:abc', 1800); // extend session by 30 min
const remaining = await cache.getTtl('session:abc');

// Monitoring
const stats = await cache.getStats(); // { hits, misses, keys }

A service caching geolocation data in DynamoDB uses the exact same methods as a service caching sessions in Redis. The caller does not know — and does not need to know — which backend handles the operation.

The CacheService is a singleton with lazy initialization. The first call to getInstance() creates the service and resolves the storage backend from the CACHE_STORAGE_TYPE environment variable. After that, it is reused across invocations within a warm Lambda instance.

You can also swap the backend at runtime via setCacheStorage(). This is useful for testing (swap to in-memory) and for graceful degradation (fall back to DynamoDB if Redis becomes unreachable).

Organized filing system representing structured DynamoDB cache storage
Fig. 2 — Organized filing system representing structured DynamoDB cache storage

03DynamoDB Cache: Zero Extra Infrastructure

DynamoDB is the default cache backend for TCTF services. The reason is operational simplicity: it requires no additional infrastructure. It uses the service's existing DynamoDB table with a key prefix to isolate cache entries from business data.

Each cache entry is stored as a DynamoDB item with four attributes:

  • PK — the prefixed cache key
  • value — the JSON-serialized cached data
  • ttl — a Unix timestamp for automatic expiration
  • createdAt — for monitoring and debugging

DynamoDB's built-in TTL feature deletes items automatically when their timestamp passes. No cleanup jobs. No scheduled Lambda functions. No manual purging.

Here is what a cache write and read look like under the hood:

import { DynamoDBCacheStorage } from '@tctf/cache';

const storage = new DynamoDBCacheStorage({
  tableName: process.env.CACHE_TABLE!,
  prefix: 'CACHE#geo:',
});

// Writing a cache entry with 24-hour TTL
await storage.set('8.8.8.8', {
  country: 'US',
  region: 'California',
  city: 'Mountain View',
}, 86400);

// Reading — returns null if expired or missing
const location = await storage.get<GeoLocation>('8.8.8.8');

Batch operations use DynamoDB's BatchGetItem and BatchWriteItem for efficiency. The has operation uses a projection expression to check existence without reading the full item.

Key prefixing prevents collisions. Every cache key is prefixed with a configurable string (e.g., CACHE#geo:, CACHE#config:). Cache entries coexist safely with business data in the same table. The prefix is stripped on retrieval, so callers work with clean keys.

The DynamoDB cache is durable. Cold starts do not clear it. Service restarts do not clear it. Data only leaves through explicit deletion or TTL expiration. This makes it the right choice for data that is expensive to recompute — geolocation lookups, external API responses, and computed aggregations.

📦

DynamoDB caching requires zero extra infrastructure. It piggybacks on your existing table. TTL handles expiration. The cache survives cold starts and restarts.

04In-Memory Cache: Fast but Volatile

The in-memory cache backend uses a JavaScript Map with TTL tracking. It is the fastest option — no network calls, no serialization, sub-microsecond access. The tradeoff: it resets on every Lambda cold start.

When does that tradeoff make sense?

  • Testing — unit tests run faster without network round-trips to DynamoDB or Redis.
  • Per-invocation data — values computed once per Lambda invocation and reused within that invocation (parsed config, validated schemas, resolved env vars).
  • Warm-start optimization — data cached in memory during warm instances, repopulated from the external cache on cold start.

Initialization is straightforward:

import { InMemoryCacheStorage } from '@tctf/cache';

const memoryCache = new InMemoryCacheStorage({
  maxSize: 500,           // max entries before FIFO eviction
  cleanupInterval: 30000, // remove expired entries every 30s
  prefix: 'MEM#',
});

CacheService.getInstance().setCacheStorage(memoryCache);

The maxSize configuration caps the number of entries. When the cache is full, the oldest entry is evicted (FIFO). This prevents unbounded memory growth, which matters in Lambda where memory is a billed resource.

The in-memory cache implements the same ICacheStorage interface as DynamoDB and Redis. TTL, batch operations, stats tracking, key prefixing — all consistent across backends. A cleanup interval runs periodically to remove expired entries and prevent memory creep in long-running instances with provisioned concurrency.

⚡

In-memory cache: sub-microsecond access, zero network calls. But volatile — resets on cold start. Best for testing, per-invocation data, and warm-start optimization.

05TTL: The Serverless Cache Invalidation Strategy

In serverless, you cannot run background workers to sweep stale entries. TTL solves this by making expiration a property of each entry rather than a system-wide process.

Every cache entry has a TTL — the number of seconds until it expires. When you call set(key, value, ttl), the backend stores the expiration timestamp. On get(key), the backend checks whether the entry has expired. If it has, the caller gets a cache miss. The stale data is never returned.

DynamoDB handles TTL natively. Items with a ttl attribute are deleted automatically by a background process — typically within 48 hours of expiration, though the item becomes invisible to reads the moment the timestamp passes.

The in-memory cache checks TTL on every get and runs a periodic cleanup to free memory proactively.

TTL values should reflect how the data changes:

  • Geolocation data — 24 hours. IP-to-location mappings rarely change.
  • Rate limit counters — 60 seconds. Matches the rate limit window.
  • Configuration data — 5 minutes. Balances freshness with read reduction.
  • Session data — matches the session expiration policy.

The CacheService also provides explicit TTL management. The expire method updates the TTL on an existing entry without re-writing the value. The getTtl method returns seconds remaining. These are useful for sliding expiration windows — extending a session each time the user makes a request, for example.

06Cache Monitoring and Health Checks

A cache that fails silently is worse than no cache at all. If the DynamoDB backend starts returning errors, the service should degrade gracefully rather than throw unhandled exceptions. The CacheMonitor provides this resilience layer.

Health checks run on a configurable interval. The monitor writes a test key, reads it back, verifies the value, and deletes it. If the check fails after a configured number of retries, it emits a CloudWatch metric and logs an error. The operations team sees the failure in the dashboard before users notice anything.

The CacheMonitor integrates with a circuit breaker. If the cache backend fails repeatedly, the circuit opens and cache operations are skipped entirely. The service operates without caching, hitting the source of truth directly. When the cache recovers, the circuit closes and caching resumes.

The getStats method on each backend returns hit count, miss count, and total keys. These metrics feed into CloudWatch dashboards showing cache hit rates per service. A dropping hit rate is an early signal — it could mean TTL values are too aggressive, the cache is too small, or access patterns have shifted.

Graceful shutdown ensures connections are closed cleanly. For DynamoDB, this is a no-op (the client manages connection pooling). For Redis (Part 2), this closes the connection to prevent leaks. For in-memory, it clears the cleanup interval.

📊

Health checks catch cache failures before users notice. The circuit breaker provides automatic fallback. CloudWatch hit rate metrics show cache effectiveness per service.

A fork in the road representing the decision between cache backend strategies
Fig. 3 — A fork in the road representing the decision between cache backend strategies

07Choosing the Right Backend

The pluggable architecture means every service picks the backend that fits its workload.

DynamoDB is the default and the right choice for most services. No extra infrastructure, durable across cold starts, automatic TTL, single-digit millisecond latency. Use it for: - Geolocation data - Configuration caching - Circuit breaker state - Any data where durability matters more than sub-millisecond speed

In-memory is for ephemeral data and testing. Use it for: - Parsed configurations within a single invocation - Validated schemas - Any data that is cheap to recompute on cold start

Do not use it as a primary cache for data that must persist across invocations.

Redis (Part 2) is for hot-path operations where sub-millisecond latency is measurably important — session validation, rate limit counters, API response caching. It requires Lambda to run inside a VPC, which adds operational complexity. Use it only when profiling shows DynamoDB latency is a bottleneck.

The decision is not permanent. Start with DynamoDB. Monitor hit rates and latency. If a service needs faster access, switch to Redis by changing one environment variable. The code stays the same. The API stays the same. Only the performance profile changes.

In Part 2, we cover ElastiCache Redis — VPC configuration for Lambda, the Redis cache storage implementation, cluster mode, and the specific use cases where Redis outperforms DynamoDB caching.

🎯

Start with DynamoDB (zero infra, durable, sufficient for most services). Add Redis only when profiling shows the need. The pluggable interface makes switching painless.

Caching in serverless is about choosing the right tool for each service — balancing speed, durability, complexity, and cost. The CacheService gives every TCTF service that choice through a single interface. DynamoDB for durability. In-memory for speed. Redis for the hot path. In Part 2, we dive into ElastiCache Redis: VPC configuration, cluster mode, and the workloads where sub-millisecond latency makes a real difference.

Editor's Note: This is Framework Series #5 in the TCTF Newsletter, Part 1 of the caching series. Part 2 covers ElastiCache Redis for sub-millisecond caching. Next: ElastiCache Redis for Low-Latency Session and API Caching.

Never miss an edition

Subscribe to get TCTF newsletters delivered to your inbox.

Subscribe
PreviousRate Limiting at Serverless Scale: Tiered Throttling with DynamoDB
NextCaching Strategies for Serverless, Part 2: ElastiCache Redis for Low-Latency Session and API Caching

In This Edition

  • The Serverless Caching Challenge
  • The CacheService: One API, Multiple Backends
  • DynamoDB Cache: Zero Extra Infrastructure
  • In-Memory Cache: Fast but Volatile
  • TTL: The Serverless Cache Invalidation Strategy
  • Cache Monitoring and Health Checks
  • Choosing the Right Backend

Browse by Month

June
  • Caching Strategies for Serverless, Part 2: ElastiCache Redis for Low-Latency Session and API Caching
  • Caching Strategies for Serverless: From In-Memory to DynamoDB-Backed TTL Caches
  • Rate Limiting at Serverless Scale: Tiered Throttling with DynamoDB
  • TCTF's DynamoDB Framework, Part 2: Building a Fluent Query Builder in TypeScript
May
  • The Struggles of Timelines and Schedules: When Building Gets Real
  • How to Stay Motivated in the Face of Uncertainties: Faith Beyond Doubt
  • Cognito Middleware: Building an Authentication Pipeline for Serverless APIs
  • Building TCTF's DynamoDB Query Framework, Part 1: Single-Table Design Patterns
April
  • Built to Last: Why Sustained Collaboration Is the Future of Tech Teams
  • Q2 2026 Roadmap: What's Next for the TCTF Portal
March
  • How We Built a Real-Time Messaging System with AWS Lambda and WebSockets
  • From Forum to Social Network: The Origin Story of Cometbid Social
  • Agentic AI: What It Means for Software Development and Why We're Paying Attention
February
  • Platform Update: Social Network Architecture, Achievement Engine, and What's Next
  • How We Built 34 Serverless Microservices: Architecture Patterns Behind the TCTF Platform
January
  • How We Secure the TCTF Platform: Principles Every Developer Should Know
  • New Year, New Projects: TCTF 2026 Roadmap

More From TCTF Newsletter

Built to Last: Why Sustained Collaboration Is the Future of Tech TeamsVol. 1, Issue 4

Built to Last: Why Sustained Collaboration Is the Future of Tech Teams

Most platforms optimize for transactions — post a job, hire, move on. TCTF is built around sustained collaboration: long-term teams, milestone-driven projects, language support that breaks barriers, and a community where everyone — not just developers — has a seat at the table.

April 15, 2026
Q2 2026 Roadmap: What's Next for the TCTF PortalQ2 2026

Q2 2026 Roadmap: What's Next for the TCTF Portal

Our quarterly roadmap for Q2 — what shipped in April, the origin of Cometbid Social, and the plan for May and June as we build toward user accounts, authentication, and the social network launch.

April 1, 2026
How We Built a Real-Time Messaging System with AWS Lambda and WebSocketsTech Series #3

How We Built a Real-Time Messaging System with AWS Lambda and WebSockets

Inside the architecture of TCTF's messaging platform — three services handling real-time chat, campaign delivery, and transactional notifications, all built on Lambda, API Gateway WebSockets, SQS, and multi-provider email with automatic failover.

March 15, 2026

Browse by Month

2026

June
  • Caching Strategies for Serverless, Part 2: ElastiCache Redis for Low-Latency Session and API Caching
  • Caching Strategies for Serverless: From In-Memory to DynamoDB-Backed TTL Caches
  • Rate Limiting at Serverless Scale: Tiered Throttling with DynamoDB
  • TCTF's DynamoDB Framework, Part 2: Building a Fluent Query Builder in TypeScript
May
  • The Struggles of Timelines and Schedules: When Building Gets Real
  • How to Stay Motivated in the Face of Uncertainties: Faith Beyond Doubt
  • Cognito Middleware: Building an Authentication Pipeline for Serverless APIs
  • Building TCTF's DynamoDB Query Framework, Part 1: Single-Table Design Patterns
April
  • Built to Last: Why Sustained Collaboration Is the Future of Tech Teams
  • Q2 2026 Roadmap: What's Next for the TCTF Portal
March
  • How We Built a Real-Time Messaging System with AWS Lambda and WebSockets
  • From Forum to Social Network: The Origin Story of Cometbid Social
  • Agentic AI: What It Means for Software Development and Why We're Paying Attention
February
  • Platform Update: Social Network Architecture, Achievement Engine, and What's Next
  • How We Built 34 Serverless Microservices: Architecture Patterns Behind the TCTF Platform
January
  • How We Secure the TCTF Platform: Principles Every Developer Should Know
  • New Year, New Projects: TCTF 2026 Roadmap