> Documentation index: https://www.gooddata.ai/docs/gooddata-ui/llms.txt lists every page of these docs as Markdown.

# Load the workspace catalog at runtime

> Load measures, attributes, and date datasets while your application runs, and turn catalog items into IMeasure and IAttribute objects.

API reference: [IWorkspaceCatalogFactory](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-backend-spi/sdk-backend-spi.iworkspacecatalogfactory/index.md) (interface), [IWorkspaceCatalog](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-backend-spi/sdk-backend-spi.iworkspacecatalog/index.md) (interface), [IWorkspaceCatalogWithAvailableItems](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-backend-spi/sdk-backend-spi.iworkspacecatalogwithavailableitems/index.md) (interface), [ICatalogMeasure](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-model/sdk-model.icatalogmeasure/index.md) (interface), [ICatalogAttribute](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-model/sdk-model.icatalogattribute/index.md) (interface)

Load the logical data model (LDM) of a workspace at runtime when your users choose what to visualize, or when you don't know the model at build time. If the model is fixed, generate constants instead; see [Export catalog](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/data-model/export-catalog/index.md).

## [Before you start](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/data-model/workspace-catalog/#before-you-start)

You need an [`IAnalyticalBackend`](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-backend-spi/sdk-backend-spi.ianalyticalbackend/index.md) and a workspace identifier. Inside a React tree wrapped in [`BackendProvider`](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-ui/sdk-ui.backendprovider/index.md) and [`WorkspaceProvider`](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-ui/sdk-ui.workspaceprovider/index.md), get both from `useBackendStrict` and `useWorkspaceStrict`.

## [Load the catalog](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/data-model/workspace-catalog/#load-the-catalog)

Ask the workspace for its catalog, restrict what to load, and call `load()`.

```ts
import { type IAnalyticalBackend, type IWorkspaceCatalog } from "@gooddata/sdk-backend-spi";

export function loadCatalog(
    backend: IAnalyticalBackend,
    workspace: string,
    signal?: AbortSignal,
): Promise<IWorkspaceCatalog> {
    let factory = backend
        .workspace(workspace)
        .catalog()
        .forTypes(["measure", "attribute", "dateDataset"])
        .withGroups(false);

    if (signal) {
        factory = factory.withSignal(signal);
    }

    return factory.load();
}
```

| Option | Effect |
|--------|--------|
| [`forTypes(types)`](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-backend-spi/sdk-backend-spi.iworkspacecatalogfactorymethods/index.md#iworkspacecatalogfactorymethodsfortypes) | Load only these item types: `"measure"`, `"attribute"`, `"fact"`, `"dateDataset"`, `"attributeHierarchy"` (see [Attribute hierarchies](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/data-model/attribute-hierarchies/index.md)). Loading less is faster. |
| [`withGroups(false)`](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-backend-spi/sdk-backend-spi.iworkspacecatalogfactorymethods/index.md#iworkspacecatalogfactorymethodswithgroups) | Skip loading catalog groups when you do not show them. |
| [`includeTags(refs)`](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-backend-spi/sdk-backend-spi.iworkspacecatalogfactorymethods/index.md#iworkspacecatalogfactorymethodsincludetags), [`excludeTags(refs)`](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-backend-spi/sdk-backend-spi.iworkspacecatalogfactorymethods/index.md#iworkspacecatalogfactorymethodsexcludetags) | Keep or drop items by tag. |
| [`forDataset(ref)`](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-backend-spi/sdk-backend-spi.iworkspacecatalogfactorymethods/index.md#iworkspacecatalogfactorymethodsfordataset) | Limit items to one dataset. |
| [`withSignal(signal)`](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-backend-spi/sdk-backend-spi.iworkspacecatalogfactorymethods/index.md#iworkspacecatalogfactorymethodswithsignal) | Cancel the request through an `AbortSignal`. |

## [Wrap it in a hook](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/data-model/workspace-catalog/#wrap-it-in-a-hook)

`useCancelablePromise` handles loading, error, and cancellation when the backend or workspace changes. It calls
your factory with an `AbortSignal`. Pass it to `withSignal`, so that switching workspaces aborts the request still in
flight instead of letting it finish in the background.

```tsx
import { useBackendStrict, useCancelablePromise, useWorkspaceStrict } from "@gooddata/sdk-ui";

export function useWorkspaceCatalog() {
    const backend = useBackendStrict();
    const workspace = useWorkspaceStrict();

    return useCancelablePromise(
        { promise: (signal) => loadCatalog(backend, workspace, signal) },
        [backend, workspace],
    );
}

export function CatalogSummary() {
    const { status, result: catalog } = useWorkspaceCatalog();

    if (status !== "success") {
        return <div>{status === "error" ? "Could not load the catalog" : "Loading catalog..."}</div>;
    }

    return <div>{catalog.measures().length} measures</div>;
}
```

Load the catalog once, high in the component tree, and pass it down through props or a context. A catalog can hold thousands of items, and each `load()` is a round trip to the analytics engine.

## [Read the items](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/data-model/workspace-catalog/#read-the-items)

Each catalog item wraps a metadata object with `id`, `ref`, `title`, `description`, and optional `tags`.

| Item | Key fields |
|------|------------|
| [`ICatalogMeasure`](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-model/sdk-model.icatalogmeasure/index.md) | `measure.ref`, `measure.id`, `measure.title`, `measure.tags` |
| [`ICatalogAttribute`](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-model/sdk-model.icatalogattribute/index.md) | `attribute.ref`, `attribute.title`, `defaultDisplayForm.ref`, `displayForms[]` |
| [`ICatalogDateDataset`](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-model/sdk-model.icatalogdatedataset/index.md) | `dataSet.ref`, `dateAttributes[].defaultDisplayForm.ref`, `dateAttributes[].granularity` |

An attribute has several display forms. Offer the default one and keep the others for a label switcher:

```ts
import { type IWorkspaceCatalog } from "@gooddata/sdk-backend-spi";

export function attributeOptions(catalog: IWorkspaceCatalog) {
    return catalog.attributes().map((item) => ({
        id: item.attribute.id,
        title: item.attribute.title,
        displayForm: item.defaultDisplayForm.ref,
        otherDisplayForms: item.displayForms.map((displayForm) => displayForm.ref),
    }));
}
```

## [Turn items into executable objects](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/data-model/workspace-catalog/#turn-items-into-executable-objects)

Visual components take [`IMeasure`](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-model/sdk-model.imeasure/index.md) and [`IAttribute`](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-model/sdk-model.iattribute/index.md), not catalog items. Build them from the references.

```tsx
import { newAttribute, newMeasure, type ICatalogAttribute, type ICatalogMeasure } from "@gooddata/sdk-model";
import { ColumnChart } from "@gooddata/sdk-ui-charts";

export function PickedChart({ measure, attribute }: { measure: ICatalogMeasure; attribute: ICatalogAttribute }) {
    return (
        <ColumnChart
            measures={[newMeasure(measure.measure.ref)]}
            viewBy={newAttribute(attribute.defaultDisplayForm.ref)}
        />
    );
}
```

## [Offer only compatible items](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/data-model/workspace-catalog/#offer-only-compatible-items)

After a user picks a measure, offer only the attributes that can slice it. The catalog computes that list for you.

```ts
import { type IWorkspaceCatalog } from "@gooddata/sdk-backend-spi";
import { newMeasure, type ICatalogMeasure } from "@gooddata/sdk-model";

export async function attributesFor(catalog: IWorkspaceCatalog, measure: ICatalogMeasure) {
    const available = await catalog
        .availableItems()
        .forItems([newMeasure(measure.measure.ref)])
        .load();

    return available.availableAttributes();
}
```

`availableItems()` also accepts `forInsight(insight)` to check compatibility with a whole visualization.

## [Notes](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/data-model/workspace-catalog/#notes)

- Titles come back in the locale of the user making the request. Reload the catalog when the locale changes.
- `tags` is optional on every metadata object. Default it to an empty array before you filter on it.
- The catalog reflects the model at load time. Reload after your application changes the model.
- To index items by [`ObjRef`](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-model/sdk-model.objref/index.md), key with `serializeObjRef`; see [Working with object references](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/data-model/object-references/index.md).
