---
title: "Sharing & Caching Data"
framework: vue
version: "2.1.2"
---

# Sharing & Caching Data

A Data Engine loads, processes, and caches data for Studio widgets. Studio creates one automatically when you pass data sources via the `data` property, but you can create the engine yourself to share it across instances, or replace it entirely with a custom backend.

## Built-in Engine

When you pass data sources directly to Studio, it creates a built-in Data Engine behind the scenes. Creating the engine externally with `createDataEngine(data)` gives you two benefits:

- **Sharing** - multiple Studio instances can point at the same engine, so they share a single copy of the data.
- **Caching across lifecycles** - the engine survives when Studio is destroyed and recreated, so data doesn't need to be re-fetched or reprocessed on remount.

#### Data Engine

```ts
import type {
  AgDataEngine,
  AgDataSourcesDefinition,
  AgReportState,
} from "ag-studio";
import { createDataEngine } from "ag-studio";
import { AgStudio } from "ag-studio-vue3";
import { createApp, defineComponent, onMounted, ref, shallowRef } from "vue";

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
            <div style="display: flex; flex-direction: column; height: 100%">
                <div class="example-controls">
                    <div class="controls-row">
                        <button v-on:click="recreate()">{{ created ? 'Destroy Studio Instance' : 'Recreate with Data Engine' }}</button>
                    </div>
                </div>
                <ag-studio
                    v-if="created"
                    style="width: 100%; height: 100%;"
                    class="my-studio-container"
                    :initialState="initialState"
                    :mode="'edit'"
                    :data="data"></ag-studio>
                <div class="my-studio-container" v-if="!created">No current Studio instance</div>
            </div>
        </div>
    `,
  components: {
    "ag-studio": AgStudio,
  },
  setup(props) {
    const initialState = ref<AgReportState>({
      pages: [
        {
          id: "page1",
          widgets: {
            "1": {
              type: "grid",
              dataMapping: {
                cols: [
                  { id: "medals.country" },
                  { id: "medals.sport" },
                  { id: "medals.gold", aggregation: "sum" },
                  { id: "medals.silver", aggregation: "sum" },
                  { id: "medals.bronze", aggregation: "sum" },
                  { id: "medals.total", aggregation: "sum" },
                ],
              },
            },
            "2": {
              type: "column-chart-grouped",
              dataMapping: {
                categoryKey: [{ id: "medals.country" }],
                valueKey: [
                  { id: "medals.gold", aggregation: "sum" },
                  { id: "medals.silver", aggregation: "sum" },
                  { id: "medals.bronze", aggregation: "sum" },
                ],
                tooltipKey: [],
              },
            },
          },
          widgetLayout: {
            "1": {
              xTrack: 0,
              yTrack: 0,
              xSpan: 24,
              ySpan: 16,
            },
            "2": {
              xTrack: 0,
              yTrack: 16,
              xSpan: 24,
              ySpan: 16,
            },
          },
        },
      ],
      selectedPageId: "page1",
      panels: {
        filters: {
          collapsed: true,
        },
        edit: {
          collapsed: true,
        },
      },
    });
    const created = ref<boolean>(true);
    const data = shallowRef<AgDataSourcesDefinition | AgDataEngine>(null);

    onMounted(() => {
      fetch("https://www.ag-grid.com/studio/example-assets/olympic-winners.json")
        .then((resp) => resp.json())
        .then(
          (respData) =>
            (data.value = createDataEngine({
              sources: [{ id: "medals", data: respData }],
            })),
        );
    });

    const recreate = () => {
      created.value = !created.value;
    };

    return {
      initialState,
      created,
      data,
      recreate,
    };
  },
});

const app = createApp(VueExample);
app.mount("#app");
```

[Live example: Data Engine](https://www.ag-grid.com/studio/examples/sharing-caching-data/data-engine/vue3/)

```ts
const dataEngine = createDataEngine({
    sources: [{
        id: 'medals',
        data: [
            {
                year: 2000,
                sport: 'Swimming',
                country: 'United States',
                // ... other fields
            },
            // ... other rows
        ],
    }],
});
```

```ts
<ag-studio
    :data="data"
    /* other studio properties ... */>
</ag-studio>

this.data = dataEngine;
```

See [Sync Data](https://www.ag-grid.com/studio/vue/sync-data/) and [Async Data](https://www.ag-grid.com/studio/vue/async-data/) for the full range of data loading patterns.

`createDataEngine(data)` accepts a `data` object of type `AgDataSourcesDefinition`.

| Property | Type | Default | Description |
| --- | --- | --- | --- |
| `sources` | `AgDataSource<TRegistry>[]` |  | One or more data sources. |
| `relationships` | `AgRelationDefinition[]` |  | When using multiple related tables, this describes the fields that link the tables together. |
| `expressions` | `AgExpressionFieldDefinition<TRegistry, AgFormat<TRegistry>, any>[]` |  | Expression field definitions for calculated columns. |
| `formats` | `TRegistry["formats"]` |  | Overrides to existing formats, or additional custom formats. |
| `description` | `string` |  | AI-facing overview of the entire dataset: what it contains, what it's for, domain quirks. |
| `calendars` | `AgCalendar[]` |  | Named time dimensions (calendars) that supply date fragments and a continuous date spine. |
| `buckets` | `TRegistry["buckets"]` |  | Additional date-fragment bucket definitions to register alongside the built-in set (year, quarter, month, week, day, monthOfYear, dayOfWeek, …). Use this to add project-specific groupings such as `weekend`, `dayOfMonth`, or `hour` that the built-in registry does not include. Provide via createBuckets so type-level registry inference works correctly. |
| `options` | `AgDataSourcesOptions` |  | Engine-wide behavioural options, such as fan-out detection policy. |

## Embedding Single Widgets

A widget cannot be used on its own outside of Studio. To place an individual widget in your own application, run a Studio instance that shows a single widget filling the canvas, with the panels hidden. Several such instances can share one engine, so the data is loaded once.

#### Single Widgets

```ts
import type { AgDataEngine, AgReportState, AgWidgetState } from "ag-studio";
import { createDataEngine, studioTheme } from "ag-studio";
import { AgStudio } from "ag-studio-vue3";
import { createApp, defineComponent, onMounted, ref, shallowRef } from "vue";

// A single full-canvas widget, no panels - a Studio instance acting as one embeddable widget.
function singleWidgetState(id: string, widget: AgWidgetState): AgReportState {
  return {
    pages: [
      {
        id: "page1",
        widgets: { [id]: widget },
        widgetLayout: { [id]: { xTrack: 0, yTrack: 0, xSpan: 1, ySpan: 1 } },
      },
    ],
    selectedPageId: "page1",
  };
}

const VueExample = defineComponent({
  template: `
        <div class="single-widgets">
            <ag-studio
                class="single-widget"
                :mode="'view'"
                :panels="{}"
                :layout="layout"
                :theme="theme"
                :initialState="gridState"
                :data="data"></ag-studio>
            <div class="app-area">Your Application</div>
            <ag-studio
                class="single-widget"
                :mode="'view'"
                :panels="{}"
                :layout="layout"
                :theme="theme"
                :initialState="chartState"
                :data="data"></ag-studio>
        </div>
    `,
  components: {
    "ag-studio": AgStudio,
  },
  setup() {
    // Remove the spacing around the canvas so the widget fills its instance edge to edge.
    const theme = studioTheme.withParams({ studioWrapperSpacing: 0 });
    const layout = {
      minWidth: 300,
      height: 300,
      columns: 1,
      rowHeight: 300,
      pagePadding: 0,
      widgetPadding: 0,
    };

    const gridState = ref<AgReportState>(
      singleWidgetState("1", {
        type: "grid",
        dataMapping: {
          cols: [
            { id: "medals.country" },
            { id: "medals.gold", aggregation: "sum" },
            { id: "medals.silver", aggregation: "sum" },
            { id: "medals.bronze", aggregation: "sum" },
          ],
        },
      }),
    );

    const chartState = ref<AgReportState>(
      singleWidgetState("2", {
        type: "column-chart-grouped",
        dataMapping: {
          categoryKey: [{ id: "medals.country" }],
          valueKey: [
            { id: "medals.gold", aggregation: "sum" },
            { id: "medals.silver", aggregation: "sum" },
            { id: "medals.bronze", aggregation: "sum" },
          ],
          tooltipKey: [],
        },
      }),
    );

    const data = shallowRef<AgDataEngine>();

    onMounted(() => {
      fetch("https://www.ag-grid.com/studio/example-assets/olympic-winners.json")
        .then((resp) => resp.json())
        // One engine, shared by both instances - the data is loaded and cached once.
        .then(
          (respData) =>
            (data.value = createDataEngine({
              sources: [{ id: "medals", data: respData }],
            })),
        );
    });

    return { theme, layout, gridState, chartState, data };
  },
});

const app = createApp(VueExample);
app.mount("#app");
```

[Live example: Single Widgets](https://www.ag-grid.com/studio/examples/sharing-caching-data/single-widgets/vue3/)

To show a single widget, give the report a one-cell layout and hide the panels:

```ts
<ag-studio
    :mode="mode"
    :panels="panels"
    :layout="layout"
    /* other studio properties ... */>
</ag-studio>

this.mode = 'view';
this.panels = {};
this.layout = { columns: 1, height: 300, rowHeight: 300, pagePadding: 0, widgetPadding: 0 };
```

Each instance is independent. Panels belong to a single instance, so one panel cannot control several instances. Only the data engine is shared.

## Custom Engines

For larger datasets or when you want to delegate query execution to a backend you already own, see the [Server-Side Data](https://www.ag-grid.com/studio/vue/server-side-data/) guide.
