<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: The Nguyen</title>
    <description>The latest articles on DEV Community by The Nguyen (@the_nguyen).</description>
    <link>https://dev.to/the_nguyen</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4077091%2Fc3bc5daf-e1e3-4f81-8d88-ebe05b557974.jpg</url>
      <title>DEV Community: The Nguyen</title>
      <link>https://dev.to/the_nguyen</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/the_nguyen"/>
    <language>en</language>
    <item>
      <title>EverShop 2.2.1: our biggest release since 2.0 — page builder, metafields, and React 19</title>
      <dc:creator>The Nguyen</dc:creator>
      <pubDate>Fri, 14 Aug 2026 06:16:27 +0000</pubDate>
      <link>https://dev.to/the_nguyen/evershop-221-our-biggest-release-since-20-page-builder-metafields-and-react-19-1g1o</link>
      <guid>https://dev.to/the_nguyen/evershop-221-our-biggest-release-since-20-page-builder-metafields-and-react-19-1g1o</guid>
      <description>&lt;p&gt;We just shipped &lt;strong&gt;EverShop 2.2.1&lt;/strong&gt; — 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.&lt;/p&gt;

&lt;p&gt;If you're upgrading an existing store, one number to keep in mind: &lt;strong&gt;31 database migrations across 10 modules run automatically on first start.&lt;/strong&gt; 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.&lt;/p&gt;

&lt;p&gt;Here's a tour of what's new, and what you'll need to change if you maintain themes or extensions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visual Page Builder
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4psqfbk3lc6hiadjskmo.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4psqfbk3lc6hiadjskmo.jpg" alt="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." width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The headline feature is a drag-and-drop editor for the storefront, living at &lt;code&gt;/admin/page-builder&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;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 &lt;strong&gt;schedule a rollout&lt;/strong&gt; for later — and those rollout plans stay editable and cancelable right up until they run.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Blog module
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fphb980tzx2apamgr09gm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fphb980tzx2apamgr09gm.jpg" alt="Creating a blog category in the EverShop admin, with the comment policy set to Moderated — hold for review, alongside the Open and Closed options." width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;EverShop now has a first-class &lt;code&gt;blog&lt;/code&gt; 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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Metafields: typed custom fields on every entity
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn1kvep4azp6fijmuzl6y.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn1kvep4azp6fijmuzl6y.jpg" alt="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." width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the feature extension authors will get the most mileage from. You can now define &lt;strong&gt;typed metafields&lt;/strong&gt; — 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.&lt;/p&gt;

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

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Metafield&lt;/span&gt; &lt;span class="na"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"care_instructions"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Rebuilt shipping and fulfillment
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F55uykbeivdtkiqodrehh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F55uykbeivdtkiqodrehh.jpg" alt="The Shipping Providers settings page showing the built-in Core Shipping provider with its methods, each row listing status and the zones it serves." width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The old flat "zone → method → rate" model has been replaced with a &lt;strong&gt;provider abstraction&lt;/strong&gt;. 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.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F31y2u8reze6klcz47am4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F31y2u8reze6klcz47am4.jpg" alt="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." width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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 &lt;code&gt;cart_item&lt;/code&gt; → &lt;code&gt;order_item&lt;/code&gt; → carrier requests. Your existing zones, methods, and rates are migrated into the Core provider automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloud storage, built in
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5jpzw3ylmzin4vzf90f2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5jpzw3ylmzin4vzf90f2.jpg" alt="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." width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Product recommendations
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0seyl5kmry49rfidwbjo.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0seyl5kmry49rfidwbjo.jpg" alt="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." width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Four new shelves shipped together, all with page-builder widgets:&lt;/p&gt;

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

&lt;h2&gt;
  
  
  The React 19 upgrade (and what it means for your code)
&lt;/h2&gt;

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

&lt;p&gt;&lt;code&gt;defaultProps&lt;/code&gt; on function components is gone — use ES default parameters instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Price&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;Price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defaultProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// After&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Price&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One more breaking change worth flagging: &lt;strong&gt;&lt;code&gt;react-toastify&lt;/code&gt; was removed in favor of &lt;code&gt;sonner&lt;/code&gt;.&lt;/strong&gt; The migration is close to drop-in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;toast&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ToastContainer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-toastify&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// After&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;toast&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sonner&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// and replace &amp;lt;ToastContainer/&amp;gt; with sonner's &amp;lt;Toaster/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security and performance
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;On performance, we load-tested a &lt;strong&gt;500k-product catalog&lt;/strong&gt; and fixed the things that fell over: indexed &lt;code&gt;url_rewrite.request_path&lt;/code&gt;, 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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Upgrading
&lt;/h2&gt;

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




&lt;p&gt;Full release notes: &lt;a href="https://evershop.io/blog/release-notes-v2-2-1" rel="noopener noreferrer"&gt;https://evershop.io/blog/release-notes-v2-2-1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Changelog: &lt;a href="https://github.com/evershopcommerce/evershop/releases/tag/v2.2.1" rel="noopener noreferrer"&gt;https://github.com/evershopcommerce/evershop/releases/tag/v2.2.1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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. ⭐&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>ecommerce</category>
      <category>typescript</category>
      <category>react</category>
    </item>
  </channel>
</rss>
