Skip to main content

freezeray generate

Generate FreezeRay artifacts (fixtures, schema tests, or migration tests) with granular control over the workflow.

Synopsis

Description

The generate command provides granular operations for creating FreezeRay artifacts separately. Most important: Use generate migration-tests when starting work on a new schema version. This lets you write and test migrations as you develop. The other subcommands (fixtures, schema-tests) are rarely needed because freeze handles them automatically.

Subcommands

migration-tests - Generate migration tests ⭐

Generates a migration test file that validates data migration between two schema versions. This is the primary use case for the generate command. See detailed documentation →

fixtures - Generate frozen fixtures (Advanced)

Generates frozen SwiftData fixtures for a specific schema version. Rarely needed: freeze does this automatically. See detailed documentation →

schema-tests - Generate drift tests (Advanced)

Generates a drift test file that validates a frozen schema hasn’t changed. Rarely needed: freeze does this automatically. See detailed documentation →

Why Use generate migration-tests?

The Correct Workflow

Migration tests should be created when you start working on a new schema version, not after:
This lets you develop with the migration test as you build the new schema.
Key insight: freeze does NOT generate migration tests. You must explicitly run generate migration-tests when starting work on a new schema version.

generate fixtures

Generate frozen fixtures for a specific schema version.

Synopsis

Description

Generates frozen SwiftData fixtures by:
  1. Discovering the @FreezeSchema(version: "X.Y.Z") annotation
  2. Running a freeze test in iOS Simulator
  3. Extracting fixtures from /tmp to FreezeRay/Fixtures/<VERSION>/

Arguments

--schema <VERSION>, -s <VERSION>

Required. The schema version to freeze (e.g., “1.0.0”). Must match a @FreezeSchema annotation in your source code:

Options

--simulator <NAME>

Default: iPhone 17 iOS Simulator to use for freezing:

--scheme <NAME>

Default: Auto-detected Xcode scheme to build:

--force

Overwrite existing fixtures (dangerous!):
Only use --force during development before shipping to production. Overwriting frozen fixtures breaks immutability.

--output <PATH>

Default: FreezeRay/Fixtures Custom output directory:

--config <PATH>

Path to FreezeRay.yaml config file (experimental):

What Gets Created

Examples

Basic usage

Output:

Short form

Custom simulator

Common Errors

”No @FreezeSchema found for version X.Y.Z”

Cause: The version doesn’t match any @FreezeSchema annotation. Fix: Add the annotation to your schema:

“Fixtures already exist”

Cause: Fixtures for this version already exist. Solutions: During development (before shipping):
After shipping to production:

generate schema-tests

Generate drift test for a frozen schema version.

Synopsis

Description

Generates a drift test file that validates the current schema definition matches the frozen fixtures. Requirements:
  • Fixtures must already exist for the specified version
  • Run freezeray generate fixtures first if needed

Arguments

--schema <VERSION>, -s <VERSION>

Required. The schema version to generate tests for (e.g., “3.0.0”).

Options

--force

Overwrite existing test file:
By default, existing test files are never overwritten (they’re user-owned).

--config <PATH>

Path to config file (experimental):

What Gets Created

Generated tests use @Suite(.serialized) to prevent parallel execution issues with SwiftData stores.

Examples

Basic usage

Output:

Short form

Regenerate (overwrite)

Common Errors

”No fixtures found for version X.Y.Z”

Cause: Fixtures don’t exist for the specified version. Fix: Generate fixtures first:

“Test file already exists”

Cause: The drift test file was already generated. Solutions: If you want to keep your custom assertions:
If you want to regenerate:

generate migration-tests

Generate migration test from one schema version to another.

Synopsis

Description

Generates a migration test file that validates data migration between two schema versions. This is the key innovation of the generate command: you can create the migration test early in your development workflow, not after the fact. Requirements:
  • Fixtures must exist for --from-schema version
  • @FreezeSchema must exist in code for --to-schema version
  • SchemaMigrationPlan must have a migration stage between versions
Behavior if test file exists:
  • Does NOT overwrite (preserves user’s custom assertions)
  • Prints skip message
  • Use --force to overwrite

Arguments

--from-schema <VERSION>, -f <VERSION>

Required. Source schema version (e.g., “2.0.0”).

--to-schema <VERSION>, -t <VERSION>

Required. Target schema version (e.g., “3.0.0”).

Options

--force

Overwrite existing test file:
Only use --force if you’re sure you want to discard custom assertions you’ve added to the test.

--config <PATH>

Path to config file (experimental):

What Gets Created

The generated test includes @Suite(.serialized) to fix parallel execution issues that cause SwiftData store conflicts.

Examples

Basic usage (early workflow)

Output:

Short form

Regenerate (overwrite custom assertions)

Output:

Common Errors

”No fixtures found for version X.Y.Z”

Cause: Source schema fixtures don’t exist. Fix: Freeze the source version first:

“No @FreezeSchema found for version X.Y.Z”

Cause: Target schema doesn’t exist in code yet. Fix: Define the target schema:
Then generate the test:

“No SchemaMigrationPlan found in codebase”

Cause: You haven’t defined a migration plan. Fix: Create a migration plan:
Then generate the test:

“Migration test already exists”

Cause: You’ve already generated the migration test. Solutions: If you’ve added custom assertions:
If you want to start over:

Complete Workflow Example

Key point: You develop with the migration test from the start, not after the fact.

Parallel Execution Fix

All generated tests now use @Suite(.serialized) to prevent parallel execution issues.

Problem (Before)

Migration tests failed when run in parallel (Swift Testing default):
Running individually worked:
Cause: Tests create/destroy SwiftData stores in temp directories with potential collisions.

Solution (After)

Generated tests now use @Suite(.serialized):
Now tests work in default harness:

Best Practices

1. Generate Migration Tests Early

Generate the migration test when you start working on the migration:

2. Never Overwrite User Tests

The generate commands never overwrite existing test files by default:
This protects your custom assertions.

3. Use freeze for Complete Workflow

For most users, freeze is still the recommended command:
Only use generate when you need fine-grained control:
  • Generate migration tests early ✅
  • Regenerate specific artifacts ✅
  • Customize the workflow ✅

4. Commit Generated Tests

Generated tests are yours to maintain:
Test files evolve with your schema, just like any other test.

What freeze Does

The freeze command is simpler than generate - it only creates fixtures and drift tests:
Internally equivalent to:
That’s it! freeze does NOT touch migration tests. Migration tests are managed separately with generate migration-tests.

Requirements

Same as freezeray freeze:
  • macOS 14+
  • Xcode 15+
  • iOS Simulator (iPhone 17 recommended)
  • Project structure:
    • @FreezeSchema(version: "X.X.X") annotations
    • Test target for running freeze tests
    • Xcode project or Swift Package with iOS target

Next Steps

freeze command

Learn about the convenience freeze command

Testing Migrations

Step-by-step guide for the new migration workflow

Migration Testing Concepts

Understand how migration tests work

Drift Detection

Learn about schema drift detection