
Sanity Best Practices
Wire Angular 19+ to Sanity with @sanity/client, signals-based fetching, Portable Text, images, SSR, and visual editing the way Sanity recommends.
Install
npx skills add https://github.com/sanity-io/agent-toolkit --skill sanity-best-practicesWhat is this skill?
- Monorepo layout: angular-app + studio from sanity-template-angular-clean
- Client service pattern with environment.ts apiVersion 2025-05-01
- Data fetching with Angular signals and the resource API
- Portable Text via @portabletext/to-html and @sanity/image-url optimization
- SSR, prerendering, Visual Editing, and structured error handling sections
Adoption & trust: 3.2k installs on skills.sh; 150 GitHub stars; 2/3 security scanners passed (skills.sh audits).
Recommended Skills
Frontend Designanthropics/skills
Vercel React Best Practicesvercel-labs/agent-skills
Remotion Best Practicesremotion-dev/skills
Vercel Composition Patternsvercel-labs/agent-skills
Develop Userscriptsxixu-me/skills
Next Best Practicesvercel-labs/next-skills
Journey fit
Primary fit
CMS-backed UI integration happens while you build the customer-facing app and studio-adjacent frontend. Frontend is the canonical shelf for Angular app structure, environment config, routing, and rendering Sanity content in components.
Common Questions / FAQ
Is Sanity Best Practices safe to install?
skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.
SKILL.md
READMESKILL.md - Sanity Best Practices
# Angular & Sanity Integration Rules Jump to the section that matches your Angular version or integration task instead of reading this guide straight through. ## Table of Contents - Setup and configuration - Client setup (service pattern) - Data fetching patterns - Routing - Portable Text rendering - Image optimization - Modern Angular features - SSR and prerendering - Visual Editing - Error handling ## 1. Setup & Configuration Use the official template `sanity-template-angular-clean` as a starting point. It provides a monorepo structure: ``` project/ ├── angular-app/ # Angular 19+ frontend └── studio/ # Sanity Studio ``` Install dependencies in the Angular app: ```bash npm install @sanity/client @sanity/image-url @portabletext/to-html ``` Configure environment files for Sanity credentials: ```typescript // environments/environment.ts export const environment = { production: false, sanity: { projectId: 'your-project-id', dataset: 'production', apiVersion: '2025-05-01', }, } ``` ```typescript // environments/environment.production.ts export const environment = { production: true, sanity: { projectId: 'your-project-id', dataset: 'production', apiVersion: '2025-05-01', }, } ``` > There is no Angular-specific Sanity SDK. Use `@sanity/client` directly, wrapped in an Angular service. ### TypeGen in a Monorepo Sanity TypeGen generates TypeScript types from your schema and GROQ queries. In the Angular monorepo template, TypeGen runs from the Studio side but scans your Angular app's source files. Ensure `studio/sanity.cli.ts` points at the Angular app: ```typescript // studio/sanity.cli.ts import { defineCliConfig } from 'sanity/cli' export default defineCliConfig({ typegen: { enabled: true, path: '../angular-app/src/**/*.ts', generates: '../angular-app/sanity.types.ts', }, }) ``` The remaining defaults (`overloadClientMethods: true`, `schema: "schema.json"`) work as-is. Include the generated types file in `angular-app/tsconfig.json` (usually covered by `"include": ["src/**/*.ts", "sanity.types.ts"]`). See `typegen.md` for the full TypeGen workflow, git strategy, and configuration options. ## 2. Client Setup (Service Pattern) Create an injectable service wrapping `@sanity/client` and `@sanity/image-url`: ```typescript import { Injectable } from '@angular/core' import { createClient, type ClientReturn, type QueryParams, type SanityClient } from '@sanity/client' import imageUrlBuilder, { type ImageUrlBuilder } from '@sanity/image-url' import type { SanityImageSource } from '@sanity/image-url/lib/types/types' import { environment } from '../environments/environment' @Injectable({ providedIn: 'root' }) export class SanityService { private client: SanityClient private builder: ImageUrlBuilder constructor() { this.client = createClient({ projectId: environment.sanity.projectId, dataset: environment.sanity.dataset, apiVersion: environment.sanity.apiVersion, useCdn: true, }) this.builder = imageUrlBuilder(this.client) } // ClientReturn resolves TypeGen's declaration-merged overloads for defineQuery strings fetch<Query extends string>(query: Query, params?: QueryParams): Promise<ClientReturn<Query>> { return this.client.fetch(query, params) } getImageUrlBuilder(source: SanityImageSource) { return this.builder.image(source) } } ``` For preview/draft content, create a second client instance with a token and `useCdn: false`. Never expose tokens in client-side bundles — use server-side rendering or a proxy endpoint for authenticated requests. ## 3. Data Fetching Patterns ### A. `resource` API (Angular 19+, Recommended) The `resource` API works natively with promises and integrates