> For the complete documentation index, see [llms.txt](https://govplane.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://govplane.gitbook.io/docs/documentation/resources/runtime-kill-switches-in-practice-5-patterns-implemented-with-govplane.md).

# Runtime Kill Switches in Practice: 5 Patterns Implemented with Govplane

<figure><img src="/files/gI8Y6XxLQ3ypSLJzlQhs" alt=""><figcaption></figcaption></figure>

In production systems, incidents rarely require a full shutdown. More often, they require selectively stopping a specific behaviour: a feature, a dependency, a region, or a segment of users. A payment provider may begin timing out, a new rollout may cause an unexpected spike in errors, or suspicious traffic may require an immediate response before the underlying issue is fully understood.

This is where kill switches become useful. In Govplane, a kill switch is not an ad hoc flag hidden inside application code. It is a policy decision evaluated locally at runtime, which means your application can change behaviour immediately without waiting for a new deployment.

This article focuses on how to implement kill switches in Govplane, with five concrete patterns and ready-to-import templates in the correct Govplane import format. Each example also includes a Node.js integration example to show how the policy is consumed inside a real execution path.

***

**Don't have a Govplane account yet? Get started right now for free!**

<a href="https://app.govplane.com/signup" class="button primary">Start for free now →</a>

***

### How Kill Switches Fit into Govplane

A Govplane policy controls a runtime decision. Your application sends a context object to the SDK, the SDK evaluates the relevant policy locally, and your code then decides how to behave based on the returned effect.

A kill switch should normally be treated as an explicit emergency outcome in the request path. In practice, that usually means one of three things:

* stop the operation altogether
* switch to a safer fallback path
* degrade gracefully while protecting the rest of the system

The important point is that the decision is externalised into policy, but enforced directly inside your own runtime.

A minimal evaluation flow in Node.js looks like this:

```js
const result = client.evaluate({
  target:  { service: "web-app", resource: "checkout_v2", action: "render" },
  context: { feature: "checkout_v2" },
});

if (result.decision === "kill_switch") {
  return legacyCheckout();
}

return newCheckout();
```

The exact surrounding code will vary depending on your service architecture, but the pattern remains the same: evaluate, inspect the returned effect, and branch into a safer behaviour when needed.

***

{% hint style="info" %}
In this article, we provide examples in Node.js, but the logic is similar in other languages. Check out the documentation for the [SDKs for Java, PHP and Python here.](broken://pages/u81NXUCMwtvlj6ZhfKNf)
{% endhint %}

***

### Example 1: Kill Switch for an External Payment Provider

A common incident pattern is a third-party dependency becoming unstable. Payment APIs are a good example because continuing to send traffic to an unstable provider can increase latency, create duplicate operations, and surface unnecessary failures to end users.

The purpose of this policy is not to disable payments globally. It is to stop one specific execution path, so the application can queue the operation, switch providers, or show a controlled fallback.

#### Ready-to-import template

```json
{
  "version": "1.0",
  "policies": [
    {
      "policyKey": "kill-external-payments",
      "env": "test",
      "friendlyName": "Kill Switch – External Payments Provider",
      "description": "Stops calls to the external payments provider so the application can fallback to queueing or an alternative provider during an incident.",
      "status": "active",
      "activeVersion": 1,
      "snapshot": {
        "defaults": { "effect": "allow" },
        "rules": [
          {
            "id": "ks-payments-external-provider",
            "status": "active",
            "priority": 100,
            "target": { "service": "billing-service", "resource": "payments_external", "action": "charge" },
            "effect": {
              "type": "kill_switch"
            },
            "description": "Kill all charge requests routed to the external payments provider"
          }
        ],
        "metadata": { "reason": "Contain third-party payment outage" }
      }
    }
  ]
}
```

#### Node.js example

In this example, the billing service evaluates the policy before calling the provider. If the returned effect is `kill_switch`, the code moves the payment into a safe queue instead of calling the provider directly.

```js
async function processPayment(client, payment) {
  const result = client.evaluate({
    target:  { service: "billing-service", resource: "payments_external", action: "charge" },
    context: { tenantId: payment.tenantId, provider: "external_payments" },
  });

  if (result.decision === "kill_switch") {
    await queuePaymentForRetry(payment);

    return {
      accepted: false,
      queued: true,
      reason: "payments_provider_disabled"
    };
  }

  return chargeWithExternalProvider(payment);
}
```

This is often a better operational response than throwing a raw provider error to the caller, because it preserves control over the user experience while protecting the dependency boundary.

***

### Example 2: Kill Switch for a New Checkout Flow

Feature rollouts fail in more subtle ways than infrastructure outages. A new checkout or onboarding flow may technically be available, yet still be producing a materially worse outcome: higher error rates, timeouts, poor conversion, or database contention.

A kill switch allows you to keep the code deployed while immediately forcing traffic back to the previous stable path.

#### Ready-to-import template

```json
{
  "version": "1.0",
  "policies": [
    {
      "policyKey": "kill-new-checkout",
      "env": "test",
      "friendlyName": "Kill Switch – New Checkout Flow",
      "description": "Disables the new checkout flow at runtime and routes traffic back to the stable checkout implementation.",
      "status": "active",
      "activeVersion": 1,
      "snapshot": {
        "defaults": { "effect": "allow" },
        "rules": [
          {
            "id": "ks-checkout-v2",
            "status": "active",
            "priority": 100,
            "target": { "service": "web-app", "resource": "checkout_v2", "action": "render" },
            "effect": {
              "type": "kill_switch"
            },
            "description": "Disable rendering of checkout_v2 and force fallback to the legacy checkout flow"
          }
        ],
        "metadata": { "reason": "Rollback checkout_v2 without redeploying code" }
      }
    }
  ]
}
```

#### Node.js example

This example assumes the application decides which checkout renderer to use at runtime.

```js
function renderCheckout(client, ctx) {
  const result = client.evaluate({
    target:  { service: "web-app", resource: "checkout_v2", action: "render" },
    context: { tenantId: ctx.tenantId, userId: ctx.userId, plan: ctx.plan },
  });

  if (result.decision === "kill_switch") {
    return renderLegacyCheckout(ctx);
  }

  return renderCheckoutV2(ctx);
}
```

This is especially useful when the issue is limited to behaviour rather than deployment integrity. You do not need to undo the release immediately; you only need to prevent traffic from entering the unstable branch.

***

### Example 3: Kill Switch for a Specific Region

Regional issues are rarely a reason to stop the whole platform. More often, you want to prevent traffic from executing a certain action in one region while allowing other regions to continue operating normally.

This pattern is useful for regional dependencies, jurisdiction-specific failures, or incidents limited to a local data path.

#### Ready-to-import template

```json
{
  "version": "1.0",
  "policies": [
    {
      "policyKey": "kill-region-eu-west",
      "env": "test",
      "friendlyName": "Kill Switch – EU West Region",
      "description": "Stops order creation in specific regional and tenant conditions during an incident.",
      "status": "active",
      "activeVersion": 1,
      "snapshot": {
        "defaults": { "effect": "allow" },
        "rules": [
          {
            "id": "ks-eu-west-orders-create-conditional",
            "status": "active",
            "priority": 100,
            "target": {
              "service": "orders-api",
              "resource": "order",
              "action": "create"
            },
            "when": {
              "op": "and",
              "conditions": [
                {
                  "op": "eq",
                  "path": "region",
                  "value": "eu-west"
                },
                {
                  "op": "or",
                  "conditions": [
                    {
                      "op": "in",
                      "path": "tenantId",
                      "values": ["tenant_123", "tenant_456"]
                    },
                    {
                      "op": "eq",
                      "path": "trafficType",
                      "value": "public"
                    }
                  ]
                }
              ]
            },
            "thenEffect": {
              "type": "kill_switch"
            },
            "elseEffect": {
              "type": "allow"
            },
            "effect": {
              "type": "allow"
            },
            "description": "Kill order creation in eu-west for affected tenants or public traffic during incident"
          }
        ],
        "metadata": {
          "reason": "Contain regional incident without affecting all tenants globally"
        }
      }
    }
  ]
}
```

#### Node.js example

The regional condition can be represented in the runtime context. The application evaluates the kill switch before processing the operation.

```js
function createOrder(client, order, ctx) {
  const result = client.evaluate({
    target: {
      service: "orders-api",
      resource: "order",
      action: "create"
    },
    context: {
      region: ctx.region,
      tenantId: ctx.tenantId,
      trafficType: ctx.trafficType
    }
  });

  if (result.decision === "kill_switch") {
    return {
      created: false,
      code: "region_temporarily_disabled",
      message: "Order creation is temporarily unavailable in this region."
    };
  }

  return persistOrder(order);
}
```

In practice, you may choose to make the region explicit in the policy logic or in the calling convention around the decision. The important operational principle is that the application can block the affected path without changing the rest of the platform.

***

### Example 4: Kill Switch for High-Risk Transactions

Fraud and abuse incidents often require an immediate response even when the detection logic is still evolving. A runtime kill switch can stop the highest-risk path first, buying time to refine the broader mitigation.

This works particularly well when your upstream systems already classify risk, but you do not want the blocking logic to remain hardcoded in business services.

#### Ready-to-import template

```json
{
  "version": "1.0",
  "policies": [
    {
      "policyKey": "kill-high-risk-transactions",
      "env": "test",
      "friendlyName": "Kill Switch – High Risk Transactions",
      "description": "Stops approval of transactions that match a high-risk fraud profile, using runtime context evaluated by Govplane.",
      "status": "active",
      "activeVersion": 1,
      "snapshot": {
        "defaults": { "effect": "allow" },
        "rules": [
          {
            "id": "ks-high-risk-charge-conditional",
            "status": "active",
            "priority": 100,
            "target": {
              "service": "risk-gateway",
              "resource": "transaction",
              "action": "approve"
            },
            "when": {
              "op": "and",
              "conditions": [
                {
                  "op": "eq",
                  "path": "riskLevel",
                  "value": "high"
                },
                {
                  "op": "or",
                  "conditions": [
                    {
                      "op": "gte",
                      "path": "amount",
                      "value": 1000
                    },
                    {
                      "op": "in",
                      "path": "country",
                      "values": ["BR", "NG", "ID"]
                    }
                  ]
                }
              ]
            },
            "thenEffect": {
              "type": "kill_switch"
            },
            "elseEffect": {
              "type": "allow"
            },
            "effect": {
              "type": "allow"
            },
            "description": "Kill high-risk transaction approvals when the order is high value or originates from a temporarily blocked country."
          }
        ],
        "metadata": {
          "reason": "Contain fraud exposure during active incident response"
        }
      }
    }
  ]
}
```

#### Node.js example

The application can evaluate this decision immediately before approval.

```js
async function approveTransaction(client, transaction) {
  const result = await client.evaluate({
    target: {
      service: "risk-gateway",
      resource: "transaction",
      action: "approve"
    },
    context: {
      riskLevel: transaction.riskLevel,
      amount: transaction.amount,
      country: transaction.country,
      tenantId: transaction.tenantId,
      paymentMethod: transaction.paymentMethod
    }
  });

  if (result.decision === "kill_switch") {
    return {
      approved: false,
      code: "blocked_high_risk",
      reviewRequired: true
    };
  }

  return finalizeTransaction(transaction);
}
```

This approach separates operational control from risk scoring itself. The scoring engine may continue to evolve, but the runtime response remains adjustable through policy.

***

### Example 5: Global Emergency Kill Switch

There are incidents where a narrow response is no longer sufficient. A widespread security issue, a control-plane compromise, or a severe data integrity concern may require stopping a critical class of requests across the whole system.

This kind of switch should be used sparingly, but it should exist before the day you need it.

#### Ready-to-import template

```json
{
  "version": "1.0",
  "policies": [
    {
      "policyKey": "kill-global-requests",
      "env": "test",
      "friendlyName": "Kill Switch – Global Emergency Requests",
      "description": "Stops all requests on a critical path during a severe incident that requires immediate global containment.",
      "status": "active",
      "activeVersion": 1,
      "snapshot": {
        "defaults": { "effect": "allow" },
        "rules": [
          {
            "id": "ks-global-api-request",
            "status": "active",
            "priority": 1000,
            "target": { "service": "api-gateway", "resource": "*", "action": "request" },
            "effect": {
              "type": "kill_switch"
            },
            "description": "Kill all gateway requests during a global emergency"
          }
        ],
        "metadata": { "reason": "Global emergency containment" }
      }
    }
  ]
}
```

#### Node.js example

A global kill switch is usually enforced high in the request path.

```js
function handleApiRequest(client, req, res, next) {
  const result = client.evaluate({
    target:  { service: "api-gateway", resource: req.route?.path || "*", action: "request" },
    context: { method: req.method, path: req.path },
  });

  if (result.decision === "kill_switch") {
    return res.status(503).json({
      error: "service_temporarily_unavailable"
    });
  }

  return next();
}
```

Because this runs close to the edge of the system, it can reduce blast radius quickly and consistently.

***

### A Combined Import with All Five Templates

For teams that want to seed a project with a baseline set of kill switches, it is often useful to keep the initial import in a single file.

#### Ready-to-import combined template

```json
{
  "version": "1.0",
  "policies": [
    {
      "policyKey": "kill-external-payments",
      "env": "test",
      "friendlyName": "Kill Switch – External Payments Provider",
      "description": "Stops calls to the external payments provider so the application can fallback to queueing or an alternative provider during an incident.",
      "status": "active",
      "activeVersion": 1,
      "snapshot": {
        "defaults": { "effect": "allow" },
        "rules": [
          {
            "id": "ks-payments-external-provider",
            "status": "active",
            "priority": 100,
            "target": { "service": "billing-service", "resource": "payments_external", "action": "charge" },
            "effect": { "type": "kill_switch" },
            "description": "Kill all charge requests routed to the external payments provider"
          }
        ],
        "metadata": { "reason": "Contain third-party payment outage" }
      }
    },
    {
      "policyKey": "kill-new-checkout",
      "env": "test",
      "friendlyName": "Kill Switch – New Checkout Flow",
      "description": "Disables the new checkout flow at runtime and routes traffic back to the stable checkout implementation.",
      "status": "active",
      "activeVersion": 1,
      "snapshot": {
        "defaults": { "effect": "allow" },
        "rules": [
          {
            "id": "ks-checkout-v2",
            "status": "active",
            "priority": 100,
            "target": { "service": "web-app", "resource": "checkout_v2", "action": "render" },
            "effect": { "type": "kill_switch" },
            "description": "Disable rendering of checkout_v2 and force fallback to the legacy checkout flow"
          }
        ],
        "metadata": { "reason": "Rollback checkout_v2 without redeploying code" }
      }
    },
    {
      "policyKey": "kill-region-eu-west",
      "env": "test",
      "friendlyName": "Kill Switch – EU West Region",
      "description": "Stops a specific request path in the affected region while allowing the rest of the platform to remain operational.",
      "status": "active",
      "activeVersion": 1,
      "snapshot": {
        "defaults": { "effect": "allow" },
        "rules": [
          {
            "id": "ks-eu-west-orders-create",
            "status": "active",
            "priority": 100,
            "target": { "service": "orders-api", "resource": "order", "action": "create" },
            "effect": { "type": "kill_switch" },
            "description": "Kill order creation requests in the affected regional execution path"
          }
        ],
        "metadata": { "reason": "Contain regional incident affecting order creation" }
      }
    },
    {
        "version": "1.0",
        "policies": [
          {
            "policyKey": "kill-high-risk-transactions",
            "env": "test",
            "friendlyName": "Kill Switch – High Risk Transactions",
            "description": "Stops approval of transactions that match a high-risk fraud profile, using runtime context evaluated by Govplane.",
            "status": "active",
            "activeVersion": 1,
            "snapshot": {
              "defaults": { "effect": "allow" },
              "rules": [
                {
                  "id": "ks-high-risk-charge-conditional",
                  "status": "active",
                  "priority": 100,
                  "target": {
                    "service": "risk-gateway",
                    "resource": "transaction",
                    "action": "approve"
                  },
                  "when": {
                    "op": "and",
                    "conditions": [
                      {
                        "op": "eq",
                        "path": "riskLevel",
                        "value": "high"
                      },
                      {
                        "op": "or",
                        "conditions": [
                          {
                            "op": "gte",
                            "path": "amount",
                            "value": 1000
                          },
                          {
                            "op": "in",
                            "path": "country",
                            "values": ["BR", "NG", "ID"]
                          }
                        ]
                      }
                    ]
                  },
                  "thenEffect": {
                    "type": "kill_switch"
                  },
                  "elseEffect": {
                    "type": "allow"
                  },
                  "effect": {
                    "type": "allow"
                  },
                  "description": "Kill high-risk transaction approvals when the order is high value or originates from a temporarily blocked country."
                }
              ],
              "metadata": {
                "reason": "Contain fraud exposure during active incident response"
              }
            }
          }
        ]
      },
    {
      "policyKey": "kill-global-requests",
      "env": "test",
      "friendlyName": "Kill Switch – Global Emergency Requests",
      "description": "Stops all requests on a critical path during a severe incident that requires immediate global containment.",
      "status": "active",
      "activeVersion": 1,
      "snapshot": {
        "defaults": { "effect": "allow" },
        "rules": [
          {
            "id": "ks-global-api-request",
            "status": "active",
            "priority": 1000,
            "target": { "service": "api-gateway", "resource": "*", "action": "request" },
            "effect": { "type": "kill_switch" },
            "description": "Kill all gateway requests during a global emergency"
          }
        ],
        "metadata": { "reason": "Global emergency containment" }
      }
    }
  ]
}
```

***

### Closing Notes

The value of a kill switch is not only that it can stop something. Its value is that it lets you stop the right thing, at the right level, without having to improvise during an incident.

In Govplane, this becomes a repeatable runtime pattern. You define the decision once, import it as policy, evaluate it locally, and integrate the response directly into your application code. That makes kill switches practical enough to use routinely, not only in worst-case scenarios.

Used well, they become part of normal operational design rather than a special emergency mechanism.

***

**Don't have a Govplane account yet? Get started right now for free!**

<a href="https://app.govplane.com/signup" class="button primary">Start for free now →</a>

***


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://govplane.gitbook.io/docs/documentation/resources/runtime-kill-switches-in-practice-5-patterns-implemented-with-govplane.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
