Pick Friday 6 November 2026 and defend it. Black Friday lands on 27 November that year, Cyber Monday on 30 November, and anything you deploy after the first week of the month has no real soak time before traffic arrives. That is the short version of a Shopify Plus BFCM code freeze: three clear weeks between your last structural change and your biggest hour of the year. If you ship a checkout UI extension on 18 November, you are testing it on paying customers.
The freeze is not one switch, though, and treating it as one is how teams end up either shipping dangerous things in week four or sitting on their hands while a competitor fixes a broken offer. Below is the version we run with US Plus merchants: what gets locked when, what stays editable right through the weekend, and what you do at 11pm on Black Friday when the discount is wrong.
Three tiers, not one date
Split everything you might change into three buckets and give each its own cutoff.
Tier 1 — code and anything that redeploys. Theme pushes, checkout UI extensions, Shopify Functions, custom app versions, new app installs, uninstalls, Web Pixels, headless front-end builds. Frozen 6 November. Changing any of these re-registers extensions, invalidates caches, or swaps files under live sessions.
Tier 2 — configuration that touches logic. Shipping rate conditions, tax settings, payment method ordering, discount combination rules, Flow workflows that create orders or tags, inventory location priorities. Frozen 13 November, a week later, because these are reversible in the admin in seconds but can still break order routing.
Tier 3 — values and content. Copy, images, collection sort order, metafield and metaobject values, discount codes created in the admin, email and SMS sends, pricing. Open right through 30 November. This is the bucket you want as fat as possible, which is really the whole design problem.
Every hour you spend in October moving a decision from Tier 1 to Tier 3 buys you flexibility on the weekend. A countdown timer hardcoded in a Liquid section is Tier 1. The same timer reading its end date from a metaobject is Tier 3.
Working backwards from 27 November
- By 10 October: every new app installed. Nothing goes in after this, including app updates you can control.
- By 17 October: checkout UI extensions and Functions built, deployed to a draft checkout profile, and tested end to end with real test orders.
- By 24 October: dress rehearsal. Run the full offer calendar on a duplicate theme and a draft checkout profile. Place orders. Watch them land in your ERP, 3PL and tax engine.
- By 31 October: fixes from the rehearsal shipped. Backup theme duplicated and named with the date. Rollback runbook written.
- 6 November: Tier 1 freeze. Lock the GitHub branch, revoke deploy access for anyone who does not need it, and tell your app vendors in writing that you want no auto-updates.
- 13 November: Tier 2 freeze.
- 23 November: values only. Someone is on call from here.
Shopify tightens its own release schedule around peak. Your app vendors mostly do not, and that is where the surprises come from. Ask each one directly whether they freeze and when.
Checkout extensibility: what is actually left
The migration deadlines are behind us. Shopify retired checkout.liquid for the information, shipping and payment steps in August 2024, and the Thank You and Order Status pages followed in August 2025, along with Shopify Scripts. If you are on Plus in 2026, you are on extensibility whether you planned it or not.
What we still find in October audits is the residue. Half-migrated Script Editor logic where the old script was deleted and the replacement Function only covers the common case. A post-purchase upsell nobody has opened since it was ported. Order Status page tracking that was rebuilt as a Web Pixel but fires on a different event, so your conversion numbers quietly stopped matching your order count. A checkout branding setting applied to one profile and not the other.
Do one pass on this in the first half of October. Open your discount Functions and ask what happens with a combined code and automatic discount, a gift card, a partially out-of-stock cart, and a subscription line item. Those four cases catch most of it.
Testing checkout UI extensions before the traffic shows up
Checkout profiles are the single most useful thing Plus gives you here. Build the BFCM checkout as a separate profile, keep the current one live, and preview the draft with the editor's preview link. Your extension renders in a real checkout against real cart data without a single customer seeing it.
Then place orders. Not one. We work through a grid: guest and logged-in, Shop Pay and Shop Pay Installments, PayPal express, Apple Pay on an actual iPhone, a card with AVS mismatch, a $0 cart after a 100% discount, an order shipping to a state where you have nexus and one where you do not, and a cart that breaches free-shipping threshold then drops back below it when a line is removed. Roughly thirty orders. It takes an afternoon.
The failures we see most are not rendering bugs. They are extensions that call an app backend synchronously and add 600ms to the shipping step, and extensions whose fallback behaviour when that call times out is to show nothing where a shipping-protection opt-in used to be. Test with the network throttled. Test with your own API returning a 500 on purpose.
One more: extensions have target placements that shift when Shopify updates the checkout layout. Re-check your preview the week of the freeze, not just the week you built it.
Shopify Functions: make the discount a value, not a deploy
The question we get every November is whether you can change a discount Function during BFCM. Technically yes. Practically, deploying a new app version mid-weekend means a version bump, extension re-registration and a window where you are not certain which logic a given cart hit. We have done it. It is not fun.
Build it so you never have to. The Function should read its thresholds, tiers, excluded collections and end times from metafields on the discount or from a metaobject. Then "spend $150, get 20% off" becomes two numbers in the admin, changeable at 11pm by someone who cannot write Rust. Everything configurable is Tier 3.
Two things to get right before the freeze. First, discount combination settings: whether your automatic order discount stacks with a code, and what happens when a customer applies both. Decide it, test it, write it down for support. Second, the input query. If your Function needs a product metafield that is empty on 400 SKUs, the fallback path is what runs on those carts, and the fallback path is the one nobody tested.
Your fastest kill switch is deactivating the automatic discount in the admin. That takes about four seconds and does not involve a deploy. If your offer architecture does not have an admin-side off switch for every discount, that is a gap worth closing before November. We build this configurability into most of the custom Functions and private apps we ship for exactly this reason.
Load testing a Shopify Plus checkout, honestly
You cannot load test Shopify's checkout, and you should not try. Hammering it with synthetic traffic violates the terms you agreed to, and the capacity you would be testing is not yours. Shopify handles checkout throughput at a scale no single merchant needs to prove.
What you can and should load test is everything you own that sits downstream. Your app backend, if a checkout extension calls it. Your order webhook consumers. The ERP or 3PL endpoint that receives orders. Your subscription platform. Your custom pixel collector.
Run the arithmetic first. Say you expect 18,000 orders across the weekend and your peak hour carries 8% of them, so 1,440 orders, or 24 a minute. Your order-created webhook posts to an endpoint that takes 4 seconds per order and processes one at a time: 15 a minute. You are falling behind by 9 orders a minute. Over a 3-hour peak that is a backlog of 1,620 orders, and your warehouse starts Saturday blind. Shopify will retry, so you probably will not lose data, but you will lose the morning. Fixing that endpoint in October costs a day. Fixing it on Black Friday costs the weekend.
Separately, check your storefront weight. Every app you added since last BFCM left script behind, and LCP tends to drift up by half a second a year without anyone noticing. Measure in October on a throttled 4G profile, not on your office wifi. SwiftStore handles the monitoring side if you want the score watched daily rather than remembered occasionally, and our speed work covers the parts an app cannot fix on its own.
App installs: the 10 October line
No new apps in November. None. The reason is not that apps are bad, it is that an install can add an app embed to your theme, inject script tags, register a checkout extension, and request scopes, all in one click, and you will not see the full effect until traffic hits.
If something is genuinely missing and you are inside the window, three rules. Install on a duplicate of the live theme first and compare PageSpeed before and after. Check the app's checkout and Order Status surfaces in a draft profile. And confirm the vendor's own freeze policy, because an app that auto-updates on 22 November has just deployed code to your store through a door you thought was locked.
Uninstalling in November is worse than installing. Removals can leave orphaned snippets and broken references in a theme that was rendering fine ten minutes earlier.
The rollback plan you write in October
Before the freeze, duplicate your live theme and name it with the date, something like LIVE-BACKUP-2026-11-06. Reverting is then one publish away and takes a few seconds.
The trap: publishing an older theme also reverts everything stored in that theme's settings, which includes app embed toggles, section content and any merchandising edits made in the customiser since the backup was taken. If your team has been editing homepage sections on the live theme through November, a rollback throws that away too. So either keep taking fresh duplicates as content changes land, or keep content in metaobjects where the theme version does not matter.
The rest of the runbook, one page, pinned where on-call can find it:
- Checkout UI extension misbehaving: deactivate it in the checkout editor, or publish the previous checkout profile. No deploy needed.
- Discount wrong: deactivate the automatic discount in the admin. Then fix the metafield value and reactivate.
- Theme broken: publish the dated backup.
- App causing trouble: disable its app embed in theme settings rather than uninstalling.
- Downstream integration backing up: pause the workflow, do not pause the orders.
Name one person per item with access to do it, and confirm that person's 2FA works on their phone on a Thursday evening in November, when they are not at a desk.
Two things US merchants break at the worst moment
Tax configuration. If you are adding states to Shopify Tax or Avalara because nexus thresholds tripped during Q3, do it in October. A registration change mid-weekend can shift what gets collected on carts already in flight, and the reconciliation afterwards is miserable.
Accessibility. Late-November additions are almost always a banner, a popup, a countdown or a spin-to-win, and those are the exact components that trap keyboard focus, hide close buttons from screen readers and fail contrast on sale pricing. Demand letters follow holiday traffic. If a modal goes live in November, tab through it with the mouse untouched before it ships.
Questions that come up in the last week of October
Is 6 November too conservative? For a store doing a few hundred orders a weekend, yes, you can push to around 13 November. For a Plus store with custom Functions, a headless front end or an ERP in the loop, 6 November is already tight. The thing you are protecting is soak time across real traffic patterns, and the three weeks before BFCM carry enough volume to expose most faults.
Can we ship copy and price changes during the freeze? Yes, that is the point of Tier 3. Prices, images, collection order, metafield values, discount codes, email sends. Anything that does not redeploy.
What if we find a genuine bug on 24 November? Fix it, but change one thing, test it on a duplicate theme or draft profile first, and have the rollback ready before you publish. Hotfixes during a freeze are allowed. Features are not.
Do we still have checkout extensibility work outstanding? The platform deadlines have passed, so the honest answer is that any remaining work is cleanup rather than migration: Scripts logic that was ported incompletely, post-purchase pages nobody has opened in a year, analytics that moved to Web Pixels and quietly changed what it counts. An hour of review in early October is usually enough to find out.
How do we rehearse the full offer calendar? Duplicate theme plus draft checkout profile, with the dates on your test discounts set to now rather than 27 November. Run each day of the calendar in sequence, including the handover moments where one offer ends and the next begins. Those transitions break more often than the offers themselves.
If you want a second pair of eyes before you lock the branch, we do a pre-peak review that covers checkout extensions, Function fallbacks, theme weight and the downstream integrations most likely to queue up. Book it for October, not November, and have your Plus build team in the room. Any later and all we can tell you is what to turn off.


