How it works
The explanation, with examples you can run.
Rolling out with a flag
A percentage rollout must give the same answer for the same user every time, or a user would flip between old and new on every page. Hashing the user id into a bucket does that:
Press Run to see what your code prints, in order.
Runs in this browser, in an isolated frame with no access to this page. console.log, info, warn and error are shown; code runs as a classic script, so use an async function for await.
Including the flag name in the hash keeps the same users from being first in line for every experiment. The allow-list lets staff and test accounts see the feature before anyone else. Raise percent in steps while watching error rates. To roll back, set it to 0; there is no redeploy.
Testing flags before they reach production: run the suite with the configuration that will be live (new flag on) and with the fallback (new flag off). Then remove the flag once the rollout is done, because every flag left in the code doubles the paths someone has to reason about.
Canary releases
A canary deploys the new version next to the old one and routes a small slice of traffic to it: a random 1%, staff first, or a single region. Compare the canary with the baseline on the same signals you load test with (error rate, p95 and p99 latency, saturation) and on business signals such as checkouts per minute. Automate the decision: tools like Argo Rollouts and Flagger, or your cloud's deployment service, can step traffic up and roll back when a metric crosses a limit.
Synthetic checks
A synthetic check is a short script that runs a critical journey against production every few minutes, from outside your network, and pages someone when it fails. A Playwright test works well:
import { expect, test } from "@playwright/test" test("search to product page works in production", async ({ page }) => { await page.goto("https://shop.example.com") await page.getByRole("searchbox", { name: "Search" }).fill("mug") await page.getByRole("searchbox", { name: "Search" }).press("Enter") await page.getByRole("link", { name: /mug/i }).first().click() await expect(page.getByRole("button", { name: "Add to cart" })).toBeEnabled()})Doing it safely
- Use dedicated test accounts that are marked as synthetic, so their traffic is left out of analytics, emails and billing.
- Never move real money. Use the payment provider's test mode for those accounts, or stop the journey before payment.
- Make checks read-only where you can. Where they write, clean up, and make it obvious which data is test data.
- Keep a kill switch for every risky change, and practise using it.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.