# Seed declaration — verbatim rules

Transcribed from docs.modern-expo.com/backend/application-developing/migrations.html (captured 2026-08-03). If an option is not in these tables, it does not exist — stop and ask.

## createSeed

A seed is created with createSeed(entityName, data, options?) and exported from a *.seed.ts file.

```ts
import { createSeed } from '@suppa/sdk';
import { EntityNamesEnum } from '../../modules';

export const workflowsSeed = createSeed(EntityNamesEnum.Workflows, [
	{
		name: 'Default',
		description: 'Default set of statuses',
		private: false,
		externalId: null,
	},
]);
```

The first argument is the entity name as a string — the same value as `name` in `@Entity()`. Keeping those names in a local enum (`EntityNamesEnum`) avoids typos across seeds.

## Idempotency

Seeds run on every application start, for every tenant. They must therefore be idempotent: a seed either inserts a record or updates the existing one, but never duplicates it.

Matching is done on the target entity's importKeyFields. So:

- Always provide all importKeyFields in every record.
- If the natural key does not fit your data, override identity per record with `$key`.

```ts
export const localizationsSeed = createSeed('Localizations', [
	{
		$key: { key: 'task-manager.greeting' },
		key: 'task-manager.greeting',
		en: 'Hello',
		uk: 'Привіт',
	},
]);
```

## Referencing Relations

Reference a related record through the target's importKeyFields, as an object — never by numeric id:

```ts
import { createSeed } from '@suppa/sdk';
import { StageStatusEnum } from '../entities';
import { EntityNamesEnum } from '../../modules';

export const stageWorkflowsSeed = createSeed(EntityNamesEnum.StageWorkflows, [
	{
		name: 'To Do',
		color: '#3069FE',
		order: 1000,
		default: true,
		status: {
			name: 'StageWorkflows.status',
			value: StageStatusEnum.Active,
		},
		workflow: { name: 'Default' },
	},
	{
		name: 'In Progress',
		color: '#47D1E2',
		order: 2000,
		status: {
			name: 'StageWorkflows.status',
			value: StageStatusEnum.InProgress,
		},
		workflow: { name: 'Default' },
	},
	{
		name: 'Done',
		color: '#75D900',
		order: 5000,
		status: {
			name: 'StageWorkflows.status',
			value: StageStatusEnum.Completed,
		},
		workflow: { name: 'Default' },
	},
]);
```

Two reference shapes appear here:

| Field type | Reference shape |
|---|---|
| @ManyToOne | { <importKeyField>: value } — e.g. { name: 'Default' } |
| @Enum | { name: '<global enum name>', value: '<enum value>' } |
| @ManyToMany | An array of reference objects. |

Because `workflow: { name: 'Default' }` resolves by name, the seed works in every tenant regardless of what id the Default workflow received there.

> **WARNING**
> Seed order matters for relations. Register a seed after the seed that creates the records it points at — workflowsSeed before stageWorkflowsSeed.

## What Not to Put in a Seed

| Never include | Why |
|---|---|
| id, createdAt, updatedAt, deletedAt, createdBy, removedBy | System columns. They differ per tenant and corrupt matching. |
| $readAccess, $updateAccess, $instanceAccess | Access metadata, not data. |
| Reverse @OneToMany fields — even as [] | Back references cannot be inserted; the import throws. |
| Numeric relation ids | They do not match across tenants. Use import-key references. |

Seeding a tabular part's owner is the same @ManyToOne reference shape as any other relation — see [references/tabular-parts.md](tabular-parts.md) for the owner-referenced seed example.

> **TIP**
> When you build a seed from an exported record, strip those keys before committing. Seed a child entity with its own seed instead of nesting it in the parent.

## Keeping Seed Files Thin

When a record carries a large payload, move the data to a static file and import it:

`src/common/database/static/currencies.ts`

```ts
export const CURRENCIES = [
	{ code: 'USD', symbol: '$' },
	{ code: 'EUR', symbol: '€' },
];
```

`src/common/database/seeds/currencies.seed.ts`

```ts
import { createSeed } from '@suppa/sdk';
import { CURRENCIES } from '../static/currencies';

export const currenciesSeed = createSeed('Currencies', CURRENCIES);
```
