| name | kv-optimization-advisor |
| description | Automatically optimizes Cloudflare KV storage patterns, suggesting parallel operations, caching strategies, and storage choice guidance |
| triggers | ["KV operations","storage access patterns","sequential storage calls","large data patterns"] |
KV Optimization Advisor SKILL
Activation Patterns
This SKILL automatically activates when:
- KV
get, put, delete, or list operations are detected
- Sequential storage operations that could be parallelized
- Large data patterns that might exceed KV limits
- Missing caching opportunities for repeated KV calls
- Storage choice patterns (KV vs R2 vs D1)
Expertise Provided
KV Performance Optimization
- Parallel Operations: Identifies sequential KV calls that can be parallelized
- Request-Scoped Caching: Suggests in-memory caching during request processing
- Storage Choice Guidance: Recommends KV vs R2 vs D1 based on use case
- Value Size Optimization: Monitors for large values that impact performance
- Batch Operations: Suggests batch operations when appropriate
- TTL Optimization: Recommends optimal TTL strategies
Specific Checks Performed
❌ KV Performance Anti-Patterns
const user = await env.USERS.get(id);
const settings = await env.SETTINGS.get(id);
const prefs = await env.PREFS.get(id);
const user1 = await env.USERS.get(id);
const user2 = await env.USERS.get(id);
✅ KV Performance Best Practices
const [user, settings, prefs] = await Promise.all([
env.USERS.get(id),
env.SETTINGS.get(id),
env.PREFS.get(id),
]);
const cache = new Map();
async function getCached(key: string, env: Env) {
if (cache.has(key)) return cache.get(key);
const value = await env.USERS.get(key);
cache.set(key, value);
return value;
}
Integration Points
Complementary to Existing Components
- edge-performance-oracle agent: Handles comprehensive performance analysis, SKILL provides immediate KV optimization
- cloudflare-architecture-strategist agent: Handles storage architecture decisions, SKILL provides immediate optimization
- workers-binding-validator SKILL: Ensures KV bindings are correct, SKILL optimizes usage patterns
Escalation Triggers
- Complex storage architecture questions →
cloudflare-architecture-strategist agent
- KV performance troubleshooting →
edge-performance-oracle agent
- Storage migration strategies →
cloudflare-architecture-strategist agent
Validation Rules
P1 - Critical (Performance Killer)
- Sequential Operations: Multiple sequential KV calls that could be parallelized
- Repeated Calls: Same KV key fetched multiple times in one request
- Large Values: Values approaching 25MB KV limit
P2 - High (Performance Impact)
- Missing Caching: Repeated expensive KV operations without caching
- Wrong Storage Choice: Using KV for data that should be in R2 or D1
- No TTL Strategy: Missing or inappropriate TTL configuration
P3 - Medium (Optimization Opportunity)
- Batch Opportunities: Multiple operations that could be batched
- Suboptimal TTL: TTL values that are too short or too long
- Missing Error Handling: KV operations without proper error handling
Remediation Examples
Fixing Sequential Operations
export default {
async fetch(request: Request, env: Env) {
const userId = getUserId(request);
const user = await env.USERS.get(userId);
const settings = await env.SETTINGS.get(userId);
const prefs = await env.PREFS.get(userId);
return new Response(JSON.stringify({ user, settings, prefs }));
}
}
export default {
async fetch(request: Request, env: Env) {
const userId = getUserId(request);
const [user, settings, prefs] = await Promise.all([
env.USERS.get(userId),
env.SETTINGS.get(userId),
env.PREFS.get(userId),
]);
return new Response(JSON.stringify({ user, settings, prefs }));
}
}
Fixing Repeated Calls with Caching
export default {
async fetch(request: Request, env: Env) {
const userId = getUserId(request);
const user1 = await env.USERS.get(userId);
const user2 = await env.USERS.get(userId);
const user3 = await env.USERS.get(userId);
return new Response('Processed');
}
}
export default {
async fetch(request: Request, env: Env) {
const userId = getUserId(request);
const cache = new Map();
async function getCachedUser(id: string) {
if (cache.has(id)) return cache.get(id);
const user = await env.USERS.get(id);
cache.set(id, user);
return user;
}
const user1 = await getCachedUser(userId);
const user2 = await getCachedUser(userId);
const user3 = await getCachedUser(userId);
return new Response('Processed');
}
}
Fixing Storage Choice
export default {
async fetch(request: Request, env: Env) {
const fileId = new URL(request.url).searchParams.get('id');
const fileData = await env.FILES.get(fileId);
return new Response(fileData);
}
}
export default {
async fetch(request: Request, env: Env) {
const fileId = new URL(request.url).searchParams.get('id');
const object = await env.FILES_BUCKET.get(fileId);
if (!object) {
return new Response('Not found', { status: 404 });
}
return new Response(object.body);
}
}
Fixing TTL Strategy
export default {
async fetch(request: Request, env: Env) {
const cacheKey = `data:${Date.now()}`;
await env.CACHE.put(cacheKey, data);
}
}
export default {
async fetch(request: Request, env: Env) {
const cacheKey = 'user:profile:123';
await env.CACHE.put(cacheKey, data, {
expirationTtl: 3600
});
await env.API_CACHE.put(apiKey, response, {
expirationTtl: 300
});
await env.STATIC_CACHE.put(staticKey, data, {
expirationTtl: 86400
});
}
}
Fixing Large Value Handling
export default {
async fetch(request: Request, env: Env) {
const reportId = new URL(request.url).searchParams.get('id');
const report = await env.REPORTS.get(reportId);
return new Response(report);
}
}
export default {
async fetch(request: Request, env: Env) {
const reportId = new URL(request.url).searchParams.get('id');
const compressed = await env.REPORTS.get(reportId);
const decompressed = decompress(compressed);
const object = await env.REPORTS_BUCKET.get(reportId);
return new Response(object.body);
}
}
Storage Choice Guidance
Use KV When:
- Small values (< 1MB typical, < 25MB max)
- Key-value access patterns
- Eventually consistent data is acceptable
- Low latency reads required globally
- Simple caching needs
Use R2 When:
- Large objects (files, images, videos)
- S3-compatible access needed
- Strong consistency required
- Object storage patterns
- Large files (> 1MB)
Use D1 When:
- Relational data with complex queries
- Strong consistency required
- SQL operations needed
- Structured data with relationships
- Complex queries and joins
MCP Server Integration
When Cloudflare MCP server is available:
- Query KV performance metrics (latency, hit rates)
- Analyze storage usage patterns
- Get latest KV optimization techniques
- Check storage limits and quotas
Benefits
Immediate Impact
- Faster Response Times: Parallel operations reduce latency by 3x or more
- Reduced KV Costs: Fewer operations and better caching
- Better Performance: Proper storage choice improves overall performance
Long-term Value
- Consistent Optimization: Ensures all KV usage follows best practices
- Cost Efficiency: Optimized storage patterns reduce costs
- Better User Experience: Faster response times from optimized storage
Usage Examples
During KV Operation Writing
During Storage Architecture
During Caching Implementation
Performance Targets
KV Operation Latency
- Excellent: < 10ms (parallel operations)
- Good: < 30ms (single operation)
- Acceptable: < 100ms (sequential operations)
- Needs Improvement: > 100ms
Cache Hit Rate
- Excellent: > 90%
- Good: > 75%
- Acceptable: > 50%
- Needs Improvement: < 50%
This SKILL ensures KV storage performance by providing immediate, autonomous optimization of storage patterns, preventing common performance issues and ensuring efficient data access.