SDK Initialization in Flagsmith
A plain-English guide to the first few seconds of a Flagsmith-powered app: what "initializing" really means, which settings matter, what happens behind the scenes, and how to start up quickly, safely and calmly, even when the network misbehaves.
Picture the moment a customer taps your app icon. Before the first screen appears, your code must decide a dozen things: show the new banner or the old one, enable the beta checkout or hide it, display five items per row or three. Those decisions come from feature flags, and your app can only make them once it has asked Flagsmith for the answers.
The step that connects your app to Flagsmith is called initialization. It happens once, very early, and it quietly sets the rules for everything that follows: how fast screens appear, what users see when the network is slow, how much load you place on Flagsmith, and how safe your secret keys are. A tidy initialization makes the rest of your flag usage almost boring. A careless one causes flickering screens, empty spinners and mysterious bugs that only appear on slow phones.
You do not need to know anything about SDKs, networks or feature flags to follow this guide. Every new word is explained when it first appears, with an everyday comparison. By the end you will understand what initialization does, which settings deserve your attention, how the process unfolds step by step, what can go wrong and how to design your own startup so it stays calm under pressure.
1Starting From Zero: Flags, SDKs and Why Startup Matters
Before initializing anything, let us be sure about what is being initialized.
Feature flags in one minute
A feature flag is a switch in your software that decides whether a feature is visible. Instead of hiding a new button by deleting code, you wrap the button in a check: “if the flag is on, show it.” Later you flip the flag in a dashboard and the button appears or disappears without shipping a new release. A remote config value is a close cousin. Instead of just on or off, it holds a number or some text, such as how many items to show per page.
What an SDK is
An SDK, short for software development kit, is a ready-made code library that makes it easy to use a service. Instead of writing the low-level conversation with Flagsmith yourself, you add the SDK to your project and call friendly functions such as “is this flag enabled?” The SDK handles the sending of requests, the reading of replies, the remembering of results and many small details you would rather not write.
Think of a translator at an international meeting. You speak your own language, the other side speaks theirs, and the translator carries meaning back and forth. You never learn the other language. The SDK is that translator between your app and Flagsmith.
What initialization means
Before a translator can work, they must arrive, introduce themselves and learn which meeting they are attending. Initialization is the same for an SDK. You tell it which Flagsmith environment to talk to, how to behave when things go wrong, and what to do with the answers. Many SDKs also fetch the first set of flags during this step so that your code has something to read straight away.
Why the first moments matter most
Flags often decide what the very first screen looks like. If your app draws the screen before the flags arrive, one of two ugly things happens. Either the user sees a blank loading spinner, or the app shows the old version and then abruptly switches to the new one, which feels like a flicker. Both make an app feel unpolished. Good initialization is how you avoid both.
Whenever you meet a new word in this guide, ask three questions: what is it, why does it exist, and what would break without it? Those answers explain most of what you need to know.
2What Initialization Does: The Short Version
Five jobs, done once, early.
Although the details differ between languages, nearly every Flagsmith SDK performs the same handful of jobs when you initialize it. Learning them as a list makes the settings that follow easy to understand, because each setting tunes one of the jobs.
Identify the environment
You provide a key that tells Flagsmith which environment, such as production or staging, your app belongs to. Everything else depends on it.
Choose where to talk
The SDK needs the address of the Flagsmith service. The hosted service address is built in. Self-hosters supply their own.
Set behaviour rules
Timeouts, retries, caching, defaults and update styles are decided here, so that later calls behave consistently.
Fetch the first flags
Many SDKs ask Flagsmith for the initial set of flags straight away, so the app has real answers early.
Get ready for questions
The SDK stores what it learned in memory so your code can ask about flags quickly, as many times as it likes, without more network trips.
Stay up to date
Depending on settings, the SDK may keep refreshing in the background or listen for live updates, so long-running apps stay current.
One copy, shared by everyone
In most apps you should initialize the SDK exactly once and share that single instance across the whole program. Creating a new instance in every screen or function wastes network calls, throws away what was already learned and invites the flicker you are trying to avoid. Think of it as hiring one translator for the whole meeting, not a fresh one for every sentence.
Names of settings and exact behaviour differ between languages and versions. This guide teaches the ideas that stay true everywhere. Always confirm the precise setting names and defaults in the official documentation for the SDK you are using.
3The Big Picture: Where the SDK Fits
One picture holds the whole story.
flowchart LR App["Your App Code"] --> SDK["Flagsmith SDK: initialized once"] SDK --> Mem["In-Memory Flag Store"] SDK -->|"environment key"| Edge["Flagsmith Edge API"] Edge --> Data["Replicated Environment Data"] Admin["Dashboard or Admin API"] --> Core["Flagsmith Core"] Core -->|"publishes changes"| Data App -->|"asks: is flag on?"| Mem
Reading the picture
On the left is your own code. It never talks to Flagsmith directly. It talks to the SDK. The SDK holds a small store in memory. When your code asks “is this flag on?”, the SDK looks in that store and answers immediately, with no network trip. Only during initialization, and again whenever the SDK refreshes, does it reach out to the Flagsmith serving layer, using your environment key to say which environment it wants.
On the right is Flagsmith itself. People change flags through the dashboard or the admin interface, which talk to the core. The core saves the changes and publishes updated settings to the serving layer. The next time your SDK asks, it receives the new values. This separation is why reading flags is fast: the SDK talks to a nearby, read-focused service, never to the busy editing system.
The two moments of contact
The SDK is in contact with Flagsmith at two kinds of moments. The first is startup, which is the subject of this guide. The second is refresh, when the SDK updates its stored answers later. Everything you configure during initialization shapes how both moments behave.
A traveller arrives in a new city and buys a local guidebook at the airport. That purchase is initialization. For the rest of the trip, they read the guidebook instead of phoning a travel agent for every question. Now and then they buy an updated edition. The guidebook is the SDK’s in-memory store.
| Moment | What happens | Who decides how |
|---|---|---|
| Startup | SDK is configured and fetches the first flags | Your initialization settings |
| Reading | Your code asks the SDK, which answers from memory | The SDK, with no network cost |
| Refresh | SDK updates its stored answers | Timers, live updates or manual refresh settings |
| Failure | Network or service is unavailable | Your defaults, cache and timeout settings |
4The Most Important Setting: The Environment Key
One short string decides whose flags you get.
Organisations, projects and environments
Flagsmith organises things in layers. An organisation is your company account. A project is usually one product. An environment is one stage of that product, such as development, staging or production. The same flag exists in every environment but can be on in one and off in another. This is how you test a feature safely before real customers see it.
What the key does
Each environment has its own environment key, a string that identifies it. When you initialize the SDK with a key, you are saying “I belong to this environment.” Flagsmith uses the key to find the right flag settings and, together with the type of key, to decide what you are allowed to see.
Two kinds of keys
This is the most important distinction in the whole guide. Flagsmith uses two kinds of environment keys, and they must never be confused.
Client-side key
Designed for code that runs on a user’s device, such as a website or mobile app. Because anyone can look inside such code, this key is treated as public. It can only read flags for its environment.
Server-side key
Designed for your own backend servers. It is a secret, and it unlocks extra abilities such as downloading the whole environment for local decisions. It must never reach a user’s device.
A client-side key is like the address printed on a shop’s window. Anybody walking past can read it, and it only tells them where the shop is. A server-side key is like the key to the stock room. It opens things that customers should never touch, so it lives in the owner’s pocket.
Where to keep keys
Client-side keys can sit in your app’s configuration, because they are designed to be seen. Server-side keys belong in a secrets manager or protected environment settings, and are injected when the server starts. They should never appear in source code repositories, build logs, chat messages or screenshots. If a server-side key is ever exposed, create a new one and retire the old one immediately.
The most common beginner mistake is placing a secret server-side key in a mobile app or a website. Treat that key like a password. If it leaks into public code, anyone can use it, and they could read your whole environment’s rules.
One key per environment, always
Use a different key for each environment, and make your build or deployment choose the right one automatically. A production app built with the staging key shows staging flags to real customers. A staging build with the production key makes your tests flip real settings. Name keys clearly in your own secrets store, such as “web-client-production,” so nobody grabs the wrong one.
5Client-Side and Server-Side SDKs
Two families of SDK, two different jobs, two different initialization styles.
Client-side SDKs
Client-side SDKs run in places users control: web browsers, phones, tablets and desktop apps. They usually serve one user at a time. They initialize with the public environment key, often together with the identity of the current user, and they ask Flagsmith “what are the flags for this person?” The answers are kept in memory, and sometimes saved to local storage so the next app launch can start instantly.
Server-side SDKs
Server-side SDKs run in your own backend: web servers, workers, scheduled jobs. A single server handles thousands of different users, so it asks about many identities. These SDKs initialize with the secret key. They can work in two ways. In remote evaluation, the server asks Flagsmith for each user’s flags. In local evaluation, the server downloads the whole environment’s rules once, keeps them in memory, and decides for each user on its own machine, refreshing the rules on a timer.
| Question | Client-side SDK | Server-side SDK |
|---|---|---|
| Runs where | Browser, phone, desktop app | Your own backend servers |
| Key type | Public client-side key | Secret server-side key |
| Users served | Usually one | Many, one request at a time |
| Typical style | Fetch this user’s flags, keep in memory | Remote evaluation or local evaluation |
| Main startup concern | Show the right screen quickly | Be ready before taking traffic |
| Biggest risk | Flicker and slow first paint | Leaked secret key |
A client-side SDK is like a personal assistant who works for one executive and keeps that person’s schedule in a notebook. A server-side SDK is like a receptionist at a busy office who serves a stream of visitors and may keep a copy of the whole company handbook on the desk to answer quickly without phoning anyone.
Why this split shapes initialization
The two families have different priorities. On a phone, the priority is to draw a correct first screen fast, even on a poor connection. On a server, the priority is to be fully ready before accepting traffic, because answering with missing data would affect many users at once. The rest of this guide returns to this difference again and again.
If you are not sure which family you need, ask where the code runs. If a stranger could open it, it is client-side. If only your own staff can reach it, it is server-side.
6Internal Working: The Life of One Startup
Follow the SDK from the moment your app launches until it is ready.
sequenceDiagram participant A as Your App participant S as Flagsmith SDK participant L as Local Cache participant F as Flagsmith Serving Layer A->>S: Initialize with key and settings S->>S: Validate settings and prepare memory store S->>L: Check for saved flags from last run L-->>S: Return saved flags if present S->>F: Request current flags with key F-->>S: Return flags and values S->>S: Store in memory and update cache S-->>A: Signal ready A->>S: Is feature enabled? S-->>A: Answer from memory
Step by step
Your app calls initialize
You pass the environment key and any settings. Nothing has touched the network yet.
The SDK checks its settings
It confirms a key was supplied, applies defaults for anything left out, and prepares an empty store in memory.
It may load saved flags
If caching is enabled, the SDK reads flags saved from the previous run. These are instantly available, though possibly a little old.
It asks Flagsmith for fresh flags
The SDK sends a request with the key, and the identity if one is known. The serving layer evaluates the rules and replies.
It stores the answer
The reply is placed in memory and, if caching is on, saved for the next launch.
It signals readiness
Initialization finishes. In many SDKs this is an awaited step or a callback, and your code should wait for it before reading flags that affect the first screen.
Your code reads flags from memory
From now on, each question is answered instantly from the stored copy, with no network cost.
What if step four fails?
Networks are not perfect. If the request fails or times out, a well-configured SDK does not crash your app. It uses what it has: saved flags from a previous run if they exist, and otherwise the default values you provided. This is why the next chapters spend so much time on defaults and caching. They are what turns a failure into a quiet non-event.
A pilot preparing for take-off runs a checklist: check the instruments, load the flight plan, request clearance. If the radio fails at the last item, the pilot does not abandon the airport. There is a printed backup plan in the cockpit. Defaults and caches are your SDK’s printed backup plan.
7Choosing the Service Address
Which Flagsmith should the SDK talk to?
The hosted service
If you use Flagsmith’s hosted cloud service, SDKs come with the right address built in, pointing at the globally distributed serving layer. In that case you normally leave the address setting alone. Providing only the environment key is usually enough to start. This is by design: the fewer settings you must get right, the fewer you can get wrong.
Self-hosted and private installations
Some organisations run Flagsmith on their own servers, because of company rules, legal requirements or a wish for full control. In that case you must tell the SDK where your installation lives by providing its address. The address should use the secure form, so the conversation is encrypted. A mistyped address is one of the most common reasons for a first test failing, so copy it carefully, including any version portion at the end that your documentation specifies.
The edge proxy
Self-hosting teams often add an edge proxy near their apps. This is a small component that holds a cached copy of environment data and answers SDK requests itself, asking the main installation only now and then for updates. In that arrangement, your SDK points at the proxy’s address instead of the main server. The benefits are lower delay and less load on your main installation.
| Your setup | Address setting | Why |
|---|---|---|
| Flagsmith hosted cloud | Leave as default | Built in and points to the distributed serving layer |
| Self-hosted, direct | Your installation’s secure address | SDK must know where your server lives |
| Self-hosted with edge proxy | The proxy’s address | Faster local answers, less load on the main server |
| Testing against a local copy | Local address, development key | Safe experiments without touching shared environments |
A delivery driver needs the correct street address. For a big chain store, the address is on the company website. For a private home, you must be told it. Pointing an SDK at a self-hosted service is giving the driver the private address.
Never switch to an unencrypted address “to make debugging easier.” Always use the secure form, and keep your environment keys and user identities from travelling across the network in the clear.
8Default Values: Your Safety Net
The most valuable setting you will ever choose is the one used when everything goes wrong.
What a default is
A default value is the answer your code uses when the SDK cannot get a real one. Maybe the phone has no signal. Maybe the service is briefly unreachable. Maybe the flag was deleted. In all these cases, your code needs to know what to do, and the default tells it.
Where defaults live
Most SDKs let you provide defaults at initialization time, through a handler or a list of fallback flag values. Some also let you pass a default each time you ask about a flag. Setting them in one place at startup is neater, because every part of the app then shares the same fallback behaviour.
Choosing good defaults
The rule is simple: the default should be the safe, stable, well-tested behaviour. For a brand-new feature that means “off.” If the network fails, users see the version of the app they already know, not an unfinished feature. For a kill switch that normally guards something risky, the safe default depends on the situation, so decide deliberately rather than by habit.
Good default thinking
- New, untested features default to off.
- Config values default to the long-standing, known setting.
- Defaults are decided with the product team, not guessed.
- The app is tested with the network switched off.
Risky default thinking
- Defaulting a half-built feature to on “so we can see it.”
- Leaving defaults unset and hoping an error never happens.
- Different defaults in different screens for the same flag.
- Never testing what happens when the answer is missing.
Every building has an emergency lighting circuit that switches on when the main power fails. It is not as bright as normal lighting, but it keeps people safe and able to find the door. A good default is the emergency lighting of your app: modest, reliable and always ready.
Keep your default flags in one small file that is reviewed like any other code. When someone adds a new flag, adding its default becomes part of the same change.
9Timeouts and Retries
How long to wait, and how often to try again.
Why timeouts matter
A request can fail loudly, with an error. It can also fail silently, by never coming back. Without a time limit, your app could wait forever for a reply that is not coming, leaving the user staring at a spinner. A timeout is the maximum time you are willing to wait. When it passes, the SDK gives up on that attempt and moves on to its fallback behaviour.
Choosing a sensible value
A timeout that is too short causes false alarms on slow networks, so users on poor connections always get fallbacks. A timeout that is too long causes long waits. For flags that gate the first screen, aim to keep the wait short, in the range of a second or two, and rely on cache and defaults beyond that. For background refreshes that nobody is waiting on, a longer limit is fine.
Retries and backoff
Some failures are temporary: a brief network blip or a busy server. Trying again often works. But retrying instantly and endlessly makes a struggling service worse. The polite approach is called backoff: wait a short time before the first retry, longer before the second, longer again before the third, and stop after a few attempts. Many SDKs let you set the number of retries. Keep the number small.
flowchart TD
S["Need flags at startup"] --> C{"Cached flags available?"}
C -->|"Yes"| U["Use cached flags immediately"]
C -->|"No"| N["Call Flagsmith with timeout"]
U --> N
N --> OK{"Reply received in time?"}
OK -->|"Yes"| V["Store fresh flags and cache them"]
OK -->|"No"| R{"Retries left?"}
R -->|"Yes"| W["Wait, then try again"]
W --> N
R -->|"No"| D["Keep cached flags or fall back to defaults"]
If you phone a friend and nobody answers, you do not redial fifty times in a row. You wait a bit, try again, wait longer, and perhaps send a message instead. Backoff is the polite way of redialing.
Never let a flag call block your whole screen with no time limit. A user on a slow train would rather see the familiar version of your app now than a perfect version never.
10Caching: Remembering Between Launches
The fastest answer is the one you already have.
Two kinds of memory
An SDK can remember flags in two ways. The first is in-memory storage, which lasts only while the app is running. When the app closes, it is gone. The second is persistent storage, which saves flags to the device or disk so they survive a restart. Persistent caching is mostly useful for client-side apps, which are opened and closed all the time.
What caching gives you
- Instant first screens. The app can draw the right screen straight away from saved flags, then update quietly if fresh flags differ.
- Resilience. If the network is down at startup, the app still has real values from the last successful run, which is far better than bare defaults.
- Fewer requests. Repeated quick launches need fewer network trips, which saves battery, data and cost.
The freshness trade-off
Cached flags can be out of date. If a product manager switched a feature off ten minutes ago, a user opening the app from cache may briefly still see it. Many SDKs let you set a time to live, the maximum age of cached flags before they are considered too old. A short lifetime means fresher flags and more requests. A long lifetime means fewer requests and a longer wait before changes reach users. Choose according to what a stale flag would cost you.
| Cache lifetime | Benefit | Cost | Suits |
|---|---|---|---|
| Very short (seconds) | Almost always fresh | Many requests, little saving | Rare, mostly debugging |
| Short (minutes) | Fresh enough, saves requests | Brief staleness | Most interactive apps |
| Long (hours) | Very few requests, strong offline start | Changes take time to arrive | Decorative features, low-risk flags |
| Not used | Always the latest | Slow starts, weak offline behaviour | Server-side designs with local evaluation |
A milk carton has a use-by date. Fresh milk tastes best, but nobody checks the dairy every morning. You keep a carton in the fridge, glance at the date, and replace it when it gets old. Cache lifetime is the use-by date on your flags.
Showing cached flags and then updating
A popular approach is to draw the first screen from cached flags immediately, fetch fresh flags in the background, and update the screen only if something changed. This gives the speed of a cache and the accuracy of a fresh fetch. Take care with the update step. Switching major layouts under the user’s finger feels jarring, so many teams apply fresh values at the next natural moment, such as the next screen or the next launch, unless the change is urgent.
Ask which flags truly must change instantly, and which can wait until the next launch. Most decorative or experimental flags can wait, which keeps screens stable and users calm.
11Identity and Traits at Startup
Telling Flagsmith who is using the app.
Why identity matters
Without knowing who the user is, Flagsmith can only give general answers that are the same for everyone. When you provide an identity, which is a stable ID for one user, Flagsmith can give personalised answers: flags that depend on the user’s group, plan or country, and consistent results in percentage rollouts.
Traits
A trait is a small fact about an identity, such as “plan equals premium” or “app version equals 5.2.” A segment is a group of users defined by rules over traits, such as “all premium users in India.” When you send traits during initialization, Flagsmith can place the user in the right segments straight away and evaluate flags accordingly.
Anonymous users
Not every visitor is signed in. For anonymous visitors, you have two choices. You can ask for the general flags that need no identity. Or you can create a temporary, random identifier, store it on the device, and reuse it on later visits, so that the person receives consistent results over time. A fresh random ID on every visit means the person drifts between rollout groups, seeing a feature one day and not the next.
When the user signs in or out
Identity can change while the app runs. A guest signs in. A user switches accounts. In those moments your code should tell the SDK about the new identity so flags are re-evaluated. Treat sign-out similarly, so that the next person on a shared device does not inherit the previous person’s flags or traits.
A hotel gives a guest a key card coded for their room. If a different guest checks in, the card is recoded. Using an old card for a new guest would open the wrong door. Telling the SDK about a new identity is recoding the key card.
Stable internal IDs
Use an internal user number rather than an email address, so identities stay stable and no personal data travels.
Few, small traits
Send only the facts you will actually use in rules, such as plan, region and app version.
Sensitive facts
Avoid putting health, financial or other sensitive details in traits. Everything sent is stored by a third party.
Changing IDs
An ID that changes each session breaks rollouts and any personal overrides you have set.
Traits are stored in Flagsmith, and may be held in several regions. Review your privacy rules before deciding what to send, and follow the principle of sending only what you need.
12Waiting for Readiness Without Freezing the App
Initialization takes time. How should the rest of the app behave while it happens?
Asynchronous start
Fetching flags takes a network trip, so initialization is usually asynchronous. That means your code starts the process, carries on, and is told later when it is complete. Different languages offer different ways to express this: an awaited call, a callback or a promise. All of them express the same idea: “start now, tell me when it is done.”
Three strategies for the first screen
Wait briefly, then continue
Hold the first screen for a short, fixed time. If flags arrive, use them. If not, continue with cache or defaults. Good when the first screen depends heavily on flags.
Draw now, update later
Draw the screen at once from cache or defaults, then update when fresh flags arrive. Fast, but may cause visible changes.
Splash while loading
Show a branded loading screen for a short, bounded time while the SDK prepares. Familiar and tidy, but only if the wait is short.
Choosing between them
Ask how much the first screen depends on flags. If a flag decides the entire layout, Strategy A or C protects users from flicker. If flags only tweak small details, Strategy B keeps the app snappy. A common blend is to wait up to a second or so for fresh flags, then proceed with whatever is available, and apply late arrivals only at safe moments.
flowchart TD
L["App launches"] --> I["Start SDK initialization"]
I --> T{"Ready within the wait budget?"}
T -->|"Yes"| F["Draw first screen with fresh flags"]
T -->|"No"| C["Draw first screen with cache or defaults"]
C --> B["Initialization finishes in background"]
B --> U{"Flags changed?"}
U -->|"Yes, urgent"| A["Apply now"]
U -->|"Yes, not urgent"| N["Apply at next screen or launch"]
U -->|"No"| D["Nothing to do"]
A restaurant host tells a family, “Your table will be ready in about five minutes.” If it is ready sooner, wonderful. If it is not, the host does not make them wait outside forever. They are shown to a temporary seat and moved when the table is free. A bounded wait is that host.
Measure how long real users wait for initialization, especially at the slow end. A timeout chosen from real data beats one chosen from a hunch.
13Local Evaluation on the Server
Server-side SDKs have an extra trick that changes how initialization works.
What local evaluation is
In ordinary remote evaluation, a server asks Flagsmith each time it needs a user’s flags. In local evaluation, the server downloads the full set of environment rules once, stores them in memory and makes decisions entirely on its own machine. No network trip is needed to answer each question, which makes decisions extremely fast and greatly reduces requests.
What changes at initialization
To use local evaluation, you enable it in the SDK settings and provide the secret server-side key, which is required to download the full environment. During startup, the SDK fetches the environment document, which is a compact bundle holding all flags, segments and rules. Until that first download completes, the SDK cannot decide locally, so a well-designed server waits for it before accepting traffic or falls back to a safe behaviour.
Refreshing the rules
Rules change over time, so the SDK refreshes its copy on a timer. A shorter interval means changes arrive sooner and more requests are made. A longer interval means fewer requests and a longer wait for changes. Typical intervals are measured in tens of seconds. If a refresh fails, the SDK keeps using its last good copy, so a brief outage of the Flagsmith service does not stop your decisions.
| Question | Remote evaluation | Local evaluation |
|---|---|---|
| Where decisions happen | At Flagsmith’s serving layer | Inside your server process |
| Network per decision | Usually one request per user lookup | None after the first download |
| Freshness | Very fresh, after a short publish delay | As fresh as the refresh interval |
| Key needed | Server-side or client-side key as appropriate | Server-side secret key |
| Best for | Simple setups, small traffic | High-volume trusted backends |
A receptionist who phones head office to check the rules for every visitor is slow but always up to date. A receptionist who keeps a copy of the handbook on the desk is quick, and replaces the handbook whenever head office sends a new edition. Local evaluation is the handbook on the desk.
Local evaluation needs the secret key, so it is only for trusted backends. Never enable it in code that runs on a user’s device, and check your SDK’s documentation for any listed differences between local and remote results.
14Staying Up to Date: Polling and Live Updates
Initialization starts the story. Updates keep it current.
Why updates matter
A web page may stay open for hours. A server may run for weeks. During that time, product managers change flags. Without some way of updating, your app would keep using the answers it learned at startup, which grow stale. Initialization is where you choose how updates will arrive.
Three update styles
No automatic updates
The app learns flags at startup and again at the next launch. Simple and cheap, but changes appear slowly.
Polling on a timer
The SDK asks again every so often, such as every minute or five minutes. Predictable, but wastes some requests when nothing changed.
Live updates
Some SDKs can keep a lightweight connection open so Flagsmith announces changes as they happen. Fast and efficient for long-lived pages, where supported.
How live updates work, simply
Live updates commonly rely on a standard technique where the server pushes small messages down a connection that stays open, so the page does not need to keep asking. When a flag changes, the message arrives within moments and the SDK refreshes. This suits web apps that stay open all day. Availability and settings differ between SDKs, so check your documentation.
Responding to a change
SDKs usually let you register a function that is called whenever flags change. Use it with care. Updating the screen the instant a flag flips can surprise users, especially if it rearranges what they are looking at. Decide, flag by flag, whether an update should show immediately or wait for a natural moment.
flowchart LR
P["Product Manager changes a flag"] --> C["Flagsmith saves and publishes it"]
C --> D{"How does the SDK learn?"}
D -->|"Timer"| T["Next scheduled refresh asks again"]
D -->|"Live connection"| L["Flagsmith announces the change"]
D -->|"Neither"| N["Learned at next app launch"]
T --> S["SDK updates its stored flags"]
L --> S
N --> S
S --> H["Change handler decides when to apply it"]
There are three ways to hear the news. You can check the paper once a morning, you can look at your phone every few minutes, or you can have an alert that rings when something important happens. Choose the one that matches how soon you truly need to know.
15Offline Mode and Working Without the Network
Sometimes there is no Flagsmith to talk to, and that can be on purpose.
Why anyone would go offline deliberately
Some environments cannot or should not reach the internet: secure internal networks, aircraft systems, test pipelines that must be repeatable, or apps that must start in a basement with no signal. Many SDKs offer an offline mode in which they never call Flagsmith and instead read flag data from a source you supply, such as a file prepared earlier.
How it works in outline
Flagsmith can export the data of an environment into a file. You package that file with your app or place it where the server can read it. At initialization you switch the SDK into offline mode and point it at the data. The SDK then evaluates flags using that data, with no network at all. To change flags, you export a new file and deploy it.
Offline handlers and fallbacks
Some SDKs also support using offline data as a fallback while normally running online: if the live service is unreachable at startup, the SDK uses the packaged data instead of bare defaults. This is a stronger safety net than defaults alone, because the packaged data reflects real rules, not just a single fixed answer per flag.
Advantages
- Works with no network at all.
- Repeatable results, ideal for automated tests.
- No outbound traffic, helpful in locked-down environments.
- Strong startup safety net when used as a fallback.
Trade-offs
- Flags change only when you ship a new data file.
- The file can grow stale if nobody refreshes it.
- Extra step in your build or deployment process.
- Personal overrides on the live service are not seen.
A hiker carries a printed map in case the phone has no signal. The map may be a little behind the satellite view, but it gets the hiker home. Offline data is the printed map of your flags.
Use offline mode in automated tests. A test that depends on a live service can fail for reasons unrelated to your code. A test that reads a fixed file gives the same answer every time.
16Analytics and Usage Reporting
An optional setting that tells Flagsmith which flags you actually use.
What it is
Many SDKs can report how often each flag is evaluated. Flagsmith uses the reports to show usage in its dashboard, which helps you see which flags are alive and which are dead. Knowing a flag has not been read by any app for three months is valuable evidence when deciding whether to delete it.
Initialization choices
You usually enable or disable this reporting when you initialize. If enabled, the SDK collects counts in memory and sends them in batches at an interval you can set, instead of making a request for every single evaluation. Batching keeps the overhead small. If you do not need the information, you can leave it off.
Do not confuse two kinds of analytics
This flag usage reporting is a feature inside Flagsmith, and it is separate from third-party analytics integrations that send flag states to tools such as product analytics platforms. The first answers “which flags are being read?” The second answers “which users saw which version, and what did they do?” You can use both.
| Setting | Effect | Consider |
|---|---|---|
| Usage reporting on | Dashboard shows which flags are read | Small extra traffic in batches |
| Usage reporting off | No usage data collected | Fewer requests, less insight for cleanup |
| Short reporting interval | Fresher usage numbers | More frequent batches |
| Long reporting interval | Fewer batches | Numbers lag, and data may be lost if the app closes first |
A library counts how often each book is borrowed. The counts help the librarian decide which books to keep on the front shelf and which to move to storage. Flag usage reporting is the borrowing record for your flags.
17Setting Up Step by Step
A calm, ordered path from nothing to a working initialization.
Create the environments
In the dashboard, make development, staging and production environments, each with its own key.
Pick the right SDK
Choose the SDK for your language and decide whether you need a client-side or server-side one.
Store the key properly
Put client-side keys in app configuration. Put server-side keys in a secrets manager.
Write one initialization routine
Create a single function or module that initializes the SDK once and exposes the shared instance to the rest of the app.
Provide defaults and limits
Add safe default flags, a timeout, a small retry count and, for clients, caching.
Decide the first-screen strategy
Choose how long to wait for flags, and what the app shows if they are late.
Test in development
Flip a flag in the dashboard, wait a few seconds, and confirm the app changes. Repeat in staging before production.
Add monitoring
Track initialization time, failures and how often defaults are used, and set alerts before launch.
A checklist of settings to review
Environment key
The right key for the right environment and the right SDK family.
Service address
Leave alone for the hosted service. Set carefully for self-hosting or a proxy.
Default flags
Safe fallbacks for every flag your code reads.
Timeout and retries
A bounded wait and a small, polite number of retries.
Caching
Saved flags for instant starts and offline resilience.
Local evaluation and refresh interval
For high-volume backends, with a sensible refresh timer.
Usage reporting
Helpful for cleanup, at the cost of small batched traffic.
Live updates and change handler
For long-lived pages that need fast change delivery.
Keep the initialization code in one small, well-named module. When something about startup needs to change, there is exactly one place to look.
18Security and Privacy at Startup
The first call sets the tone for everything that follows.
Keys again, because they matter most
Use the public client-side key in apps and the secret server-side key only on servers. Keep secrets out of source control and build logs. Scan your repositories for accidentally committed keys. Rotate server-side keys on a schedule and immediately when a person who knew them leaves.
Encryption in transit
Initialization requests travel over HTTPS, which scrambles the conversation so anyone listening on the network sees only noise. Never use an unencrypted address, even in development, because habits formed in development tend to follow code into production.
What leaves the device
When you send an identity and its traits during initialization, you are sending information about your users to a third party and storing it there. Follow data minimisation: send only what rules need. Prefer internal IDs over emails and coarse facts like a plan name over detailed personal ones. If strict rules such as the European Union’s GDPR apply to your users, check where the data is stored and whether regional options are available.
Cached data on devices
Saved flags and traits on a device are stored in the app’s local storage. Treat them as readable by the device owner. Do not cache anything you would not want shown on a screen. On shared devices, clear cached identity data on sign-out.
| Risk | Example | Simple defence |
|---|---|---|
| Secret key in an app | Server key shipped inside a mobile build | Use only client-side keys on devices |
| Wrong environment | Production build using the staging key | Automatic key selection per build, tested before release |
| Over-sharing | Emails and names sent as traits | Use internal IDs and coarse traits |
| Unencrypted traffic | Plain address in a test build | Secure addresses everywhere |
| Leftover identity | Previous user’s cached flags on a shared device | Clear cache and identity on sign-out |
When you hand a parcel to a courier, you decide what goes inside. Once sealed and collected, it cannot be pulled back. Anything sent to an outside service at startup works the same way, so decide first what truly belongs in the parcel.
19Performance and Scalability
Startup is the busiest moment of an app’s life, so it deserves care.
Why startup is expensive
At launch, an app is doing many things at once: loading code, drawing screens, reading storage and talking to several services. Adding a slow flag request to that crowd can noticeably delay the first useful screen. A careful initialization keeps its own footprint small.
Habits that keep it light
- Initialize once. A second initialization repeats the network trip and discards what was learned.
- Request all flags at once. One request that returns every flag is cheaper than many requests for single flags.
- Start early, read late. Begin initialization as early as possible and read flags only when needed, so the network trip overlaps with other startup work.
- Use the cache. Drawing from saved flags removes the network from the critical path.
- Keep the key lookup cheap. Avoid slow work, such as reading remote configuration, just to find the key.
The thundering herd
Imagine a marketing email sends a million people to your app within minutes, and every app instance initializes at once. That sudden crowd is called a thundering herd. Flagsmith’s serving layer is built to absorb such spikes, but your own servers must cope too. For server fleets, stagger restarts so every instance does not download the environment at the same instant, and add small random delays to refresh timers so instances do not all refresh together.
When a concert ends, a thousand people reach for the exit at once, and the doors jam. A venue that opens several exits and staggers departures empties smoothly. Staggering server restarts and refresh timers is opening several exits.
Measure the time between app launch and the first useful screen with and without flags. If initialization adds more than a barely noticeable delay, revisit your wait budget and caching.
20Monitoring, Logging and Metrics
If you cannot see how startup behaves on real devices, you are guessing.
Three kinds of signals
Metrics are numbers over time. Logs are text records of events. Traces follow one action through several steps. Together they are called observability, and they let you answer questions about your app without guessing.
What to measure about initialization
Initialization duration
How long from the start call to readiness, with attention to the slowest one percent, split by region and network type.
Failure rate
The share of startups where the fetch failed or timed out. A rise is an early warning for the network, the service or your own settings.
Default and cache usage
How often the app started from defaults or saved flags. A healthy app rarely needs bare defaults.
Age of flags in use
How old the flags were that the app actually used, to check your cache lifetime choices.
Requests per launch
Should usually be one. More means repeated initialization or runaway refreshes.
Update delivery delay
The gap between saving a change in the dashboard and seeing it in a test app.
Logging that explains itself
Many SDKs offer an option to turn on more detailed logging. Enable it in development and in test builds, and keep it quieter in production. A good log line says which environment, whether the cache was used, how long the fetch took, and what the SDK decided. “Flags failed” tells a stranger nothing. “Fetch for production timed out after two seconds, using saved flags aged forty minutes” tells them everything.
Connect flag changes to graphs
A strong habit is placing markers on your dashboards whenever a flag changes, using Flagsmith’s integrations with monitoring tools. When a startup metric jumps, a marker beside the jump shows whether a flag change was involved.
Set a target
Write down what good means, such as “ninety-nine percent of launches are ready within two seconds, and fewer than one in a thousand starts from bare defaults.” A target turns vague feelings into something you can measure and discuss. Such targets are often called service level objectives.
Record the SDK version in your logs and metrics. When a problem appears after an upgrade, being able to filter by version saves hours.
21Design Patterns and Anti-Patterns
Habits that make startup calm, and habits that make it painful.
Patterns worth copying
Single shared instance
Initialize once in one module and hand the instance to everything else.
Safe defaults file
One reviewed list of fallback values, updated whenever a flag is added.
Bounded wait
The first screen waits a short, fixed time for flags and then continues with what it has.
Cache then refresh
Draw from saved flags immediately, fetch fresh ones in the background, apply at a safe moment.
Ready gate on servers
A server reports itself ready for traffic only after local evaluation data has loaded.
Wrapper around the SDK
Your own small interface hides the SDK, so swapping or upgrading it touches one file.
Advantages and trade-offs of a careful startup
Advantages
- Fast, steady first screens without flicker.
- Graceful behaviour on poor networks.
- Fewer requests, lower cost and less battery use.
- Easy to test and reason about.
- Changes to flag handling touch a single place.
Trade-offs
- More settings to choose and document.
- Cached flags can be briefly stale.
- A bounded wait sometimes shows defaults to a user.
- Extra code for readiness and fallbacks.
- Defaults must be maintained alongside the flags.
Anti-patterns to avoid
What people do
They initialize the SDK again in every screen, component or request handler.
Why it hurts
Each initialization repeats the network trip, discards stored flags and can cause flicker. Request counts balloon and costs rise.
Better approach
Initialize once at startup and share the single instance everywhere.
What people do
They read flags before initialization has finished and treat the empty answers as real.
Why it hurts
Features that should be on appear off, or the reverse, and the bug seems random because it depends on network speed.
Better approach
Wait for readiness, or deliberately use defaults and handle late updates properly.
What people do
They block the entire app on flag loading with no time limit.
Why it hurts
On a bad connection the app appears frozen. Users leave before the first screen ever appears.
Better approach
Set a timeout, use cache and defaults, and let the app continue.
What people do
They place the server-side key in a mobile app because it “just works.”
Why it hurts
Anyone can extract the key from the app and read the environment’s full rules.
Better approach
Ship only the client-side key in apps, and keep secrets on servers.
22Best Practices and Common Mistakes
A practical checklist drawn from everything so far.
Do these
- Initialize exactly once and share the instance.
- Use the right key in the right place: client-side keys in apps, server-side keys on servers only.
- Provide safe defaults for every flag, and test with the network switched off.
- Set a timeout and a small retry count so nothing waits forever.
- Cache on clients so the next launch starts instantly.
- Use stable, non-personal identities and small, non-sensitive traits.
- Wait for readiness on servers before taking traffic when using local evaluation.
- Monitor initialization time and fallback usage on real devices.
Common mistakes and quick cures
| Mistake | What you see | Cure |
|---|---|---|
| Wrong environment key | Flags from staging appear in production, or nothing matches the dashboard | Select keys automatically per build and print the environment name in logs |
| Reading flags too early | Features randomly missing on slow networks | Wait for readiness or handle late arrival deliberately |
| No defaults | Blank screens or crashes when the network fails | Provide safe defaults for every flag |
| Fresh anonymous ID every launch | Users flip between old and new versions | Store and reuse a stable ID |
| Cache never expires | Old flags linger long after changes | Set a sensible time to live |
| Refresh interval too short | Huge request counts and rate limits | Lengthen the interval or use live updates |
| Server key on a device | Secret exposed in public code | Rotate the key and use the client-side key instead |
23Troubleshooting Guide
When startup misbehaves, check in a calm and predictable order.
The usual suspects
All flags are off or at defaults
The fetch is probably failing. Check the key, the address, the network and the logs. Confirm the flags exist in the environment that the key belongs to.
Unauthorised errors
The key is missing, mistyped, revoked, or of the wrong type for this SDK. Re-copy it from the dashboard.
Flags differ from the dashboard
Wait a few seconds for publishing, check you edited the same environment, and look for cached copies or a long refresh interval.
Flicker after launch
The app drew defaults, then received real flags. Wait briefly for flags, or apply late updates at a safe moment.
One user sees different flags
Look for an identity override or a segment rule that matches only that user, and check the traits being sent.
Browser console shows a cross-origin error
A gateway or proxy in front of the service is not allowing your website address. Update its allowed origins.
A calm order of checks
First, confirm the environment key belongs to the environment you are looking at in the dashboard. Second, confirm the key type matches the SDK family. Third, confirm the service address, especially for self-hosted setups. Fourth, turn on detailed SDK logging and read what the SDK says. Fifth, check that the identity and traits are what you expect. Sixth, look at the status page and your own network. Going through this order avoids blaming the service for a mistake in your settings.
Test with a clean slate
When results are confusing, try a brand new test identity that has never been used, with only the traits you choose. If a clean identity behaves correctly, the problem is likely an old override or stored trait on the other identity. If a clean identity also behaves wrongly, the problem lies in the environment settings or the key.
Self-hosted extras
With a self-hosted installation, additional causes appear: expired certificates, a gateway stripping headers, a stopped background worker so changes never publish, or a firewall blocking outgoing connections. When everything seems right but changes never reach the app, suspect the background worker first.
When a lamp does not light, you check the bulb, the switch, the plug and the fuse in that order, not the power station. Troubleshooting startup follows the same short path outward from your own settings.
Keep a development environment and a test identity with a clearly fake ID, such as test-user-001. They give you a safe, repeatable way to check behaviour without touching real customers.
24Testing and Rehearsing Your Startup
A fallback you have never tried is only a hope.
Why test the unhappy paths
Most people test that flags load when everything is fine. The real value lies in testing what happens when things are not fine: the network drops, the answer is slow, the key is wrong, or the service returns an error. Those are exactly the situations in which your defaults, timeouts and caches are supposed to save you.
Happy path
Flip a flag in a test environment and confirm the app changes within a few seconds. Note how long it takes.
No network at first launch
Install the app fresh, switch the network off, and start it. Confirm it opens with defaults and shows no scary errors.
No network at second launch
Run once online, switch the network off, and start again. Confirm the app uses saved flags rather than bare defaults.
Slow network
Use a throttling tool to make the connection very slow. Confirm the timeout works and the first screen appears within your wait budget.
Wrong key
Use a deliberately wrong key in a test build. Confirm the app falls back cleanly and the logs make the cause obvious.
Recovery
Restore the network and confirm the app picks up fresh flags without a restart.
Test the sign-in and sign-out moments
Create fake identities with different traits, such as a premium user, a free user and a user from another country. Sign in as each, check the flags, then sign out and confirm the next identity does not inherit anything. These small tests catch stale identity bugs that are otherwise very hard to reproduce.
Automate what you can
Add a test to your build process that starts the app with offline data and checks the main screens. A second test can use a test environment with a known set of flags. Automated checks catch accidents early, such as a developer removing a default or renaming a flag without noticing.
Never rehearse failures against real customers. Use separate test environments and test identities, and tell the team in advance so nobody mistakes a drill for a real incident.
25A Worked Example: A Ride-Booking App Gets Its Startup Right
A made-up company shows how the pieces fit together.
The story below is hypothetical. Imagine a ride-booking company called Swift Route, with a mobile app, a website and a pricing service on its servers. The team wants to launch a new “shared rides” option safely and make sure the app opens quickly even in tunnels and lifts.
Step one: separate keys
The team creates development, staging and production environments. The mobile app and website receive the client-side keys. The pricing service receives the server-side key from a secrets manager. The build system picks the right key automatically for each release.
Step two: one initialization module
In each app, a single module initializes the SDK at launch and exposes the shared instance. No screen creates its own. A shared file lists safe defaults: “shared_rides” off, “max_pickup_suggestions” at three.
Step three: a bounded wait
The mobile app waits up to one and a half seconds for fresh flags during the splash screen. If they have not arrived, it continues with saved flags from the last run, or defaults on a first launch. Late flags are applied at the next screen change.
Step four: identity and traits
After sign-in, the app tells the SDK the rider’s internal ID and two traits: city and app version. Guests get a stored random ID so their experience stays consistent between visits. On sign-out, saved identity data is cleared.
Step five: local evaluation on the pricing service
The pricing service uses local evaluation, so it can decide flags for thousands of riders per second without network trips. Each instance reports itself ready for traffic only after its first download completes. Refresh timers include a small random offset so instances do not refresh together.
Step six: gradual launch
“shared_rides” is enabled for staff, then five percent of riders in one city, then wider. A change marker on the dashboards shows each step, and the team watches startup times and error rates alongside.
Step seven: a tunnel and an outage
A rider opens the app in a tunnel. The fetch times out, the app continues with saved flags, and the rider books without noticing anything. Later, a brief Flagsmith network problem affects one region. Backend instances keep their last good copy of the rules and carry on. A small rise in fallback usage appears on a dashboard and then fades.
Step eight: full release and cleanup
The feature is released to everyone. The team removes the flag and the old code path, then removes its default from the defaults file and closes the ticket.
What made this smooth
Nothing needed heroics. The team used separate keys for safety, one shared initialization for efficiency, a bounded wait for responsiveness, caching and defaults for resilience, and local evaluation for the busiest service. Each simple habit covered a different risk, and together they turned a nerve-racking launch into a routine one.
26The Same Idea in the Wider World
Preparing a client library carefully at startup is a habit found across the whole industry.
Every service that offers a client library asks you to configure it at startup, and the same few questions repeat: which account, which address, how long to wait, what to do on failure, and what to remember. Recognising the pattern makes any new library easier to learn. The examples below describe publicly known styles in general terms, not any company’s private design.
Connection pools
Database libraries are set up once with an address, credentials and time limits, then shared by the whole program, because opening connections repeatedly is slow.
Payment libraries
Payment providers ask you to configure a secret key on servers and a public key in browsers, with separate test and live keys, exactly like the key split described here.
Telemetry agents
Monitoring libraries start early, batch their reports and send them on a timer, so they add little to the app’s startup cost.
Map and location libraries
These load once, cache what they can, and degrade gracefully when the connection is poor.
Remote configuration
Large companies have long used remote settings that apps fetch at startup, cache locally and refresh in the background, with built-in defaults as a safety net.
OpenFeature
An open standard for flag clients lets an application talk to a common interface while a small provider connects it to a specific service.
The shared pattern
Across all of these, the same habits repeat. Configure once. Keep secrets on servers. Set time limits. Provide fallbacks. Remember what you learned. Report what happened. Once you know these habits, any new client library feels like a familiar room with different furniture.
Moving into a rented flat, you check the same things every time: which keys open which doors, where the fuse box is, what to do if the heating fails. The flat changes, but the checklist does not. SDK initialization is that checklist for software.
Lessons you can reuse
- Configure a client library once, in one place.
- Separate test credentials from live ones.
- Always know what your app does when the service is unreachable.
- Prefer a small wrapper around third-party libraries, so changing them is easy.
- Measure startup on real devices, not only on a fast office network.
27Limits: What Initialization Cannot Do
Knowing a tool’s limits is as valuable as knowing its strengths.
It cannot make a slow network fast
Initialization can hide delay with caches, defaults and bounded waits, but it cannot make a bad connection good. Users in poor coverage will sometimes start from saved flags or defaults, and your design should accept that gracefully.
It cannot guarantee instant freshness
Flags change in the dashboard, are published to the serving layer, and then reach each app by timer, live update or next launch. This takes a short time. Do not build features that need every user to see a change at the same millisecond. For strict coordination, use tools built for it.
It cannot protect secrets on a device
Anything inside a mobile app or web page can be inspected. A client-side key is safe to expose only because it can do very little. Flag values delivered to a device can be seen and possibly altered by the person holding it, so never use a client-side flag as the only guard for a sensitive action. Enforce permissions on your server.
It is not a user database
Traits exist to drive flag decisions. They are not a place to store customer profiles. Keep real customer records in your own systems.
It is not a substitute for testing
Flags make careful releases easier, but they do not remove bugs. Code behind a flag still needs tests in both its on and off states.
| You want to | Use | Not |
|---|---|---|
| Start fast on a poor network | Cache, defaults and a bounded wait | An unbounded wait for fresh flags |
| Guard a sensitive action | Server-side permission checks | A client-side flag |
| Decide at huge volume on a server | Local evaluation with a secret key | Remote lookup for every request |
| Coordinate machines at an exact moment | Locks and queues | A flag flip |
| Store customer profiles | Your own database | Identity traits |
If a design feels awkward, step back and ask whether you are using flags for what they do best: fast, gradual, reversible control over what users see.
28A Plain-English Glossary
Quick definitions of the words used in this guide.
SDK
A ready-made code library that makes using a service easy.
Initialization
The one-time setup that connects an SDK to a service and prepares it for use.
Environment key
The string that tells Flagsmith which environment an app belongs to.
Client-side key
A public key that is safe to place in apps and can only read flags.
Server-side key
A secret key for trusted backends only.
Default value
The answer used when the SDK cannot get a real one.
Timeout
The longest time you will wait for a reply.
Backoff
Waiting longer between each retry so a struggling service is not overwhelmed.
Time to live
How long a cached copy counts as fresh enough.
Identity and trait
One user known by an ID, and a small fact about that user.
Segment
A group of users defined by rules over traits.
Remote evaluation
Asking the service to decide the flags for you.
Local evaluation
Downloading the rules once and deciding on your own machine.
Environment document
The compact bundle of all flags and rules for one environment.
Offline mode
Running with flag data supplied from a file, with no network calls.
Edge proxy
A component you run near your apps that caches environment data and answers SDK requests.
Thundering herd
A sudden crowd of requests all arriving at once.
Service level objective
A measurable target for how well a service should perform.
29Upgrading SDKs and Living With Change
Libraries evolve, and your startup code has to evolve with them.
Why upgrades happen
SDKs receive improvements regularly: new features, performance fixes, better error handling and security patches. Staying reasonably current means you benefit from these, and you avoid the painful situation of jumping across many versions at once. The risk is that an upgrade changes how a setting behaves, renames something or removes an old option.
A safe upgrade routine
Read the release notes
Look for words such as deprecated, removed, renamed and changed. Note anything touching initialization settings.
Upgrade in a branch
Change the version in a separate branch, not directly in your main code line.
Run your startup tests
Repeat the unhappy-path experiments: no network, slow network, wrong key, recovery. Compare the behaviour with the old version.
Release gradually
Ship to staff or a small slice of users first, and watch initialization time and failure rate by SDK version.
Record what you learned
Write a short note about any behaviour that changed, for the next person who upgrades.
Protect yourself with a wrapper
If all your code talks to a small interface of your own, such as “is this feature on,” and only that interface talks to the SDK, then an upgrade or even a complete replacement touches one file instead of hundreds. This is the same idea as keeping all the plumbing behind one panel in a house. It also makes testing easy, because tests can supply a fake version of the interface with fixed answers.
A travel adapter lets one charger work in many countries. If the wall sockets change, you swap the adapter and keep the charger. Your own small interface is the adapter, and the SDK is the plug shape for a given country.
Mobile apps are special
On servers, you control when new code runs. On phones, old versions of your app linger for months, because users do not update promptly. That means several SDK versions may be alive at once, all asking the same service for flags. Test new flags against the oldest app version you still support, and use an “app version” trait so you can hide features from versions that cannot display them.
Pin SDK versions in your build files and upgrade deliberately. An automatic jump to a newer version during a routine build can change startup behaviour without anyone deciding it should.
Standards and portability
Some teams reduce lock-in by using OpenFeature, an open standard for how applications ask for flags. Your code talks to the standard interface, and a small provider connects it to Flagsmith. If you ever change flag services, the application code stays almost the same. Whether to adopt it is a judgement call: native SDKs may expose features more directly, while the standard offers freedom.
30Startup Runbook, Ninety-Day Plan and Cheat Sheet
Three practical tools to keep beside your team’s notes.
Part one: when startup goes wrong
A runbook is a short, step-by-step guide that a tired person can follow at three in the morning. Here is one for the day users report that the app is slow to open or shows the wrong features.
Check the dashboards
Look at initialization time, failure rate and fallback usage. Note the regions, networks and app versions affected.
Look for recent changes
Open the Flagsmith audit log and your release history. Was a flag changed or a new app version shipped just before the trouble began?
Check the service status
Open the provider’s status page and your own network monitoring. Separate your problems from theirs.
Reverse the suspect change
If a flag change is a plausible cause, switch it back. Because flags are switches, this is usually faster than a new release.
Confirm recovery
Watch the same graphs and a test device. Remember the short publishing delay before apps see the repair.
Write it down
Record the cause, the fix and one improvement, such as a shorter wait budget or a better default.
Part two: a ninety-day plan
Get the basics right
One shared initialization module, correct keys per environment, safe defaults and a timeout. Test with the network off.
Make it fast and resilient
Add caching on clients, a bounded first-screen wait, identity handling on sign-in and sign-out, and monitoring of startup metrics.
Make it sustainable
Introduce local evaluation where traffic justifies it, a wrapper interface, an upgrade routine, a runbook and a quarterly review of flags and defaults.
Part three: a one-page cheat sheet
- Initialize once. One module, one shared instance.
- Pick the key by place. Public key on devices, secret key on servers only.
- Default to safe. Every flag has a fallback that keeps the stable behaviour alive.
- Bound every wait. A timeout, a few retries, and a limited first-screen budget.
- Cache on clients. Instant starts and resilience when the network fails.
- Keep identities steady. Stable IDs give stable rollouts, and clear them on sign-out.
- Share less data. Small, coarse, non-sensitive traits only.
- Be ready before traffic. Servers using local evaluation wait for the first download.
- Measure the real world. Startup time, failures and fallback rate, by region and version.
- Upgrade on purpose. Read notes, test the unhappy paths, release gradually.
Pin this list beside your team’s runbook. New joiners can read it in two minutes, and experienced engineers will find that it settles most design arguments quickly. Good habits around the first few seconds of an app are what turn raw speed into a calm, dependable experience for the people who use your product, wherever in the world they happen to be.
One last piece of advice concerns patience. Nobody designs the perfect startup on the first attempt. Begin with a single environment, a couple of flags, safe defaults and a basic dashboard. Observe how the app behaves on real devices for a few weeks, note the surprises, and improve one habit at a time. Teams that grow their practice gradually end up with simpler, sturdier setups than teams that try to build everything before launch, because every addition is justified by a real need they have already seen.
Five questions to ask before you ship
Before any release that touches startup or flags, pause and answer five short questions. Doing so takes a few minutes and prevents most of the problems described in this guide.
- Which key does this build use? Confirm the environment and the key type, and print the environment name in a startup log line.
- What does the app do if the answer never arrives? Name the default for each new flag and confirm it is the safe behaviour.
- How long will a user wait? State the wait budget in seconds and confirm it was tested on a slow connection.
- Who is the user to Flagsmith? Check the identity and traits for signed-in, guest and signed-out states.
- How will we know it worked? Decide the graph, log line or test device you will check after release.
These five questions work for a tiny change and for a company-wide migration alike. Teams that make them a habit rarely have dramatic startup failures, because small problems are noticed and fixed while they are still small, long before they can interfere with a launch, an experiment or an incident response. Treat your initialization code like any other product you ship: give it an owner, keep it small and well described, review it regularly, and remove whatever nobody needs any more.
Finally, write down what you learn. A short note beside the initialization module, explaining why the wait budget is what it is, why each default was chosen, and which incidents shaped the current settings, will save a future teammate from undoing a careful decision by accident. Settings that look arbitrary are changed casually, and settings that carry a clear reason are respected. A few thoughtful sentences left behind today are a gift to everyone who inherits your code, including your future self on a tired evening.
If you take only one idea from this guide, let it be that startup is a design decision, not an afterthought. Decide deliberately what your app shows in the first second, what it does when answers are late, and how it recovers. Everything else in this guide is detail in service of that decision.
31Frequently Asked Questions
Quick answers to the questions beginners ask most often.
32Summary and Key Takeaways
The whole guide on one page.
Key Takeaways
- Initialize once, share everywhere. One setup at startup, one shared instance, and flags read from memory afterwards with no network cost.
- The key decides everything. Use the public client-side key in apps and the secret server-side key only on servers, one per environment, selected automatically per build.
- Defaults are your safety net. Choose the safe, stable behaviour for every flag and test the app with the network switched off.
- Bound the wait. Use a short timeout, a few polite retries and a limited first-screen wait, then continue with cache or defaults.
- Cache on clients, evaluate locally on busy servers. Saved flags give instant starts, and local evaluation gives fast decisions with fewer requests.
- Be thoughtful with identity. Use stable, non-personal IDs and small, non-sensitive traits, and clear them on sign-out.
- Watch it in the real world. Monitor initialization time, failures and fallback usage, set a target, and rehearse the unhappy paths before launch.