Tutorial

Black Friday 2026: keeping your online store up under load

Deployment13 min read8 steps

A store that goes down during Black Friday loses sales that no follow-up email wins back, at the moment visitors are most numerous. A server cannot be guessed: it is measured on a copy, with free tools, by reading the peak and not the average. This article gives a four-week calendar, a repeatable load test with k6, the cache and database settings to check, and a fallback plan to write before the peak. No capacity is promised: your own measurement gives your store's limit.

Contents· The peak is a date, and so is the preparation1/14
  1. 01The peak is a date, and so is the preparation
  2. 02What takes a store down during the peak
  3. 03Freeze changes: four weeks, one cut-off date
  4. 04Preparation calendar to replay every year
  5. 05Measure on a copy with k6 and ab
  6. 06Reading the result: the peak, not the average
  7. 07Symptoms during the test and leads to follow
  8. 08Cache: what is served fast, what must never be
  9. 09Database and object cache
  10. 10Only load what belongs to you
  11. 11Sizing: a hypothesis to validate by measurement
  12. 12If you do not run this test yourself
  13. 13The fallback plan, one line per decision
  14. 14After the peak: keep the measurement for next year

The peak is a date, and so is the preparation

Black Friday falls the day after Thanksgiving, which US federal law sets on the fourth Thursday of November. In 2026 that gives Thursday 26 November for Thanksgiving, Friday 27 November for Black Friday and Monday 30 November for Cyber Monday. These dates are calculated from that rule: cross-check them with your market's retail calendar, which may start or extend its own promotions.

Four weeks remain at the date of this article. That is enough to freeze, measure and fix, not enough to rebuild everything. The goal is therefore not the biggest possible server, but to learn your server's limit before traffic finds it for you, then to decide in advance what you do if it is reached.

What takes a store down during the peak

  • A cache that only serves anonymous visitors — as soon as a cart or session cookie is present, the page is rebuilt by PHP and the database on every request.
  • SQL queries that are tolerable at low traffic — a slow query bothers nobody with five visitors. With two hundred at once, it holds connections and makes every following request wait.
  • Too many PHP processes for the available memory — each process uses RAM.
  • A last-minute change — an extension, a theme or a badly configured promo code pushed the day before. It is the most avoidable cause, and the freeze removes it.
  • A third-party service called on every page view — a shipping, review or loyalty module queried synchronously. If it slows down, the store slows with it, though your server is not at fault.
  • No written instructions — nobody knows who decides to switch a feature off, at what threshold, or who informs the client. People improvise during the outage, which lengthens the outage.

Freeze changes: four weeks, one cut-off date

The freeze is the least costly and most effective measure: as long as code and configuration do not move, what you measured stays true. Pick a cut-off date, for example Friday 20 November, one week before the peak. After it, no CMS update, no new extension, no theme change. Only critical bug fixes get through, tested on the copy and then logged.

The freeze does not cover automatic updates: turn them off for the period. The table below can be replayed every year by shifting the dates.

Take a full backup just before the freeze (files, database, server configuration), then restore it once on the copy and time the operation: that duration is an input to the fallback plan. The difference between a snapshot and a backup is explained in VPS snapshot or backup.

Preparation calendar to replay every year

Scroll the table

PeriodWhat gets doneExpected evidence
By 6 NovemberInventory: CMS version, extensions, third-party services, scheduled tasks, hosting planA dated table, with one person responsible per line
9 to 13 NovemberCopy of the store and a baseline load testResult kept with the exact command and scenario
16 to 19 NovemberCache, database and PHP settings, then a new testSame scenario, same parameters, results compared
Friday 20 NovemberChange freeze, full backupRestore tested, not just the backup taken
21 to 26 NovemberCritical fixes only, after a trial on the copyChange log kept up to date
27 to 30 NovemberPeak monitoring, fallback plan ready to useAlerts active and an on-call person named

Measure on a copy with k6 and ab

  1. Prepare a copy of the store

    Never test the live store: a load test can bring it down, pollute your statistics and create fake orders. Restore a backup onto a test VPS or hosting account of the same kind as production, with the same PHP version and the same database. Anonymise customers, turn off outgoing email and put payment modules in test mode.

  2. Write the scenario before choosing the tool

    List a buyer's journey: home page, category page, product page, add to cart, cart page, then the start of checkout. Decide the weight of each step, for example many product pages and few payments. A scenario limited to the home page measures the cache, not the store.

  3. Install k6

    k6 is Grafana's open-source load-testing tool, a single binary. Follow the installation steps in the official k6 documentation on the machine that generates the load, never on the server under test, then check with k6 version.

  4. Write the script around a gradual ramp

    In a file named charge.js, import http from k6/http and check from k6. Declare a scenario with executor: 'ramping-arrival-rate' (k6 documentation): it sets a number of iterations per second regardless of how fast the site answers, which resembles visitors arriving better than a fixed number of virtual users. Fill in startRate, timeUnit, preAllocatedVUs, maxVUs and stages that climb in steps. In the default function, chain http.get on the product page then http.post on add to cart, with a check on status 200.

  5. Set thresholds that fail the test

    Add thresholds to the options: http_req_failed: ['rate<0.01'] and http_req_duration: ['p(95)<800']. The values are yours, set according to what your customers tolerate, not copied from a figure. If a threshold is not met, k6 exits with a non-zero code, which makes the test replayable in an automatic routine. Note that check calls do not have that effect: only thresholds fail the test.

  6. Run the test and watch the server at the same time

    Run k6 run -e BASE_URL=https://copy.your-domain.com charge.js. In an SSH session on the server under test, leave top or htop running and watch free -m for memory and swap. Note at which step of the ramp response times take off and which resource saturates first: processor, memory, database connections or disk.

  7. Complete with a quick ab test

    ApacheBench checks one specific page in a single line: ab -n 500 -c 20 -k https://copy.your-domain.com/product/example/. The -n option sets the total number of requests, -c the number of simultaneous requests and -k enables persistent connections. Apache's documentation states that the tool does not implement HTTP/1.x in full: keep it for before-and-after comparisons around a setting, not for measuring capacity.

  8. Replay the same test after every change

    Change one thing at a time: cache, number of PHP processes, a database index. Rerun exactly the same command and store the results in a dated file.

Reading the result: the peak, not the average

An average response time hides what the unlucky buyer experiences. Read the 95th percentile, or the 99th for the slowest cases, and the error rate. A store whose average stays fine but where one buyer in twenty waits several seconds loses carts without the average showing it.

Look at the shape of the curve too. A stable time followed by a sudden collapse signals a hard limit, such as a maximum number of database connections or PHP processes. This test does not tell you how many real visitors you will get: it tells you at what arrival rate your copy, under the test conditions, starts to degrade.

No numerical result is published here, on purpose: a figure measured on a test machine says nothing about yours, and the script above was only run against a dummy target to check its syntax, which proves no capacity. The only measurement that counts is the one you take on your own copy.

Symptoms during the test and leads to follow

Scroll the table

What you observeLikely causeWhat to measure
Response time rising with load, processor at its maximumToo many pages built by PHP instead of served from cacheShare of pages served from cache for anonymous visitors
Memory full, then swap in useToo many PHP processes for the available RAMMemory per PHP process and number of processes allowed
502 or 504 errors in burstsAll PHP processes busy, or a saturated queuePHP pool setting and duration of the slowest requests
Calm processor but high response timeWaiting on the database or a third-party serviceSlow query log, duration of external calls
"Too many connections" errorDatabase connection limit reachedValue of `max_connections` and connections actually used
Fast product pages but slow cartThe cart bypasses the cache, as it should, and weighs on the databaseQueries triggered by add to cart

Cache: what is served fast, what must never be

The WooCommerce documentation is clear: the cart, checkout and account pages must stay dynamic, because they show information specific to the customer. Exclude them from every cache, at plugin, server and delivery-network level, and check the session and cart cookies your WooCommerce version uses. A cart page cached by mistake shows another buyer's cart, which is worse than an outage.

For the rest, list what can be served as is: home page, categories, product pages for visitors without cookies. The detail of paths to exclude at the delivery-network level is covered in our guide to Cloudflare and caching for a client site. On PrestaShop, the developer documentation recommends enabling the Smarty cache on the Performance page, and not enabling the Cache section when MySQL or MariaDB runs on the same machine. Check these settings in your version's back office, then replay the test after each change.

Database and object cache

Turn on MariaDB's slow query log before the test: SET GLOBAL slow_query_log=1; then SET GLOBAL long_query_time=1; for a one-second threshold, a value you should adjust. These runtime settings disappear on restart; to keep them, put them in the configuration. From MariaDB 10.11, the variables are renamed with the log_slow_ prefix, so check the name used by your version.

An object cache such as Redis relieves the database by keeping repeated results in memory. Give it a limit with maxmemory and choose the eviction policy with maxmemory-policy: The Redis documentation says allkeys-lru is a good default when some keys are read far more often than the rest, while noeviction returns an error when memory is full. Watch keyspace_hits and keyspace_misses in INFO stats during the test: a low hit rate signals a cache that is not helping.

Only load what belongs to you

Point the test at your copy, never at the payment gateway, a shipping service or a third-party API: the tool would overload them and could get your account blocked. If your scenario must go through payment, use the provider's test mode, with their agreement.

Sizing: a hypothesis to validate by measurement

If the test shows the copy saturates too early, there are two routes: fix the software, or change plan. If the machine remains the limiting factor, raise memory or cores in steps and replay the same test after each step, until the curve holds with a margin you judge sufficient.

A resource recommendation read on a website, this one included, remains a hypothesis: only your measurement on your store counts. The method for reading consumption is detailed in sizing a VPS for a client's site. When one machine is no longer enough, HAProxy on a VPS spreads the load, at the price of a more complex architecture.

If you do not run this test yourself

Many merchants hand the store to an agency or a host. The test is still needed: you have to ask for it. Require three things in writing before the freeze date: the dated result of a load test on a copy, with the scenario and the 95th percentile response time read at the peak; the list of planned changes and the agreed freeze date; a signed fallback plan that names the person allowed to switch features off or restore the backup. A report that only quotes the average, or an 'everything is ready' with no result, does not answer the request.

Also decide with them who makes the call on the day: the fallback costs features, therefore sales, and that decision belongs to the business, not only to the technical provider.

The fallback plan, one line per decision

  • Who decides — a named person, with a deputy, authorised to trigger the fallback without consulting a committee.
  • At what threshold — for example an error rate or response time you defined during the tests, read by monitoring and not by eye.
  • Load-shedding action — switch off non-essential features: product recommendations, reviews, predictive search, heavy extensions tested one by one during the trial.
  • Second action — enable a clear queue or maintenance page with the expected return time, rather than a raw error.
  • Last resort — restore the pre-freeze backup, with the restore time you measured and the agreement of the person who decides.
  • Who informs — the client, the marketing team pushing the campaign and your host, with a message already written.

After the peak: keep the measurement for next year

Keep the script, the command, the results and the change log in a dated folder. Next year you will replay the same test on the new version of the store, and the comparison will show whether extensions added during the year made the journey heavier.

To follow store availability during the period, see the client site availability report.

A sales peak deserves a server whose limit you know

Hosting and VPS in the same place as your domain, backups depending on the plan, migration from your current host. Your store stays yours. Plans from 199 DH/year for hosting and 99 DH/month for a VPS.

Need help?

Browse our help center and FAQ, or reach our team — callback, WhatsApp or email. Support in French, English and Arabic.

Message us on WhatsAppopens in a new tab