Project structure
Where things live, and the one boundary rule worth knowing before you move a file.
Two applications, one repository
The Nuxt app is at the root; the Sanity Studio is in studio/. They have separate package.json files and separate `.env` files, and they are deployed separately — the Studio to Sanity's hosting, the frontend wherever you like.
They meet in exactly two places: the schemas in studio/ define the shape of the content, and the typed GROQ queries in app/services/groq-queries.ts fetch it. Everything else is on one side or the other.
| Path | What lives there |
|---|---|
| app/components/ui/ | The standard block library — blocks, elements, utilities |
| app/components/custom/ | Your project-specific blocks |
| app/components/ui/shadcn/ | shadcn-vue / Reka UI primitives, hand-adapted |
| app/composables/ | Composition functions, auto-imported |
| app/services/groq-queries.ts | Every GROQ query and projection |
| app/services/helpers/ | Pure TypeScript helpers, unit-tested in isolation |
| app/stores/ | Pinia state, including the theme store |
| studio/schemas/web/ | Content schemas — documents, blocks, custom, elements |
| studio/schemas/web/custom/ | Your customisation entry point |
| scripts/ | Setup, scaffolding and build-time generators |
Pages and routing
There are almost no file-based marketing routes. A catch-all route resolves any slug to a page document, so pricing, features, and contact are content, not files. You add file routes only for genuinely new _types_ of thing — a products section, say — and the docs cover the four-line normalisation that hands theme and fonts to it.