Skip to content

Documentation

Content Type System & Code Generation

How SveltyCMS generates TypeScript types for collections at build time, using the consolidated content architecture.

9/22/2026
3 min read Edit on GitHub

SveltyCMS uses a build-time code generation system to create TypeScript types for your collections, providing full type safety across the entire codebase.

🎯 Overview

When you define collections in config/collections/, SveltyCMS automatically:

  1. ✅ Compiles TypeScript definitions to .compiledCollections/*.js (Vite build).
  2. ✅ Scans compiled modules via engine.server.ts (scanCompiledCollections) with mtime caching.
  3. ✅ Loads schemas via loader.server.ts (loadSchemaNative() or worker pool in production).
  4. ✅ Generates TypeScript union types via scripts/generate-content-types.ts.
  5. ✅ Updates src/content/types.generated.ts with the ContentTypes union and CollectionMap.
  6. ✅ Provides IDE autocomplete for all collection names (re-exported from src/content/types.ts).

🔄 How It Works

1. Type Generation Script

Types are generated by scripts/generate-content-types.ts, not by a Vite plugin:

  • It scans .compiledCollections/ for *.js modules and builds the ContentTypes string union plus CollectionMap field stubs.
  • It is invoked from the collection watcher in vite.config.ts:497-511 after a successful compile — if ((result.compiled?.processed ?? 0) > 0) → generateContentTypes(server) — and a failure there is logged, never fatal to HMR.
  • The write is atomic (temp file + rename) and skipped when the content is unchanged.

2. Marker Comments for Stability

To prevent file corruption during rapid Vite reloads, the generator rewrites only the Marker Comments region: /* AUTOGEN_START: ContentTypes */ and /* AUTOGEN_END: ContentTypes */ (see src/content/types.generated.ts). Everything outside those markers — manual types, imports — is preserved.

3. No Separate Production Path

Runtime schema discovery does not depend on the generated types: engine.server.ts (scanCompiledCollections()) is the same scanner used by the generator and by runtime reconciliation, so a stale types file can never break boot. Run the generator only for IDE/type-checking accuracy.


📊 Benefits

1. Type Safety Everywhere

Autocomplete for collection names and validation for field types.

import type { ContentTypes } from "@src/content/types";
function getCollection(name: ContentTypes) {
  return contentSystem.getCollection(name);
}

2. Refactoring Safety

When you rename a collection file, TypeScript catches all references across the app.


📁 Key Files

File Purpose
src/content/index.ts Browser-safe public API facade
src/content/index.server.ts Server-only entry (init, CRUD, ensureContentInitialized)
src/content/engine.server.ts Scanner, reconciliation, cache, watcher
src/content/loader.server.ts Schema module loading (native + worker pool)
src/stores/content-registry.svelte.ts Reactive state using Svelte 5 runes
src/content/content-utils.ts Navigation, metrics, pure helpers
src/content/types.ts Unified interfaces; re-exports generated types
src/content/types.generated.ts Autogenerated ContentTypes union (do not edit manually)
scripts/generate-content-types.ts Generates the union from .compiledCollections/ (AUTOGEN markers)

🚀 Performance

  • Zero Runtime Overhead: Types are stripped during compilation.
  • Tree-Shakable: Server-only logic in engine.server.ts / loader.server.ts is never sent to the client.
  • Incremental Updates: Only modified collections trigger an update in the types file.
  • Single scanner: Vite and runtime share scanCompiledCollections() — consistent schema discovery.

Related

developertypescollectionscode-generationtypescript
Was this page helpful?