Shipeasy

Sticky bucketing

Keep a user's variant assignment stable across allocation changes — a session cookie in the browser, a pluggable store on the server.

Production readyOn this page · 4 min readUpdated · June 19, 2026Works with · @shipeasy/sdk · server + client

Bucketing is already deterministic — the same user hashes to the same group every time. But if you change an experiment's allocation or weights mid-flight, the hash boundaries move, and some users can flip groups. Sticky bucketing locks a user's first assignment so it survives weight changes.

Configured on the Engine

Sticky bucketing is an Engine construction option — pass it to configure(...) (which builds the shared engine for the bound-client flow) or to a directly-constructed Engine. Everyday flag reads still use new Client(user).

Browser — on by default

The browser engine persists the assignment map and replays it on every evaluation. It's enabled by default; pass stickyBucketing: false to opt out:

import { configure } from "@shipeasy/sdk/client";

configure({
  clientKey: process.env.NEXT_PUBLIC_SHIPEASY_CLIENT_KEY!,
  // stickyBucketing: true is the default
});

The sticky map rides in a first-party cookie and is sent with the evaluation request, so a returning visitor keeps their variant even after you reshuffle the experiment.

Server — a pluggable store

On the server you provide a StickyBucketStore so assignments persist across requests and processes. In-memory works for a single long-lived process; back it with Redis (or your own store) for a fleet:

import { configure, type StickyBucketStore } from "@shipeasy/sdk/server";

const store: StickyBucketStore = {
  get: async (key) => redis.get(key),
  set: async (key, value) => void redis.set(key, value),
};

configure({
  apiKey: process.env.SHIPEASY_SERVER_KEY!,
  stickyStore: store,
});
Sticky vs deterministic

Without a sticky store, assignment is still deterministic — it just tracks the current allocation. The sticky store is what protects in-flight users when you deliberately change weights. If you never change allocation mid-experiment, deterministic bucketing alone is enough.

When to use it

  • You ramp an experiment's allocation (e.g. 10% → 50%) while it's running.
  • You change variant weights after exposure has started.
  • Long-running or multi-instance servers where a user hits different processes.
Was this page helpful?
✎ Edit this page

On this page