freezeray freeze
Freeze a schema version by generating immutable fixture artifacts from the actual SwiftData schema running in iOS Simulator.Synopsis
Description
Thefreeze command captures an immutable snapshot of your SwiftData schema at a specific version. It:
- Auto-detects your Xcode project and scheme
- Discovers
@FreezeSchema(version: "X.X.X")annotations in source files - Builds and runs your project in iOS Simulator
- Extracts fixtures from the simulator container to
FreezeRay/Fixtures/ - Scaffolds drift test (if it doesn’t already exist)
- Updates Xcode project to include test files and fixture resources
Arguments
<VERSION>
Required. The version string to freeze (e.g., “1.0.0”, “2.0.0”).
Must match a @FreezeSchema(version: "X.X.X") annotation in your source code:
Options
--simulator <NAME>
Default: iPhone 17
Specify which iOS Simulator to use for freezing:
Always use a consistent simulator across your team to avoid subtle schema differences.
--scheme <NAME>
Default: Auto-detected
Specify the Xcode scheme to build:
--force
Dangerous! Overwrite existing frozen fixtures for the specified version.
- You’re iterating on an unreleased schema version
- Fixtures were corrupted and need regeneration
- The version has been shipped to production users
- Other developers depend on the frozen fixtures
--output <PATH>
Default: FreezeRay/Fixtures/<VERSION>/
Override the output directory for fixtures:
Custom output paths are useful for monorepos or non-standard project structures.
--config <PATH>
Experimental. Specify path to .freezeray.yml config file:
What Gets Created
After runningfreezeray freeze 1.0.0, you’ll find:
Fixtures: FreezeRay/Fixtures/1.0.0/
| File | Description |
|---|---|
App-1_0_0.sqlite | Real SQLite database with schema structure |
schema-1_0_0.json | Human-readable schema metadata (entity names, counts) |
schema-1_0_0.sql | SQL DDL statements for schema structure |
schema-1_0_0.sha256 | SHA256 checksum for drift detection |
export_metadata.txt | Timestamp and version info |
Tests: FreezeRay/Tests/
| File | Description |
|---|---|
AppSchemaV1_DriftTests.swift | Drift detection test (scaffolded if doesn’t exist) |
Drift test files are scaffolded once and then owned by you. Customize them with assertions as needed.Migration tests are NOT created by
freeze. Use freezeray generate migration-tests when starting work on a new schema version.Examples
Basic usage
Complete workflow with migration
freeze 2.0.0:
freeze does NOT generate migration tests. You created MigrateV1_0_0toV2_0_0_Tests.swift earlier with the generate command.
Custom simulator
Force overwrite (development only)
Requirements
- macOS 14+
- Xcode 15+
- iOS Simulator (iPhone 17 recommended)
- Project structure:
- Must have
@FreezeSchema(version: "X.X.X")annotation in source code - Must have a test target (for running freeze tests)
- Xcode project or Swift Package with iOS target
- Must have
Common Errors
”No @Freeze(version: “X.X.X”) annotation found”
Cause: The specified version doesn’t match any@FreezeSchema annotation in your source files.
Fix:
“Fixtures for vX.X.X already exist”
Cause: You’ve already frozen this version. Solution: If you haven’t shipped to production yet:“Build failed” or “Tests failed”
Cause: Your project doesn’t build or tests are failing. Fix:- Ensure your project builds in Xcode: ⌘B
- Ensure your tests pass in Xcode: ⌘U
- Check the Xcode console for specific errors
- Missing dependencies
- Syntax errors in schema
- Test target not configured correctly
”Simulator not found: iPhone 17”
Cause: The specified simulator doesn’t exist. Fix: List available simulators:“Could not update Xcode project”
Cause: Xcode project manipulation failed (rare). Solution: Manually add files to Xcode:- Open Xcode
- Drag
FreezeRay/Tests/to your test target - Add
FreezeRay/folder to test target’s Copy Bundle Resources:- Select test target
- Build Phases → Copy Bundle Resources → + → Add
FreezeRay/folder
How It Works
Step 1: Project Discovery
FreezeRay auto-detects:- Xcode project (
*.xcodeproj) or Swift Package (Package.swift) - Scheme (first available scheme or user-specified)
- Test target (inferred from scheme name)
Step 2: Source Parsing
Uses SwiftSyntax to parse all.swift files and find:
@FreezeSchema(version: "X.X.X")annotationsSchemaMigrationPlantypes
Step 3: Test Generation
Creates a temporary test file:Step 4: Simulator Execution
Runs:- Creates a ModelContainer with your schema
- Generates SQLite database in simulator’s Documents directory
- Exports fixtures to
/tmp/FreezeRay/Fixtures/1.0.0/
Step 5: Fixture Extraction
CLI copies fixtures from/tmp/FreezeRay/Fixtures/1.0.0/ to your project’s FreezeRay/Fixtures/1.0.0/.
iOS Simulator can’t write directly to your source tree, so fixtures go through
/tmp as an intermediary.Step 6: Test Scaffolding
Generates permanent test files: Drift test:Step 7: Xcode Project Update
For Xcode projects (not Swift Packages):- Adds test files to test target’s sources
- Adds
FreezeRay/folder to test target’s resources
Best Practices
Commit Fixtures Immediately
- Fixtures are in version control
- CI can run drift/migration tests
- Team members get the fixtures