DEV Community

The Nguyen
The Nguyen

Posted on Edited on Originally published at evershop.io

EverShop 2.2.1: our biggest release since 2.0 — page builder, metafields, and React 19

We just shipped EverShop 2.2.1 — the largest release since 2.0. It folds in the React 19 work that had been sitting in an unpublished 2.1.3 branch and stacks four months of development on top of it: a visual page builder, a blog module, entity custom fields, a multi-language storefront with a translated admin, a rebuilt shipping and fulfillment stack, built-in cloud storage, product recommendations, and a serious security and performance pass.

If you're upgrading an existing store, one number to keep in mind: 31 database migrations across 10 modules run automatically on first start. Several of them transform data and drop legacy tables, so back up your database first and read the breaking-changes section below. This release also patches several security vulnerabilities, so upgrading promptly is the right move.

Here's a tour of what's new, and what you'll need to change if you maintain themes or extensions.

Visual Page Builder

The EverShop page builder: a widget palette on the left with Content and Commerce categories, the live storefront canvas in the middle, and device preview, undo/redo and Publish controls in the top bar.

The headline feature is a drag-and-drop editor for the storefront, living at /admin/page-builder.

You edit any storefront route — plus CMS pages and landing pages — by composing widgets into your theme's areas, with layout-aware drag/drop. The workflow is draft-based: changes accumulate in a per-admin, per-theme draft changeset with per-widget auto-save. When you're ready you can publish immediately, or schedule a rollout for later — and those rollout plans stay editable and cancelable right up until they run.

There's inline editing on the canvas (text and images edited in place, with an image picker that understands cloud storage), a layers panel, a "Globals" view for site-wide areas, and per-widget styling controls. Link fields resolve products, categories, CMS pages, and blog posts through a single unified link resolver.

Because it's touching public-facing content, the whole editor pipeline went through a dedicated security-hardening pass and ships with an end-to-end test suite.

Blog module

Creating a blog category in the EverShop admin, with the comment policy set to Moderated — hold for review, alongside the Open and Closed options.

EverShop now has a first-class blog core module: posts, categories, and tags, with per-post SEO descriptions, comments, and reactions. Comment moderation is set per category (open, moderated, or closed), so you can run an open comment section on tutorials while locking it on announcements. You get storefront blog pages out of the box plus blog widgets for the page builder.

Metafields: typed custom fields on every entity

Defining a metafield in the EverShop admin: name, description, key and type, with toggles for Allow multiple, Required and Visible to customer, and a collapsible Validation section.

This is the feature extension authors will get the most mileage from. You can now define typed metafields — text, long text, rich text, number, boolean, date, select, JSON/group, and list variants — and attach them to products, categories, collections, customers, orders, blog posts, and the shop itself.

Values are stored per entity in a JSONB meta_data column and validated on write. GraphQL exposure is audience-gated, so you decide whether a field is customer-visible or admin-only.

The part worth calling out for theme developers: a theme can declare its own metafield definitions in theme.json, and they get provisioned automatically at theme activation and on boot. You render values with a new storefront component:

<Metafield entity={product} name="care_instructions" />
Enter fullscreen mode Exit fullscreen mode

Rebuilt shipping and fulfillment

The Shipping Providers settings page showing the built-in Core Shipping provider with its methods, each row listing status and the zones it serves.

The old flat "zone → method → rate" model has been replaced with a provider abstraction. Shipping rates now come from registered providers; the built-in Core provider reproduces the classic setup (flat, percentage, price/weight-based, and API-calculated rates), and extension providers can quote live rates with configurable per-provider timeouts. Zones also became multi-country: a single "EU" zone can cover every member state.

Fulfillment went from one-to-one to multi-shipment: an order can ship in several packages, each shipment carrying its own item assignments, status, tracking, and optionally a purchased label. order.shipment_status becomes an item-based rollup over physical items (digital items excluded).

A shipment card on an order in the EverShop admin, listing the items in that parcel with its own Shipped status, carrier, tracking number, and per-shipment actions to mark delivered, edit tracking or cancel.

There's also a carrier registry — register carriers that create labels, generate tracking URLs, and push status updates back into EverShop — and package management for admin-defined parcel sizes with dimension/weight snapshots that flow from cart_itemorder_item → carrier requests. Your existing zones, methods, and rates are migrated into the Core provider automatically.

Cloud storage, built in

The System Setting page in the EverShop admin, offering local file system, Amazon S3, Azure Blob Storage and Google Cloud Storage as file storage providers.

S3, Azure Blob, and Google Cloud Storage are now part of core (they used to be separate extensions). You pick and configure a provider at runtime from a new System Setting page — no restart — and secrets are masked in the admin. The rewrite also fixed a batch of defects from the old extensions: regional S3 endpoints (plus custom endpoint / path-style for R2 and MinIO), correct Content-Type on upload, listing beyond 1,000 keys, and Azure public-access handling.

Product recommendations

The Recommendations card on a product edit page, with rules set to inherit category or global rules, a manual picks list, and a preview of what shoppers will see.

Four new shelves shipped together, all with page-builder widgets:

  • Related Products — rule-based (same category / collection / attribute values, with price bands, priority ordering, and manual picks), configurable globally, per category, and per product.
  • Frequently Bought Together — driven by co-purchase statistics (association confidence + lift), rebuilt nightly and on demand.
  • Upsell shelf — derived automatically from the related-products rules restricted to pricier products, exposed as Product.upsellProducts.
  • Cart cross-sell — aggregates co-purchase candidates across everything in the cart, excluding what's already in it.

The React 19 upgrade (and what it means for your code)

EverShop moved from React 17 to React 19. Because the framework resolves React through a single hoisted copy (a webpack alias), every extension and theme now runs on React 19 too. If you maintain either, budget time for these:

defaultProps on function components is gone — use ES default parameters instead:

// Before
function Price({ amount }) { /* ... */ }
Price.defaultProps = { amount: 0 };

// After
function Price({ amount = 0 }) { /* ... */ }
Enter fullscreen mode Exit fullscreen mode

One more breaking change worth flagging: react-toastify was removed in favor of sonner. The migration is close to drop-in:

// Before
import { toast, ToastContainer } from 'react-toastify';

// After
import { toast } from 'sonner';
// and replace <ToastContainer/> with sonner's <Toaster/>
Enter fullscreen mode Exit fullscreen mode

Most of the React 19 breaking changes fail silently — no build error, just a blank area or an ignored default at runtime — so it's worth reading the full migration guide before you upgrade a custom theme.

Security and performance

On security, this release fixes an unauthenticated SSRF, an unauthenticated IDOR on customer endpoints, stored XSS, and an account-takeover path via a missing authorization check on the customer update endpoint — plus clearing all high-severity dependency alerts.

On performance, we load-tested a 500k-product catalog and fixed the things that fell over: indexed url_rewrite.request_path, fixed a keyword-search query that was bypassing the GIN index, and removed an O(n^2) id-list pattern that was also hitting Postgres's 65,535-parameter wire limit.

Upgrading

  1. Back up your database — the migrations run on first start, several destructive to legacy tables, with no down-migration.
  2. Update @evershop/evershop, reinstall dependencies, run npm run build. Migrations apply automatically.
  3. Re-upload your logo under Store Setting → Branding (themeConfig.logo is gone).
  4. If your navigation relied on include_in_nav, rebuild it with the menu widgets.
  5. Review your shipping setup under the new provider-based UI — data is migrated, but verify your rates.
  6. For custom themes/extensions: apply the React 19 notes, switch react-toastify to sonner, and update anything that touched the widget table or legacy shipping tables directly.

Full release notes: https://evershop.io/blog/release-notes-v2-2-1

Changelog: https://github.com/evershopcommerce/evershop/releases/tag/v2.2.1

EverShop is open source and MIT-licensed. If you build something on it, or hit a snag upgrading, come find us on GitHub — issues and PRs welcome. ⭐

Top comments (0)