Recipes

Instant List → Detail Navigation

Reuse list query cache on a slug page for immediate title/description rendering.

Goal

Make a detail page feel instant after clicking from a list/grid:

  • show cached title/description immediately
  • fetch the full detail record in the background
  • avoid undocumented helper APIs

Pattern

Use the supported primitives together:

  • getQueryKey(...)
  • useNuxtData(...)
  • useConvexQuery(..., { default })

getQueryKey is intentionally not auto-imported. Use an explicit import from better-convex-nuxt/composables.

List Page (populate cache)

<script setup lang="ts">
import { api } from '~~/convex/_generated/api'

const { data: posts } = await useConvexQuery(api.posts.list, {})
</script>

Detail Page (reuse cache, then load full data)

<script setup lang="ts">
import { api } from '~~/convex/_generated/api'
import { getQueryKey } from 'better-convex-nuxt/composables'

const route = useRoute()
const slug = computed(() => route.params.slug as string)

const listCacheKey = getQueryKey(api.posts.list, {})
const { data: cachedPosts } = useNuxtData(listCacheKey)

const cachedCard = computed(() => cachedPosts.value?.find((post) => post.slug === slug.value))

const { data: post } = await useConvexQuery(
  api.posts.getBySlug,
  computed(() => ({ slug: slug.value })),
  {
    default: () =>
      cachedCard.value
        ? {
            title: cachedCard.value.title,
            description: cachedCard.value.description,
            content: null,
          }
        : undefined,
    transform: (fullPost) =>
      fullPost
        ? {
            title: fullPost.title,
            description: fullPost.description,
            content: fullPost.content,
          }
        : null,
  },
)
</script>

Why This Is Better Than Old Cache Helpers

  • Uses Nuxt-native cache access (useNuxtData)
  • Uses the library’s exported cache-key source of truth (getQueryKey)
  • Keeps behavior explicit and easy to debug
  • Works without introducing extra public APIs like useConvexCached

Playground Demo

There is a working playground version of this pattern at:

  • /labs/query-features/cache-reuse

It uses a slug-shaped route ([slug].vue) and shows whether the detail page is currently rendering:

  • cached preview data
  • or full data from the detail query