Canvas Client SDK

The Canvas Client (CanvasClient from @uniformdev/canvas) provides programmatic access to compositions and component definitions in a Uniform project. Use it for server-side data fetching, static site generation, build scripts, content migrations, or any scenario where you need to work with compositions outside of the standard rendering pipeline.

The client wraps the composition endpoints of the Uniform APIs; see the OpenAPI specification for the underlying API reference.


The Canvas Client is part of the @uniformdev/canvas package:

npm install @uniformdev/canvas

import { CanvasClient } from "@uniformdev/canvas"; const canvasClient = new CanvasClient({ apiKey: process.env.UNIFORM_API_KEY, projectId: process.env.UNIFORM_PROJECT_ID, });
OptionTypeDescription
apiKeystringAPI key with read access to the project (write access for management operations)
projectIdstringThe Uniform project ID
apiHoststringUniform API host, used when data resolution is skipped and for management operations. Default: https://uniform.app
edgeApiHoststringEdge API host, used when fetching compositions with data resolution. Default: https://uniform.global
disableSWRbooleanWhen true, disables stale-while-revalidate caching on the edge and always returns fresh data
bypassCachebooleanWhen true, bypasses API caching entirely. UncachedCanvasClient is a shortcut for this

There is only one Canvas Client implementation. The App Router SDK provides getCanvasClient, a factory that returns the same CanvasClient pre-configured for Next.js: credentials are read from environment variables, and a custom fetch wires composition requests into the Next.js data cache (per-composition cache tags, revalidate, and draft-mode cache bypass):

import { getCanvasClient } from "@uniformdev/next-app-router"; const canvasClient = getCanvasClient({ cache: { type: "no-cache" }, });

Use getCanvasClient in App Router server code so composition fetches participate in Next.js caching and revalidation; use new CanvasClient(...) everywhere else.


The client provides one method per lookup key. All of them accept the same options and return the same response shape:

MethodLooks up by
getCompositionByIdComposition ID
getCompositionBySlugComposition slug
getCompositionByNodePathProject map node path (accepts optional projectMapId)
getCompositionByNodeIdProject map node ID (accepts optional projectMapId)
import { CANVAS_PUBLISHED_STATE } from "@uniformdev/canvas"; const { composition } = await canvasClient.getCompositionBySlug({ slug: "/company/about-us", state: CANVAS_PUBLISHED_STATE, }); console.log(composition._name, composition.parameters);
OptionTypeDescription
statenumberPublishing state to fetch: CANVAS_DRAFT_STATE (0) for draft, CANVAS_PUBLISHED_STATE (64) for published.
localestringLocale(s) to localize the response to. Accepts a single value (en-US), a comma-delimited list (fr-CA,fr), or Accept-Language header syntax. When omitted, all locales' data is returned.
releaseIdstringFetch the composition as it would appear in the given release.
withComponentIDsbooleanWhen true, includes the _id of each non-root component in the response.
skipPatternResolutionbooleanWhen true, pattern references are left unresolved. Useful when serializing compositions and patterns separately.
versionIdstringFetch a historical version (retrieved from getCompositionHistory). Only valid with getCompositionById.
skipDataResolutionbooleanSkip edge-side data resolution (see below).
resolutionDepthnumberHow many levels deep content references are resolved.
dataSourceVariant"unpublished"When set, data resources that support it fetch unpublished data from their data source.

By default, single-composition fetches go through the Uniform Edge API, which resolves data resources, dynamic tokens, and referenced entries before returning the composition. Pass skipDataResolution: true to fetch the raw, unresolved composition from the origin API instead -- appropriate for serialization, migration scripts, or when you resolve data yourself:

const { composition } = await canvasClient.getCompositionById({ compositionId: "abc123", state: CANVAS_PUBLISHED_STATE, skipDataResolution: true, });

getCompositionList fetches multiple compositions, optionally filtered by root component type:

const { compositions } = await canvasClient.getCompositionList({ type: "landingPage", state: CANVAS_PUBLISHED_STATE, }); for (const { composition } of compositions) { console.log(composition._name, composition._slug); }

In addition to the common options, list queries accept:

OptionTypeDescription
typestring | string[]Filter by root component type (public ID). Components in slots are not matched.
keywordstringMatches compositions whose name, slug, or definition name contains the keyword. Not a full-text search.
searchstringFull-text search on textual fields, including resolved pattern content. Use for "where does this content appear" queries.
patternboolean | "any"true returns only patterns, false only regular compositions. Default: both.
orderBystringSorting: updated_at_DESC, updated_at_ASC, created_at_DESC, created_at_ASC, name_DESC, name_ASC, slug_DESC, slug_ASC. Default: name ascending.
limit / offsetnumberPagination.
withTotalCountbooleanInclude the total result count in the response (impacts performance).
resolveDatabooleanWhen true, the list is fetched through the edge API with data resolution applied to each composition. Default: false.
filtersCompositionFiltersStructured field filters (see below).
selectProjectionSpecData projection applied to each composition.

The Canvas Client supports the same structured filter syntax as the Content Client, but compositions use parameters where entries use fields:

const response = await canvasClient.getCompositionList({ filters: { "type[eq]": "landingPage", "parameters.heroTitle[match]": "summer", }, });

See the Content Client filter reference for the full list of operators.


The select option fetches a subset of each composition instead of the whole thing, reducing payload size and skipping server-side resolution work for content you don't need. For compositions, the fields bucket selects parameters by name and the slots bucket controls how much of the component tree is returned:

const response = await canvasClient.getCompositionList({ filters: { "type[eq]": "landingPage" }, select: { fields: { only: ["pageTitle", "slug"] }, slots: { depth: 1 }, }, });

See data projection on the Content Client page for the full projection reference. The same option is available on RouteClient.getRoute.


getComponentDefinitions fetches the component definitions of a project -- useful for tooling, validation, or generating typed component maps:

const { componentDefinitions } = await canvasClient.getComponentDefinitions(); const compositionTypes = componentDefinitions.filter( (definition) => definition.canBeComposition );

The client can also create, update, and delete compositions and component definitions. These operations require an API key with write permissions:

MethodDescription
updateComposition(body, options?)Creates or updates a composition. Pass options.ifUnmodifiedSince for optimistic concurrency control (the API returns HTTP 409 if the composition changed since that timestamp).
removeComposition(body)Deletes a composition by ID.
getCompositionHistory(options)Fetches historical versions of a composition or pattern.
updateComponentDefinition(body)Creates or updates a component definition.
removeComponentDefinition(body)Deletes a component definition.
await canvasClient.updateComposition({ state: CANVAS_DRAFT_STATE, composition: updatedComposition, });

warning

Most front ends only need the read methods. Management operations modify project content directly -- prefer running them in scripts or trusted server environments, never in browser code.


ExportPackageDescription
CanvasClient@uniformdev/canvasMain composition client
UncachedCanvasClient@uniformdev/canvasCanvas Client with API caching bypassed
CANVAS_DRAFT_STATE / CANVAS_PUBLISHED_STATE@uniformdev/canvasConstants for the state option
ProjectionSpec@uniformdev/canvasType for the select data projection option
getCanvasClient@uniformdev/next-app-routerPre-configured canvas client (server-only, App Router)