Shipeasy

Java

The Shipeasy Java server SDK — configure once, bind a Client per request, servlet anon filter, local evaluation, configs, kill switches, and metric tracking.

Production readyOn this page · 4 min readUpdated · August 9, 2026Works with · Java 17+ · Maven · Gradle
Generated from the Java SDK repo's own /docs/ — the same Markdown shipeasy docs get --sdk java overview returns, served raw at https://shipeasy-ai.github.io/sdk-java/pages/overview.md. Edit it in the SDK repo, not here.

shipeasy (ai.shipeasy:shipeasy) is the server-side Java SDK for Shipeasy — feature flags, dynamic configs, kill switches, A/B experiments, metric tracking, and see() error reporting. Rules are evaluated locally against a cached blob fetched from the edge, so there is no network call per evaluation.

Install

<dependency>
  <groupId>ai.shipeasy</groupId>
  <artifactId>shipeasy</artifactId>
  <version>0.20.1</version>
</dependency>

Full wiring — frameworks, options, env vars — is in Installation.

The mental model: configure() once, new Client(user) per request

You learn exactly two things. First, configure the SDK once at startup. This authenticates with your server key and kicks off the initial rules fetch:

import ai.shipeasy.Shipeasy;
import ai.shipeasy.Client;
import java.util.Map;

// Once, at startup (main(), an @PostConstruct bean, a static initializer):
Shipeasy.configure(System.getenv("SHIPEASY_SERVER_KEY"));

// Per user / per request, anywhere downstream. The user is bound at
// construction, so every read takes NO user argument:
Client c = new Client(Map.of("user_id", "u_123", "plan", "pro"));

boolean enabled = c.getFlag("new_checkout");
Object  cfg     = c.getConfig("billing_copy");
boolean killed  = c.getKillswitch("panic_button");

Assignment cta = c.universe("hero_cta").assign(); // <=1 experiment; auto-logs exposure
c.track("purchase", Map.of("amount", 49));  // record the conversion

new Client(user) is cheap — it owns no HTTP connection, blob cache, or poll timer. It runs the configured attributes transform on your user object once, binds the resulting attribute map, and forwards every call to the single process-wide engine that configure() built. Construct one per request and throw it away.

Constructing a Client before configure() has run throws IllegalStateException.

Pages

  • Installation — Maven/Gradle coordinates, per-framework wiring, and the canonical configure() setup with its options table.
  • Configurationconfigure(), the attributes transform, one-shot vs background poll, env vars.
  • FlagsgetFlag, defaults, getFlagDetail.
  • ConfigsgetConfig, typed values, defaults.
  • Kill switchesgetKillswitch and named per-key switches.
  • Error reportingsee() structured error reporting.
  • TestingconfigureForTesting() / configureForOffline() + the override statics.
  • OpenFeature — the ShipeasyProvider server provider.
  • Advanced — auto-exposure, private attributes, sticky bucketing, anon-id middleware, change listeners, SSR.

The blocks below are the SDK repo's own snippets — the same ones shipeasy docs get --sdk java release/flags returns, with a worked example baked in.

Feature flags

Read new_checkout off a user-bound Client. Assumes configure() ran at startup — see Installation.

import ai.shipeasy.Client;
import java.util.Map;

// construct once per callsite (cheap; binds the user)
Client client = new Client(Map.of("user_id", "u_123"));

boolean enabled = client.getFlag("new_checkout"); // gate name
// optional default overload — returned ONLY when unresolvable (engine not
// ready / flag absent), never when the flag legitimately evaluates to false:
// boolean enabled = client.getFlag("new_checkout", true /* default */);

Dynamic configs

Read the dynamic config billing_copy (with a fallback when absent). Assumes configure() ran at startup — see Installation.

import ai.shipeasy.Client;
import java.util.Map;

// construct once per callsite (cheap; binds the user)
Client client = new Client(Map.of("user_id", "u_123"));

Object cfg = client.getConfig(
    "billing_copy",          // config name
    Map.of("title", "Default")); // fallback returned when the config is absent
// one-arg overload returns null when absent: client.getConfig("billing_copy")

Kill switches

Check whether the kill switch payments is killed. Assumes configure() ran at startup — see Installation.

import ai.shipeasy.Client;
import java.util.Map;

// construct once per callsite (cheap; binds the user)
Client client = new Client(Map.of("user_id", "u_123"));

boolean killed = client.getKillswitch("payments"); // killswitch name
// optional second arg reads one named per-key switch (null = whole killswitch):
// boolean off = client.getKillswitch("payments", "eu_region" /* switchKey */);

if (killed) {
    // disable the protected path
}

Track a conversion

Track a metric/conversion event from the bound Client. Metrics in the dashboard are computed from these events. Assumes Shipeasy.configure(...) ran at startup — see Installation.

Track an event

import ai.shipeasy.Client;
import java.util.Map;

Client client = new Client(Map.of("user_id", "u_123")); // construct once per callsite

// track(eventName, props)
//   eventName — the event your metric is built on (required)
//   props     — optional payload; numeric/string fields you can sum/filter on in
//               a metric (private attributes are stripped before egress)
client.track("checkout_started", Map.of("amount", 49, "currency", "usd"));

Fire-and-forget (never blocks your response) and a no-op under Shipeasy.configureForTesting / configureForOffline. The unit is the bound user (user_id, else anonymous_id); with no unit the call is a no-op.

Track without properties

Client client = new Client(Map.of("user_id", "u_123")); // construct once per callsite

client.track("checkout_started", Map.of()); // props are optional (pass an empty map)
Was this page helpful?
Updated July 26, 2026

On this page