Skip to content

Tags, Queries, Invalidations

Tags are the first step in caching. They’re a way for you to give logical names to your database and API operations.

For example, if you have a user with ID 123, you might tag it as ['user', '123']. If that user has posts, you might tag those as ['user', '123', 'posts'].

tl;dr - tags are simple names for the things you care about.

const tags = defineTags({
user: (id: string) => ['user', id],
userPosts: (id: string) => ['user', id, 'posts'],
});

Queries are read-only interactions with a database, API, blockchain, file system, or any otherwise persnickety entity. We attach tags to queries to say “instead of doing that expensive operation every time, when we see this tag again, use the cached result.”

// "get user 123, and remember it by this tag"
const getUser = t87s.query((id: string) => ({
tags: [tags.user(id)],
fn: () => db.users.findById(id),
}));

Nothing in this world is permanent (except impermanence itself), and that’s why you need invalidations. They tell the caching engine that data is stale and needs to be refetched.

// "user 123 changed, forget what you knew"
const updateUser = t87s.mutation(async (id, data) => {
const user = await db.users.update(id, data);
return {
result: user,
invalidates: [tags.user(id)],
};
});

So there you have it:

  1. Tags give operations names
  2. Queries use tags to know when we can hit the speedy cache instead of the slow operation
  3. Invalidations tell the cache that data is stale and needs to be refreshed

Here’s how they work together:

// First call: cache miss, fetches from DB
const user = await getUser('123');
// Second call: cache hit, instant
const userAgain = await getUser('123');
// Update triggers invalidation
await updateUser('123', { name: 'New Name' });
// Next call: cache miss (was invalidated), fetches fresh data
const freshUser = await getUser('123');

You might have noticed tags are arrays like ['user', '123'] instead of strings like 'user:123'. This enables something we call “hierarchical invalidation”, which sounds as pretentious as it is. When you invalidate ['user', '123'], it also invalidates ['user', '123', 'posts'] and ['user', '123', 'settings'].

See Prefix Matching for the details.