datocms-cda
DatoCMS Content Delivery API Skill
Expert at querying DatoCMS CDA (read-only GraphQL) using @datocms/cda-client. Follow steps in order.
Step 1: Detect Context
If context already established, skip broad detection. Re-inspect only when needed.
Examine project setup:
-
Read
package.jsonfor@datocms/cda-client. Not installed?npm install @datocms/cda-client -
Find existing
executeQueryorrawExecuteQueryimports to understand usage patterns. -
Check
.env,.env.localfor DatoCMS API token:DATOCMS_CDA_TOKENDATOCMS_READONLY_TOKENDATOCMS_API_TOKENNEXT_PUBLIC_DATOCMS_CDA_TOKEN
-
Check framework (Next.js, Astro, Remix, Nuxt, SvelteKit) to determine server vs client queries. Don't expose tokens to browser unless using public read-only token.
-
Check type generation setup:
- gql.tada:
gql.tadain dependencies +initGraphQLTadacall (typicallylib/datocms/graphql.ts) - graphql-codegen:
@graphql-codegen/cliin devDependencies +graphql.config.ts - Context only — match existing setup. Don't suggest setting up type generation.
- gql.tada:
CDA only needs read-only token. If DATOCMS_API_TOKEN is also used for CMA, better suggesting a separate read-only token for CDA.
Step 2: Understand Task
Classify task:
| Category | Examples |
|---|---|
| Basic querying | Fetch by slug/ID, single-instance, list collections |
| Filtering | Field filters, AND/OR, meta filters, deep filtering |
| Pagination & ordering | Paginate, sort, tree/hierarchical |
| Localization | Localized fields, fallback, all-locale values |
| Modular content | Block fields with fragments, nested blocks |
| Structured text | DAST value/blocks/links, render |
| Images & media | Responsive images, imgix, placeholders, focal, video |
| SEO & meta | _seoMetaTags, favicons, globalSeo, OG tags |
| Draft/preview & caching | Draft mode, strict mode, cache tags, CDN, Content Link |
| Type generation | gql.tada, graphql-codegen, schema types, typed queries |
Clear request? Proceed directly.
Step 3: Load References
Read relevant references from references/. Always load core client reference, then only relevant files.
Always load:
references/client-and-config.md— client setup, options, error handling, limits, scalars
Load per category:
| Task | Reference |
|---|---|
| Basic (records, collections, meta) | references/querying-basics.md |
| Filtering (fields, AND/OR, deep, uploads) | references/filtering.md |
| Pagination & ordering (first/skip, auto, trees) | references/pagination-and-ordering.md |
| Localization | references/localization.md |
| Modular content (blocks, fragments) | references/modular-content.md |
| Structured text (DAST, render) | references/structured-text.md |
| Images & media (responsiveImage, video) | references/images-and-videos.md |
| SEO & meta | references/seo-and-meta.md |
| Draft/preview, cache, environments, Content Link | references/draft-caching-environments.md |
| Type generation (gql.tada, graphql-codegen, types) | references/type-generation.md |
| gql.tada fragment discipline (masking, composition, page query) | references/fragment-patterns.md |
Cross-cutting:
- Filtering localized →
references/localization.md - Structured text with modular content →
references/modular-content.md - Images in blocks →
references/images-and-videos.md - Paginating filtered collection →
references/pagination-and-ordering.md - Complex nesting →
references/pagination-and-ordering.mdfor complexity costs - Writing/extending fragments in a
gql.tadaproject →references/fragment-patterns.md
Step 4: Mandatory Rules to Generate Code
Client Usage
- Default:
executeQueryfrom@datocms/cda-client(or repo's existing wrapper around it) - Use
buildRequestHeaders()/buildRequestInit()for frameworkfetchintegration, tagging, custom plumbing - Use
executeQueryWithAutoPaginationto fetch 500+ records - Use
rawExecuteQueryonly if response headers are needed (cache tags) - Store API token in env variable — never hardcode
GraphQL Queries
- Write as template literal strings (unless project uses
TypedDocumentNode/gql.tada) - Use GraphQL variables for all dynamic values — no string interpolation
- Request only needed fields — don't over-fetch
- Use DatoCMS custom scalars in declarations (
$first: IntType,$id: ItemId) - Prepend template string with
/* GraphQL */(comment-tagged templates) for syntax highlighting
const query = /* GraphQL */ `query { ... }`
Structured Text
- Query all relevant sub-fields (
value,blocks,links,inlineBlocks) — omitting causes silent data loss
Error Handling
- Catch
ApiErrorfrom@datocms/cda-clientat appropriate boundaries - No custom retry logic —
autoRetryhandles rate limits
TypeScript
- Follow strictness: no
as unknown as, no unnecessaryas - Let TypeScript infer types
- Use
import type { ... }for type-only imports
Step 5: Verify
Before presenting final code:
- Token — env variable, read permissions
- Error handling —
ApiErrorcaught at boundaries - Pagination — 500+ records? use
executeQueryWithAutoPagination - Draft mode —
includeDraftsintentional (not exposing unpublished in prod) excludeInvalid— recommend for stable schemas. Changing schema? usefilter: { _isValid: { eq: true } }instead- Type safety — no
asto silence errors - Imports — CDA from
@datocms/cda-client; keep generated GraphQL helpers if type-gen wired - Variables — all dynamic via GraphQL variables, no interpolation
- Structured text — all relevant sub-fields included
- Fetch integration — framework-native
fetch? usebuildRequestHeaders()/buildRequestInit() - Type generation — gql.tada or graphql-codegen? use project's
graphql()function, check scalar mappings - gql.tada fragment discipline — masked-by-default,
readFragment()at boundary, imports mirror spreads (seereferences/fragment-patterns.md)
Cross-Skill Routing
This skill covers reading via GraphQL CDA. Route to companion skill for:
| Condition | Route to |
|---|---|
| Mutating content, schema/uploads/webhooks, scripts (including REST queries) | datocms-cma |
| Draft mode endpoints, Web Previews, Content Link, subscriptions, cache tags | datocms-frontend-integrations |
| Building plugin | datocms-plugin-builder |