Quickstart
Wire a killswitch around a risky subsystem in five minutes — so the 3am on-call has one switch to flip.
A killswitch is the lever you pull when something is on fire. This walkthrough takes you from zero to a wired-in killswitch around an outbound-email path. By the end, on-call can disable email sending in under five seconds without touching code.
The 5-minute path
create · wire · test the flipCreate the killswitch (default OFF)
Guard the dangerous path
Flip it, watch it stop
Subscribe a connector (Slack / GitHub / etc.)
1. Create the killswitch
shipeasy killswitch create transactional.emails-enabled \
--description "Disables outbound transactional email" \
--value falseKillswitch names must be folder.name. --value false means "killed = false" by
default — the call to flags.ks(...) returns false, your code reads "not
killed, proceed". Flip it to true to kill the path in production. Until the
SDK has fetched the first blob, reads return false (the safer default for
"is this killed?") — so a cold cache won't accidentally kill your emails.
2. Wire it into the code path
Wrap the dangerous call with the killswitch read — it returns true when the
killswitch is flipped, false (or the SDK default) otherwise:
import { flags } from "@shipeasy/sdk/server";
export async function sendOrderEmail(order: Order) {
if (flags.ks("transactional.emails-enabled")) {
logger.warn("emails paused via killswitch", { orderId: order.id });
return;
}
await mailer.send(order);
}Killswitches ride the same blob as flags. Read them from the evaluate result; see Python for the full client API.
Killswitches ride the same blob as flags. Read them from the evaluate result; see Go for the full client API.
Killswitches ride the same blob as flags. Read them from the evaluate result; see Ruby for the full client API.
Killswitches ride the same blob as flags. Read them from the evaluate result; see Java for the full client API.
Killswitches ride the same blob as flags. Read them from the evaluate result; see Kotlin for the full client API.
Killswitches ride the same blob as flags. Read them from the evaluate result; see PHP for the full client API.
Killswitches ride the same blob as flags. Read them from the evaluate result; see Swift for the full client API.
Three things to internalise:
undefinedforctx. Killswitches don't target — they're global. The second arg is just there to keep the function signature aligned withgate().defaultValue: trueis load-bearing. Don't omit it. If KV is unreachable during the very incident that prompted the kill, you do not want the killswitch to silently default tofalseand amplify the outage.- Log the bypass. When the killswitch is engaged, log a structured warn so post-mortem can reconstruct what was suppressed.
Deploy this. Killswitch is on, fallback is true, behaviour is unchanged from before.
3. Rehearse the flip
The most common reason a killswitch fails to help during an incident is that no one has ever flipped it before. Rehearse in staging:
# Flip the killswitch to true ("kill the path") — single-value form
shipeasy killswitch update transactional.emails-enabled --value true
# Confirm via the SDK eval endpoint
curl "https://api.shipeasy.ai/sdk/evaluate" \
-H "Authorization: Bearer $SHIPEASY_SERVER_KEY" \
-H "Content-Type: application/json" \
-d '{ "user": { "user_id": "drill-user" } }' \
| jq '.killswitches["transactional.emails-enabled"]'
# → true
# Verify no emails flow in staging
# … run your normal email test path …
# Re-enable (flip back to false = "not killed")
shipeasy killswitch update transactional.emails-enabled --value falseTime how long it takes from "decide to flip" to "next email is suppressed." With the default 30-second poll interval on Free / 60-second on Team, the next call should return the new value within that window of flipping.
4. Get notified when the killswitch flips
A killswitch is a social signal as much as a technical one. Flipping it should announce itself on the team's incident channel and create a paper trail.
Today this is wired through the Feedback → Connectors surface in the
dashboard. Pick killswitch.flipped as the event, point it at a Slack or
GitHub connector, and configure the filter (e.g. only fire for prod, or
only for specific killswitch names). The connector payload includes who
flipped it, when, and the new value — wire it into your incident channel
and your runbook ("if you see this, page primary on-call within 2 minutes").
For production-grade pages, point the connector at PagerDuty or Opsgenie — that way flipping the killswitch is declaring the incident, which is usually the right move.
What you have now
- A killswitch in the dashboard at Killswitches → emails-enabled.
- A wrapped code path that respects it on every call.
- A rehearsed flip-and-restore drill that took < 5 seconds.
- An alert on the flip event so the team knows when production is in degraded mode.
That's the whole pattern. Repeat for every system whose pause-button you'd want on the lock screen of your phone.
Where to next
When to add a killswitch→
Which subsystems deserve one — and which should stay feature flags.
Feature flags vs killswitches→
Same primitive at the wire level, different ergonomics. When to reach for which.
Worked example: paused emails→
The walkthrough from the case-studies page, with more context on the incident.