Tag Design
Good tag design makes invalidation natural. Bad tag design leads to stale data, mass hysteria, and eventually a Hacker News post that nobody will read about why caching is bad.
Hierarchical Structure
Section titled “Hierarchical Structure”Structure tags from general to specific:
// Good: hierarchicalconst tags = defineTags({ org: (id: string) => ['org', id], orgTeams: (id: string) => ['org', id, 'teams'], team: (orgId: string, teamId: string) => ['org', orgId, 'team', teamId], teamMembers: (orgId: string, teamId: string) => ['org', orgId, 'team', teamId, 'members'],});
// Invalidate org → invalidates all teams, members# Good: hierarchicaltags = define_tags({ "org": lambda id: ("org", id), "org_teams": lambda id: ("org", id, "teams"), "team": lambda org_id, team_id: ("org", org_id, "team", team_id), "team_members": lambda org_id, team_id: ("org", org_id, "team", team_id, "members"),})
# Invalidate org → invalidates all teams, membersAvoid Flat Tags
Section titled “Avoid Flat Tags”// Bad: flat (no prefix matching benefit)const tags = defineTags({ user: (id: string) => ['user', id], posts: (userId: string) => ['posts', userId], // Not under 'user'});
// Invalidating user doesn't invalidate posts!# Bad: flat (no prefix matching benefit)tags = define_tags({ "user": lambda id: ("user", id), "posts": lambda user_id: ("posts", user_id), # Not under "user"})
# Invalidating user doesn't invalidate posts!Include All Relevant IDs
Section titled “Include All Relevant IDs”// Good: includes both IDsconst tags = defineTags({ postComments: (postId: string, authorId: string) => ['post', postId, 'comments', 'author', authorId],});
// Can invalidate by post OR by author# Good: includes both IDstags = define_tags({ "post_comments": lambda post_id, author_id: ( "post", post_id, "comments", "author", author_id ),})
# Can invalidate by post OR by author