Skip to main content

Context

Feature Flags, Dynamic Logging and Config are most powerful when we can target specific users, teams or parts of our infrastructure. Context is how we do that.

Setting context in a filter allows you to set this knowledge once and use it everywhere when you evaluate feature flags, configs, and targeted log levels without having to pass your context data deeply around your app.

In a web app, the life-cycle of contexts are the life-cycle of the request. You set context at the beginning of the request and then it is cleared out when the request finishes.

For feature flags, context usage is optional but a useful ergonomic -- you can always pass in your context just-in-time to your FF evaluations.

For usage examples, see your relevant SDK client documentation.

Global and scoped context

To avoid deeply passing around awareness of the current user, request, etc., Prefab allows you to set Context globally and also for a thread/request scope or block. The mechanisms for doing so will vary by language and framework.

When context is set, log levels and feature flags will be evaluated in that context. If you provide just-in-time context to your FF evaluations, it will be merged with the thread/request context and global context. More on merging below.

The most-specific context will always win. If you set the same key in your JIT context that is present in another context, it will clobber the global context and thread/request context for the duration of the evaluation.

We can use a block to specify the context for the duration of the block.


Prefab.init(global_context: {application: {key: "my.corp.web"}})

context = { device: { key: "abcdef", mobile: mobile? } }

Prefab.with_context(context) do
# ...
end

Context keys

note

key is special

The key is the one special attribute of a context. It should be the unchanging, primary key of whatever your context is. For a user, that's likely the tracking ID set when you first saw them. For a team, it's probably the primary key of the table. For a Kubernetes pod, the pod id. Key is the handle Prefab if you want to add this context entity to a feature flag.

It's ok if there isn't a good key. If you add {cloud: {region: us-east, availability-zone: us-east-1a}}, you'll be able to target cloud.region or cloud.availability-zone with rules. If you add cloud.key: "i-1234567890abcdef0" you'll additionally be able to search for this context entity in context search tool.

If you provide a name attributes (as a sibling to key), it will be used in the Prefab UI to display the context entity as a "friendly" alternative to key. If you don't provide a name, Prefab will use the key as the display name.

Dot notation

When referencing fields from context, we use dot notation.

Given the context:

{
user: {
key: "1234",
email: "test@example.com",
},

device: {
key: "abcd123e-a123-bcFG-d123",
mobile: true,
},
}

You can reference user.key and device.mobile in the property field in the UI.

dot notation in UI

Advanced: Adding to and Merging Contexts

If you provide a context that conflicts with an existing context, your new context values will clobber any previous value.

Let's use this example as our initial context. It has two contexts: "request" and "subscription".

{
"request": {
"mobile": true,
"country": "US"
},
"subscription": {
"key": "s_123",
"allow_overages": false,
"plan": "Pro"
}
}

If we set the "request" context to { key: "f1e6461a", type: "iPhone" } then we lose the mobile and country attributes of our "request" context. Our current context is now

{
"request": {
"key": "f1e6461a",
"device_type": "iPhone"
},
"subscription": {
"key": "s_123",
"allow_overages": false,
"plan": "Pro"
}
}

If we provide Just-In-Time (JIT) context to our flag evaluation call, then the JIT keys clobber the current context keys only for the duration of the evaluation.

jit_context = {
subscription: { allow_overages: true },
user: { admin: true }
}

Prefab.enabled?("my.flag.name", jit_context)

That enabled? check uses this context

{
"request": {
"key": "f1e6461a",
"type": "iPhone"
},
"subscription": { "allow_overages": true },
"user": { "admin": true }
}

But then the current context after that evaluation is still

{
"request": {
"key": "f1e6461a",
"type": "iPhone"
},
"subscription": {
"key": "s_123",
"allow_overages": false,
"plan": "Pro"
}
}

You can, of course, do your own merging before re-setting the context key.