Backend

Queries

Read data from your Convex database with reactive queries.

Queries read data from your database. They are reactive — the UI updates automatically when underlying data changes.

Queries are read-only and cannot modify data. Use mutations to write data.

Basic Query

Create a query in your convex/ directory:

convex/tasks.ts
import { v } from 'convex/values'
import { query } from './_generated/server'

export const list = query({
  args: { userId: v.string() },
  handler: async (ctx, { userId }) => {
    return await ctx.db
      .query('tasks')
      .withIndex('by_user', q => q.eq('userId', userId))
      .order('desc')
      .collect()
  },
})

The query function defines a server-side function that:

  • Accepts typed arguments
  • Accesses the database through ctx.db
  • Returns data to the client

Fetching a Single Document

Use ctx.db.get() to fetch a document by ID:

convex/tasks.ts
export const get = query({
  args: { id: v.id('tasks') },
  handler: async (ctx, { id }) => {
    return await ctx.db.get(id)
  },
})

Query Methods

The database query builder provides several methods:

MethodDescription
.query('table')Start a query on a table
.withIndex()Filter using an index
.filter()Filter with a predicate
.order('asc'/'desc')Sort results
.collect()Return all matching documents
.first()Return first matching document
.take(n)Return first n documents

Using in Components

Call queries from Vue components with useConvexQuery:

app/pages/tasks.vue
<script setup lang="ts">
import { api } from '#convex/api'

const { data: tasks, isLoading } = useConvexQuery(api.tasks.list, { userId: 'user_123' })
</script>

<template>
  <ul v-if="!isLoading">
    <li v-for="task in tasks" :key="task._id">
      {{ task.title }}
    </li>
  </ul>
</template>

See useConvexQuery for full documentation.

Next Steps