Why does my flag work locally but not in Docker?
Last updated:
The SDK key almost certainly did not reach the container. A key read from a local env file that is never passed through in your compose file or Dockerfile arrives empty, and the SDK serves your default value rather than failing loudly. After that, suspect outbound network. A container on an internal-only network cannot reach the evaluation endpoint, so the first payload never arrives.
Your code did not change between the two runs. The difference is in what reaches the process, and it comes down to a missing key or a blocked route almost every time.
Either one ends with an empty flag snapshot, and an empty snapshot means every call returns the default value you passed. That is the fail-safe behavior you want in production. It also makes local and containerized runs diverge without ever raising an error.
Check the key first
Usually your shell has the key and the container does not.
# On the host: the key is in your shell or a local env fileecho $FEATUREFLIP_SDK_KEY # sdk_server_...
# In the container: nothing was passed throughdocker compose exec api sh -c 'echo "[$FEATUREFLIP_SDK_KEY]"' # []A local env file that your dev server loads automatically stays invisible to a container unless your compose file passes it through. Log the key’s prefix at startup, never the key itself, and you will catch this in seconds without opening a single configuration file.
While you are there, confirm it is the right kind of key. A server key sees every flag in the project, a client key sees only the flags explicitly marked client-side visible. Container work often involves moving evaluation from a browser to a backend or the reverse, and the key needs to move with it.
Then check outbound access
A container attached only to an internal network cannot reach the evaluation endpoint. The SDK will keep retrying and keep serving defaults in the meantime.
Confirm from inside the container, not from the host, since the container’s namespace is the one that matters. If your environment requires an egress proxy, the SDK’s HTTP client needs to know about it, and a long-lived streaming connection needs a proxy that does not buffer responses.
The third possibility
If both check out, compare which environment each run is pointed at. A development key and a production key are different keys, and a flag enabled in one is often disabled in the other. There is a separate answer on why one key cannot serve every environment if that is where you have landed.
Whichever of the three it turns out to be, the reason you got no error is the same. Reliability covers why an empty snapshot is treated as a survivable state instead of a fault.
Related questions
Why does my flag work in dev but not production?
Flags are configured per environment, so enabling one in development changes nothing elsewhere. Rules and rollout percentages are per environment too.
Can I use one SDK key for every environment?
No. The SDK key is what selects the environment, so sharing one collapses dev and production onto the same flag configuration.
Why is my feature flag returning the default value?
Six reasons a Featureflip flag falls back to the default you passed, ordered by how often each one is the real cause, with the check for each.
Still stuck?
The docs cover every SDK, and the free Solo plan is enough to reproduce most of these locally.