Skip to content

Prerequisites

  • Sanity account (https://manage.sanity.io)
  • Project ID and a dataset (e.g., production)
  • A least-privilege Sanity API token required by apps/marketing/src/sanity/env.ts
  • A deploy token from 1Password for CI or fallback CLI deployment of Studio

Environment

Create or update apps/marketing/.env.local (and CI variables):

bash
SANITY_STUDIO_PROJECT_ID=your_project_id
SANITY_STUDIO_DATASET=production
SANITY_STUDIO_API_VERSION=2025-09-07
SANITY_STUDIO_HOST=studio.your-domain.tld
SANITY_STUDIO_API_TOKEN=your_read_only_token

Sanity exposes SANITY_STUDIO_* variables to the Studio browser bundle. Use a read-only token with the minimum project and dataset access needed for content queries. Never use an administrator, editor, or deploy token for SANITY_STUDIO_API_TOKEN. Keep local values in ignored environment files and CI values in the appropriate environment secrets.

Local Development

To run Sanity Studio locally for development:

Prerequisites

  • Sanity CLI (available via pnpm dlx, no installation needed)
  • Environment variables configured in apps/marketing/.env.local

Running Sanity Studio Locally

  1. Navigate to the marketing app directory:
bash
cd apps/marketing
  1. Start the Sanity Studio development server:
bash
pnpm exec sanity dev
  1. Access the Studio at http://localhost:3333 (default port)

Port conflict

If port 3333 is in use (e.g., by the AdonisJS server running on the host), Sanity will automatically try the next available port. To run the API server separately, use pnpm run dev -- --filter=server.

The Studio will automatically reload when you make changes to schemas or configuration files.

Environment Variables for Local Development

For local development, use a development dataset instead of production:

bash
SANITY_STUDIO_PROJECT_ID=your_project_id
SANITY_STUDIO_DATASET=dev  # Use 'dev' instead of 'production' for local work
SANITY_STUDIO_API_VERSION=2025-09-07
SANITY_STUDIO_HOST=studio.your-domain.tld
SANITY_STUDIO_API_TOKEN=your_read_only_token

Development Workflow

  • Local Studio: Use pnpm exec sanity dev for schema development and content editing during development
  • Hosted Studio: The marketing workflow deploys it automatically; use the CLI only as a fallback
  • Dataset Considerations: Use dev dataset locally to avoid affecting production content
  • Schema Changes: Schema modifications in apps/marketing/src/sanity/schemaTypes/ are automatically reflected in the local Studio

Troubleshooting

  • Port Conflicts: If port 3333 is in use, Sanity will automatically try the next available port
  • Authentication Issues: Ensure the required read-only SANITY_STUDIO_API_TOKEN is set
  • Environment Variable Errors: Verify all required variables are set in apps/marketing/.env.local

Studio (Hosted)

  • Config: apps/marketing/sanity.config.ts
  • Embedded Studio route has been removed from the marketing app to reduce bundle size.
  • Pushes affecting marketing trigger .github/workflows/deploy-marketing.yml. After the OpenNext Worker deploy succeeds, the workflow deploys the hosted Studio with the environment-specific *_SANITY_STUDIO_DEPLOY_TOKEN.
  • For an approved fallback, deploy from apps/marketing:
bash
pnpm exec sanity deploy -y
  • Authenticate the manual deployment non-interactively with a token env var:
bash
SANITY_AUTH_TOKEN=<deploy-token> pnpm exec sanity deploy -y

Set the environment-specific SANITY_STUDIO_PROJECT_ID, SANITY_STUDIO_DATASET, and SANITY_STUDIO_HOST values before running the fallback command. Those values determine the Studio deployment target.

Verify both the marketing Worker and hosted Studio after the workflow. A manual Studio deployment does not deploy the marketing Worker.

Notes

  • SANITY_STUDIO_API_TOKEN is currently required when marketing or Studio configuration loads. Because Studio-prefixed variables are available to the Studio browser bundle, use only a least-privilege read-only token.
  • CI maps two distinct credentials:
    • CLI reads: SANITY_AUTH_TOKEN
    • App config reads: SANITY_STUDIO_API_TOKEN
  • SANITY_AUTH_TOKEN is the deploy credential. Never assign it to a SANITY_STUDIO_* variable. The workflow provides it only to the Studio deployment step. It is excluded from generated marketing configuration and is not persisted through $GITHUB_ENV.

Schemas (already included)

  • author (name, slug, image, bio)
  • post (title, slug, author ref, mainImage, categories[], publishedAt, body)
  • category (title, slug, description)
  • blockContent (Portable Text)

Fetching content (helpers)

  • Post: getPostResource(slug)apps/marketing/src/utils/blog/posts.ts
    • Returns: Promise<{ data: TPost | null; error: string | null }>
  • Author: getAuthorResource(slug)apps/marketing/src/utils/blog/authors.ts
    • Returns: Promise<{ data: TAuthor | null; error: string | null }>
  • Category: getCategoryResource(slug)apps/marketing/src/utils/blog/categories.ts
    • Returns: Promise<{ data: TCategory | null; error: string | null }>

Frontend routes

  • Post: /blog/[slug]
  • Author: /blog/author/[slug]
  • Category: /blog/category/[slug]

Images

  • Next.js is configured for Sanity images: cdn.sanity.io is allowed in apps/marketing/next.config.ts.

Deployment Notes

  • The marketing site and hosted Studio deploy in the marketing workflow.
  • SANITY_STUDIO_API_TOKEN is currently required during marketing and Studio configuration loading. Use the least-privilege read-only token described above.
  • SANITY_AUTH_TOKEN is the separate credential used by the Studio deployment command.
  • Keep static assets in apps/marketing/public/ and avoid embedding Studio in the marketing bundle.

Built with ❤️ by the Jubiloop team