Seed Loader
Seed Loader protocol schemas
Seed Loader Protocol
Defines the schemas for metadata-driven seed data loading with automatic relationship resolution, dependency ordering, and multi-pass insertion.
Architecture Alignment
- Salesforce Data Loader: External ID-based upsert with relationship resolution
- ServiceNow: Sys ID and display value mapping during import
- Airtable: Linked record resolution via display names
Loading Flow
1. Build object dependency graph from field metadata (lookup/master_detail)
2. Topological sort → determine insert order (parents before children)
3. Pass 1: Insert/upsert records, resolve references via externalId
4. Pass 2: Fill deferred references (circular/delayed dependencies)
5. Validate & report unresolved references
6. Return structured result with per-object statsSource: packages/spec/src/data/seed-loader.zod.ts
TypeScript Usage
import { ObjectDependencyGraphSchema, ObjectDependencyNodeSchema, ReferenceResolutionSchema, ReferenceResolutionErrorSchema, SeedIdentitySchema, SeedLoadResultSchema, SeedLoaderConfigSchema, SeedLoaderRequestSchema, SeedLoaderResultSchema } from '@objectstack/spec/data';
import type { ObjectDependencyGraph, ObjectDependencyNode, ReferenceResolution, ReferenceResolutionError, SeedIdentity, SeedLoadResult, SeedLoaderConfig, SeedLoaderRequest, SeedLoaderResult } from '@objectstack/spec/data';
// Validate data
const result = ObjectDependencyGraphSchema.parse(data);ObjectDependencyGraph
Complete object dependency graph for seed data loading
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| nodes | { object: string; dependsOn: string[]; references: object[] }[] | ✅ | All objects in the dependency graph |
| insertOrder | string[] | ✅ | Topologically sorted insert order |
| circularDependencies | string[][] | ✅ | Circular dependency chains (e.g., [["a", "b", "a"]]) |
ObjectDependencyNode
Object node in the seed data dependency graph
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| object | string | ✅ | Object name (snake_case) |
| dependsOn | string[] | ✅ | Objects this object depends on |
| references | { field: string; targetObject: string; targetField: string; fieldType: Enum<'lookup' | 'master_detail' | 'user'>; … }[] | ✅ | Field-level reference details |
ReferenceResolution
Describes how a field reference is resolved during seed loading
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| field | string | ✅ | Source field name containing the reference value |
| targetObject | string | ✅ | Target object name (snake_case) |
| targetField | string | ✅ | Field on target object used for matching |
| fieldType | Enum<'lookup' | 'master_detail' | 'user'> | ✅ | Relationship field type |
| multiple | boolean | optional | Field stores an array of references (multiple: true) |
ReferenceResolutionError
Actionable error for a failed reference resolution
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| sourceObject | string | ✅ | Object with the broken reference |
| field | string | ✅ | Field name with unresolved reference |
| targetObject | string | ✅ | Target object searched for the reference |
| targetField | string | ✅ | ExternalId field used for matching |
| attemptedValue | any | ✅ | Value that failed to resolve |
| recordIndex | integer | ✅ | Index of the record in the dataset |
| message | string | ✅ | Human-readable error description |
SeedIdentity
Identity context for resolving os.user / os.org in seed CEL values
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| user | { id: string; role?: string; email?: string } | optional | Subject bound to os.user in seed CEL expressions |
| org | { id: string; tier?: string } | optional | Organization bound to os.org in seed CEL expressions |
SeedLoadResult
Result of loading a single dataset
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| object | string | ✅ | Object that was loaded |
| mode | Enum<'insert' | 'update' | 'upsert' | 'replace' | 'ignore'> | ✅ | Import mode used |
| inserted | integer | ✅ | Records inserted |
| updated | integer | ✅ | Records updated |
| skipped | integer | ✅ | Records skipped |
| errored | integer | ✅ | Records with errors |
| total | integer | ✅ | Total records in dataset |
| referencesResolved | integer | ✅ | References resolved via externalId |
| referencesDeferred | integer | ✅ | References deferred to second pass |
| referencesDropped | integer | ✅ | Reference fields dropped from records that were still written |
| summariesStale | integer | ✅ | Roll-up summary values left stale by writes for this dataset |
| errors | { sourceObject: string; field: string; targetObject: string; targetField: string; … }[] | ✅ | Reference resolution errors |
SeedLoaderConfig
Seed data loader configuration
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| dryRun | boolean | ✅ | Validate references without writing data |
| haltOnError | boolean | ✅ | Stop on first reference resolution error |
| multiPass | boolean | ✅ | Enable multi-pass loading for circular dependencies |
| defaultMode | Enum<'insert' | 'update' | 'upsert' | 'replace' | 'ignore'> | ✅ | Default conflict resolution strategy |
| batchSize | integer | ✅ | Maximum records per batch insert/upsert |
| transaction | boolean | ✅ | Wrap entire load in a transaction (all-or-nothing) |
| env | Enum<'prod' | 'dev' | 'test'> | optional | Only load datasets matching this environment |
| organizationId | string | optional | Target organization id for per-tenant seed replay |
| identity | { user?: object; org?: object } | optional | Identity bound to os.user / os.org when resolving CEL seed values |
SeedLoaderRequest
Seed loader request with datasets and configuration
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| seeds | { object: string; externalId: string | string[]; mode: Enum<'insert' | 'update' | 'upsert' | 'replace' | 'ignore'>; env: Enum<'prod' | 'dev' | 'test'>[]; … }[] | ✅ | Seeds to load |
| config | { dryRun: boolean; haltOnError: boolean; multiPass: boolean; defaultMode: Enum<'insert' | 'update' | 'upsert' | 'replace' | 'ignore'>; … } | ✅ | Loader configuration |
SeedLoaderResult
Complete seed loader result
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| success | boolean | ✅ | Overall success status |
| dryRun | boolean | ✅ | Whether this was a dry-run |
| dependencyGraph | { nodes: object[]; insertOrder: string[]; circularDependencies: string[][] } | ✅ | Object dependency graph |
| results | { object: string; mode: Enum<'insert' | 'update' | 'upsert' | 'replace' | 'ignore'>; inserted: integer; updated: integer; … }[] | ✅ | Per-object load results |
| errors | { sourceObject: string; field: string; targetObject: string; targetField: string; … }[] | ✅ | All reference resolution errors |
| summary | { objectsProcessed: integer; totalRecords: integer; totalInserted: integer; totalUpdated: integer; … } | ✅ | Summary statistics |