Migrating from DropZones to slots
Puck’s <DropZone> is deprecated in favour of slot fields , which store nested components inline, support defaultProps and resolveData, and render on the server. Existing DropZones keep working, so migrate when you are ready. New components should use slots.
See Slots for how slot fields work in general. The migration has two parts: change your components, then convert the templates stored in Strapi.
1. Change your components
Replace each <DropZone zone="name" /> with a slot field called name:
export const ColumnsConfig = {
fields: {
left: { type: "slot" },
right: { type: "slot" },
},
defaultProps: { left: [], right: [] },
render: ({ left: Left, right: Right }) => (
<div className="grid grid-cols-2">
<Left />
<Right />
</div>
),
}In TypeScript, a slot’s stored value is typed Slot, and what your render function receives is a SlotComponent; both are exported from the library. Slot fields accept allow and disallow lists, and <Left /> accepts className, style, allow and disallow:
import { Slot, SlotComponent } from "@wecre8websites/strapi-page-builder-react";
type ColumnsProps = { left: Slot; right: Slot };
type ColumnsRenderProps = { left: SlotComponent; right: SlotComponent };Your root component no longer needs a <DropZone zone="default-zone" />: render the children it receives instead.
A zone whose name is built from the component id, for example zone={`${id}-dropzone`}, is a dynamic zone. Give it any static slot name (for example items) and map it in step 3.
2. Allow the migration on Strapi
The migration reads and writes your templates through two API-token endpoints that are off by default. Turn them on for the duration of the migration only:
PAGE_BUILDER_SLOT_MIGRATION=trueRestart Strapi. While the setting is on, Strapi logs a warning at startup. The endpoints (GET and PUT /api/page-builder/migration/templates) answer 404 otherwise. Create a Full access API token in Settings > API Tokens to use for the run, and delete it afterwards.
3. Run the migration
From your web project:
# Preview. Nothing is written.
npx strapi-page-builder-migrate-slots --url http://localhost:1337 --token $STRAPI_MIGRATION_TOKEN --dry-run
# Migrate. A backup of every template is written first.
npx strapi-page-builder-migrate-slots --url http://localhost:1337 --token $STRAPI_MIGRATION_TOKEN-
Zones whose name equals a slot field name migrate automatically.
-
--slot Component=fieldmoves the dynamic zone of a component intofield, for example--slot TestimonialGrid=items. Repeat the option for several components. -
--map ./slot-map.mjstakes a module whose default export is Puck’smigrateDynamicZonesForComponent, for components with several dynamic zones or custom shapes:slot-map.mjsexport default { Columns: (props, zones) => ({ ...props, columns: Object.values(zones).map((zone) => ({ column: zone })) }), } -
--backup file.jsonchooses where the backup goes (default: a timestamped file in the current folder). -
Templates that cannot be migrated are listed with the reason and left untouched; a real run then exits with an error. A dynamic zone with no
--slotrule is reported with the exact option to add. -
It is safe to run again: templates without DropZones are skipped.
The command does not need your block configuration; it only needs the slot field names to match the zone names (or your --slot / --map rules).
4. Finish
- Remove
PAGE_BUILDER_SLOT_MIGRATIONfrom Strapi’s environment and restart, then delete the API token. - Open a few templates in the editor and check them. The backup file holds every template’s original
json, so you can restore any template from it; take a database backup before you start as well.
Notes
- Root-level DropZones (
default-zone) store their content in the template’scontentand are not migrated; usechildrenin your root component if you want to drop DropZone entirely. - Localized templates are migrated one by one, per locale.