group.experiment()

Selects and executes a single variant from a set of options. The selection is memoized as a durable step, so the same variant runs on retries and replays.


group.experiment(id, options): Promise

  • Name
    id
    Type
    string
    Required
    required
    Description

    A unique identifier for the experiment. Used in logs and to memoize the variant selection across retries and replays.

  • Name
    options
    Type
    object
    Required
    required
    Description

    Configuration for the experiment:

    Properties
    • Name
      variants
      Type
      Record<string, () => unknown>
      Required
      required
      Description

      A map of variant names to callbacks. Each callback should contain one or more step.* calls. Only the selected variant's callback is executed.

    • Name
      select
      Type
      ExperimentSelectFn
      Required
      required
      Description

      A selection strategy that determines which variant to run. Use one of the built-in strategies: experiment.fixed(), experiment.weighted(), experiment.bucket(), or experiment.custom().

Basic usage
const { result } = await group.experiment("my-experiment", {
  variants: {
    a: () => step.run("variant-a", () => doA()),
    b: () => step.run("variant-b", () => doB()),
  },
  select: experiment.weighted({ a: 50, b: 50 }),
});
Variant name and reference
const { result, variant, experimentRef } = await group.experiment("my-experiment", {
  variants: {
    a: () => step.run("variant-a", () => doA()),
    b: () => step.run("variant-b", () => doB()),
  },
  select: experiment.fixed("a"),
});
// variant === "a"

Return value

Resolves to an object with the selected variant's output and a reference for scoring:

  • Name
    result
    Type
    unknown
    Required
    optional
    Description

    The value returned by the selected variant's callback.

  • Name
    variant
    Type
    string
    Required
    optional
    Description

    The name of the variant that was selected and run.

  • Name
    experimentRef
    Type
    ExperimentRef
    Required
    optional
    Description

    A stable handle to the selected variant ({ experimentName, variant }). Pass it to inngest.score.experiment() or defer() to attach a score to this experiment.

Every variant callback must invoke at least one step.* tool (e.g., step.run()). Code that runs outside of a step is not memoized and will re-execute on every replay. The SDK throws a NonRetriableError if a variant completes without calling any step tools.

Selection strategies

Import the experiment object from the inngest package:

import { experiment } from "inngest";

experiment.fixed(variantName)

Always selects the specified variant. Useful for manual overrides or testing a specific code path.

select: experiment.fixed("control")

experiment.weighted(weights)

Weighted random selection, seeded with the current Inngest run ID. Deterministic: the same run always gets the same variant, even across retries.

select: experiment.weighted({ control: 80, treatment: 20 })

Weights are relative, not percentages. { a: 1, b: 3 } gives a a 25% chance and b a 75% chance.

experiment.bucket(value, options?)

Consistent hashing. The same input value always maps to the same variant. Useful for user-level bucketing where a user should see the same variant across multiple runs.

select: experiment.bucket(event.data.userId, {
  weights: { control: 70, treatment: 30 },
})

When weights are omitted, equal weights are derived from the variant names:

select: experiment.bucket(event.data.userId)

If value is null or undefined, the SDK hashes an empty string and attaches a warning to the step metadata.

experiment.custom(fn)

Provide your own selection logic. The function can be synchronous or asynchronous. The result is memoized durably, so it only runs once per function run.

select: experiment.custom(async () => {
  const flag = await getFeatureFlag("checkout-variant");
  return flag; // Must return a key from `variants`
})

The custom function must return a string that matches one of the keys in variants. If it returns an unknown variant name, the SDK throws a NonRetriableError.

Observability

The selection step carries experiment metadata: the experiment name, selected variant, strategy, available variants, and weights. This metadata is visible in the Inngest dashboard.

Steps executed within the selected variant's callback also carry experiment context, so you can trace which experiment and variant produced each step in a run.