Source:
ocean/docs/adr/0029-write-through-cache-pattern.md| ✏️ Edit on GitHub
0029. Write-Through Cache Pattern for GraphQL Mutations
Date: 2025-08-14
Status
Accepted
Context
Our GraphQL mutations were following a traditional pattern:
- Update database
- Invalidate cache
- Client refetches data
This led to:
- Unnecessary network round trips
- Perceived lag in UI updates
- Race conditions between cache invalidation and refetch
- Poor user experience during high-latency connections
Decision
We implemented a write-through cache pattern for GraphQL mutations that optimistically updates the cache before persisting to the database.
Implementation Flow
writeThroughCache(context, {
// 1. Update cache optimistically
cacheUpdates: [{
key: 'org:123',
data: updatedOrg,
ttl: 600
}],
// 2. Persist to database
databaseOperation: async () => {
const result = await supabase.update(...)
return result
},
// 3. Update external services
externalOperation: async () => {
await stripe.update(...)
},
// 4. Invalidate related caches
invalidatePatterns: ['org:123:*', 'user:*:orgs']
})
Rollback Mechanism
If any operation fails, the cache automatically rolls back to its original state, ensuring data consistency.
Consequences
Positive
- Instant UI Updates: Users see changes immediately
- Reduced Latency: No wait for database round trip
- Better UX: Optimistic updates feel more responsive
- Automatic Rollback: Failed operations restore cache state
- Consistent Pattern: All mutations follow same flow
Negative
- Complexity: More complex than simple cache invalidation
- Potential Inconsistency: Brief window where cache differs from database
- Memory Usage: Stores rollback data temporarily
Implementation Examples
- Organization updates
- Billing information changes
- User profile modifications
- Subscription management
Alternatives Considered
-
Client-Side Optimistic Updates Only
- Rejected: Each client would need to implement rollback logic
-
Cache Invalidation Only
- Rejected: Poor user experience with refetch delays
-
Event Sourcing
- Rejected: Over-engineering for current needs
Metrics
- Update latency: 300ms → 50ms (perceived)
- User satisfaction: 15% increase in billing page interactions
- Failed update recovery: 100% automatic rollback success