Guides

Realtime

Update data instantly when changes happen on the server.

Realtime Provider

Use a Realtime provider to enable instant updates in your application. This provider handles subscriptions to events (like record creation, updates, or deletions) and publishing custom events.

The Realtime interface defines the contract:

interface Realtime {
    // Subscribe to updates
    subscribe: (props: SubscribeProps) => UnsubscribeFn
    // Unsubscribe from updates (optional)
    unsubscribe?: (props: UnsubscribeProps) => void
    // Publish a custom event (optional)
    publish?: (event: RealtimeEvent) => void
}

Modes

There are two main ways to handle realtime events: Auto and Manual.

ModeHow It WorksWhen to Use
AutoFramework automatically invalidates queries and refetches dataMost common - reduces boilerplate code
ManualYou handle events in callbacks with full controlComplex logic - conditional updates, multiple actions

Auto Mode

In auto mode, the framework automatically invalidates related queries when an event is received. For example, if a "post" is updated on the server, any active useGetList or useGetOne queries for that post will be refetched automatically.

Scenario: Real-time collaborative editor where multiple users edit the same document.

<script setup lang="ts">
import { useGetOne } from '@ginjou/vue'

// Auto mode (default)
const { data: post } = useGetOne({
    resource: 'posts',
    id: '123',
})

// When another user updates this post on server:
// 1. Event is received
// 2. Query cache is invalidated
// 3. useGetOne automatically refetches
// 4. UI updates with latest data
</script>

<template>
    <div>
        <h1>{{ post?.title }}</h1>
        <p>Last updated: {{ post?.updatedAt }}</p>
    </div>
</template>

Manual Mode

In manual mode, you handle the event yourself in a callback. This provides total control over how the UI responds to changes.

<script setup lang="ts">
import { GetOne, RealtimeMode } from '@ginjou/core'
import { useGetOne, useQueryClientContext } from '@ginjou/vue'

const queryClient = useQueryClientContext()
const { data: post } = useGetOne({
    resource: 'posts',
    id: '123',
    realtime: {
        mode: RealtimeMode.Manual,
        callback: (event) => {
            console.log(event) // { channel: "resources/posts", action: "updated", payload: { ids: ["123"] }, date: new Date(), meta: { fetcherName: "default" }
        },
    }
})
</script>

<template>
    <div>
        <h1>{{ post?.title }}</h1>
        <p>Last updated: {{ post?.updatedAt }}</p>
    </div>
</template>

Integrated Data Query

The framework integrates realtime events with data queries, allowing automatic synchronization between the server and client. These hooks automatically subscribe to their resource channels and respond to realtime events based on the mode configuration.

The following sequence diagram shows how data is updated in auto mode when a record is modified:

mermaid
sequenceDiagram
    participant User
    participant Client1 as Client 1
    participant Server as Server
    participant Client2 as Client 2

	Client1->>Server: useGetList subscribe "posts"
	Client2->>Server: useGetList subscribe "posts"

    User->>Client1: Submit new "posts"
    Client1->>Server: useUpdateOne update "posts"
    Server->>Server: Update record
	Server->>Client1: Response "posts" data

    alt Realtime Provider has "publish" function
        Client1->>Server: Publish event via realtime provider
    end

    Server-->>Client1: Send "resources/posts" event with action "updated"
    Server-->>Client2: Send "resources/posts" event with action "updated"

    par Auto Mode - Query Invalidation & Refetch
        Client1->>Client1: Invalidate cache
        Client2->>Client2: Invalidate cache
        Client1->>Server: Refetch useGetList
        Client2->>Server: Refetch useGetList
		Server-->>Client1: Return updated list
		Server-->>Client2: Return updated list
		Client1->>Client1: Update UI with new data
		Client2->>Client2: Update UI with new data
    end

Get List

The useGetList hook automatically subscribes to the resources/{resource} channel and listens for all event types.

<script setup lang="ts">
import { useGetList } from '@ginjou/vue'

useGetList({ resource: 'posts' })
</script>

Subscribes to:

{
    "channel": "resources/posts",
    "actions": ["*"],
    "params": {
        "type": "list",
        "resource": "posts",
        "pagination": {
            "current": 1,
            "perPage": 10
        },
        "sorters": [],
        "filters": [],
        "meta": {}
    }
}

Get One

The useGetOne hook automatically subscribes to the resources/{resource} channel with a specific record ID.

<script setup lang="ts">
import { useGetOne } from '@ginjou/vue'

useGetOne({ resource: 'posts', id: '1' })
</script>

Subscribes to:

{
    "channel": "resources/posts",
    "actions": ["*"],
    "params": {
        "type": "one",
        "resource": "posts",
        "id": "1",
        "meta": {}
    }
}

Get Many

The useGetMany hook automatically subscribes to the resources/{resource} channel for multiple specific record IDs.

<script setup lang="ts">
import { useGetMany } from '@ginjou/vue'

useGetMany({ resource: 'posts', ids: ['1', '2', '3'] })
</script>

Subscribes to:

{
    "channel": "resources/posts",
    "actions": ["*"],
    "params": {
        "type": "many",
        "resource": "posts",
        "ids": ["1", "2", "3"],
        "meta": {}
    }
}

Create Operation

The useCreateOne and useCreateMany hooks automatically publish created events when records are successfully created.

<script setup lang="ts">
import { useCreateOne } from '@ginjou/vue'

const { mutate } = useCreateOne()

mutate({
    resource: 'posts',
    values: { title: 'New Post' },
})
</script>

Publishes:

{
    "channel": "resources/posts",
    "action": "created",
    "payload": {
        "ids": ["newly-created-id"]
    },
    "date": "...ISO Date"
}

Update Operation

The useUpdateOne and useUpdateMany hooks automatically publish updated events when records are successfully updated.

<script setup lang="ts">
import { useUpdateOne } from '@ginjou/vue'

const { mutate } = useUpdateOne()

mutate({
    resource: 'posts',
    id: '1',
    values: { title: 'Updated Title' },
})
</script>

Publishes:

{
    "channel": "resources/posts",
    "action": "updated",
    "payload": {
        "ids": ["1"]
    },
    "date": "...ISO Date"
}

Delete Operation

The useDeleteOne and useDeleteMany hooks automatically publish deleted events when records are successfully deleted.

<script setup lang="ts">
import { useDeleteOne } from '@ginjou/vue'

const { mutate } = useDeleteOne()

mutate({
    resource: 'posts',
    id: '1',
})
</script>

Publishes:

{
    "channel": "resources/posts",
    "action": "deleted",
    "payload": {
        "ids": ["1"]
    },
    "date": "...ISO Date"
}

Subscribe

Use useSubscribe to listen for events on a specific channel or resource.

<script setup lang="ts">
import { useSubscribe } from '@ginjou/vue'

useSubscribe({
    channel: 'resources/posts',
    actions: ['created', 'updated', 'deleted'],
    callback: (event) => {
        console.log('Realtime event received:', event)
    },
})
</script>

Publish

Use usePublish to send custom events to other users or components.

<script setup lang="ts">
import { usePublish } from '@ginjou/vue'

const publish = usePublish()

function handleInteraction() {
    // Publish custom event
    publish({
        channel: 'resources/posts',
        action: 'updated',
        payload: {
            ids: ['1234'],
            otherAttrs: 'ya',
        },
    })
}
</script>

<template>
    <button @click="handleInteraction">
        Move cursor
    </button>
</template>
Copyright © 2026