Skip to main content

Feature flag SDK with zero dependencies

Project description

Switchbox

Feature flags served from a CDN. Zero dependencies. Sub-millisecond evaluation.

PyPI Python License

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)  │
                                       └──────────────┘
  1. You create and toggle flags in the dashboard or API
  2. On every change, the API generates a static JSON file and uploads it to Cloudflare R2
  3. This SDK polls that JSON file from the CDN every 30 seconds
  4. 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

switchbox_flags-0.5.0.tar.gz (38.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

switchbox_flags-0.5.0-py3-none-any.whl (11.9 kB view details)

Uploaded Python 3

File details

Details for the file switchbox_flags-0.5.0.tar.gz.

File metadata

  • Download URL: switchbox_flags-0.5.0.tar.gz
  • Upload date:
  • Size: 38.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for switchbox_flags-0.5.0.tar.gz
Algorithm Hash digest
SHA256 84955c3125b43b6d089cec265764d21fa3ee4dd84a241717e8f4077d9eaed213
MD5 3e50f6b651080f070c77899f90807217
BLAKE2b-256 e0d45b94d789dab9e09f6dafe0b37150acb051b61a6cc8b11064b1e4c922d62d

See more details on using hashes here.

Provenance

The following attestation bundles were made for switchbox_flags-0.5.0.tar.gz:

Publisher: publish.yml on ignat14/switchbox-sdk-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file switchbox_flags-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: switchbox_flags-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 11.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for switchbox_flags-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f0c2bf87a1d2c9e708e0118382acd11709eab6fe3a4a70c21abcd3e995dd3bca
MD5 190d44df49c65d9333d738ac06f5bd08
BLAKE2b-256 210257b04961fd291dc2fd15d5039b82f08654a33f25e6eceb763f7ef87bb5fc

See more details on using hashes here.

Provenance

The following attestation bundles were made for switchbox_flags-0.5.0-py3-none-any.whl:

Publisher: publish.yml on ignat14/switchbox-sdk-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page