Hot reload not working after using a reference field from a custom component in the editor

What are you trying to accomplish
I’m integrating a custom component that uses a reference input field. Functionally, it works fine on the frontend, but in the Builder visual editor, after using this component, newly added components don’t appear in the preview iframe until the user manually refreshes the page.

I’ve stripped everything back to confirm the cause — the reference component’s content model has only a single input, and the referenced model is equally minimal. The issue still occurs regardless of which model is referenced.

Video link

Code stack you are integrating Builder with
Next.js v15.4.1
Builder SDK v6.1.2

Reproducible code example
Below is a simplified version of the content-model.ts for one of the components that triggers the issue. It only contains one reference-type input. The referenced model can be swapped for any other, and the component still works — but the hot-refresh issue persists.

import dynamic from 'next/dynamic';
import { Builder } from '@builder.io/react';
import { Input } from '@builder.io/sdk';
import { BuilderBlockNames } from '@/types/builder';
import { getBuilderIconUrl } from '@/utils/url';
import { BUILDER_MODEL_ID } from '@/constants/builder';

const AlternatingBlockComponent = dynamic(() => import('./index' as string));

const baseConfig = {
friendlyName: 'Alternating Block',
image: getBuilderIconUrl('alternating-block'),
};

const sharedInputs: Input[] = [
  {
name: 'internalLinkStandardPage',
friendlyName: 'Link to a Standard page',
type: 'reference',
model: 'standard-page',
helperText: 'Select a Standard page',
  },
];

export const registerAlternatingBlockStandardPage = () =>
Builder.registerComponent(AlternatingBlockComponent, {
name: BuilderBlockNames.ALTERNATING_BLOCK,
...baseConfig,
models: [BUILDER_MODEL_ID.STANDARD_PAGE],
inputs: sharedInputs,
  });

Observed behaviour

  • After dragging this component onto the preview page and selecting a reference in the internalLinkStandardPage field, subsequent components added to the page (even the same one) appear in the Layers panel and are editable.

  • However, they only become visibly rendered in the preview iframe about 1 in 5 times.

  • A manual refresh (via the preview URL or page reload) immediately shows all components correctly.

Expected behaviour

The visual editor should update live every time a component is added or removed, even after a component with a reference field has been used.

Additional notes

  • The issue only occurs after a reference input is populated in the editor.
  • I’ve confirmed it happens on multiple machines and networks.
  • Preview updates correctly after a manual refresh, so the data itself is saving fine — it seems specific to the hot-reload path inside the visual editor iframe.
  • This happens on local environments and our Vercel-hosted environments.

Hello @TC_Support,

Thank you for sharing the detailed explanation and reproducible code example. We’ve reviewed your setup and the component configuration, and based on our initial testing, we weren’t able to reproduce the issue on our end.

It’s possible that the behavior you’re seeing may be related to the way Builder is integrated within your Next.js environment rather than the reference input itself. Could you please confirm whether the same issue occurs when using a similar component without a reference field?

Additionally, to help us investigate further, please share the relevant part of your Builder integration code (for example, how you’ve initialized or rendered Builder components in your Next.js project). This will allow us to check if there are any interaction points between the integration and the visual editor’s hot-reload process that might be causing the issue.

Once we have that information, we can take a closer look and provide more targeted guidance.

Kind regards,

Thank you for looking into this for us @manish-sharma.

From our testing, this issue isn’t reproducible for us with any components that don’t have a reference field. Even if a component does have a reference field, everything works as expected until the user populates one of the reference fields with an object.

As for our Builder integration code, here are some snippets of the relevant integration code;

render-builder-content.tsx:

builder.init(process.env.NEXT_PUBLIC_BUILDER_IO_API_KEY!);

builderRegistry();

type BuilderPageProps = ComponentProps<typeof BuilderComponent>;

export function RenderBuilderContent(props: BuilderPageProps) {
  const isEditing = Builder.isEditing;

  if (props.content || isEditing) {
    return (
      <ReactQueryProvider>
        <BuilderComponent
          {...props}
          content={props.content}
          options={{ includeRefs: true }}
        />
      </ReactQueryProvider>
    );
  }
  return null;
}

builder-registry.ts:

const builderRegistry = () => {
  Builder.register('editor.settings', { customInsertMenu: true });

  const builderBlockItems: { name: BuilderBlockNames }[] = [
    { name: BuilderBlockNames.ALERT_BLOCK },
    { name: BuilderBlockNames.ALTERNATING_BLOCK },
    { name: BuilderBlockNames.CARDS_BLOCK },
    // Rest of the blocks go here
  ];

  const contentBlockItems: { name: BuilderBlockNames }[] = [
    { name: BuilderBlockNames.CONTENT_CONTAINER },
    { name: BuilderBlockNames.NEWS_PAGE_SIDE_NAVIGATION },
    { name: BuilderBlockNames.RICH_TEXT },
    // etc.
  ];

  Builder.register('insertMenu', {
    name: 'Builder Blocks',
    items: builderBlockItems,
  });

  Builder.register('insertMenu', {
    name: 'Content Blocks',
    items: contentBlockItems,
  });

  // COMPONENT REGISTRATION 
  registerAlertBlockPortalPage();
  registerAlternatingBlockStandardPage();
  registerCardsBlock();
// etc.

  registerContentBlockStandardPage();
  registerContentBlockNewsPage();
  registerNewsPageSideNavigation();
// etc.

  // The Breadcrumbs component is not used in the builder, but it is inserted into the page content
  // therefore it needs to be a registered component
  Builder.registerComponent(Breadcrumbs, {
    name: 'Breadcrumbs',
    canHaveChildren: false,
    hideFromInsertMenu: true,
  });

  Builder.registerComponent(NewsListingsBlock, {
    name: 'News Listings Block',
    canHaveChildren: false,
    hideFromInsertMenu: true,
  });
};

export default builderRegistry;

An example of the registerComponent functions can be seen from the content-model snippit at the top of the thread.

Hopefully this context helps, please shout out if there’s any more information needed to help reproduce this scenario.

Kind regards

Hello @TC_Support,

We were able to reproduce the issue on our end and have confirmed that it can be resolved by enabling the “Use debounced edits in content editor” option located under Settings → Advanced Settings → Performance.

Please let us know if the issue still persists — we’ll be happy to investigate it further.

Thanks,

Thank you @manish-sharma for the recommendation of enabling the " Use debounced edits in content editor" option. This has seemingly fixed our hot reload issues.

Out of curiosity, I have a few questions:

  • Why does this toggle enable fix our hot reload editor issues?
  • What is happening behind the scenes in a technical sense?
  • Are there any other alternative options to resolve our issues or is this debounced content edits in editor the recommended method?

Thank you for your help :slightly_smiling_face:

1 Like

Hello @TC_Support,

I’m glad to hear that enabling the “Use debounced edits in content editor” option helped resolve your hot reload issues — thank you for confirming!

This setting likely resolved the issue because it introduces a short delay when applying changes in the Visual Editor. That delay helps manage cases where the editor’s behavior may appear delayed or inconsistent, often caused by rapid successive updates that can lead to performance bottlenecks.

From a technical perspective, debouncing is a method that combines multiple rapid actions into a single update after a brief delay. This approach helps prevent excessive or conflicting updates from occurring too frequently — a common source of instability during frequent edits.

As for alternative solutions, the “Use debounced edits in content editor” setting is one of several performance-related options in Builder. Another related option is “Debounce text edits,” which applies a similar delay specifically to text changes. These settings can help improve Visual Editor performance in specific scenarios.

You can find more details in our documentation:

I hope this clarifies how the toggle works and why it’s effective. Please don’t hesitate to reach out if you’d like a deeper technical walkthrough or have any other questions.

Thanks,

1 Like