Skip to content

Conversation

@judofyr
Copy link
Contributor

@judofyr judofyr commented Nov 21, 2025

Description

Due to the dynamic nature of sanity.config.ts it's very easy to create enormous schemas without really being aware of this. A common gotcha is to inline types/fields instead of defining a named type.

This adds a command sanity schema validate --debug-metafile-path <path> which writes a file with information about the size of the serialized schema which follows ESBuild's metafile format. This can then be analyzed through https://esbuild.github.io/analyze/.

Here are some screenshots on dev/test-studio's schema:

Screenshot 2025-11-21 at 12 26 43 Screenshot 2025-11-21 at 12 26 51 Screenshot 2025-11-21 at 12 26 34

I've added this to the sanity schema validate command since it seems to be quite similar: It's about analyzing the schema to help the developer understand potential problems.

What to review

  • Try this out on some Studioes maybe?

Testing

  • I've tested it on dev/test-studio

Notes for release

  • sanity schema validate --debug-metafile-path <path> is now available. I think we should have a separate guide for how to explore the schema bloat before this gets merged.

@vercel
Copy link

vercel bot commented Nov 21, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
page-building-studio Ready Ready Preview Comment Nov 27, 2025 2:23pm
test-studio Ready Ready Preview Comment Nov 27, 2025 2:23pm
2 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
studio-workshop Ignored Ignored Preview Nov 27, 2025 2:23pm
test-next-studio Ignored Ignored Nov 27, 2025 2:23pm

@github-actions
Copy link
Contributor

github-actions bot commented Nov 21, 2025

🧪 E2E Preview environment

🔑 Environment Variables for Local Testing

This is the preview URL for the E2E tests: https://e2e-studio-p2oyipfer.sanity.dev

To run the E2E tests locally, you can use the following environment variables, then run pnpm test:e2e --ui to open the Playwright test runner.

💬 Remember to build the project first with pnpm build:e2e.

  SANITY_E2E_PROJECT_ID=ittbm412
  SANITY_E2E_BASE_URL=https://e2e-studio-p2oyipfer.sanity.dev
  SANITY_E2E_DATASET="update depending the project you want to test (pr-11224-chromium-19739211937 || pr-11224-firefox-19739211937 )"
  SANITY_E2E_DATASET_CHROMIUM=pr-11224-chromium-19739211937
  SANITY_E2E_DATASET_FIREFOX=pr-11224-firefox-19739211937

@github-actions
Copy link
Contributor

github-actions bot commented Nov 21, 2025

📊 Playwright Test Report

Download Full E2E Report

This report contains test results, including videos of failing tests.

@github-actions
Copy link
Contributor

github-actions bot commented Nov 21, 2025

⚡️ Editor Performance Report

Updated Thu, 27 Nov 2025 17:43:42 GMT

Benchmark reference
latency of sanity@latest
experiment
latency of this branch
Δ (%)
latency difference
article (title) 28.6 efps (35ms) 26.7 efps (38ms) +3ms (+7.1%)
article (body) 38.8 efps (26ms) 37.3 efps (27ms) +1ms (+4.1%)
article (string inside object) 29.0 efps (35ms) 29.9 efps (34ms) -1ms (-2.9%)
article (string inside array) 25.0 efps (40ms) 25.6 efps (39ms) -1ms (-2.5%)
recipe (name) 54.1 efps (19ms) 55.6 efps (18ms) -1ms (-2.7%)
recipe (description) 71.4 efps (14ms) 71.4 efps (14ms) +0ms (-/-%)
recipe (instructions) 99.9+ efps (5ms) 99.9+ efps (5ms) +0ms (-/-%)
singleString (stringField) 71.4 efps (14ms) 71.4 efps (14ms) +0ms (-/-%)
synthetic (title) 17.4 efps (58ms) 17.2 efps (58ms) +1ms (+0.9%)
synthetic (string inside object) 17.5 efps (57ms) 17.5 efps (57ms) +0ms (-/-%)

efps — editor "frames per second". The number of updates assumed to be possible within a second.

Derived from input latency. efps = 1000 / input_latency

Detailed information

🏠 Reference result

The performance result of sanity@latest

Benchmark latency p75 p90 p99 blocking time test duration
article (title) 35ms 40ms 58ms 110ms 29ms 10.1s
article (body) 26ms 34ms 72ms 108ms 52ms 5.9s
article (string inside object) 35ms 43ms 60ms 95ms 0ms 5.5s
article (string inside array) 40ms 44ms 58ms 96ms 0ms 6.2s
recipe (name) 19ms 21ms 24ms 45ms 0ms 6.8s
recipe (description) 14ms 18ms 21ms 31ms 0ms 4.0s
recipe (instructions) 5ms 9ms 11ms 31ms 0ms 3.0s
singleString (stringField) 14ms 18ms 21ms 32ms 0ms 6.0s
synthetic (title) 58ms 60ms 122ms 177ms 374ms 14.9s
synthetic (string inside object) 57ms 59ms 66ms 158ms 217ms 7.9s

🧪 Experiment result

The performance result of this branch

Benchmark latency p75 p90 p99 blocking time test duration
article (title) 38ms 45ms 65ms 102ms 27ms 10.1s
article (body) 27ms 31ms 63ms 118ms 90ms 6.0s
article (string inside object) 34ms 38ms 43ms 85ms 3ms 5.6s
article (string inside array) 39ms 42ms 62ms 113ms 0ms 6.1s
recipe (name) 18ms 21ms 23ms 49ms 0ms 7.5s
recipe (description) 14ms 17ms 20ms 41ms 0ms 4.1s
recipe (instructions) 5ms 9ms 11ms 29ms 0ms 3.0s
singleString (stringField) 14ms 16ms 18ms 30ms 0ms 5.9s
synthetic (title) 58ms 61ms 65ms 128ms 324ms 15.1s
synthetic (string inside object) 57ms 62ms 126ms 273ms 573ms 8.4s

📚 Glossary

column definitions

  • benchmark — the name of the test, e.g. "article", followed by the label of the field being measured, e.g. "(title)".
  • latency — the time between when a key was pressed and when it was rendered. derived from a set of samples. the median (p50) is shown to show the most common latency.
  • p75 — the 75th percentile of the input latency in the test run. 75% of the sampled inputs in this benchmark were processed faster than this value. this provides insight into the upper range of typical performance.
  • p90 — the 90th percentile of the input latency in the test run. 90% of the sampled inputs were faster than this. this metric helps identify slower interactions that occurred less frequently during the benchmark.
  • p99 — the 99th percentile of the input latency in the test run. only 1% of sampled inputs were slower than this. this represents the worst-case scenarios encountered during the benchmark, useful for identifying potential performance outliers.
  • blocking time — the total time during which the main thread was blocked, preventing user input and UI updates. this metric helps identify performance bottlenecks that may cause the interface to feel unresponsive.
  • test duration — how long the test run took to complete.

@github-actions
Copy link
Contributor

github-actions bot commented Nov 21, 2025

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 44.64% 63658 / 142589
🔵 Statements 44.64% 63658 / 142589
🔵 Functions 48.23% 3397 / 7043
🔵 Branches 79.33% 12920 / 16286
File CoverageNo changed files found.
Generated in workflow #46468 for commit d114d13 by the Vitest Coverage Report Action

@judofyr judofyr marked this pull request as ready for review November 21, 2025 11:49
@judofyr judofyr requested a review from a team as a code owner November 21, 2025 11:49
@judofyr judofyr requested review from jordanl17 and removed request for a team November 21, 2025 11:49
@judofyr judofyr force-pushed the cldx-4337/sanity-validate-metafile branch from 2c36abb to 19f4022 Compare November 21, 2025 11:51
Base automatically changed from sdk-655/resolve-config-in-schema-validate to main November 24, 2025 08:30
@judofyr judofyr force-pushed the cldx-4337/sanity-validate-metafile branch from 19f4022 to 7e30900 Compare November 24, 2025 08:31
@judofyr judofyr force-pushed the cldx-4337/sanity-validate-metafile branch from 7e30900 to b7b96cd Compare November 24, 2025 15:35
stipsan
stipsan previously approved these changes Nov 25, 2025
Copy link
Member

@stipsan stipsan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fascinating! I think for a guide it would be helpful to show a before/after to demonstrate the impact of refactoring a schema from using inline types to named types, to better understand what to look for in the esbuild visualizer graphs.

I've triggered a preview release so I can try it on some test studios.

Is there a measurable runtime difference in how long prepareConfig spends processing the schema as well? We have to resolve it up front before the studio can load, and it's resolved again during hot reload cycles if the schema is edited in any way 🤔

@judofyr
Copy link
Contributor Author

judofyr commented Nov 25, 2025

@stipsan: Nice, nice! I fixed a build error, but now it seems like the publishing failed. I can wait with merging this until you've tested it.

Is there a measurable runtime difference in how long prepareConfig spends processing the schema as well? We have to resolve it up front before the studio can load, and it's resolved again during hot reload cycles if the schema is edited in any way 🤔

Not sure if I follow you. This doesn't change anything related to prepareConfig, but is only in the CLI.

@stipsan
Copy link
Member

stipsan commented Nov 25, 2025

@stipsan: Nice, nice! I fixed a build error, but now it seems like the publishing failed. I can wait with merging this until you've tested it.

Hmmm seems like pkg.pr.new isn't working atm, so we can just merge to main and test with sanity@next 👍

Is there a measurable runtime difference in how long prepareConfig spends processing the schema as well? We have to resolve it up front before the studio can load, and it's resolved again during hot reload cycles if the schema is edited in any way 🤔

Not sure if I follow you. This doesn't change anything related to prepareConfig, but is only in the CLI.

I understand that this PR in itself doesn't affect prepareConfig in any way. What I mean is that if someone uses --debug-metafile-path to refactor inline types to named types it could lead to the schema being significantly smaller.
A much smaller schema should be faster to process by prepareConfig, as it has to resolve schema types at runtime as well as pass the resolved schema to a SchemaBuilder.compile step (createSchema calls SchemaBuilder.compile):

let schemaTypes
try {
schemaTypes = resolveSchemaTypes({
config: source,
context: {projectId, dataset},
})
} catch (e) {
throw new ConfigResolutionError({
name: source.name,
type: 'source',
causes: [e],
})
}
const schema = createSchema({
name: source.name,
types: schemaTypes,
})

stipsan
stipsan previously approved these changes Nov 25, 2025
@judofyr
Copy link
Contributor Author

judofyr commented Nov 25, 2025

Ah, yes! It's true that interpreting this number can be a bit tricky. It's now only for the "new" server-side schema approach (which even used by anything proper yet). A smaller schema from this file doesn't necessarily mean that prepareConfig will be faster. It will however matter for the long-term server-side schema bits and pieces, and I believe it either way will be a good proxy for overall schema complexity.

This adds a command `sanity schema validate --debug-metafile-path
<path>` which writes a file with information about the size of the
serialized schema which follows ESBuild's metafile format.

This can then be analyzed through https://esbuild.github.io/analyze/
@github-actions
Copy link
Contributor

Preview this PR with pkg.pr.new

Create a new project

npx https://pkg.pr.new/create-sanity@23db03f

Note: This installs the latest Sanity Studio from the npm registry. To apply the changes from this PR in your newly created project, run the install commands below for each package listed in your package.json

...Or run the Sanity CLI

npx https://pkg.pr.new/@sanity/cli@23db03f <command>

...Or upgrade project dependencies

pnpm logo Using pnpm

📦 sanity
pnpm install https://pkg.pr.new/sanity@d114d13
📦 @sanity/vision
pnpm install https://pkg.pr.new/@sanity/vision@d114d13
📦 Other packages…
📦 create-sanity
pnpm install https://pkg.pr.new/create-sanity@d114d13
📦 groq
pnpm install https://pkg.pr.new/groq@d114d13
📦 @sanity/cli
pnpm install https://pkg.pr.new/@sanity/cli@d114d13
📦 @sanity/codegen
pnpm install https://pkg.pr.new/@sanity/codegen@d114d13
📦 @sanity/diff
pnpm install https://pkg.pr.new/@sanity/diff@d114d13
📦 @sanity/migrate
pnpm install https://pkg.pr.new/@sanity/migrate@d114d13
📦 @sanity/mutator
pnpm install https://pkg.pr.new/@sanity/mutator@d114d13
📦 @sanity/schema
pnpm install https://pkg.pr.new/@sanity/schema@d114d13
📦 @sanity/types
pnpm install https://pkg.pr.new/@sanity/types@d114d13
📦 @sanity/util
pnpm install https://pkg.pr.new/@sanity/util@d114d13

npm logo Using npm

📦 sanity
npm install https://pkg.pr.new/sanity@d114d13
📦 @sanity/vision
npm install https://pkg.pr.new/@sanity/vision@d114d13
📦 Other packages…
📦 create-sanity
npm install https://pkg.pr.new/create-sanity@d114d13
📦 groq
npm install https://pkg.pr.new/groq@d114d13
📦 @sanity/cli
npm install https://pkg.pr.new/@sanity/cli@d114d13
📦 @sanity/codegen
npm install https://pkg.pr.new/@sanity/codegen@d114d13
📦 @sanity/diff
npm install https://pkg.pr.new/@sanity/diff@d114d13
📦 @sanity/migrate
npm install https://pkg.pr.new/@sanity/migrate@d114d13
📦 @sanity/mutator
npm install https://pkg.pr.new/@sanity/mutator@d114d13
📦 @sanity/schema
npm install https://pkg.pr.new/@sanity/schema@d114d13
📦 @sanity/types
npm install https://pkg.pr.new/@sanity/types@d114d13
📦 @sanity/util
npm install https://pkg.pr.new/@sanity/util@d114d13

View Commit (d114d13)

@judofyr
Copy link
Contributor Author

judofyr commented Nov 27, 2025

@stipsan: I've now rebased from latest main and did a tiny change in the format.

@judofyr judofyr requested a review from stipsan November 27, 2025 14:24
Copy link
Member

@stipsan stipsan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's go!

Copy link
Contributor Author

judofyr commented Nov 28, 2025

Merge activity

  • Nov 28, 9:22 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Nov 28, 9:23 AM UTC: @judofyr merged this pull request with Graphite.

@judofyr judofyr merged commit 721e6d2 into main Nov 28, 2025
69 of 73 checks passed
@judofyr judofyr deleted the cldx-4337/sanity-validate-metafile branch November 28, 2025 09:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants