Seed Loader schema — Data Protocol reference Defines the schemas for metadata-driven seed data loading with automatic relationship resolution, dependency ordering, and multi-pass insertion.
Defines the schemas for metadata-driven seed data loading with automatic
relationship resolution, dependency ordering, and multi-pass insertion.
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
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 stats
Source: packages/spec/src/data/seed-loader.zod.ts
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);
Complete object dependency graph for seed data loading
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[][]optional (default: []) Circular dependency chains (e.g., [["a", "b", "a"]])
Object node in the seed data dependency graph
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
Object node in the seed data dependency graph
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
Describes how a field reference is resolved during seed loading
Property Type Required Description field string✅ Source field name containing the reference value targetObject string✅ Target object name (snake_case) targetField stringoptional (default: "name") Field on target object used for matching fieldType Enum<'lookup' | 'master_detail' | 'user'>✅ Relationship field type multiple booleanoptional Field stores an array of references (multiple: true)
Describes how a field reference is resolved during seed loading
Property Type Required Description field string✅ Source field name containing the reference value targetObject string✅ Target object name (snake_case) targetField stringoptional (default: "name") Field on target object used for matching fieldType Enum<'lookup' | 'master_detail' | 'user'>✅ Relationship field type multiple booleanoptional Field stores an array of references (multiple: true)
Actionable error for a failed reference resolution
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
Identity context for resolving os.user / os.org in seed CEL values
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
Result of loading a single dataset
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 integeroptional (default: 0) Reference fields dropped from records that were still written summariesStale integeroptional (default: 0) Roll-up summary values left stale by writes for this dataset landedIds string[]optional (default: []) Ids of the stored rows this dataset landed on: inserted, updated, or matched on replay errors { sourceObject: string; field: string; targetObject: string; targetField: string; … }[]optional (default: []) Reference resolution errors
Actionable error for a failed reference resolution
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
Seed data loader configuration
Property Type Required Description dryRun booleanoptional (default: false) Validate references without writing data haltOnError booleanoptional (default: false) Stop on first reference resolution error multiPass booleanoptional (default: true) Enable multi-pass loading for circular dependencies defaultMode Enum<'insert' | 'update' | 'upsert' | 'replace' | 'ignore'>optional (default: "upsert") Default conflict resolution strategy batchSize integeroptional (default: 1000) Maximum records per batch insert/upsert transaction booleanoptional (default: false) Wrap entire load in a transaction (all-or-nothing) env Enum<'prod' | 'dev' | 'test'>optional Only load datasets matching this environment locale stringoptional Only load datasets scoped to this locale (BCP-47 tag) organizationId stringoptional 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
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
Seed loader request with datasets and configuration
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'>; … }optional (has default) Loader configuration
Property Type Required Description object string✅ Target Object Name externalId string | string[]optional (default: "name") Field (or composite list of fields) matched for the uniqueness check mode Enum<'insert' | 'update' | 'upsert' | 'replace' | 'ignore'>optional (default: "upsert") Conflict resolution strategy env Enum<'prod' | 'dev' | 'test'>[]optional (default: ["prod","dev","test"]) Applicable environments locale string[]optional Applicable locales (BCP-47 tags); omitted applies to every locale. The publish and install paths do not filter by locale — they load every dataset and warn records Record<string, any>[]✅ Data records _lock Enum<'none' | 'no-overlay' | 'no-delete' | 'full'>optional Item-level lock — controls overlay & delete (ADR-0010). _lockReason stringoptional Human-readable reason shown when a write is refused by _lock. _lockSource Enum<'artifact' | 'package' | 'env-forced'>optional Layer that set _lock (artifact | package | env-forced). _provenance Enum<'package' | 'org' | 'env-forced'>optional Origin of the item (package | org | env-forced). _packageId stringoptional Owning package machine id. _packageVersion stringoptional Owning package version. _lockDocsUrl stringoptional Optional documentation link surfaced next to _lockReason.
Property Type Required Description dryRun booleanoptional (default: false) Validate references without writing data haltOnError booleanoptional (default: false) Stop on first reference resolution error multiPass booleanoptional (default: true) Enable multi-pass loading for circular dependencies defaultMode Enum<'insert' | 'update' | 'upsert' | 'replace' | 'ignore'>optional (default: "upsert") Default conflict resolution strategy batchSize integeroptional (default: 1000) Maximum records per batch insert/upsert transaction booleanoptional (default: false) Wrap entire load in a transaction (all-or-nothing) env Enum<'prod' | 'dev' | 'test'>optional Only load datasets matching this environment locale stringoptional Only load datasets scoped to this locale (BCP-47 tag) organizationId stringoptional 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
Complete seed loader result
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
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[][]optional (default: []) Circular dependency chains (e.g., [["a", "b", "a"]])
Result of loading a single dataset
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 integeroptional (default: 0) Reference fields dropped from records that were still written summariesStale integeroptional (default: 0) Roll-up summary values left stale by writes for this dataset landedIds string[]optional (default: []) Ids of the stored rows this dataset landed on: inserted, updated, or matched on replay errors { sourceObject: string; field: string; targetObject: string; targetField: string; … }[]optional (default: []) Reference resolution errors
Actionable error for a failed reference resolution
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
Property Type Required Description objectsProcessed integer✅ Total objects processed totalRecords integer✅ Total records across all objects totalInserted integer✅ Total records inserted totalUpdated integer✅ Total records updated totalSkipped integer✅ Total records skipped totalErrored integer✅ Total records with errors totalReferencesResolved integer✅ Total references resolved totalReferencesDeferred integer✅ Total references deferred totalReferencesDropped integeroptional (default: 0) Total reference fields dropped from written records totalSummariesStale integeroptional (default: 0) Total roll-up summary values left stale across the load circularDependencyCount integer✅ Circular dependency chains detected durationMs number✅ Load duration in milliseconds