@pinia/colada 1.4.5
The smart data fetching layer for Vue.js, built on Pinia. Queries read and cache
data (useQuery), mutations write data (useMutation), everything lives in
Pinia stores (useQueryCache, useMutationCache).
- Docs: https://pinia-colada.esm.dev
- API types:
dist/index.d.mtsin the prepared package source - Runtime exports:
dist/index.mjs:1487 - Peers:
vue ^3.5.41,pinia ^2.2.6 || ^3.0.0 || ^4.0.2(pinia 4 allowed since 1.4.1,package.json:91-94) - Bundled codemods:
codemods/rules/*.yamlin the package
Setup
npm install pinia @pinia/colada
import { createPinia } from 'pinia'
import { PiniaColada } from '@pinia/colada'
const app = createApp(App)
app.use(createPinia())
// install after pinia; the options object is required for correct typing
app.use(PiniaColada, {
queryOptions: { staleTime: 60_000 },
plugins: [],
})
Global options go under queryOptions / mutationOptions (dist/index.d.mts:1601-1618).
Mental model
- A query is identified by its
key: a JSON-serializable array (EntryKey,dist/index.d.mts:119). Keys are hierarchical:{ key: ['todos'] }also matches['todos', { filter: 'done' }]when filtering. statusis the data status:'pending' | 'success' | 'error'.asyncStatusis the operation status:'idle' | 'loading'. They are separate on purpose (https://pinia-colada.esm.dev/guide/queries.md).- Defaults:
staleTime: 5000,gcTime: 300_000,refetchOnMount,refetchOnWindowFocus,refetchOnReconnect,enabled: true(dist/index.mjs:92-97). MutationgcTimedefault is60_000(dist/index.d.mts:1379).
Core patterns
Basic query
<script setup lang="ts">
import { useQuery } from '@pinia/colada'
const { state, asyncStatus } = useQuery({
key: ['todos'],
query: () => fetch('/api/todos').then(res => res.json()),
})
</script>
<template>
<div v-if="state.status === 'pending'">Loading...</div>
<div v-else-if="state.status === 'error'">{{ state.error.message }}</div>
<ul v-else>
<li v-for="todo in state.data" :key="todo.id">{{ todo.text }}</li>
</ul>
</template>
Use the grouped state object for type narrowing in templates. TypeScript
cannot narrow separate data / error refs from status
(https://pinia-colada.esm.dev/guide/queries.md).
Reactive keys: pass a getter
Everything the query function reads (route params, refs) must be in the key.
Pass key as a getter so the query refetches when dependencies change:
const { data } = useQuery({
key: () => ['contacts', route.params.id as string],
query: () => fetch(`/api/contacts/${route.params.id}`).then(r => r.json()),
})
Guard queries with enabled
Prevent invalid fetches when a required param is absent (common in stores and global queries):
useQuery({
key: () => ['decks', route.params.deckId],
query: () => fetchDeck(route.params.deckId as string),
enabled: () => 'deckId' in route.params,
})
Type-safe shared options: defineQueryOptions
export const todoOptions = defineQueryOptions((id: string) => ({
key: ['todos', id],
query: () => fetchTodo(id),
}))
// single-function form; the returned key is tagged so queryCache infers TData
const { data } = useQuery(() => todoOptions(route.params.id as string))
const todo = queryCache.getQueryData(todoOptions('1').key) // typed
useQuery accepts options or a getter returning options
(dist/index.d.mts:733). Since 1.0 the two-parameter form
useQuery(options, paramsGetter) is removed; see
references/migration.md.
Shared query state: defineQuery
Wrap queries used by multiple components so refs are created once, like a tiny Pinia store. The setup function must be synchronous:
export const useFilteredTodos = defineQuery(() => {
const search = ref('')
const query = useQuery({
key: () => ['todos', { search: search.value }],
query: () => fetchTodos(search.value),
})
return { ...query, search }
})
Details: references/queries.md.
Mutation + invalidation
const queryCache = useQueryCache()
const { mutate, isLoading } = useMutation({
mutation: (text: string) => createTodo(text),
async onSettled() {
await queryCache.invalidateQueries({ key: ['todos'] })
},
})
mutate(vars)never rejects; use it in templates and event handlers.mutateAsync(vars)returns a promise and rejects on failure.- Put
onMutatebeforemutationin the options object so its returned context is inferred in later hooks (dist/index.d.mts:1410-1433). - Optimistic updates: write to the cache in
onMutate, roll back inonErroronly if the cache still holds your optimistic value. Full pattern in references/mutations.md.
Queries have no onSuccess/onError
This is intentional: a query can have many watchers. Use watch(data, ...),
or global hooks via PiniaColadaQueryHooksPlugin
(https://pinia-colada.esm.dev/plugins/official/query-hooks.md).
Version-critical rules (1.x)
useQuery(setup, paramsGetter)anduseQueryState(setup, paramsGetter)were removed in 1.0.0. Migrate with the shipped codemod:ast-grep scan -r node_modules/@pinia/colada/codemods/rules/migration-0-21-to-1-0.yaml -i src(https://github.com/posva/pinia-colada/blob/main/CHANGELOG.md).useQueryState(key)reads query state without fetching; the key is the only argument (dist/index.d.mts:920-926).initialDatachanges query state tosuccess;placeholderDatadoes not change the cache (dist/index.d.mts:558-600).- To reset an entry's state manually use
queryCache.setEntryState(entry, state); setting data toundefinedviasetQueryData()no longer resets state. - Infinite query data is
{ pages, pageParams }; usesetInfiniteQueryData()(added 1.2.0), notsetQueryData(), to prime infinite entries. - Devtools are a separate package:
@pinia/colada-devtools. - Nuxt: install the
@pinia/colada-nuxtmodule; it handles SSR serialization automatically.
References
- queries.md:
useQueryAPI, options, return values,useQueryState,defineQuery,defineQueryOptions, key factories - mutations.md:
useMutationAPI, hooks and context, optimistic updates,defineMutation,defineMutationOptions - infinite-queries.md:
useInfiniteQuery,defineInfiniteQueryOptions,setInfiniteQueryData,maxPages - query-cache.md: cache stores, invalidation, filters, manual cache writes, error codes
- plugins.md: plugin API,
PiniaColadaQueryHooksPlugin,TypesConfigaugmentation, official plugin packages - ssr.md: serialization and hydration, lazy queries,
PiniaColadaSSRNoGc - migration.md: 0.x to 1.x changes and codemods