Composables
All composables are auto-imported and fully typed from your ZModel schema. They communicate with the auto-generated server endpoints and keep a normalized store in sync.
useZenstackCreate
Creates a new record.
const { mutate, data, error, status, loading, schema, reset } =
useZenstackCreate("User");Usage
NOTE
The useZenstackCreate composable does not allow setting relational fields.
const { mutate: createUser, error, loading } = useZenstackCreate("User");
const state = ref<$ZcreateData<"User">>({
email: "[email protected]",
name: "Alice",
});
async function onSubmit() {
await createUser(state.value);
}Returns
| Property | Type | Description |
|---|---|---|
data | Ref<Item | null> | The created record |
error | Ref<$Zerror | null> | Error from the last call |
status | Ref<'idle' | 'pending' | 'success' | 'error'> | Current status |
loading | ComputedRef<boolean> | true while the status is pending |
schema | ZodObject | The Zod object schema for the model (see Input Validation) |
mutate | (input) => Promise<Item | null> | Trigger the create operation |
reset | () => void | Reset data, error, and status to initial values |
useZenstackRead
Fetches a single record by ID.
const { data, error, status, loading, query } = await useZenstackRead(
"User",
userId,
);Usage
const { data: user } = await useZenstackRead("User", userId);
// With related models
const { data: user } = await useZenstackRead("User", userId, {
include: { posts: true },
});Options
| Option | Type | Default | Description |
|---|---|---|---|
fetchPolicy | FetchPolicy | module default | Override the global fetch policy for this call |
immediate | boolean | true | Run the query immediately on call |
include | object | — | Related models to include (typed from schema) |
Returns
| Property | Type | Description |
|---|---|---|
data | Ref<Item | null> | The fetched record |
error | Ref<$Zerror | null> | Error from the last query |
status | Ref<Status> | Current status |
loading | ComputedRef<boolean> | true while fetching |
query | () => Promise<void> | Re-run the query manually |
useZenstackReadMany
Fetches a list of records with optional filtering, ordering, and pagination.
const { data, error, status, loading, query, queryMore, canQueryMore, reset } =
await useZenstackReadMany("User");Usage
// Basic list
const { data: users } = await useZenstackReadMany("User");
// Filtered and ordered
const search = ref("");
const { data: users } = await useZenstackReadMany("User", {
where: () => ({ name: { contains: search.value } }),
orderBy: { createdAt: "desc" },
take: 20,
watch: true, // re-query automatically when reactive `where`/`orderBy` change
});
// Load more (cursor-based pagination)
const {
data: posts,
queryMore,
canQueryMore,
} = await useZenstackReadMany("Post", {
take: 10,
});
// Call queryMore() to append the next page
await queryMore();
// Example with VueUse useInfiniteScroll
import { useInfiniteScroll } from "@vueuse/core";
const containerRef = ref<HTMLElement | null>(null);
useInfiniteScroll(containerRef, () => queryMore(), {
distance: 10,
canLoadMore: () => canQueryMore.value,
});Options
| Option | Type | Default | Description |
|---|---|---|---|
fetchPolicy | FetchPolicy | module default | Override the global fetch policy |
immediate | boolean | true | Run the query immediately |
include | object | — | Related models to include |
where | MaybeRefOrGetter<Where> | — | Filter criteria |
orderBy | MaybeRefOrGetter<OrderBy> | — | Sort criteria |
take | number | — | Max records per page |
watch | boolean | false | Re-query when where/orderBy refs change |
Returns
| Property | Type | Description |
|---|---|---|
data | Ref<Item[] | null> | The fetched records |
error | Ref<$Zerror | null> | Error from the last query |
status | Ref<Status> | Current status |
loading | ComputedRef<boolean> | true while fetching |
canQueryMore | Ref<boolean> | false when all records have been loaded |
query | () => Promise<void> | Re-run the query (resets to first page) |
queryMore | () => Promise<void> | Append the next page of results |
reset | () => void | Reset data and pagination state |
useZenstackUpdate
Updates an existing record by ID.
const { mutate, data, error, status, loading, schema, reset } =
useZenstackUpdate("User");Usage
NOTE
The useZenstackUpdate composable does not allow setting relational fields.
import type { $ZupdateData } from "#imports";
const { mutate: updateUser, loading } = useZenstackUpdate("User");
const state = ref<$ZupdateData<"User">>({
name: "Current Name",
});
async function onSubmit(userId: string) {
await updateUser(userId, state.value);
}Returns
| Property | Type | Description |
|---|---|---|
data | Ref<Item | null> | The updated record |
error | Ref<$Zerror | null> | Error from the last call |
status | Ref<Status> | Current status |
loading | ComputedRef<boolean> | true while the status is pending |
schema | ZodObject | The Zod object schema for the model (see Input Validation) |
mutate | (id, input) => Promise<Item | null> | Trigger the update |
reset | () => void | Reset state |
useZenstackDelete
Deletes a record by ID.
const { mutate, data, error, status, loading, reset } =
useZenstackDelete("User");Usage
IMPORTANT
Deletion of relational entities triggered by cascading operations does not automatically update the store. The related entities will not be automatically removed.
const { mutate: deleteUser, loading } = useZenstackDelete("User");
await deleteUser(userId);Returns
| Property | Type | Description |
|---|---|---|
data | Ref<Item | null> | The deleted record |
error | Ref<$Zerror | null> | Error from the last call |
status | Ref<Status> | Current status |
loading | ComputedRef<boolean> | true while the status is pending |
mutate | (id) => Promise<Item | null> | Trigger the delete |
reset | () => void | Reset state |
Error Handling
All composables return an error ref typed as $Zerror | null. This type is an extension of FetchError that includes ZenStack's specific ORMError properties when a database or policy error occurs.
$Zerror Properties
When the server encounters a ZenStack error, the error object will contain the following properties inside its data payload:
| Property | Type | Description |
|---|---|---|
reason | ORMErrorReason | The reason code for the error (e.g., 'rejected-by-policy', 'not-found', 'db-query-error', 'invalid-input'). |
model | string | The name of the ZModel that the error pertains to. |
dbErrorCode | unknown | The raw error code given by the underlying database driver. |
dbErrorMessage | string | The raw error message given by the underlying database driver. |
rejectedByPolicyReason | RejectedByPolicyReason | If reason is 'rejected-by-policy', this indicates why ('no-access', 'cannot-read-back', etc). |
statusCode | number | The HTTP status code returned by the auto-generated API endpoint (e.g., 403 for policy rejections). |
For more details on ZenStack's error handling, refer to the ZenStack ORM Errors Documentation.
Type Generics
The module exports several TypeScript generics that are useful for strongly typing your application state and payload. These types are auto-imported and can also be explicitly imported from #imports.
| Type | Description |
|---|---|
$Zschema | The main SchemaType generated by ZenStack |
$Zmodel | Union type of all your defined models (e.g. 'User' | 'Post') |
$Zid<Model> | The ID type of a given model |
$Zitem<Model, Include?> | The structure of a given model record, optionally with relations |
$ZcreateData<Model> | Payload type for useZenstackCreate (omits relational fields) |
$ZupdateData<Model> | Payload type for useZenstackUpdate (omits relational fields) |
$Zwhere<Model> | Where filter argument types for read queries |
$ZorderBy<Model> | Order by argument types for read queries |
Usage Example
import type { $Zitem, $Zwhere, $Zmodel } from "#imports";
type UserModel = $Zitem<"User">;
type PostWithAuthor = $Zitem<"Post", { author: true }>;
const customFilter: $Zwhere<"User"> = {
age: { gt: 18 },
};Input Validation
The schema returned by the Create and Update composables is a Zod object schema automatically generated by ZenStack. It accurately reflects the types and validation rules defined in your ZModel.
You can securely use this schema directly with your frontend form validation libraries (e.g. Nuxt UI) to perform client-side validation that perfectly mirrors your server's validation rules. ZenStack supports a wide range of validation attributes like @email, @regex, @length, and more.
For more details on defining validation rules in your ZModel, see the official ZenStack documentation:
Example
Given the following ZModel definition:
model User {
id String @id @default(cuid())
email String @unique
@@validate(isEmail(email), 'Email is invalid', ['email'])
@@validate(length(email) >= 10, 'Email must have at least 10 characters', ['email'])
}When you use the composables useZenstackCreate('User') or useZenstackUpdate('User'), the returned schema will automatically enforce these exact same validation rules on your frontend forms before submission.