Client-Side vs Server-Side SDKs in Flagsmith

Client-Side vs Server-Side SDKs in Flagsmith

Client-Side vs Server-Side SDKs in Flagsmith

Where your code runs changes everything: which key it may hold, how it asks for flags, how fast it answers, what users can see, and what happens when the network fails. This guide explains both families of Flagsmith SDKs and how to choose between them.

Picture two programs that both need to know whether a new feature is switched on. One is a web page open in a stranger’s browser. The other is a service running quietly inside your own data center. Both ask Flagsmith the same simple question, yet the right way to ask is completely different for each. The browser is a place you do not control, full of people who can read anything you send. The server is a place you do control, where secrets are safe and speed matters enormously.

Flagsmith therefore offers two families of SDKs, client-side and server-side, built for these two very different worlds. Picking the wrong one is one of the most common mistakes teams make, and it leads to leaked rules, slow pages, noisy bills, and surprising outages. In this guide you will learn what each family does, how each works inside, where each shines, and how to combine them into a design that is fast, safe, and easy to run.

1Why the Split Between Client and Server Matters

The same question, asked from two different places, deserves two different answers.

One service, two kinds of caller

Flagsmith is a service that decides which features are on for which users. Your applications ask it questions, and it replies. But not all applications are alike. Some run on machines you own and secure. Others run on devices that belong to your customers: their laptops, their phones, their tablets. The difference between these two places is the difference between your own house and a public square.

Trust is the real dividing line

In your own house, you can leave valuable papers on the table. In a public square, anything you set down can be read, copied, or changed by passers-by. Software works the same way. Code running on your server is trusted: nobody outside your company can look inside it. Code running in a browser or phone app is untrusted: a curious user can open the developer tools, read every network request, and even change values in memory.

Analogy

Think of a bank. Inside the vault, staff can see the complete ledger of every account. At the customer counter, a teller shows a customer only the details of that customer’s own account. The vault is the server side, where full rules and secrets live. The counter is the client side, where only a personal, limited view is shown. You would never wheel the whole ledger out to the front desk.

What this guide will cover

We will start with the basics of SDKs and keys, then look inside each family to see how it fetches and caches flags. We will compare them on speed, cost, freshness, security, and reliability. Then we will look at special cases such as browsers, mobile apps, and serverless functions, and finish with decision guides, patterns, mistakes to avoid, and a troubleshooting table.

2
families of SDKs: client-side and server-side
2
kinds of environment keys: public and secret
2
ways to evaluate: remotely, or locally in memory
i
Tip

If you remember one sentence from this guide, make it this: put the secret and the heavy work on the server, and put only the final, limited answer in front of the user.

2What an SDK Is and Where Your Code Runs

Before comparing the two families, let us be clear about the word SDK and the places code can live.

What an SDK is

An SDK, short for software development kit, is a ready-made library that you add to your application so it can talk to a service without you writing every web request yourself. The Flagsmith SDK knows how to build the request, send the key, read the reply, remember the answers, and hand your code simple results such as “this feature is on” or “this setting is twenty-five”. It saves effort and prevents many mistakes.

Where code can run

  • In a web browser. Code downloaded by the visitor and run on their computer. Everything in it can be inspected.
  • In a mobile or desktop app. Code installed on the user’s device. It can be unpacked and studied by anyone determined enough.
  • On a server. Code running on machines you operate, such as a web back-end, a worker, or a scheduled job. Users never see inside it.
  • In a serverless function. Code that runs on demand in a short-lived environment managed by a cloud provider. It is server-side in trust, but unusual in lifetime.

Languages and families

Flagsmith publishes SDKs for many languages. Broadly, those aimed at browsers and devices, such as JavaScript for the web, React, mobile frameworks, Android, and iOS, belong to the client-side family. Those aimed at back-end languages, such as Python, Java, .NET, Go, Ruby, PHP, Rust, and Node.js running on a server, belong to the server-side family. The list changes over time, so check the current documentation for your language. Notice that the family is decided by where the code runs, not by the language. JavaScript can run in a browser, where it is client-side, or on a server, where it is server-side, and you pick the SDK that matches.

Where code runsWho controls the machineTrust levelSDK family
Web browserThe visitorUntrustedClient-side
Mobile appThe userUntrustedClient-side
Back-end serviceYouTrustedServer-side
Scheduled job or workerYouTrustedServer-side
Serverless functionYou, on rented machinesTrustedServer-side
i
Note

Language support and SDK features change as Flagsmith grows. Treat this guide as the map of ideas, and use the current SDK documentation for your language as the source for exact setup steps and options.

3Meet the Two Families Side by Side

Here is the whole comparison at a glance. The rest of the guide explains each row.

QuestionClient-side SDKsServer-side SDKs
Runs inBrowsers and user devicesServers you operate
Environment keyClient-side key, public by designServer-side key, kept secret
Who is the user?Usually one person, the current userMany different users, one per request
How flags are decidedFlagsmith decides (remote evaluation)Flagsmith decides, or your server decides locally
Sees full targeting rules?No, only its own resultsYes, in local evaluation mode
Speed of a flag checkCached value, or one network tripIn memory when local, one trip when remote
FreshnessOn each fetch or refreshEach request when remote; each refresh when local
Main riskAnything sent can be read or tampered withLeaked key exposes all rules
Main benefitInstant personalised interfaceFast, powerful, trusted decisions

Two cheerful ways to remember the difference

Client-side

The customer counter

Shows one customer their own, limited view. Safe to expose because it holds nothing secret.

Server-side

The vault and back office

Holds the whole ledger and makes the decisions. Never open to the public.

Analogy

A theatre has an usher and a stage manager. The usher walks the aisles, helps one patron at a time, and knows only what that patron needs to find their seat. The stage manager sits in the control room with the entire script and every cue sheet. Both are vital to the show, but you would not hand the control-room keys to the usher, and you would not ask the stage manager to walk the aisles.

4Trust and Keys: Public Versus Secret

Everything else follows from one fact: the two families use two different kinds of environment key.

The environment key

Every request to Flagsmith carries an environment key that identifies which project and environment to read. Think of it as both an address and a password. Flagsmith gives each environment two kinds of key, matching the two families of SDKs.

The client-side key

The client-side environment key is meant to be public. You can place it in a web page, a mobile app, or a public code repository, and nothing terrible happens. This is because it is limited in what it can do. It can ask for the flags that apply to a user, and it can send that user’s identity and traits, but it cannot download the full set of rules, and it cannot change anything.

The server-side key

The server-side environment key is a secret. It can do everything the client key can, and more: it can download the entire configuration of the environment, including every feature, every segment, every rule, and every override. That power is what makes local evaluation possible, and it is also what makes the key dangerous if leaked. It must live only on servers you control, in a secrets manager, and never in a browser bundle, a mobile app, or a public repository.

KeyPublic?Can read user-specific flagsCan download all rulesWhere it may live
Client-side keyYes, by designYesNoWeb pages, mobile apps, anywhere
Server-side keyNo, secretYesYesServers and secrets managers only
flowchart TD
    K["Which kind of code is asking?"] --> Q{"Does it run on a machine you control?"}
    Q -->|"No: browser or user device"| C["Use the client-side key"]
    Q -->|"Yes: your own server"| S["Use the server-side key"]
    C --> C1["Gets only its own user's flags"]
    S --> S1["Can also download all rules for local evaluation"]
    
The place the code runs decides the key, and the key decides what the code can learn.
Analogy

A visitor badge opens the front door and lets you see the lobby. A master key opens every room, including the records office. A company happily prints a thousand visitor badges, but guards the master key closely. The client key is the visitor badge. The server key is the master key.

!
Warn

The most serious mistake in this whole topic is putting a server-side key into front-end or mobile code. Anyone can then download your complete targeting rules, including pricing tiers, internal groups, and the names of unreleased features. If it ever happens, treat the key as stolen: create a new one and revoke the old one at once.

5How Client-Side SDKs Work Inside

A client-side SDK lets Flagsmith do the thinking, then remembers the answer for a while.

Step by step

When your app starts, the client-side SDK is set up with the client-side key. Usually the app also tells it who the user is by giving it an identity, such as a customer number, and perhaps a few traits, such as the plan name. The SDK sends this to Flagsmith over a secure connection. Flagsmith evaluates every rule for that one user and sends back the final list of flags, each with its state and value. The SDK stores the list in memory, and often in the device’s local storage, and your code reads from it.

Remote evaluation

This style is called remote evaluation, because the decision is made remotely, inside Flagsmith. The device never sees the rules. It only sees the result for its own user. That is why it is safe to give the device a public key: there are no secrets on the device to steal, beyond the answers for that one user.

Caching and refreshing

Asking over the network on every screen would be slow, so client SDKs keep the answers they have received. Many can store them in the browser’s local storage or the phone’s equivalent, so that the next launch of the app can start with the last known answers while fresh ones are fetched in the background. Most also let you provide default values, so the app has something sensible to show before any answer arrives, and callbacks that tell your interface when flags change so it can redraw.

flowchart LR
    APP["App starts"] --> INIT["SDK set up with client-side key and identity"]
    INIT --> CACHE{"Cached flags on device?"}
    CACHE -->|"Yes"| SHOW["Show cached flags at once"]
    CACHE -->|"No"| DEF["Show defaults"]
    SHOW --> FETCH["Fetch fresh flags from Flagsmith"]
    DEF --> FETCH
    FETCH --> SAVE["Save new flags and update the screen"]
    
A client SDK starts fast with what it already knows, then quietly fetches the latest answers.
Analogy

A traveller arriving in a city already has a paper map from last time. They start walking using the old map, and meanwhile a friendly local hands them an updated one. The old map keeps them moving. The fresh map corrects any streets that have changed. A client SDK uses cached flags and fresh flags in the same way.

What the client SDK is good at

  • Personalising an interface for the one person looking at it.
  • Showing or hiding screens and buttons without a new app release.
  • Reacting to changes while the app is open.
  • Working offline from the last cached answers.

What it cannot do

It cannot download your rules, so it cannot evaluate them for other users. It cannot protect anything by itself, because the user controls the device. And it adds a network request each time the app starts or refreshes, which matters when you have millions of devices.

6How Server-Side SDKs Work Inside

A server-side SDK has two modes. It can ask Flagsmith each time, or it can carry the rulebook itself.

Mode one: remote evaluation from a server

In the simpler mode, the server SDK behaves much like the client one, but with a secret key. For each user your server is handling, it sends the identity and traits to Flagsmith, which evaluates the rules and sends back the answers. This is easy to start with and keeps the logic in one place, but each check needs a network trip.

Mode two: local evaluation

In local evaluation mode, the server SDK uses its secret key to download the complete environment document once, holds it in memory, and then answers every flag check itself. It takes the user’s identity and traits from your code, runs the segment rules and rollout calculations inside your own process, and returns the answer in a tiny fraction of the time a network trip would take. The SDK refreshes the document on a schedule, commonly about once a minute, though you can adjust the interval.

flowchart TD
    SRV["Server process starts with server-side key"] --> MODE{"Which mode?"}
    MODE -->|"Remote evaluation"| R["Send identity and traits to Flagsmith for each user"]
    R --> RA["Receive answers for that user"]
    MODE -->|"Local evaluation"| L["Download environment document"]
    L --> MEM["Hold rules in memory and refresh on a schedule"]
    MEM --> LA["Answer each check inside the process"]
    
Server SDKs choose between asking Flagsmith every time and carrying the rulebook in memory.
Analogy

A lawyer’s assistant can phone the senior partner every time a client asks a question, or can keep a copy of the firm’s policy book on the desk, updated each morning. Phoning gives the very latest answer but takes time on every call. The desk copy answers instantly and keeps the phone free, but it may be a few hours behind the newest memo.

One client, many users

A key difference from the client side is that a server handles many users at once. A single SDK object is usually created when the server starts and then shared by all requests. For each request, your code passes in that request’s identity and traits. The SDK does not “belong” to one user.

Other server-side features

  • Default handlers that return safe answers when something fails.
  • Offline mode, where flags come from a stored file instead of the network, helpful for tests and locked-down environments.
  • Reuse of connections, so repeated calls are cheap.
  • Optional usage reporting, to show which flags are actually read.

7Data Flow: One Flag Check in Each World

Following a single question from start to finish shows how different the two paths really are.

The client-side path

A user opens the app. The SDK reads cached flags from the device and shows them. It then sends a request with the public key and the user’s identity to Flagsmith. Flagsmith checks the user against every rule and returns the user’s final flags. The SDK stores them, tells the interface to update, and the user sees the latest version of the screen.

The server-side path with local evaluation

A user’s request arrives at your server. Your code asks the SDK whether a feature is on for this user, passing the user’s ID and traits. The SDK looks at the rules already in memory, matches segments, calculates any rollout bucket, and replies within a tiny moment. There is no network trip for that check at all. Meanwhile, in the background, the SDK refreshes its copy of the rules once in a while.

sequenceDiagram
    participant U as User
    participant C as Client SDK in App
    participant F as Flagsmith
    participant S as Your Server
    participant L as Server SDK in Local Mode
    U->>C: Open the app
    C->>C: Read cached flags and show them
    C->>F: Fetch with client key and identity
    F-->>C: Flags for this user only
    C-->>U: Update the screen
    U->>S: Send a request to your server
    S->>L: Is feature on for this user
    L->>L: Check rules held in memory
    L-->>S: Answer in microseconds
    S-->>U: Reply
    L->>F: Periodic refresh with server key
    F-->>L: Full environment document
    
The client path talks to Flagsmith for its own user. The local server path answers from memory and refreshes occasionally.

What to notice

  • The client talks to Flagsmith about one user. The server, in local mode, talks about everyone, but only once in a while.
  • On the client, the network is part of starting up. On the server, the network is only used for background refresh.
  • The client receives answers. The server receives rules.

Everyday use case: a plan-based feature

A project tool shows an “advanced reports” tab only on the enterprise plan. In the browser, the client SDK is told the user’s plan as a trait, and Flagsmith replies that the tab is on, so the tab appears. On the server, the report-building code checks the same flag locally before allowing the report to be generated. The browser decides what to show. The server decides what is allowed.

8Identity: One User or Many

Who is “the user” depends entirely on where the code runs.

An identity in Flagsmith

An identity is a unique ID for one user, device, or account. It lets Flagsmith give a personal answer and keep a rollout stable, so that a person who was included in the first ten percent stays included as the percentage grows.

On the client: one identity at a time

A browser tab or a phone app usually represents a single person. The client SDK is typically set to that identity when the app starts or when the user logs in, and it stays that way until the user logs out. Switching identity, for example after login, makes the SDK fetch a fresh set of flags for the new identity.

On the server: a new identity for every request

A server handles thousands of different people. For each request, your code supplies the identity of the person it is serving. The same SDK object answers for user A, then user B, then user C, within milliseconds. This is why server SDKs take identity as an input to each flag check, rather than as a setting on the SDK.

AspectClient-sideServer-side
Identities per SDK objectOne at a timeMany, changing with every request
When identity is setAt start-up or loginOn every flag check
Change of identityTriggers a new fetchJust a different input
Anonymous usersNeed a generated, saved IDYour server must supply an ID

The anonymous visitor problem

Many sites have visitors who have not logged in. They still need a stable identity so that a percentage rollout gives them the same answer every time. A common approach is to generate a random ID the first time they arrive, store it in a cookie or local storage, and use it as the identity. When they later log in, you may switch to their account ID. Be aware that this switch can change which flags they receive, and so can make the screen change mid-visit. Plan for it, for example by switching identity at a natural break such as the login page.

Analogy

A hotel doorman greets the same guest all evening, so he learns their name and preferences. A hotel reception desk serves a new guest every few minutes, and must ask for a name each time. The client SDK is the doorman, who knows his one guest. The server SDK is the reception desk, who asks “and who are you?” with each customer.

i
Tip

Use the same identifier format on the client and on the server. If the browser uses a customer number and the server uses an email address, the same person will be treated as two different people, and may see a feature on in one place and off in another.

9Traits: Where the Facts Come From

Targeting needs facts about the user. The two families get those facts from different places.

What traits are

A trait is a named fact about an identity, such as plan, country, app version, or signup date. Segment rules compare traits to values to decide which group a user belongs to. Good traits are small, stable, and non-sensitive.

Traits on the client

A client app knows things the server may not: the app version, the device type, the language setting, the operating system, and what the user has just done on screen. These are natural traits for a client SDK to send. Because anything sent from the client can be altered by a determined user, treat client-supplied traits as hints, not as proof. If a trait controls something important, such as a paid feature, confirm it on the server.

Traits on the server

Your server knows things that the client cannot be trusted to say: the real subscription plan from your billing system, the account’s age, the role granted by your permission system. A server SDK is the right place to supply these traits, because the values come from your trusted data.

Which side should supply which trait?

TraitBetter sourceReason
App versionClientOnly the app knows which version is running
Device or browser typeClientDetected on the device
Interface languageClientChosen on the device
Subscription planServerComes from billing records and cannot be forged
Account role or permissionsServerSecurity-related, must be trusted
Signup date or account ageServerHeld in your database
Analogy

If a passenger tells the airline their seat class, the airline checks the ticket to be sure. What the passenger says is useful, but what the ticket says is the truth. Traits sent by a client are the passenger’s words. Traits that come from your server are the ticket.

!
Warn

Avoid sending sensitive personal details as traits from either side. Use simple categories such as plan and region, and internal numbers for identities. Less data sent means less data that could ever be exposed.

10Local Evaluation in Depth

This is the signature feature of server-side SDKs, and it deserves a closer look.

What is in the environment document

The environment document is a complete snapshot of one environment. It holds every feature and its default state and value, every segment and its rules, every segment override and its priority, any multivariate options and their weights, and personal overrides for specific identities. In short, it is everything Flagsmith needs to answer any question about any user in that environment.

How a local check runs

When your code asks for a flag, the SDK follows the same order Flagsmith itself would. It begins with the default for the feature. If the identity has a personal override, that wins. Otherwise it walks through the segment overrides in priority order and applies the first one whose rules match the traits you supplied. For multivariate and percentage rules, it runs a repeatable calculation on the identity and feature to assign a stable bucket. The result is the same as a remote answer would have been, computed in your own memory.

The refresh cycle

A background process inside the SDK downloads a fresh copy of the document at regular intervals. Between refreshes, all checks use the copy in memory. This means a flag change made in the dashboard reaches your servers within one refresh interval, not instantly. If a refresh fails, the SDK keeps using the previous copy and tries again later, so a short network problem does not stop your service.

1

Start

The server starts, and the SDK downloads the environment document using the server-side key.

2

Serve

Every flag check is answered from the copy in memory, using the identity and traits your code provides.

3

Refresh

On a schedule, the SDK downloads a newer document and swaps it in without interrupting requests.

4

Survive failures

If a refresh fails, the old document stays in use and the SDK tries again at the next interval.

When local evaluation is a good fit

  • High-traffic back-end services where every millisecond counts.
  • Services that check many flags for each request.
  • Systems that must keep working even if Flagsmith is briefly unreachable.
  • Teams that want to reduce the number of requests they send to Flagsmith.

When to be careful

Local evaluation holds your complete rules in the memory of every server, so those servers must be secure. It also means changes take up to one refresh interval to arrive, so for flags that act as emergency switches, choose a refresh interval you are comfortable with. And very large environments produce larger documents, which take a little more memory and time to download.

Analogy

A pilot flies with a flight manual on board rather than radioing the airline for each procedure. The manual is updated before each trip. If the radio fails mid-flight, the pilot keeps flying by the manual. Local evaluation gives your server the same independence.

11Remote Evaluation and Caching in Depth

Remote evaluation keeps the rules private, and caching keeps it fast enough for humans.

Why client SDKs use remote evaluation

The device is untrusted, so the rules must stay with Flagsmith. The device sends its identity and traits, and receives only the final answers. This protects your targeting logic, keeps the data sent to the device small, and means the device does not need clever code to apply rules.

The cost: a network request

The price of remote evaluation is that every fresh answer needs a request. On a fast connection that is quick, but on a slow mobile network, in a lift, or in a tunnel, it may be slow or impossible. This is why client SDKs lean so heavily on caching and defaults.

Layers of caching on a client

  1. In memory: flags kept while the app is open, so each screen can read them instantly.
  2. On the device: flags saved in local storage or the phone’s equivalent, so the next launch starts with the last known answers.
  3. Defaults in code: a built-in fallback for anything with no cached or fresh answer.
flowchart TD
    N["Screen needs a flag"] --> M{"In memory?"}
    M -->|"Yes"| U["Use it"]
    M -->|"No"| D{"Saved on device?"}
    D -->|"Yes"| U
    D -->|"No"| F["Use the default in code"]
    U --> R["Refresh from Flagsmith in the background"]
    F --> R
    
A flag is read from the nearest available layer, while a refresh fetches the latest answers behind the scenes.

Staleness on devices

A cached answer might be hours or days old, especially for an app that is opened rarely. For decorative flags this does not matter. For flags that protect against a problem, decide how fresh the answer must be, and refresh at launch and whenever the app returns to the foreground.

Updates while the app is open

Some client SDKs can notice changes while the app is running, either by checking again at intervals or, depending on the SDK and plan, by receiving updates as they happen. Check the current documentation for what your SDK supports. If your interface listens for such changes, take care that the screen does not change suddenly under the user’s finger. A flag that flips while a person is reading a form can be confusing, so apply many changes at a calm moment, such as the next screen.

Analogy

A shop window display is arranged in the morning and changed only when the shop is quiet. If the display were rearranged while a customer was pointing at an item, they would be confused. Apply flag changes to a user interface in the same considerate way.

12Freshness: How Fast Do Changes Arrive?

When you press the switch in the dashboard, how long until each kind of SDK notices?

The path of a change

A change begins in the dashboard or through the management API. It is saved, and then copied to the layer that serves flag reads. Only then can SDKs see it. After that, each SDK picks it up in its own way and at its own pace.

SDK styleHow it learns of a changeTypical delay
Server, remote evaluationOn the next request it makesVery short, subject to any caches
Server, local evaluationAt the next refresh of the environment documentUp to one refresh interval, often about a minute by default
Client, fetch at start-up onlyNext time the app starts or refreshesCould be minutes to days
Client, periodic refreshOn each scheduled fetchUp to the refresh interval
Client, live updates, where supportedPushed from the serviceSeconds, depending on the setup

Matching freshness to the job

Not every flag needs to be fresh to the second. A banner message can wait. An emergency kill switch cannot. Look at each flag and ask “how long can we live with the old answer?” For emergency switches, prefer paths with short delay, and consider keeping the switch on the server, where you control the refresh interval, instead of on a distant device that may not refresh for hours.

Consistency between client and server

Because the client and the server learn of a change at different moments, they can briefly disagree. The browser might show the old screen for a few minutes after the server has started enforcing a new rule. This is normal in distributed systems. Design for it: make sure the server always checks the rule itself, so that a stale screen is merely cosmetic and never a security hole.

Analogy

When an airport changes a gate, the announcement system, the departure boards, and the staff’s tablets do not all update at the same instant. For a short time, a traveller reading an old board may walk to the wrong gate. The gate agent at the right gate still decides who boards. The board is helpful but the agent has the final word, just as the server should.

i
Tip

Write the expected delay next to each emergency flag in your team’s notes, for example “reaches servers within about a minute, reaches installed apps on next launch”. Knowing the number before an incident removes guesswork when time matters most.

13Performance and Scalability

A flag check sits on the busiest path in your product, so how it is answered matters.

Speed on the client

For a human using an app, the important question is how long they wait before the screen looks right. If the answer is cached on the device, the check itself takes almost no time, and the only delay is the background refresh, which the user does not feel. If there is no cache, the first screen must wait for a network trip or show defaults. Good client design hides this by showing sensible defaults or a short loading state.

Speed on the server

On a server, flag checks may happen thousands of times a second, often several times per request. Remote evaluation adds a network round trip to each check, which can add up to a noticeable delay. Local evaluation answers in memory, so a check costs only a tiny amount of computing time. The difference can be dramatic for busy services.

Load on Flagsmith

Here the two families affect the service very differently. A client SDK generates traffic in proportion to the number of devices and sessions. A million users opening an app means a million start-up fetches. A server SDK in local mode generates traffic in proportion to the number of servers. A hundred servers refreshing once a minute is a tiny stream.

flowchart LR
    subgraph CL["Client-side load"]
        D1["Many devices"] -->|"One fetch per start or refresh"| FS1["Flagsmith"]
    end
    subgraph SV["Server-side load, local mode"]
        D2["Few servers"] -->|"One refresh per interval"| FS2["Flagsmith"]
    end
    
Client traffic scales with the number of users. Server traffic in local mode scales with the number of servers.

Scaling tips

  • Client: cache on the device, avoid refreshing on every screen, and do not fetch again if the data is recent.
  • Server: use local evaluation for busy services, and share one SDK object across the process.
  • Both: fetch all flags together rather than one at a time.
  • Hosted service: the platform serves reads from a distributed layer near the caller, which helps global user bases.
  • Self-hosted: add instances and a cache, and consider a lightweight proxy in front of Flagsmith so that many clients share one upstream connection.
Analogy

A city can hand out a printed bus timetable to every resident, or it can run a phone line for each question. If a million residents all phone at breakfast time, the line collapses. If the city instead sends a few hundred bundles of timetables to bus depots, which then answer questions on the spot, the load almost vanishes. Local evaluation on servers works like the depot bundles.

14Counting the Requests: A Simple Cost Example

Numbers make the difference between the families easy to feel. These figures are made up for clarity, not measured from any real system.

The setup

Imagine a company with one million active mobile app users. The average user opens the app three times a day. The company also runs a back-end of eighty servers that together handle fifty thousand requests a second, each checking about three flags.

The client side

If each app launch fetches flags once, that is three million fetches a day from devices. Spread across a day, this averages about thirty-five requests a second, with peaks at busy hours of perhaps several times that. If the app also refreshes every time it comes back from the background, the numbers can double or triple. A sensible refresh rule, such as “no more than once every ten minutes”, can cut this significantly.

The server side with remote evaluation

Fifty thousand requests a second with three checks each is a hundred and fifty thousand flag checks a second. If every check were a network request, Flagsmith would face that traffic directly, and each user request would wait for several round trips. Even fetching all flags once per request would mean fifty thousand calls a second.

The server side with local evaluation

With local evaluation, each of the eighty servers downloads the environment once a minute. That is eighty downloads a minute, or just over one per second. The hundred and fifty thousand checks a second all happen in memory.

About 35
requests a second from three million daily app launches
150,000
flag checks a second on the servers
About 1
request a second from servers using local evaluation
DesignRequests to FlagsmithWaiting added to user requests
Servers check every flag remotelyAbout 150,000 a secondSeveral network trips each
Servers fetch once per requestAbout 50,000 a secondOne network trip each
Servers use local evaluationAbout 1 a secondNone
i
Tip

For hosted plans that count requests, the biggest savings usually come from two habits: use local evaluation on busy servers, and add sensible refresh limits in client apps. Check your own plan’s current rules for how requests are counted.

15Security on the Client Side

Assume the user can see and change everything on their own device.

What a user can see

Anyone using a web page can open the browser’s developer tools and read every request and response. They can see the client-side key, which is fine, and they can see every flag value your app receives. A determined person can unpack a mobile app and find the same. This is why nothing secret should ever be placed in a flag value delivered to a client: no private addresses, no passwords, no tokens, no confidential pricing logic.

What a user can change

The user can also modify what is stored on their device. They may edit the cached flags in local storage, use a browser extension to change responses, or alter variables in memory. If your interface shows an “admin” button because a flag says so, a user might make the button appear. That is harmless only if the server refuses to do anything for them when they click it.

What the client key cannot do

The client-side key is limited on purpose. It cannot download your segment rules, so the user cannot see who else is targeted or how. It cannot change flags. A leak of this key reveals very little, which is why it may be public.

QuestionAnswer on the client
Can users read flag values they receive?Yes, assume so
Can users edit cached flags?Yes, assume so
Can they see other users’ flags?No, only their own
Can they see your targeting rules?No, with the client-side key
Can they change flags in Flagsmith?No, the client key is read-only for flags
Analogy

A concert ticket shows your seat number. Anyone can read it, and a cheeky person might even draw a different seat number on a photocopy. The usher at the gate does not trust the paper alone. They check the real seating chart. Client-side flags are the paper ticket. The server’s checks are the real seating chart.

!
Warn

Never use a client-side flag as the only thing standing between a user and sensitive data or a powerful action. Flags decide what is displayed. Real permissions must be checked on the server, every time.

16Security on the Server Side

The server is trusted, but it holds the master key, so it must be guarded.

Protect the server-side key

  • Store it in a secrets manager and supply it to the program at start-up.
  • Never write it in source code, build files, or chat messages.
  • Never print it in logs or error messages.
  • Use a separate key for each environment and each service, so one leak has a small reach.
  • Rotate keys regularly and whenever someone with access leaves.
  • Scan repositories automatically for accidentally committed secrets.

What a leaked server key exposes

A stolen server-side key lets a stranger download your whole environment document. They learn every feature name, every segment definition, and every rule. This does not let them change flags, because that needs a management credential, but the information can be commercially sensitive: unreleased features, pricing groups, and internal test accounts.

Local evaluation and memory

With local evaluation, the complete rules sit in the memory of every server process. Treat those servers as holding confidential data. Avoid exposing debug endpoints that could print the document, and keep memory dumps and crash reports protected.

Keep traits clean

Servers often supply the most reliable traits, but with great access comes great temptation. Send only what the rules need. Prefer internal IDs. Avoid names, emails, and sensitive details. If you must use a sensitive fact to decide a flag, evaluate it locally and never send it to Flagsmith at all.

SEC-SRV-01Anti-pattern
The mistake

A team puts the server-side key into a shared configuration file that is also bundled into the front-end build, because “it was easier to keep all settings in one place”.

Why it fails

Everything in a front-end bundle is public. The secret key now ships to every visitor’s browser, and anyone can download the complete rules.

The fix

Keep client configuration and server configuration in separate files. Build the front end with only the client-side key, and inject the server-side key only into server processes.

17Flags Are Not Permissions: Where to Enforce

One of the most useful habits is to split every decision into “what to show” and “what to allow”.

Two different questions

When a feature is gated by a flag, two separate questions arise. First: should the user see this feature in the interface? Second: should the user be allowed to use it? The first is about presentation and can be decided on the client. The second is about security and must be decided on the server.

The safe pattern

Let the client SDK drive what appears on the screen. Let the server SDK, together with your real permission system, decide what the back-end will actually do. Both read the same flag from Flagsmith, so they usually agree. When they briefly disagree, because of timing or tampering, the server’s answer wins.

flowchart TD
    U["User clicks the new feature"] --> C["Client: flag on, so the button is visible"]
    C --> REQ["Request sent to your server"]
    REQ --> S{"Server checks the flag and the user's permission"}
    S -->|"Allowed"| OK["Perform the action"]
    S -->|"Not allowed"| NO["Refuse the request"]
    
The client decides what is visible. The server decides what is permitted.

Everyday use case: a new export tool

A company is trialling a data export tool with a small group. The client SDK shows the export button only to that group. If someone outside the group forces the button to appear and clicks it, the server checks the same flag, along with the user’s permissions, and refuses the request. The button is a convenience. The check on the server is the lock.

Analogy

A restaurant menu may leave certain dishes off for children, but the kitchen still checks the order ticket. The menu shapes what people ask for, while the kitchen decides what is actually cooked. If someone writes a forbidden dish on the order, the kitchen simply does not make it.

18Reliability on the Client: Defaults, Cache, and Offline

User devices live in the real world of weak signal, tunnels, and aeroplane mode. Plan for it.

The network will fail

Unlike a server in a data center, a phone or laptop may be offline for long stretches. A good client design makes this boring. The app opens, shows something sensible, and quietly catches up when the network returns.

The three layers of safety

  1. Fresh answer: use it when it arrives in time.
  2. Cached answer: use the last saved flags if the fresh answer is late or missing.
  3. Built-in default: use the safe value written into the app if there is nothing else.

Choosing safe defaults

The default for a new, unfinished feature should be off, so a failure never exposes something half-built. The default for a protective switch should be its protective state. The default for a setting such as a page size should be the number the app used before the flag existed. Defaults are what users see in the worst moment, so choose them as if the worst moment will come.

Startup behaviour

Decide in advance what the app does while waiting for flags at launch. There are three common choices. Show the interface at once using cached flags or defaults, and update later. Wait a very short time for fresh flags, then continue regardless. Or hold the screen until flags arrive, which is risky on slow networks. Most teams choose the first or second.

flowchart TD
    L["App launches"] --> W{"Fresh flags arrive within the short wait?"}
    W -->|"Yes"| F["Use fresh flags"]
    W -->|"No"| C{"Cached flags exist?"}
    C -->|"Yes"| U["Use cached flags"]
    C -->|"No"| D["Use built-in defaults"]
    F --> G["Continue and keep refreshing"]
    U --> G
    D --> G
    
A launch sequence that never leaves the user staring at a blank screen.
Analogy

A mountain walker carries a printed map, a compass, and a simple rule of thumb such as “follow the stream downhill”. When phone signal fails, the walker is not lost. The printed map is the cache, and the rule of thumb is the default. A good app carries the same layers of backup.

Test it on purpose

Run your app in aeroplane mode, with a slow connection, and with the flag service blocked. If the screen looks wrong, broken, or empty in any of these cases, fix the defaults before users find the problem.

19Reliability on the Server: Start-Up, Staleness, and Failure

Servers face different failures: slow start-ups, silent staleness, and the temptation to depend on a remote call.

Start-up

In local evaluation, a server must download the environment document before it can answer. Decide what happens if that first download fails. Options include starting anyway and using defaults until the document arrives, waiting a limited time, or loading a saved copy from a file. For services that must always start, prefer “start with defaults and keep trying”, since a flag service problem should not stop your servers from booting.

Silent staleness

The worst failure for local evaluation is the quiet one: a server whose refresh has stopped working and which keeps using older rules without anyone noticing. Guard against it by recording the age of the document held in memory and alerting when the age is much larger than the refresh interval.

Timeouts for remote calls

If a server uses remote evaluation, every call needs a short timeout and a fallback. A request that hangs ties up a worker, and enough hanging requests will bring the whole service to a halt. A short wait followed by a default answer keeps your service moving.

A circuit breaker for remote use

When remote calls begin to fail, stop making them for a short while and use fallbacks, then test again carefully. This protects your service from wasted waiting, and gives Flagsmith space to recover.

FailureClient-side effectServer-side effectBest protection
Flagsmith unreachableCached or default flags usedLast document used (local) or fallbacks (remote)Defaults, caches, timeouts
Slow responsesDelayed refresh, screen may update lateSlow requests if remoteShort timeouts, local evaluation
Refresh silently failsOld answers on deviceStale rules in memoryMonitor age and alert
Wrong key or environmentDefaults only, or wrong flagsDefaults only, or wrong flagsConfiguration checks at start-up
Analogy

A ship’s navigator who stops receiving radio updates continues with the last known weather chart but does not forget to notice that the chart is getting old. A good server also tracks how old its rulebook is, and raises a flag when the chart has gone stale.

i
Tip

Add a health check to your service that reports the age of the loaded rules. Then your usual monitoring and alerting tools can warn you about stale flags just like they warn you about stale caches of any other kind.

20Special Concerns for Web Browsers

The browser is the most visible client, and it brings its own quirks.

Flicker

If a page draws the old design first and then swaps to the new one when the flag arrives, users see a jarring flash. There are three common cures. You can wait briefly for flags before drawing the interesting part of the page. You can fetch flags on the server and send them inside the page, so the browser already has them. Or you can reuse the previous visit’s cached flags immediately and refresh them behind the scenes. The server-delivered option gives the smoothest result, and is the heart of server-side rendering with flags.

Server-side rendering and hydration

Modern web frameworks often build the first version of a page on the server, then let the browser take over. If the server uses a server-side SDK to read the flags and passes them to the browser as the starting state, the client SDK can begin with correct answers instead of waiting for its own request. This avoids flicker, reduces requests, and keeps the page consistent between the server’s draw and the browser’s draw.

Ad blockers and privacy tools

Some browser extensions block requests to third-party services they consider trackers. A request to a feature flag service can occasionally be caught by such tools. When that happens, the client SDK behaves as if the network failed and falls back to cache or defaults. Reduce the risk by delivering initial flags from your own server, or by routing requests through a domain you own.

Cross-origin rules

Browsers apply rules about which websites may call which services. These rules usually work smoothly with the hosted Flagsmith service. If you self-host, make sure the service allows requests from the addresses of your web pages, otherwise the browser will refuse the calls even though the key is correct.

Storage and consent

Caching flags or an anonymous identifier in the browser means writing to local storage or a cookie. Some regions require user consent for certain kinds of storage. Check with your privacy team how an anonymous identifier should be handled, and what the page should do if the user has declined storage.

sequenceDiagram
    participant B as Browser
    participant W as Your Web Server
    participant S as Server SDK
    participant C as Client SDK
    B->>W: Request the page
    W->>S: Get flags for this visitor
    S-->>W: Flags from memory
    W-->>B: Page plus initial flags
    B->>C: Start client SDK with the initial flags
    C-->>B: Page is correct on the first draw
    C->>C: Refresh later in the background
    
The server hands the browser its first set of flags, so the page is right the first time it is drawn.
Analogy

A good restaurant seats you at a table that is already set, rather than bringing the cutlery after you sit down. Passing flags from the server to the browser sets the table before the guest arrives, so the meal begins smoothly.

21Special Concerns for Mobile Apps

Mobile apps are where flags earn their keep, because releases are slow and users update when they please.

Release speed

Putting a new version into an app store takes preparation, review, and then days or weeks for users to update. Some users never update. Flags break this dependence. If the code for a feature already ships inside the app, a flag lets you turn it on, off, or adjust it any time, without waiting for the store.

Many versions in the wild

At any moment, your Production environment is serving flags to several app versions at once. A flag that is safe on the newest version might crash an old one that does not understand it. Send the app version as a trait, and make a segment such as “version at least six”. Attach the new feature to that segment only, so older apps never receive it.

Cold starts and the first launch

On the very first launch there is no cache. Ship the app with sensible built-in defaults, show the interface straight away, and apply fresh flags at a calm moment, such as the next screen or next launch. Avoid blocking the first screen on a network call.

Background and foreground

Phones suspend apps in the background. A good rule is to refresh flags when the app comes to the foreground, but not more often than a sensible limit, such as once every few minutes. This keeps flags reasonably fresh without draining battery or sending a request on every glance at the phone.

Offline use

Test every important flow in aeroplane mode. The last cached flags should keep the app consistent, and nothing should break because a flag could not be fetched.

Mobile concernGood habit
Old app versionsSend the version as a trait and target by version
First launchShip defaults, do not block on the network
Return from backgroundRefresh with a minimum gap between fetches
No signalUse cached flags and defaults
Battery and dataFetch all flags together, avoid constant polling
Store review rulesMake sure flagged code is included and reviewed in the shipped build

Everyday use case: protecting older app versions

A travel app adds a new booking screen in version six. The team creates a segment for version six and above, and attaches the booking flag to that segment. Customers on version five never see a screen their app cannot draw, and nobody sees a crash from a missing feature.

22Serverless Functions and Short-Lived Runtimes

Serverless code is trusted like a server, yet lives for seconds like a page view. That mix needs care.

What serverless means for SDKs

A serverless function starts when a request arrives, may serve a few more requests while it stays warm, and is then shut down. You have no control over exactly when. This is awkward for local evaluation, which assumes a process that lives long enough to download rules once and answer many checks.

The cold-start cost

If every new function instance downloads the full environment document at start-up, you add that download time to the first request, and you multiply downloads by the number of instances. For a large environment, or a function that starts thousands of times an hour, that can be slow and wasteful.

Options

  • Use remote evaluation with a server-side key. Simple, and fine for modest traffic, with a short timeout and a safe default.
  • Create the SDK object outside the request handler. It is then reused for warm invocations, so the document is downloaded only once per instance.
  • Use local evaluation with a long refresh interval. Because the instance may not live long, a background refresh timer may never fire, so rely on the document loaded at start and refresh only when the instance has lived for some time.
  • Bundle a saved copy of the rules. An offline file included in the deployment allows an instance to start with no network call, at the cost of rules that are only as fresh as the last deployment.
  • Put a small shared service in front. A lightweight proxy or cache near your functions answers their requests, so the functions need not talk to Flagsmith directly.
flowchart TD
    FN["Serverless function starts"] --> Q{"Instance already warm?"}
    Q -->|"Yes"| REUSE["Reuse the SDK object and its loaded rules"]
    Q -->|"No"| COLD["Create SDK object"]
    COLD --> LOAD{"Load rules how?"}
    LOAD -->|"From network"| NET["Download environment document"]
    LOAD -->|"From bundled file"| FILE["Read the offline copy"]
    NET --> USE["Answer flag checks"]
    FILE --> USE
    REUSE --> USE
    
Reuse what a warm instance already holds, and choose the cheapest way to load rules on a cold start.
Analogy

A pop-up food stall that sets up for an hour cannot afford to haul in a whole pantry each time. It either brings a small packed box of what it needs, or buys from a shop next door. Serverless functions face the same choice: carry a small bundled copy, or ask a nearby shared service.

!
Warn

Do not create a new SDK object inside the handler for every request. Doing so repeats the set-up and any document download every time, which wastes time and sends many unnecessary requests to Flagsmith.

23Hybrid Architectures: Using Both Families Together

Most real products use both families. The art is in how they cooperate.

Pattern 1: independent clients and servers

The simplest design lets each side talk to Flagsmith on its own. The browser or app uses a client-side SDK for the interface, and your servers use server-side SDKs for back-end behaviour. It is easy to set up. Its weakness is that the two sides can briefly disagree.

Pattern 2: the server decides, the client displays

A back-end service uses a server-side SDK to compute all the flags a particular user needs, and returns them to the app in an ordinary response. The app holds no key for Flagsmith at all. This keeps your rules private, avoids a second network path from the device, and guarantees that the client and server agree, since both come from one decision.

Pattern 3: bootstrap, then refresh

The server hands the page or app its first set of flags, as in server-side rendering. The client SDK starts with those and then takes over, refreshing on its own. This combines instant correctness with ongoing freshness.

Pattern 4: decide at the edge, pass it along

In a system of many services, the first service to receive a request asks for the flags once and passes the results along inside the request, so each downstream service uses the same answers. This reduces calls and prevents inconsistent behaviour within a single request.

flowchart LR
    APP["Web or Mobile App"] -->|"Ask for my flags"| BFF["Your Back-End Service with server SDK"]
    BFF -->|"Local evaluation"| MEM["Rules in memory"]
    BFF -->|"Only the flags this user needs"| APP
    BFF -->|"Refresh with server key"| FS["Flagsmith"]
    
The app never holds a Flagsmith key. Your service decides, and returns only the answers needed.
PatternStrengthWeaknessGood for
Independent client and serverSimple to startShort disagreements possibleSmall products
Server decides, client displaysPrivate rules, consistent answersNeeds a back-end endpointApps with sensitive rules
Bootstrap then refreshNo flicker, ongoing updatesMore moving partsServer-rendered websites
Decide at the edgeConsistency across servicesMust pass context carefullyMicroservice systems
Analogy

A newsroom has reporters in the field and editors at the desk. In one style, each reporter phones the library separately to check facts. In another, the desk checks everything once and gives reporters the final briefing. The second style takes more organisation, but the story is consistent from first line to last.

24How to Choose: A Decision Guide

Three questions settle most choices.

Question one: where does the code run?

If it runs in a browser or on a user’s device, you must use a client-side SDK, with the public key. If it runs on your own machines, you should use a server-side SDK, with the secret key. This question alone usually decides the family.

Question two: does it serve many users or one?

A process that handles many users, such as a web back-end, wants an SDK that can take an identity for each check and, ideally, evaluate locally. A process that represents one user, such as an app on one phone, wants an SDK that holds one identity and caches its answers.

Question three: can the rules be shown to the caller?

If the rules include anything you would not want a customer or competitor to see, the caller must not receive them. That means remote evaluation for anything outside your control, and local evaluation only on trusted servers.

flowchart TD
    A["Where does the code run?"] --> B{"Machine you control?"}
    B -->|"No: browser or device"| C["Client-side SDK with public key"]
    B -->|"Yes: your server"| D{"High traffic or many checks per request?"}
    D -->|"Yes"| E["Server-side SDK with local evaluation"]
    D -->|"No"| F["Server-side SDK with remote evaluation is fine"]
    C --> G{"Must the rules stay private and the answers consistent with the back-end?"}
    G -->|"Yes"| H["Let your server decide and pass the answers down"]
    G -->|"No"| I["Client SDK talking to Flagsmith directly"]
    
A short path from “where does my code run” to a sensible SDK choice.
SituationSuggested choiceWhy
Single-page web app showing or hiding screensClient-side SDK, ideally bootstrapped from the serverFast interface updates, no secrets in the page
Native mobile appClient-side SDK with cache and defaultsRuns on the device, must work offline
High-traffic API serviceServer-side SDK, local evaluationInstant checks, minimal load
Background worker or batch jobServer-side SDKTrusted, no interface needed
Serverless functionServer-side SDK, remote or bundled rulesShort-lived process
App with confidential pricing rulesServer decides and returns answersRules never reach the device
Marketing website with simple bannersClient-side SDK or server-rendered flagsLow risk, easy to set up
i
Tip

When in doubt, favour the more private option. It is easy to move a decision from the server to the client later if the rule turns out to be harmless. It is much harder to take back rules that were already delivered to thousands of devices.

25Consistency Across Many Services and Screens

When one product is made of many pieces, every piece must tell the same story about a flag.

The problem

A single user action may touch the browser, a gateway, several back-end services, and a notification system. If each asks Flagsmith separately, at slightly different moments, they might receive different answers around a change. The user then sees a page that promises one thing and a receipt that says another.

One decision per request

The usual cure is to decide once, at the earliest trusted point, and pass the answer along. A gateway or first service reads the flags for the user, then attaches them to the request context. Later services read from the context instead of asking again. This also removes repeated calls and makes the whole request behave as one unit.

One identity everywhere

Every part must use the same identifier for the same person. Mixed identifiers split one user into several in Flagsmith, so rollout buckets and segment matches differ between parts.

Sequence the change safely

When a rollout needs both new client code and new server code, deploy code that understands the new behaviour everywhere first, and only then turn the flag on. Flipping the flag before every copy is ready means some copies receive a setting they cannot handle.

1

Deploy the back-end code

Ship the new server behaviour behind the flag while the flag is still off.

2

Release the front-end or app

Ship the client code that can display the feature, still behind the flag.

3

Wait for adoption

For mobile apps, wait until enough users have the new version, or target by app version.

4

Turn the flag on gradually

Start with staff, then a small share of users, and widen while watching your graphs.

Analogy

When a country switches from driving on one side of the road to the other, every road sign, bus, and traffic light must be ready before the switch, and then everything changes at the same agreed moment. Flipping a flag before all the parts are ready is like switching sides while half the signs still point the old way.

26Testing Each Kind of SDK

Flags add paths through your code, and each path deserves a test.

Test both sides of every flag

Every flag creates two versions of your product, one with the feature on and one with it off. Both reach real users at some point. A common mistake is to test only the new path and then discover that turning the flag off breaks the old one.

Do not depend on the live service in unit tests

Automated tests should be repeatable and fast. Use the offline mode of a server SDK, or a small fake that returns exactly the flag values the test needs. Tests that call the real service are slower, can fail for unrelated reasons, and may change as people edit flags.

Client-side testing

  • Run interface tests with flags forced on and forced off, and check that both screens look right.
  • Test the first launch with no cache and no network.
  • Test a change of identity, such as logging in, and confirm the screen updates sensibly.
  • Test with an old cached set of flags, to see what a long-absent user would see.

Server-side testing

  • Test with the document loaded, with a stale document, and with no document and defaults only.
  • Test that behaviour is correct for users in and out of each segment you rely on.
  • Test that start-up works when the flag service is unreachable.

Keep the combinations small

Two flags make four combinations, and five flags make thirty-two. You cannot test them all, so keep flags independent where you can, retire them quickly, and test the combinations that are meant to occur together.

TestClientServer
Flag on and offYesYes
No networkYes, aeroplane modeYes, blocked path to Flagsmith
Stale dataOld cache on deviceOld document in memory
Identity changeLogin and logoutDifferent users in turn
Slow responseDelayed refreshTimeouts and fallbacks
i
Tip

Add one end-to-end test that runs against a dedicated staging environment with flags set on purpose. It confirms that keys, addresses, and rules really work together, which fakes in unit tests cannot prove.

27Monitoring and Observability for Both Families

If you cannot see how your SDKs behave, you will learn about problems from your users.

What to watch on servers

  • Document age: how old the rules in memory are. Alert when it is far above the refresh interval.
  • Refresh success rate: how often background downloads succeed.
  • Fallback count: how often defaults were used instead of real answers.
  • Remote call duration and errors: if you use remote evaluation anywhere.
  • Memory size of the document: especially for very large environments.

What to watch on clients

  • Fetch success and time: how often and how fast flags arrive on real devices.
  • Cache hit rate: how often screens start with saved flags.
  • Defaults used: how often the app showed a built-in default.
  • App version spread: which versions are alive in the wild, to guide targeting.

Mark flag changes on your graphs

A flag change is a production change. Send flag-change events to your monitoring tool through webhooks or integrations, so a marker appears on your error and speed graphs at the moment a flag was flipped. When something goes wrong, the first question is “what changed?”, and this answers it in seconds.

Respect privacy in logs

Log the flag name, the result, and timing. Do not log keys, tokens, or personal trait values. On clients, avoid sending detailed flag state to analytics tools beyond what you need for experiments.

flowchart LR
    CL["Client SDKs"] -->|"Fetch time and fallbacks"| MON["Monitoring tool"]
    SV["Server SDKs"] -->|"Document age and refresh results"| MON
    FS["Flagsmith"] -->|"Flag change events"| MON
    MON --> AL["Alerts and dashboards"]
    
Three streams of information in one place make flag problems quick to spot.
Analogy

A good ship’s bridge has a compass, a depth sounder, a weather radio, and a log of every order given to the crew. If the ship goes off course, the captain checks each instrument and then the log of orders. Monitoring your SDKs and your flag changes together gives you the same complete view.

28Anti-Patterns and Common Mistakes

These traps catch teams again and again. Knowing them in advance saves a great deal of pain.

SDK-01Anti-pattern
A server-side key in front-end or mobile code

The key ships to every user. Anyone can download your full rules, which may reveal pricing groups, internal users, and unreleased work.

The fix

Use the client-side key in browsers and apps. Keep the server-side key on servers, in a secrets manager.

SDK-02Anti-pattern
Trusting a client-side flag for security

A hidden button is not a locked door. A user can reveal it, call your API directly, or edit cached flags.

The fix

Enforce permissions on the server for every sensitive action, whatever the client shows.

SDK-03Anti-pattern
Creating a new SDK object for every request

On a server, building a new SDK object for each request repeats start-up work, defeats caching, and floods Flagsmith with requests.

The fix

Create one SDK object when the process starts and share it across all requests.

SDK-04Anti-pattern
No defaults and no timeouts

When the service is slow or unreachable, the app hangs or shows broken screens.

The fix

Give every flag a safe default, set short timeouts, and test the failure path on purpose.

SDK-05Anti-pattern
Fetching on every screen

An app that fetches flags each time any screen opens wastes battery and data, and multiplies traffic by the number of users.

The fix

Fetch at launch and on return from background, with a minimum gap, and read from memory in between.

More mistakes to avoid

  • Using different identifiers in different places. The same person is then treated as several people.
  • Pointing a test app at the Production key. It is an easy way to flip real flags by accident.
  • Letting local evaluation go stale unnoticed. Monitor the age of the rules.
  • Putting secrets in flag values. Any value sent to a client can be read.
  • Sending sensitive personal traits. Use simple categories and internal IDs.
  • Flicker from late flags. Pass initial flags from the server, or use cache and defaults.
  • Ignoring old app versions. Target new features only at versions that can handle them.

29Best Practices Checklist

If you keep only one page of this guide, keep this one.

Keys

Public on the client, secret on the server

Check every build and repository to make sure the secret never leaves your servers.

Keys

One key per use

Separate keys for each environment and service, so one leak has a small reach.

Decisions

Show on the client, allow on the server

Use client flags for interface and server checks for permissions.

Speed

Local evaluation for busy servers

Cut traffic and latency by answering checks in memory.

Speed

Cache on the device

Start from saved flags and refresh quietly in the background.

Reliability

Safe defaults everywhere

Every flag has a built-in answer for the worst moment.

Reliability

Timeouts and circuit breakers

Never let a slow flag service slow your product.

Consistency

Decide once, pass it on

Choose at the first trusted point and hand the answers down.

Identity

One identifier format

The same ID on the client and on every server.

Privacy

Send the minimum

Simple categories and internal IDs, never sensitive details.

Visibility

Watch ages and fallbacks

Monitor document age, fetch success, and defaults used, and mark flag changes on graphs.

Hygiene

Remove flags when done

Release flags should be short-lived; delete them and their code after launch.

Put the secrets and the heavy lifting on the server. Put only the final, limited answer in front of the user.

30Real-World Usage Scenarios

Common ways teams put the two families to work. These describe general practices, not any named customer.

An online store releasing a new checkout

The checkout page shows a new design on the client, driven by a client-side flag bootstrapped from the server so there is no flicker. The payment code on the server checks the same flag locally to choose the new payment provider. A small group goes first, and the audience is widened step by step. If errors rise, the flag is switched off and servers pick up the change within a minute, while pages follow on their next refresh.

A mobile app with a beta programme

Customers who opted in to early access are matched by a trait. The client SDK in the app fetches flags at launch and on return from the background, no more than once every few minutes. New screens appear for the beta group only, and only on app versions that can display them.

A streaming service with a kill switch

An optional recommendation row calls a heavy back-end service. During a traffic spike, an engineer switches off the row with one click. Servers using local evaluation pick up the change at their next refresh, and the main video playback is unaffected.

A confidential pricing experiment

A company tests two pricing layouts. The rules and variations are too sensitive to hand to the browser, so the back-end uses a server-side SDK to decide which layout each visitor gets, and sends only the chosen layout to the page. Competitors who inspect the page see one layout, never the experiment design.

Scheduled jobs and workers

A nightly billing job checks a flag to decide whether to use a new tax calculation. It is trusted code on a server, uses the server-side SDK, and loads the rules once at the start of the run.

A marketing site with seasonal banners

A simple site changes its banner text and colours using remote config values. A client-side SDK is perfectly adequate, since nothing sensitive is involved and the main goal is to let the marketing team change content without a deployment.

31Advantages, Disadvantages, and Trade-offs

Neither family is better in every way. Each one gives something up to gain something else.

Client-side: advantages

  • Public key, safe to place in pages and apps.
  • Personalised interface for the one user in front of it.
  • Can update the screen without a new release.
  • Works offline from cached answers.
  • Rules never reach the device, only the user’s own results.

Client-side: disadvantages

  • Everything it receives can be read and changed by the user.
  • A network request at start-up and refresh, multiplied by every device.
  • Answers may be stale on devices that rarely refresh.
  • Flicker and ad-blocker issues in browsers.
  • Cannot be the sole guard for anything sensitive.

Server-side: advantages

  • Trusted environment, so it can hold the secret key.
  • Local evaluation gives near-instant checks and tiny load on Flagsmith.
  • Keeps working through short network failures.
  • Can supply trustworthy traits from your own data.
  • Real permission checks can sit right next to flag checks.

Server-side: disadvantages

  • The secret key must be guarded with care.
  • Local mode holds all rules in the memory of every process.
  • Changes take up to one refresh interval to arrive.
  • Awkward in very short-lived serverless runtimes.
  • Cannot, by itself, change what an already-open screen shows.

The big trade-offs in plain words

ChoiceYou gainYou give up
Remote evaluationPrivate rules, latest answersA network trip for each fresh answer
Local evaluationSpeed and tiny loadInstant freshness, and rules held in server memory
Client decides displayResponsive, personal interfaceTrust in what is shown
Server decides, client displaysPrivate rules and consistencyAn extra back-end endpoint and a little more work
Long refresh intervalFewer requestsSlower arrival of changes
Short refresh intervalFaster changesMore requests and more load
Analogy

Choosing between the families is like choosing between a loudspeaker and a private phone call. The loudspeaker, the client path, reaches many listeners cheaply, but everyone nearby hears it. The private call, the server path, carries confidential details safely, but each call needs a line and a person on it. A wise team uses both for what each does best.

32Moving a Decision from the Client to the Server

Many teams start with client-side flags and later discover that some decisions belong on the server. Here is how to move them calmly.

Why you might move

  • A rule has become sensitive, such as pricing or a partner deal.
  • A feature needs real protection, not just hiding.
  • The client and server keep disagreeing about a flag.
  • Client traffic is growing and costing more than expected.
  • Flicker or ad blockers are hurting the experience.

A safe path

1

List the flags the client reads

Group them into decorative flags, which can stay, and sensitive or important ones, which should move.

2

Add a server endpoint

Create a back-end route that uses a server-side SDK and returns the flags for the current user.

3

Run both in parallel

Let the client read from the new endpoint while logging any disagreement with the old direct path.

4

Switch over

When the two agree for a good period, make the endpoint the only source of flags for the client.

5

Remove the client key

Take the Flagsmith client from the front end, delete its key from the build, and add server checks for any sensitive action.

flowchart LR
    BEFORE["Before: app talks to Flagsmith directly"] --> STEP["Add back-end endpoint and compare answers"]
    STEP --> AFTER["After: app asks your back-end, which asks Flagsmith"]
    
The change in shape: your own back-end becomes the single place that talks to Flagsmith.

The opposite move

Sometimes a team over-builds and puts a back-end call behind every harmless decorative flag. If a flag only changes the colour of a banner, the added work may not be worth it. Keep simple, low-risk flags on the client, where they are cheap and quick, and reserve the server for decisions that need trust.

i
Tip

While you migrate, keep a short document listing every flag, which side reads it, and why. It becomes a handy map of your system, and it shows at a glance which flags carry real risk.

33Troubleshooting Guide

When something looks wrong, start with the symptom and work towards the cause.

SymptomLikely causeWhat to check
Client gets only default valuesWrong key, wrong environment, or blocked requestWhich key is configured, and whether the request reaches Flagsmith in the network tool
Segment rules never apply on the clientNo identity or traits sentThe identity is set before flags are read, and traits are included
Segment rule fails to matchTrait missing, misspelled, or wrong typeTrait name and case, and number versus text
Server cannot load the environment documentClient-side key used on a serverUse the server-side key for local evaluation
Dashboard change not seen on serversRefresh interval has not elapsed, or refresh is failingDocument age, refresh logs, and the interval setting
Dashboard change not seen in the appCached flags, no refresh, or an older app versionWhen the app last fetched, refresh rules, and app version
Client and server disagreeDifferent timing, different identities, or tamperingSame identifier format, timing of last refresh, and server-side enforcement
Page flickers from old to new designFlags arrive after the first drawBootstrap flags from the server, or use cache and defaults
Browser blocks flag requestsAd blocker or cross-origin ruleNetwork errors, extensions, and allowed origins on a self-hosted service
Many requests to Flagsmith from serversNew SDK object per request, or remote evaluation per checkCreate one SDK object per process and use local evaluation
Serverless function is slow on first callDownloading rules on cold startReuse the SDK object, bundle a saved copy, or use a shared proxy
Rollout percentage seems unevenIdentifier not stable or not uniqueUse a stable, unique ID, not a changing value

A calm routine for any problem

  1. Check what changed. Read the audit log and the recent deployments first.
  2. Confirm the basics. Right key kind, right environment, right identity, right address.
  3. Find which side is wrong. Compare what the client shows with what the server believes.
  4. Reproduce in isolation. Make a simple request outside your app and compare the answer.
  5. Fix, then add a guard. Add a log, an alert, or a test so the same problem is caught sooner next time.

34Glossary of Terms

Every important word in this guide, in one place.

TermMeaning
SDKA ready-made library that lets your application talk to Flagsmith without writing raw web requests.
Client-side SDKAn SDK for code running in browsers and on user devices, using the public key.
Server-side SDKAn SDK for code running on servers you control, using the secret key.
Environment keyThe credential that identifies which environment an SDK is reading.
Client-side keyA public environment key, safe to ship in pages and apps.
Server-side keyA secret environment key that can download full rules; for servers only.
Remote evaluationFlagsmith decides the answer and returns it to the SDK.
Local evaluationThe SDK decides the answer itself, from a downloaded copy of the rules held in memory.
Environment documentA complete snapshot of an environment’s features, segments, and rules.
IdentityA unique ID for one user, device, or account.
TraitA named fact about an identity used by segment rules.
SegmentA reusable group of identities defined by rules over traits.
Default valueThe answer used when no real answer is available.
CacheA saved copy of answers kept for quick reuse.
Refresh intervalHow often an SDK fetches newer data.
Offline modeAn SDK mode that reads flags from a stored file instead of the network.
BootstrappingGiving a client SDK its first set of flags from the server, so the page is right on first draw.
FlickerA visible flash from an old interface to a new one when flags arrive late.
Serverless functionCode that runs on demand in a short-lived environment managed by a cloud provider.
Cold startThe first run of a new function instance, before it has anything loaded.
Circuit breakerLogic that stops calling a failing service for a while so it can recover.
Kill switchAn operational flag used to quickly turn off a failing or costly feature.
Eventual consistencyThe property that all parts of a system will agree after a short delay.
Least privilegeGiving each credential only the power it needs and no more.

35Frequently Asked Questions

Q1What is the single biggest difference between the two SDK families?
Trust. Client-side SDKs run on devices you do not control and use a public key. Server-side SDKs run on machines you control and use a secret key that can download your full rules.
Q2Is it safe to put the client-side key in my website or app?
Yes, that is what it is designed for. It cannot download your rules or change anything. Just remember that any flag value sent to the client can be read, so never put secrets in values.
Q3What happens if I use the server-side key in the browser by mistake?
Anyone can read it and download your complete rules. Treat it as stolen: create a new key, update your servers, and revoke the old one right away.
Q4Can one language have both a client and a server SDK?
Yes. JavaScript is the common example: one SDK for browsers, and another for servers running JavaScript. Pick the one that matches where the code runs, not the language.
Q5What is local evaluation and who can use it?
Local evaluation lets a server SDK download the rules and answer checks from memory. It needs a server-side key, so it is for trusted servers, not for browsers or user devices.
Q6How quickly do changes reach each kind of SDK?
Server SDKs using remote evaluation see changes on the next request. Servers in local mode see them at the next refresh, often within about a minute by default. Client SDKs see them at the next fetch, which depends on your refresh rules, or sooner if live updates are available and enabled for your SDK and plan.
Q7Do I need both kinds of SDK?
Many products do, because they have both interfaces and back-ends. A simple option is to let your back-end decide and send the answers to the app, so the app needs no Flagsmith key at all.
Q8Why does my segment rule work on the server but not on the client?
Usually the client was not given an identity, or the traits differ between the two. Make sure the same identifier and the same trait names and types are used on both sides.
Q9How do I stop my page from flickering?
Pass the initial flags from the server inside the page, so the client SDK starts with them. Or reuse cached flags immediately and refresh in the background.
Q10What should I do in serverless functions?
Create the SDK object outside the request handler so warm instances reuse it, and consider remote evaluation, a bundled offline copy of the rules, or a shared proxy to avoid downloading the full document on each cold start.
Q11How can I reduce the number of requests my apps make?
On servers, use local evaluation and share one SDK object. On clients, fetch at launch and on return from the background with a minimum gap, cache flags on the device, and fetch all flags together.
Q12Can I use a flag to protect an admin page?
Use it to hide the link, but protect the page and its API with real permission checks on the server. A flag decides what is shown. Authorisation decides what is allowed.
Q13What if Flagsmith is unreachable?
Clients use cached or default values. Servers in local mode keep using the last document, and servers in remote mode use fallbacks. Safe defaults and short timeouts are what make this work smoothly.
Q14Where can I find the exact setup steps for my language?
In the current Flagsmith SDK documentation for your language. Options and features differ between SDKs and change over time, so treat the documentation as the final word.

36Summary and Key Takeaways

Flagsmith gives you two families of SDKs because there are two very different kinds of place where your code can run. Client-side SDKs live where you cannot control the machine, so they use a public key, receive only their own user’s answers, and rely on caches and defaults. Server-side SDKs live where you can, so they hold a secret key, can carry the full rules in memory, and answer in a fraction of a moment. The best designs use each for what it does well, and let the server have the final word on anything that matters.

Key Takeaways

  • Choose by where the code runs: browsers and devices use client-side SDKs; your own servers use server-side SDKs.
  • Keys decide power: the client-side key is public and limited; the server-side key is secret and can download all rules. Never ship the secret one to users.
  • Remote versus local evaluation: clients ask Flagsmith to decide; busy servers can download the rules and decide in memory, cutting latency and load dramatically.
  • Show on the client, allow on the server: a client flag changes what is displayed; real permissions must be checked on the server every time.
  • Plan for failure: use caches, safe defaults, short timeouts, and monitor the age of the rules so staleness never goes unnoticed.
  • Keep everything consistent: use one identifier format, decide once and pass answers along, and turn flags on only after all the code that needs them is deployed.
  • Mind the special cases: bootstrap flags from the server to avoid flicker, target by app version for mobile, and reuse the SDK object in serverless functions.