#3422·vendure

Expandability for custom fields with type `relation`

Author: kwerieCreated Mar 18, 2025Updated Sep 19, 2026
Labels@vendure/coretype: feature ✨P4: lowT3: Systemic

Is your feature request related to a problem? Please describe. Whenever I define a relation on an entity, a foreign key is created (duh), but I do not have the ability to specify what happens to the column (or row) when the referenced column is updated or deleted.

Let's say I have a plugin that has a custom field definition on the Product entity that relates to a custom entity:

typescript
{
    type: "relation",
    entity: RevenueGroup,
    name: "revenueGroupId",
    nullable: true,
    public: false,
    readonly: true,
}

The custom entity definition looks like this:

typescript
import { DeepPartial, Product, VendureEntity } from "@vendure/core";
import { Column, Entity, Index, OneToMany } from "typeorm";
import { RevenueGroupKind } from "../generated-admin-types";

@Entity()
export class RevenueGroup extends VendureEntity {
    constructor(input?: DeepPartial<RevenueGroup>) {
        super(input);
    }

    @Column()
    @Index({ unique: true })
    code: number;

    @Column({ nullable: true })
    description: string;

    @Column({
        type: "enum",
        enum: RevenueGroupKind,
        default: RevenueGroupKind.GOODS,
        nullable: false,
    })
    kind: RevenueGroupKind;

    @OneToMany(() => Product, (product) => product.customFields.revenueGroupId)
    products: Product[];
}

This results in a column being created on the product entity like this:

ALTER TABLE product ADD CONSTRAINT FK_41a265244115fe63127e554b20c FOREIGN KEY (customFieldsRevenuegroupidid) REFERENCES revenue_group(id) ON DELETE NO ACTION ON UPDATE NO ACTION

I would like to be able to control what happens ON DELETE or ON UPDATE

Describe the solution you'd like I would like the RelationCustomFieldConfig type/interface to support customizability for the ON DELETE and ON UPDATE options just like we can when defining relationships in (custom) entities through decorators.

An example type could look like this:

typescript
export type RelationCustomFieldConfig = TypedCustomFieldConfig<'relation', Omit<GraphQLRelationCustomFieldConfig, 'entity' | 'scalarFields'>> & {
    entity: Type<VendureEntity>;
    graphQLType?: string;
    eager?: boolean;
    inverseSide?: string | ((object: any) => any);
	onDelete?: SomeType; // Typed to 'SET NULL' | 'CASCADE' | 'SET DEFAULT' etc..
	onUpdate?: SomeType; // Typed to 'SET NULL' | 'CASCADE' | 'SET DEFAULT' etc..
};

Describe alternatives you've considered

  1. a custom migration, and setting the custom field's type to int but that did not work like expected, because when developing locally synchronize cannot be set to true since the migration would just be undone (because schema mismatch).
  2. I have tried setting synchronize to false and calling runMigrations(config) before bootstrapping the application, but that resulted in warnings being printed to the console that I needed to create another migration to remove the foreign key:
    bash
    [server] Successfully ran migration: AddOnDeletionTriggerForRevenueGroups1742218462222
    [server] Your database schema does not match your current configuration. Generate a new migration for the following changes: 
    [server] - ALTER TABLE `product` DROP FOREIGN KEY `FK_RG_ID`
  3. Single table inheritance.

Additional context