Feature flag SDK with zero dependencies
Project description
Switchbox
Feature flags served from a CDN. Zero dependencies. Sub-millisecond evaluation.
What is this?
Switchbox is a feature flag SDK that reads configs from a CDN instead of an API server. Flag configs are static JSON files on the edge — your app fetches them directly. Rules and rollouts are evaluated locally in the SDK, not on a server.
Install
pip install switchbox-flags
Quick Start
from switchbox import Switchbox
client = Switchbox(sdk_key="your-sdk-key-from-dashboard")
if client.enabled("new_checkout", user={"user_id": "42"}):
show_new_checkout()
client.close()
Features
- CDN-first — fetches flag configs from static JSON on a CDN, no server in the read path
- Zero dependencies — Python stdlib only, nothing to install beyond the package
- Sub-millisecond evaluation — rules and rollouts evaluated locally in-process
- Background polling — syncs configs every 30 seconds (configurable)
- Offline resilient — keeps working on cached configs if the CDN is unreachable
- Thread-safe — safe to use from multiple threads
- Context manager — supports
with Switchbox(...) as client:for automatic cleanup
Usage
Boolean Flags
from switchbox import Switchbox
client = Switchbox(sdk_key="your-sdk-key-from-dashboard")
if client.enabled("dark_mode"):
enable_dark_mode()
client.close()
String / Number Flags
version = client.get_value("search_algorithm", user={"user_id": "42"}, default="v1")
print(f"Using search {version}")
max_results = client.get_value("max_search_results", user={"user_id": "42"}, default=10)
All Flags at Once
flags = client.get_all_flags(user={"user_id": "42"})
# {"dark_mode": True, "search_algorithm": "v2", "max_search_results": 50}
Targeting Rules
Pass a user dict with attributes you want to target on. Rules are configured in the dashboard.
user = {
"user_id": "42",
"email": "alice@company.com",
"plan": "enterprise",
"age": "30",
}
# Flag with rule: email ends_with "@company.com"
client.enabled("internal_tools", user=user) # True
# Flag with rule: plan equals "enterprise"
client.enabled("advanced_analytics", user=user) # True
# Flag with rule: plan in_list ["pro", "enterprise"]
client.enabled("export_csv", user=user) # True
Supported operators: equals, not_equals, contains, ends_with, in_list, gt, lt.
Rules use OR logic — if any rule matches, the flag is on for that user.
Percentage Rollouts
Rollouts use deterministic hashing (sha256(user_id:flag_key) % 100). The same user always gets the same result for a given flag — no flickering between requests.
# Flag with rollout_pct=25 — 25% of users get this flag
client.enabled("new_onboarding", user={"user_id": "42"}) # deterministic True/False
A user_id (or id) key is required in the user dict for percentage rollouts.
Offline / Fail-safe Behavior
If the CDN is unreachable, the SDK keeps using the last successfully fetched config. Your flags keep working.
If the SDK has never successfully fetched a config (e.g., CDN is down on first startup), enabled() returns False and get_value() returns the default you pass in. No exceptions are raised.
Context Manager
with Switchbox(sdk_key="your-sdk-key-from-dashboard") as client:
if client.enabled("new_checkout", user={"user_id": "42"}):
show_new_checkout()
# client.close() is called automatically
Configuration
client = Switchbox(
sdk_key="your-sdk-key-from-dashboard", # required — get from Environments tab
poll_interval=60, # seconds between polls (default: 30)
on_error=lambda e: logger.warning(e), # called on fetch errors (default: None)
)
| Parameter | Type | Default | Description |
|---|---|---|---|
sdk_key |
str |
— | SDK key from the environment in the dashboard |
poll_interval |
int |
30 |
Seconds between background config refreshes |
on_error |
Callable[[Exception], None] |
None |
Callback invoked when a fetch or parse fails |
The SDK builds the CDN URL automatically from the SDK key. You can override with cdn_base_url if self-hosting.
How It Works
┌──────────┐ ┌──────────┐ ┌─────────────┐
│Dashboard │──────>│ API │──────>│ Postgres │
│ │ HTTP │ (Fly.io) │ SQL │ (Neon) │
└──────────┘ └────┬─────┘ └─────────────┘
│
│ publish on every change
v
┌─────────────┐ ┌──────────────┐
│CDN Publisher│──────>│Cloudflare R2 │
│ │ PUT │(static JSON) │
└─────────────┘ └──────┬───────┘
│
│ HTTP GET (SDK polls)
v
┌──────────────┐
│ Your App │
│ (this SDK) │
└──────────────┘
- You create and toggle flags in the dashboard or API
- On every change, the API generates a static JSON file and uploads it to Cloudflare R2
- This SDK polls that JSON file from the CDN every 30 seconds
- Flag evaluation (rules, rollouts) happens locally — no network call per flag check
The API server is only in the write path. All read traffic goes to the CDN.
API Reference
Switchbox(sdk_key, poll_interval=30, on_error=None)
Creates a new client. Performs an initial synchronous fetch on creation, then starts background polling.
client.enabled(flag_key, user=None) -> bool
Check if a boolean flag is enabled. Returns False if the flag doesn't exist.
| Parameter | Type | Description |
|---|---|---|
flag_key |
str |
The flag key to check |
user |
dict | None |
User context for targeting/rollouts |
client.get_value(flag_key, user=None, default=None) -> Any
Get the resolved value of any flag type (string, number, JSON). Returns default if the flag doesn't exist.
| Parameter | Type | Description |
|---|---|---|
flag_key |
str |
The flag key to check |
user |
dict | None |
User context for targeting/rollouts |
default |
Any |
Value returned if flag doesn't exist |
client.get_all_flags(user=None) -> dict[str, Any]
Get all flag values resolved for a user. Returns an empty dict if no config is available.
client.close() -> None
Stop background polling. Call this on application shutdown.
Contributing
git clone https://github.com/ignat14/switchbox-sdk-python.git
cd switchbox-sdk-python
pip install -e ".[dev]"
pytest
ruff check .
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file switchbox_flags-0.3.0.tar.gz.
File metadata
- Download URL: switchbox_flags-0.3.0.tar.gz
- Upload date:
- Size: 36.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dbdf12d0aaab46da53c9b14f26f0f662e17fa6e44384dc3285790d60b5279640
|
|
| MD5 |
9f52e88286a67c3360a22c1bd80e2dbe
|
|
| BLAKE2b-256 |
10ff239b99de3bb1bba444a42c4ee9c551d33ce459d5c411447aed2bbd25bb13
|
Provenance
The following attestation bundles were made for switchbox_flags-0.3.0.tar.gz:
Publisher:
publish.yml on ignat14/switchbox-sdk-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
switchbox_flags-0.3.0.tar.gz -
Subject digest:
dbdf12d0aaab46da53c9b14f26f0f662e17fa6e44384dc3285790d60b5279640 - Sigstore transparency entry: 1838596778
- Sigstore integration time:
-
Permalink:
ignat14/switchbox-sdk-python@fa965fc6650978ba84c257b29bec148abd597404 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/ignat14
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fa965fc6650978ba84c257b29bec148abd597404 -
Trigger Event:
push
-
Statement type:
File details
Details for the file switchbox_flags-0.3.0-py3-none-any.whl.
File metadata
- Download URL: switchbox_flags-0.3.0-py3-none-any.whl
- Upload date:
- Size: 11.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c3769e6db2d12ec96bc984798309afd1e7a57b40aa66ce5c9a28780c18357654
|
|
| MD5 |
5c36c758cb761b180677438683012584
|
|
| BLAKE2b-256 |
efc4330e3ec1e8900b47e408176727693da5ea5dad99799f735cb1f81b55de8f
|
Provenance
The following attestation bundles were made for switchbox_flags-0.3.0-py3-none-any.whl:
Publisher:
publish.yml on ignat14/switchbox-sdk-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
switchbox_flags-0.3.0-py3-none-any.whl -
Subject digest:
c3769e6db2d12ec96bc984798309afd1e7a57b40aa66ce5c9a28780c18357654 - Sigstore transparency entry: 1838596866
- Sigstore integration time:
-
Permalink:
ignat14/switchbox-sdk-python@fa965fc6650978ba84c257b29bec148abd597404 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/ignat14
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fa965fc6650978ba84c257b29bec148abd597404 -
Trigger Event:
push
-
Statement type: