[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"navigation":3,"url-settings":86,"blog-\u002Fblog\u002Ffeature-toggles-react-frontends-flagsmith":671,"blog-author-\u002Fblog\u002Ffeature-toggles-react-frontends-flagsmith":1327,"i-material-symbols:arrow-back-rounded":1342},{"id":4,"extension":5,"footer":6,"header":73,"meta":83,"stem":84,"__hash__":85},"navigation\u002Fdata\u002Fshared\u002Fnavigation.yml","yml",{"brand":7,"columns":13,"legal":63},{"name":8,"tagline":9,"downloadCta":10},"Pieces","The memory layer for modern work.",{"label":11,"href":12},"All downloads","\u002Fdownloads",[14,26,39,51],{"title":15,"links":16},"Product",[17,20,23],{"label":18,"href":19},"Pieces Desktop","\u002F",{"label":21,"href":22},"Pieces Enterprise","\u002Fenterprise",{"label":24,"href":25},"Pieces MCP","\u002Fmcp",{"title":27,"links":28},"Resources",[29,33,36],{"label":30,"href":31,"external":32},"Documentation","url:docs.home",true,{"label":34,"href":35},"Blog","\u002Fblog",{"label":37,"href":38,"external":32},"GitHub","url:github.org",{"title":40,"links":41},"Community",[42,45,48],{"label":43,"href":44,"external":32},"Discord","url:social.discord",{"label":46,"href":47,"external":32},"X \u002F Twitter","url:social.x",{"label":49,"href":50,"external":32},"LinkedIn","url:social.linkedin",{"title":52,"links":53},"Company",[54,57,60],{"label":55,"href":56},"About","\u002Fabout",{"label":58,"href":59},"Updates","\u002Fupdates",{"label":61,"href":62},"Contact","\u002Fcontact",[64,67,70],{"label":65,"href":66},"Privacy Policy","\u002Flegal\u002Fprivacy",{"label":68,"href":69},"Refund Policy","\u002Flegal\u002Frefund",{"label":71,"href":72},"Terms of Service","\u002Flegal\u002Fterms",{"links":74,"signIn":75,"contact":78,"cta":80},[],{"label":76,"href":77},"Manage account","url:portal.home",{"label":79,"href":62},"Get in touch",{"label":81,"href":82},"Download","url:routes.downloads",{},"data\u002Fshared\u002Fnavigation","XlSALC7vYCXHcmcXnjJViwIZKsqnQWF4bn4o9RrcSBE",{"id":87,"extension":5,"links":88,"meta":668,"stem":669,"__hash__":670},"urlSettings\u002Fdata\u002Fshared\u002Furls.yml",[89,93,97,101,105,109,113,117,121,125,129,133,137,141,145,149,153,157,161,165,169,173,177,181,185,189,192,196,200,204,208,212,216,220,224,228,232,236,240,244,248,252,256,260,264,268,272,276,280,284,288,292,296,300,303,307,311,314,318,322,326,330,334,338,342,346,350,354,358,362,366,370,374,378,382,386,390,394,398,402,406,410,414,418,422,426,430,434,438,442,446,450,454,458,461,465,469,473,477,481,485,488,491,494,497,501,505,508,512,516,520,524,528,532,536,540,544,548,552,556,559,563,567,571,575,579,582,585,588,592,595,599,603,607,611,614,618,622,625,628,631,635,639,643,646,649,652,656,660,664],{"key":90,"label":91,"href":92},"downloads.desktop","Desktop download page","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fdownload",{"key":94,"label":95,"href":96},"downloads.macOS.dmgArm64","macOS DMG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fdmg-arm64\u002Fdownload",{"key":98,"label":99,"href":100},"downloads.macOS.dmgIntel","macOS DMG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fdmg\u002Fdownload",{"key":102,"label":103,"href":104},"downloads.macOS.pkg","macOS PKG","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg\u002Fdownload",{"key":106,"label":107,"href":108},"downloads.macOS.universal","Desktop macOS Universal","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fmacos-universal\u002Fdownload",{"key":110,"label":111,"href":112},"downloads.macOS.pkgArm64","Desktop macOS PKG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pfd-arm64\u002Fdownload",{"key":114,"label":115,"href":116},"downloads.macOS.pkgIntel","Desktop macOS PKG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pfd\u002Fdownload",{"key":118,"label":119,"href":120},"downloads.windows.appinstaller","Windows App Installer","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fappinstaller\u002Fpieces_for_x.appinstaller",{"key":122,"label":123,"href":124},"downloads.windows.exe","Windows EXE","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fwindows-exe\u002Fdownload",{"key":126,"label":127,"href":128},"downloads.windows.msix","Windows MSIX","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fwindows-msix\u002Fdownload",{"key":130,"label":131,"href":132},"downloads.windows.suiteManager","Windows Suite Manager","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_suite_windows\u002Fappinstaller\u002Fdownload",{"key":134,"label":135,"href":136},"downloads.linux.flatpakRepo","Linux Flatpak repository","https:\u002F\u002Fbuilds.pieces.app\u002Fpieces-flatpak-repo\u002Fpieces-flatpak.flatpakrepo",{"key":138,"label":139,"href":140},"downloads.linux.snapDesktop","Linux Snap Desktop","https:\u002F\u002Fsnapcraft.io\u002Fpieces-for-developers",{"key":142,"label":143,"href":144},"downloads.linux.snapPiecesOS","Linux Snap PiecesOS","https:\u002F\u002Fsnapcraft.io\u002Fpieces-os",{"key":146,"label":147,"href":148},"downloads.linux.snap","Desktop Linux Snap package","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fsnap\u002Fdownload",{"key":150,"label":151,"href":152},"downloads.piecesOS.macOS.dmgArm64","PiecesOS macOS DMG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fdmg-arm64\u002Fdownload",{"key":154,"label":155,"href":156},"downloads.piecesOS.macOS.dmgIntel","PiecesOS macOS DMG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fdmg\u002Fdownload",{"key":158,"label":159,"href":160},"downloads.piecesOS.macOS.universal","PiecesOS macOS Universal","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fmacos-universal\u002Fdownload",{"key":162,"label":163,"href":164},"downloads.piecesOS.macOS.pkgArm64","PiecesOS macOS PKG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pos-launch-only-arm64\u002Fdownload",{"key":166,"label":167,"href":168},"downloads.piecesOS.macOS.pkgIntel","PiecesOS macOS PKG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pos-launch-only\u002Fdownload",{"key":170,"label":171,"href":172},"downloads.piecesOS.windows.appinstaller","PiecesOS Windows App Installer","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fappinstaller\u002Fos_server.appinstaller",{"key":174,"label":175,"href":176},"downloads.piecesOS.windows.exe","PiecesOS Windows EXE","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fwindows-exe\u002Fdownload",{"key":178,"label":179,"href":180},"downloads.piecesOS.windows.msix","PiecesOS Windows MSIX","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fwindows-msix\u002Fdownload",{"key":182,"label":183,"href":184},"downloads.piecesOS.linux.snap","PiecesOS Linux Snap package","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fsnap\u002Fdownload",{"key":186,"label":187,"href":188},"downloads.combined.macOS.appleSilicon","Combined macOS installer Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-arm64\u002Fdownload",{"key":190,"label":191,"href":104},"downloads.combined.macOS.intel","Combined macOS installer Intel",{"key":193,"label":194,"href":195},"downloads.guides.macOS","macOS installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Fmacos-installation-guide",{"key":197,"label":198,"href":199},"downloads.guides.windows","Windows installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Fwindows-installation-guide",{"key":201,"label":202,"href":203},"downloads.guides.linux","Linux installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Flinux-installation-guide",{"key":205,"label":206,"href":207},"downloads.guides.linuxFlatpak","Linux Flatpak installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Flinux-installation-guide\u002Fflatpak",{"key":209,"label":210,"href":211},"downloads.guides.linuxSnap","Linux Snap installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Flinux-installation-guide\u002Fsnap",{"key":213,"label":214,"href":215},"downloads.guides.piecesOS","PiecesOS manual installation","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os\u002Fmanual-installation",{"key":217,"label":218,"href":219},"extensions.chrome","Chrome extension","https:\u002F\u002Fchrome.google.com\u002Fwebstore\u002Fdetail\u002Fpieces-save-code-snippets\u002Figbgibhbfonhmjlechmeefimncpekepm",{"key":221,"label":222,"href":223},"extensions.firefox","Firefox add-on","https:\u002F\u002Faddons.mozilla.org\u002Fen-US\u002Ffirefox\u002Faddon\u002Fpieces-save-code-from-the-web\u002F",{"key":225,"label":226,"href":227},"extensions.edge","Edge add-on","https:\u002F\u002Fmicrosoftedge.microsoft.com\u002Faddons\u002Fdetail\u002Fpieces-save-code-snippet\u002Fhglfimcdgonaeeobjckfdabcldfidmim",{"key":229,"label":230,"href":231},"extensions.vscode","VS Code extension","https:\u002F\u002Fmarketplace.visualstudio.com\u002Fitems?itemName=MeshIntelligentTechnologiesInc.pieces-vscode",{"key":233,"label":234,"href":235},"extensions.visualStudio","Visual Studio extension","https:\u002F\u002Fmarketplace.visualstudio.com\u002Fitems?itemName=MeshIntelligentTechnologiesInc.PiecesVisualStudio",{"key":237,"label":238,"href":239},"extensions.jetbrains","JetBrains plugin","https:\u002F\u002Fplugins.jetbrains.com\u002Fplugin\u002F17328-pieces--save-search-share--reuse-code-snippets",{"key":241,"label":242,"href":243},"extensions.obsidian","Obsidian plugin","https:\u002F\u002Fobsidian.md\u002Fplugins?id=pieces-for-developers",{"key":245,"label":246,"href":247},"extensions.sublime","Sublime package","https:\u002F\u002Fpackagecontrol.io\u002Fpackages\u002FPieces",{"key":249,"label":250,"href":251},"extensions.neovim","Neovim plugin","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fplugin_neo_vim",{"key":253,"label":254,"href":255},"extensions.jupyterlab","JupyterLab plugin","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fjupyterlab-pieces",{"key":257,"label":258,"href":259},"extensions.cli","Pieces CLI","https:\u002F\u002Fpypi.org\u002Fproject\u002Fpieces-cli\u002F",{"key":261,"label":262,"href":263},"docs.home","Documentation home","https:\u002F\u002Fdocs.pieces.app",{"key":265,"label":266,"href":267},"docs.getStarted","Get started docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces",{"key":269,"label":270,"href":271},"docs.api","API docs","https:\u002F\u002Fdocs.pieces.app\u002Fapi",{"key":273,"label":274,"href":275},"docs.desktop.overview","Desktop overview","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop",{"key":277,"label":278,"href":279},"docs.desktop.onboarding","Desktop onboarding","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fonboarding",{"key":281,"label":282,"href":283},"docs.desktop.timeline","Desktop timeline docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Ftimeline",{"key":285,"label":286,"href":287},"docs.desktop.summaries","Desktop summaries docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fsingle-click-summaries",{"key":289,"label":290,"href":291},"docs.desktop.search","Desktop conversational search docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fconversational-search",{"key":293,"label":294,"href":295},"docs.desktop.drive","Desktop drive docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fdrive",{"key":297,"label":298,"href":299},"docs.desktop.account","Desktop account settings docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fconfiguration\u002Faccount",{"key":301,"label":302,"href":92},"docs.desktop.download","Desktop download docs",{"key":304,"label":305,"href":306},"docs.piecesOS.overview","PiecesOS overview docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies",{"key":308,"label":309,"href":310},"docs.piecesOS.details","PiecesOS details docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os",{"key":312,"label":313,"href":215},"docs.piecesOS.install","PiecesOS install docs",{"key":315,"label":316,"href":317},"docs.piecesOS.quickMenu","PiecesOS quick menu docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os\u002Fquick-menu",{"key":319,"label":320,"href":321},"docs.piecesOS.storage","On-device storage docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fon-device-storage",{"key":323,"label":324,"href":325},"docs.piecesOS.troubleshooting","PiecesOS troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os\u002Ftroubleshooting",{"key":327,"label":328,"href":329},"docs.mcp.overview","MCP overview docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp",{"key":331,"label":332,"href":333},"docs.mcp.cursor","MCP Cursor docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fcursor",{"key":335,"label":336,"href":337},"docs.mcp.vscode","MCP VS Code docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fvs-code",{"key":339,"label":340,"href":341},"docs.mcp.claudeDesktop","MCP Claude Desktop docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fclaude-desktop",{"key":343,"label":344,"href":345},"docs.mcp.claudeCode","MCP Claude Code docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fclaude-code",{"key":347,"label":348,"href":349},"docs.mcp.claudeCowork","MCP Claude Cowork docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fclaude-cowork",{"key":351,"label":352,"href":353},"docs.mcp.githubCopilot","MCP GitHub Copilot docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fgithub-copilot",{"key":355,"label":356,"href":357},"docs.mcp.goose","MCP Goose docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fgoose",{"key":359,"label":360,"href":361},"docs.mcp.windsurf","MCP Windsurf docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fwindsurf",{"key":363,"label":364,"href":365},"docs.mcp.zed","MCP Zed docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fzed",{"key":367,"label":368,"href":369},"docs.mcp.jetbrains","MCP JetBrains docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fjetbrains-ides",{"key":371,"label":372,"href":373},"docs.mcp.continueDev","MCP Continue docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fcontinue-dev",{"key":375,"label":376,"href":377},"docs.mcp.cline","MCP Cline docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fcline",{"key":379,"label":380,"href":381},"docs.mcp.raycast","MCP Raycast docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fraycast",{"key":383,"label":384,"href":385},"docs.mcp.rovoDevCli","MCP Rovo Dev CLI docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Frovo-dev-cli",{"key":387,"label":388,"href":389},"docs.mcp.openaiCodexCli","MCP OpenAI Codex CLI docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fopenai-codex-cli",{"key":391,"label":392,"href":393},"docs.mcp.googleGeminiCli","MCP Google Gemini CLI docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fgoogle-gemini-cli",{"key":395,"label":396,"href":397},"docs.mcp.amazonQ","MCP Amazon Q docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Famazon-q-developer",{"key":399,"label":400,"href":401},"docs.mcp.chatgptDev","MCP ChatGPT Developer Mode docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fchatgpt-developer-mode",{"key":403,"label":404,"href":405},"docs.mcp.openclaw","MCP OpenClaw docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fopenclaw",{"key":407,"label":408,"href":409},"docs.mcp.mcpRemote","MCP Remote docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fmcp-remote",{"key":411,"label":412,"href":413},"docs.mcp.ngrok","MCP ngrok docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fngrok-setup",{"key":415,"label":416,"href":417},"docs.troubleshooting.macOS","macOS troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Ftroubleshooting\u002Fmacos",{"key":419,"label":420,"href":421},"docs.troubleshooting.windows","Windows troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Ftroubleshooting\u002Fwindows",{"key":423,"label":424,"href":425},"docs.troubleshooting.linux","Linux troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Ftroubleshooting\u002Flinux",{"key":427,"label":428,"href":429},"docs.privacy","Privacy and security docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fprivacy-security-your-data",{"key":431,"label":432,"href":433},"docs.support","Support docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fsupport",{"key":435,"label":436,"href":437},"portal.home","Pieces portal","https:\u002F\u002Fportal.pieces.app",{"key":439,"label":440,"href":441},"site.home","Website home","https:\u002F\u002Fpieces.app",{"key":443,"label":444,"href":445},"site.about","About page","https:\u002F\u002Fpieces.app\u002Fabout",{"key":447,"label":448,"href":449},"site.features","Features page","https:\u002F\u002Fpieces.app\u002Ffeatures",{"key":451,"label":452,"href":453},"site.plugins","Plugins page","https:\u002F\u002Fpieces.app\u002Fplugins",{"key":455,"label":456,"href":457},"site.contact","Contact page","https:\u002F\u002Fpieces.app\u002Fcontact",{"key":459,"label":58,"href":460},"site.updates","https:\u002F\u002Fpieces.app\u002Fupdates",{"key":462,"label":463,"href":464},"site.news","News","https:\u002F\u002Fpieces.app\u002Fnews",{"key":466,"label":467,"href":468},"site.events","Community events","https:\u002F\u002Fpieces.app\u002Fcommunity\u002Fevents",{"key":470,"label":471,"href":472},"site.userStories","User stories","https:\u002F\u002Fpieces.app\u002Fuser-stories",{"key":474,"label":475,"href":476},"site.academy","Academy","https:\u002F\u002Fpieces.app\u002Flearn\u002Facademy",{"key":478,"label":479,"href":480},"site.support","Website support","https:\u002F\u002Fpieces.app\u002Fsupport",{"key":482,"label":483,"href":484},"site.standup","Standup","https:\u002F\u002Fpieces.app\u002Fstandup",{"key":486,"label":34,"href":487},"site.blog","https:\u002F\u002Fcode.pieces.app\u002Fblog",{"key":489,"label":43,"href":490},"social.discord","https:\u002F\u002Fdiscord.gg\u002Fgetpieces",{"key":492,"label":46,"href":493},"social.x","https:\u002F\u002Fx.com\u002Fgetpieces",{"key":495,"label":496,"href":493},"social.twitter","Twitter",{"key":498,"label":499,"href":500},"social.instagram","Instagram","https:\u002F\u002Fwww.instagram.com\u002Fgetpieces\u002F",{"key":502,"label":503,"href":504},"social.tiktok","TikTok","https:\u002F\u002Fwww.tiktok.com\u002F@getpieces",{"key":506,"label":49,"href":507},"social.linkedin","https:\u002F\u002Fwww.linkedin.com\u002Fcompany\u002Fgetpieces\u002F",{"key":509,"label":510,"href":511},"social.youtube","YouTube","https:\u002F\u002Fyoutube.com\u002F@getpieces",{"key":513,"label":514,"href":515},"github.org","GitHub organization","https:\u002F\u002Fgithub.com\u002Fpieces-app",{"key":517,"label":518,"href":519},"github.support","GitHub support","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fsupport",{"key":521,"label":522,"href":523},"github.issues","GitHub issues","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fsupport\u002Fissues",{"key":525,"label":526,"href":527},"github.discussions","GitHub discussions","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fsupport\u002Fdiscussions",{"key":529,"label":530,"href":531},"github.documentation","GitHub documentation","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fdocumentation",{"key":533,"label":534,"href":535},"github.opensource","GitHub open source","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fopensource",{"key":537,"label":538,"href":539},"github.sdks.python","Python SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-python",{"key":541,"label":542,"href":543},"github.sdks.typescript","TypeScript SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-typescript",{"key":545,"label":546,"href":547},"github.sdks.dart","Dart SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-dart",{"key":549,"label":550,"href":551},"github.sdks.kotlin","Kotlin SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-kotlin",{"key":553,"label":554,"href":555},"github.plugins.obsidian","Obsidian plugin repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fobsidian-pieces",{"key":557,"label":558,"href":255},"github.plugins.jupyterlab","JupyterLab plugin repository",{"key":560,"label":561,"href":562},"github.plugins.sublime","Sublime plugin repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fplugin_sublime",{"key":564,"label":565,"href":566},"github.plugins.neovim","Neovim plugin repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fplugin_neovim",{"key":568,"label":569,"href":570},"github.cliAgent","CLI agent repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fcli-agent",{"key":572,"label":573,"href":574},"github.mcpDart","MCP Dart repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fmcp_dart",{"key":576,"label":577,"href":578},"github.awesomePieces","Awesome Pieces repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fawesome-pieces",{"key":580,"label":581,"href":66},"legal.privacyPolicy","Privacy policy",{"key":583,"label":584,"href":69},"legal.refundPolicy","Refund policy",{"key":586,"label":587,"href":72},"legal.terms","Terms",{"key":589,"label":590,"href":591},"legal.security","Legal security","https:\u002F\u002Fpieces.app\u002Flegal\u002Fsecurity",{"key":593,"label":594,"href":511},"videos.youtubeChannel","YouTube channel",{"key":596,"label":597,"href":598},"videos.gettingStartedDesktop","Getting started desktop video","https:\u002F\u002Fyoutu.be\u002FdUr1lRM_TYk",{"key":600,"label":601,"href":602},"videos.snippetDiscoveryxR","Snippet discovery video","https:\u002F\u002Fyoutu.be\u002FG6vb1USw-30",{"key":604,"label":605,"href":606},"sales.bookACall","Book a sales call","https:\u002F\u002Fcalendar.app.google\u002FWVUDtUfNy5Vst3sH7",{"key":608,"label":609,"href":610},"sales.enterprise","Enterprise form","https:\u002F\u002Fgetpieces.typeform.com\u002Fto\u002FaVQFTvpE",{"key":612,"label":613,"href":527},"sales.feedback","Feedback discussions",{"key":615,"label":616,"href":617},"sales.earlyAccess","Early access form","https:\u002F\u002Fgetpieces.typeform.com\u002Fearlyaccess",{"key":619,"label":620,"href":621},"sales.supportEmail","Support email","mailto:support@pieces.app",{"key":623,"label":624,"href":19},"routes.home","Home route",{"key":626,"label":627,"href":56},"routes.about","About route",{"key":629,"label":630,"href":12},"routes.downloads","Downloads route",{"key":632,"label":633,"href":634},"routes.thanks","Post-install thanks route","\u002Finstall\u002Fthanks",{"key":636,"label":637,"href":638},"routes.pricing","Pricing route","\u002Fpricing",{"key":640,"label":641,"href":642},"cta.freeTrial","Start free trial CTA (Pieces Pro) — used by \u002Fcampaigns\u002F* landing pages","https:\u002F\u002Fcampaigns.pieces.app\u002F",{"key":644,"label":645,"href":22},"routes.enterprise","Enterprise route",{"key":647,"label":648,"href":62},"routes.contact","Contact route",{"key":650,"label":651,"href":59},"routes.updates","Updates route",{"key":653,"label":654,"href":655},"routes.migrationError","Migration error route","\u002Fmigration\u002Ferror",{"key":657,"label":658,"href":659},"routes.authenticated","Post-login authenticated route","\u002Fauth\u002Fsigned-in",{"key":661,"label":662,"href":663},"routes.signed-out","Signed out route","\u002Fauth\u002Fsigned-out",{"key":665,"label":666,"href":667},"routes.authentication-error","Authentication error route","\u002Fauth\u002Ferror",{},"data\u002Fshared\u002Furls","2AvfSWI6bZACH5Kr1ZS3txMLjteRjCjbDR_ul1uRZ9Q",{"id":672,"title":673,"author":674,"authorPhoto":675,"authorPhotoAlt":676,"authorSlug":677,"body":678,"buttonText":1314,"buttonUrl":1314,"category":1315,"date":1316,"description":1317,"draft":1318,"editorsPick":1318,"extension":1319,"featured":1318,"image":1320,"imageAlt":1321,"meta":1322,"navigation":32,"ogImage":1314,"ogImageAlt":1314,"path":1323,"seo":1324,"stem":1325,"tags":1314,"__hash__":1326},"blog\u002Fblog\u002Ffeature-toggles-react-frontends-flagsmith.md","Feature Toggles for React Frontends Using Flagsmith","Gaurav Pasarkar","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Ffeature-toggles-react-frontends-flagsmith\u002Fauthor.jpeg","Gaurav Pasarkar.","gaurav-pasarkar",{"type":679,"value":680,"toc":1295},"minimark",[681,685,690,710,713,720,727,732,735,747,755,761,765,768,774,785,788,807,810,814,821,831,834,838,841,847,850,857,870,880,884,887,893,896,902,909,913,916,922,925,931,945,949,952,960,964,967,984,987,994,997,1000,1004,1012,1018,1021,1024,1030,1033,1044,1059,1065,1068,1074,1080,1089,1096,1099,1102,1107,1109,1114,1117,1123,1126,1132,1135,1141,1144,1147,1153,1156,1162,1176,1181,1184,1188,1191,1197,1200,1206,1209,1216,1223,1229,1236,1245,1253,1256,1264,1267,1272],[682,683,684],"p",{},"Feature Toggles (often also referred to as Feature Flags) are a powerful technique that allows teams to modify system behavior without changing code. They allow you to manage components and compartmentalize risk. But before we jump into the how, let’s take a brief walk into why.",[686,687,689],"h2",{"id":688},"why-use-feature-toggles","Why use Feature Toggles?",[682,691,692,693,700,701,705,706,709],{},"It’s 2023; I don’t have to talk about why you should be using a version control system (",[694,695,699],"a",{"href":696,"rel":697},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FVersion_control",[698],"nofollow","VCS","). That being said, ",[702,703,704],"strong",{},"Git"," is the (almost) obvious choice. In my experience, there are two major strategies for managing ",[702,707,708],{},"Git branches",".",[682,711,712],{},"Git flow is a legacy Git workflow that was originally a disruptive and novel strategy for managing Git branches.",[682,714,715],{},[716,717],"img",{"alt":718,"src":719},"A git flow diagram.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Ffeature-toggles-react-frontends-flagsmith\u002Fimg-001.png",[682,721,722],{},[694,723,726],{"href":724,"rel":725},"https:\u002F\u002Fnvie.com\u002Fposts\u002Fa-successful-git-branching-model\u002F",[698],"Git flow in a nutshell",[728,729,731],"h3",{"id":730},"so-should-everyone-use-git-flow","So, Should Everyone Use Git flow?",[682,733,734],{},"In my experience, Git flow is more suitable for packaged software (a product that you release on occasion).",[682,736,737,738,742,743,746],{},"When you have feature branches, release branches, a master branch, a development branch, a hotfix branch, and git tags, they all have to be tracked, understood and accounted for in your build and release process. More than that, you need to constantly keep track of which branch is which. With ",[739,740,741],"code",{},"git-flow",", the number of things you’re keeping track of increases even more, because there are three other branches (of varying lifetimes) that merge into ",[739,744,745],{},"develop",": feature branches, release branches and hot fixes. Now, the potential for merge conflicts is not linear; these branches potentially triple the opportunities for merge conflicts.",[682,748,749,750,709],{},"If your team is a startup or an internet-facing website or web application, you might have multiple releases in a day. When you’re working at scale, you don't want those merge conflicts to get in the way of delivery. ",[694,751,754],{"href":752,"rel":753},"https:\u002F\u002Fwww.reddit.com\u002Fr\u002Fdevops\u002Fcomments\u002Fg8ktuu\u002Fhow_come_amazon_deploys_23000_times_a_day_what\u002F",[698],"Amazon deploys roughly every 11.6 secs",[682,756,757],{},[716,758],{"alt":759,"src":760},"Comic that says, ","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Ffeature-toggles-react-frontends-flagsmith\u002Fimg-002.jpeg",[728,762,764],{"id":763},"is-there-a-simpler-way","Is There a Simpler Way?",[682,766,767],{},"GitHub flow\u002Ftrunk-based development is a lightweight, branch-based workflow. The GitHub flow is useful for everyone, not just developers.",[682,769,770],{},[716,771],{"alt":772,"src":773},"A GitHub flow diagram.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Ffeature-toggles-react-frontends-flagsmith\u002Fimg-003.png",[682,775,776,777,780,781,784],{},"The primary problem associated with ",[739,778,779],{},"git flow"," is managing long-lived branches. With trunk-based development, we only have one deployable branch, aka ",[739,782,783],{},"master\u002Fmain",". As the other branches are short-lived (literally a few hours), we can achieve continuous integration. So our code is always deployable at any instant. Perfect for web development. Or is it?",[682,786,787],{},"This looks great in theory, but then how do we:",[789,790,791,795,798,801,804],"ul",{},[792,793,794],"li",{},"Develop long-running features?",[792,796,797],{},"Test experiments before rolling them out to everyone?",[792,799,800],{},"Refactor code without breaking everything?",[792,802,803],{},"Do performance improvements without compromising user experience?",[792,805,806],{},"Improve functionality without making it worse?",[682,808,809],{},"The answer is feature toggles. :)",[686,811,813],{"id":812},"how-do-you-use-feature-toggles","How Do You use Feature Toggles?",[682,815,816,817,820],{},"We will be focusing on ",[739,818,819],{},"react-js"," as our authoring view library for managing feature toggles. The simplest implementation of React feature flags is a boolean variable:",[822,823,828],"pre",{"className":824,"code":826,"language":827},[825],"language-text","const flag = true | false\n","text",[739,829,826],{"__ignoreMap":830},"",[682,832,833],{},"This tiny flag will introduce a branch in the code and allow us to render a different component. The concept of a React feature flag really is that simple.",[728,835,837],{"id":836},"scenario-1","Scenario 1",[682,839,840],{},"Let’s say we want to enable certain components only for a specific country. The simplest implementation is as follows:",[682,842,843],{},[716,844],{"alt":845,"src":846},"A code snippet with feature toggles.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Ffeature-toggles-react-frontends-flagsmith\u002Fimg-004.png",[682,848,849],{},"Country-based toggle",[682,851,852],{},[694,853,856],{"href":854,"rel":855},"https:\u002F\u002Fuser-a00e97da-3485-43fd-bbec-75dcb17f675d-fhcmbheklq-uc.a.run.app\u002F?p=50b64e9377",[698],"Save this code",[682,858,859,863,864,863,867],{},[860,861,862],"em",{},"The condition"," ",[739,865,866],{},"user.country === 'IN'",[860,868,869],{},"is essentially a feature toggle.",[682,871,872,873,876,877,709],{},"Evaluating the condition in order to render a component is now a responsibility of ",[739,874,875],{},"MyComponent",". Imagine the scenario wherein multiple components need to change based on country. You can argue that the computation can be abstracted out to a utility method. Something like ",[739,878,879],{},"const isIndia = (user) => user.country === 'IN'",[728,881,883],{"id":882},"scenario-2","Scenario 2",[682,885,886],{},"Let’s say we have a new UX and want user feedback on it. The simplest implementation is as follows:",[682,888,889],{},[716,890],{"alt":891,"src":892},"A code snippet that implements feature toggles.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Ffeature-toggles-react-frontends-flagsmith\u002Fimg-005.png",[682,894,895],{},"Target user-based toggle",[682,897,898],{},[694,899,856],{"href":900,"rel":901},"https:\u002F\u002Fuser-a00e97da-3485-43fd-bbec-75dcb17f675d-fhcmbheklq-uc.a.run.app\u002F?p=07574d9c5d",[698],[682,903,904,905,908],{},"Every time we need to add a user to the set of targeted users, the code needs to change. You can argue that we could fetch the list of users using some API, but the evaluation of the condition viz. ",[739,906,907],{},"targetedUsers.includes(user.id)"," sits in the code.",[728,910,912],{"id":911},"scenario-3","Scenario 3",[682,914,915],{},"Let’s say we have a brand new feature, but the underlying APIs are not completely ready for it to work. We definitely do not want our code to rot in a branch while the APIs are being finished, but we sure as hell cannot release it. Here's how we could implement feature toggles for it:",[682,917,918],{},[716,919],{"alt":920,"src":921},"A React code snippet.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Ffeature-toggles-react-frontends-flagsmith\u002Fimg-006.png",[682,923,924],{},"New feature toggle",[682,926,927],{},[694,928,856],{"href":929,"rel":930},"https:\u002F\u002Fuser-a00e97da-3485-43fd-bbec-75dcb17f675d-fhcmbheklq-uc.a.run.app\u002F?p=cb224bbc9c",[698],[682,932,933,936,937,940,941,944],{},[739,934,935],{},"isBrandNewFeatureEnabled"," is just a boolean flag; it doesn’t need any other variables to be evaluated. Whenever the APIs are ready, we can test the feature in lower environments like ",[739,938,939],{},"qa"," or ",[739,942,943],{},"stage",". When we’re happy with it, turning on the feature toggles in production should be a piece of cake. You can argue that such a small boolean flag can be kept in an environment variable, but updating the environment variable would require a redeployment. :(",[728,946,948],{"id":947},"evaluating-feature-toggles","Evaluating Feature Toggles",[682,950,951],{},"There are many other use cases for feature toggles. The point that I am trying to highlight is that the evaluation criteria of a feature flag can and will be very diverse. Having that logic in the source code just slows us down. Also, any changes to the evaluation criteria have to go into the source code, then via the build pipeline to publish a fresh deployment. You have to think about those odd days when you toggle a feature on and the world breaks down. Would you be willing for your build pipeline to finish the rollback while a rogue feature is out killing your users’ experience? Heck no. You want the ability to turn things off in an instant.",[682,953,954,955,709],{},"We can solve any problem by introducing an ",[694,956,959],{"href":957,"rel":958},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FFundamental_theorem_of_software_engineering",[698],"extra level of indirection",[686,961,963],{"id":962},"feature-toggle-implementation","Feature Toggle Implementation",[682,965,966],{},"To solve this, we’ll delegate the responsibility of managing the lifecycle of feature toggles to an external service. There are two popular implementations for feature flags:",[968,969,970,977],"ol",{},[792,971,972],{},[694,973,976],{"href":974,"rel":975},"https:\u002F\u002Fflagsmith.com\u002F",[698],"Flagsmith",[792,978,979],{},[694,980,983],{"href":981,"rel":982},"https:\u002F\u002Flaunchdarkly.com\u002F",[698],"Launch Darkly",[682,985,986],{},"There are many others, but their underlying methods of integration are roughly the same.",[682,988,989,990,993],{},"Any feature flag service has three main constructs. First, a way to initialize the client SDK which would involve passing the ",[739,991,992],{},"API-key",". Second, a way to identify the user who will then be used for the flag evaluation. Lastly, a way to get the value of the feature flag.",[682,995,996],{},"So, we will create a very thin layer of abstraction. This will allow us to write components without worrying too much about feature toggles. It will also allow us to change to a different feature flag provider without much hassle.",[682,998,999],{},"In this article, we will focus on Flagsmith React. Let's get cracking!",[728,1001,1003],{"id":1002},"setting-up-flagsmith","Setting up Flagsmith",[682,1005,1006,1007,1011],{},"Head over to ",[694,1008,976],{"href":1009,"rel":1010},"https:\u002F\u002Fapp.flagsmith.com\u002Fsignup",[698]," and create an account. We're going to create an Organization and a Project.",[682,1013,1014],{},[716,1015],{"alt":1016,"src":1017},"Creating a project in Flagsmith.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Ffeature-toggles-react-frontends-flagsmith\u002Fimg-007.png",[682,1019,1020],{},"Creating a project in Flagsmith",[682,1022,1023],{},"Next, we will create a simple boolean feature flag to start:",[682,1025,1026],{},[716,1027],{"alt":1028,"src":1029},"Creating feature toggles in Flagsmith.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Ffeature-toggles-react-frontends-flagsmith\u002Fimg-008.png",[682,1031,1032],{},"Creating a feature flag in Flagsmith",[682,1034,1035,1036,1039,1040,1043],{},"Then, we will create a sample app using ",[739,1037,1038],{},"create-react-app"," and add ",[739,1041,1042],{},"react-native-flagsmith"," as a dependency. That's all we need!",[682,1045,1046,1047,1050,1051,1054,1055,1058],{},"To start, we will create our own ",[739,1048,1049],{},"Provider"," using ",[739,1052,1053],{},"provider-pattern"," to encapsulate ",[739,1056,1057],{},"flagsmith",". This should look like this:",[682,1060,1061],{},[716,1062],{"alt":1063,"src":1064},"A Flagsmith code snippet.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Ffeature-toggles-react-frontends-flagsmith\u002Fimg-009.png",[682,1066,1067],{},"Feature flag provider",[682,1069,1070],{},[694,1071,856],{"href":1072,"rel":1073},"https:\u002F\u002Fuser-a00e97da-3485-43fd-bbec-75dcb17f675d-fhcmbheklq-uc.a.run.app\u002F?p=ff444e9b4b",[698],[682,1075,1076,1079],{},[739,1077,1078],{},"REACT_APP_FLAGSMITH_ID"," is a client-specific id that you can use on the URL when you look at features or under environment settings. The default environment is development. In an actual production setup, we will have multiple environments. This way, you can control which features are on\u002Foff across different environments.",[682,1081,1082,1083,1088],{},"There are three things that we are doing here. One, we are allowing Flagsmith to identify the user. For the sake of simplicity, we have mocked the user information; in the real world, we would fetch this user information from some API. We are passing this information to Flagsmith so that we can create ",[694,1084,1087],{"href":1085,"rel":1086},"https:\u002F\u002Fdocs.flagsmith.com\u002Fbasic-features\u002Fmanaging-segments",[698],"user segments"," in the future. This allows us to dynamically enable\u002Fdisable features for certain users based on their attributes. (We’ll get to this later.)",[682,1090,1091,1092,1095],{},"The second thing we are doing is fetching all of the flags that are enabled for this environment. As we have also identified the user before fetching the flags, the response of ",[739,1093,1094],{},"getAllFlags"," is going to be enabled\u002Fdisabled flags for the identified user.",[682,1097,1098],{},"The last thing we are doing here is setting the flag data in a map that can be used by the consumers.",[682,1100,1101],{},"Let's go back a little to this piece of code:",[682,1103,1104],{},[716,1105],{"alt":1106,"src":921},"A React code snippet with feature toggles.",[682,1108,924],{},[682,1110,1111],{},[694,1112,856],{"href":929,"rel":1113},[698],[682,1115,1116],{},"Every component where we do the feature flag evaluation is going to have a similar signature:",[822,1118,1121],{"className":1119,"code":1120,"language":827},[825],"flag === true ? compA : compB1\n",[739,1122,1120],{"__ignoreMap":830},[682,1124,1125],{},"So, the skeleton is duplicated. We end up with unnecessary wrapper components just to branch out. Let's abstract that out in a small utility component.",[682,1127,1128],{},[716,1129],{"alt":1130,"src":1131},"An abstracted utility component.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Ffeature-toggles-react-frontends-flagsmith\u002Fimg-011.png",[682,1133,1134],{},"Feature toggle",[682,1136,1137],{},[694,1138,856],{"href":1139,"rel":1140},"https:\u002F\u002Fuser-a00e97da-3485-43fd-bbec-75dcb17f675d-fhcmbheklq-uc.a.run.app\u002F?p=e39a41942f",[698],[682,1142,1143],{},"All we are doing here is wrapping up the evaluation of feature flags for React. We already have a context provider that has all of the flags, and we’ve added a context consumer to consume those values. The rest is self-explanatory.",[682,1145,1146],{},"Let's see how this all stitches together.",[682,1148,1149],{},[716,1150],{"alt":1151,"src":1152},"A React code snippet that demonstrates feature toggles with Flagsmith.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Ffeature-toggles-react-frontends-flagsmith\u002Fimg-012.png",[682,1154,1155],{},"Everything together",[682,1157,1158],{},[694,1159,856],{"href":1160,"rel":1161},"https:\u002F\u002Fuser-a00e97da-3485-43fd-bbec-75dcb17f675d-fhcmbheklq-uc.a.run.app\u002F?p=331f479f5d",[698],[682,1163,1164,1165,1168,1169,1172,1173,1175],{},"The wrapper component ",[739,1166,1167],{},"FeatureToggle"," makes it easy to add ",[739,1170,1171],{},"Active\u002FInActive"," components. So at any point in the DOM, if we feel like adding a branch, all we do is add the ",[739,1174,1167],{}," component. The rest of the code is isolated from all of the Flagsmith code.",[682,1177,1178],{},[860,1179,1180],{},"As everything is encapsulated, for local environments we can easily switch to using a stub service for feature toggles. I will leave that to your imagination.",[682,1182,1183],{},"The real benefit of a feature flag provider is that we can enable\u002Fdisable flags for certain users. We had parked this a while back— let's pick it back up.",[686,1185,1187],{"id":1186},"implementing-user-segmentation-for-feature-toggles","Implementing User Segmentation for Feature Toggles",[682,1189,1190],{},"Let's take an example wherein we want to enable our feature only for users based in India. Assuming we have the country information as a part of the identification process, this should be straightforward. All we need to do is to create a user segment in Flagsmith.",[682,1192,1193],{},[716,1194],{"alt":1195,"src":1196},"Creating a user segment in Flagsmith.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Ffeature-toggles-react-frontends-flagsmith\u002Fimg-013.png",[682,1198,1199],{},"Creating a user segment",[682,1201,1202],{},[716,1203],{"alt":1204,"src":1205},"Editing a user segment in Flagsmith.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Ffeature-toggles-react-frontends-flagsmith\u002Fimg-014.png",[682,1207,1208],{},"Enabling a feature for a user segment",[682,1210,1211,1212,1215],{},"Now even if the feature is disabled globally, the flag would resolve to ",[739,1213,1214],{},"true"," for all of the users in that user segment. Isn't that cool? And we didn't have to touch a single line of code!",[682,1217,1218,1219,1222],{},"What about those use cases where you don’t have the required attributes to add to Flagsmith for identification? Let’s say we want to enable a feature for all users whose age is ",[739,1220,1221],{},"\u003C18",". As we do not have age as an attribute, we can’t create a segment out of it. This can be achieved as a choreography in two steps. Assuming we have a way to know the age of a particular user that we fetch using our API, all we need to do is update this line of code:",[822,1224,1227],{"className":1225,"code":1226,"language":827},[825],"await flagsmith.identify(user.id, {\nemail: user.email,\ncountry: user.country,\nage: user.age\n});\n",[739,1228,1226],{"__ignoreMap":830},[682,1230,1231,1232,1235],{},"The primary key for a user in Flagsmith is the first attribute of the ",[739,1233,1234],{},"identify"," method. Anytime we add additional traits, Flagsmith auto-merges the identified user. The second step would be to add a user segment and then update the feature flag accordingly.",[682,1237,1238,1239,1244],{},"This should cover the majority of use cases. If you want to perform A\u002FB testing based on the volume of users, that's easy to configure as well. Have a read through the ",[694,1240,1243],{"href":1241,"rel":1242},"https:\u002F\u002Fdocs.flagsmith.com\u002Fadvanced-use\u002Fab-testing",[698],"A\u002FB testing"," documentation.",[686,1246,1248],{"id":1247},"with-great-power-comes-great-responsibility",[694,1249,1252],{"href":1250,"rel":1251},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FWith_great_power_comes_great_responsibility",[698],"With Great Power Comes Great Responsibility",[682,1254,1255],{},"Feature flags in React have a tendency to multiply rapidly, particularly when they are first introduced. They are useful and cheap to create, so we often create many. Feature toggles require a robust engineering process, solid technical design, and mature toggle life-cycle management. Without these three key considerations, the use of feature toggles can be counter-productive.",[682,1257,1258,1259,709],{},"If you don't think this can happen, read about ",[694,1260,1263],{"href":1261,"rel":1262},"https:\u002F\u002Fdougseven.com\u002F2014\u002F04\u002F17\u002Fknightmare-a-devops-cautionary-tale\u002F",[698],"Knight Capital Group's $460 million dollar mistake",[682,1265,1266],{},"Remember that the main purpose of toggles is to perform releases and experiments with minimum risk. Once a release is complete, toggles need to be removed. In order to keep the number of feature flags manageable, a team must be proactive in removing feature flags that are no longer needed. Some teams have a rule of always adding a toggle removal task to the team's backlog when a toggle is first introduced. We can also apply a lean approach to reducing inventory by placing a limit on the number of feature flags a system is allowed to have at any one time. Once that limit is reached, if someone wants to add a new toggle they will first need to do the work to remove an existing flag.",[682,1268,1269],{},[702,1270,1271],{},"References:",[789,1273,1274,1281,1288],{},[792,1275,1276],{},[694,1277,1280],{"href":1278,"rel":1279},"https:\u002F\u002Fmartinfowler.com\u002Farticles\u002Ffeature-toggles.html",[698],"Feature Toggles, aka Feature Flags",[792,1282,1283],{},[694,1284,1287],{"href":1285,"rel":1286},"https:\u002F\u002Fharness.io\u002Fblog\u002Ftrunk-based-development",[698],"Trunk-based Development",[792,1289,1290],{},[694,1291,1294],{"href":1292,"rel":1293},"https:\u002F\u002Fwww.atlassian.com\u002Fcontinuous-delivery\u002Fcontinuous-integration",[698],"Continuous Integration",{"title":830,"searchDepth":1296,"depth":1296,"links":1297},2,[1298,1303,1309,1312,1313],{"id":688,"depth":1296,"text":689,"children":1299},[1300,1302],{"id":730,"depth":1301,"text":731},3,{"id":763,"depth":1301,"text":764},{"id":812,"depth":1296,"text":813,"children":1304},[1305,1306,1307,1308],{"id":836,"depth":1301,"text":837},{"id":882,"depth":1301,"text":883},{"id":911,"depth":1301,"text":912},{"id":947,"depth":1301,"text":948},{"id":962,"depth":1296,"text":963,"children":1310},[1311],{"id":1002,"depth":1301,"text":1003},{"id":1186,"depth":1296,"text":1187},{"id":1247,"depth":1296,"text":1252},null,"Software Development","2022-09-29T00:00:00.000Z","Feature Toggles allow teams to modify system behavior without changing code. Use them to manage components and compartmentalize risk.",false,"md","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Ffeature-toggles-react-frontends-flagsmith\u002Fhero.jpeg","An aerial view of three roads merging into one.",{},"\u002Fblog\u002Ffeature-toggles-react-frontends-flagsmith",{"title":673,"description":1317},"blog\u002Ffeature-toggles-react-frontends-flagsmith","8p1Rsxn9nQrgxMRcsDtYkkegaWkvchLXisWhaPdtRJY",{"id":1328,"title":674,"body":1329,"description":1333,"draft":1318,"extension":1319,"meta":1336,"navigation":32,"path":1337,"photo":1338,"photoAlt":1314,"seo":1339,"stem":1340,"__hash__":1341},"authors\u002Fauthors\u002Fgaurav-pasarkar.md",{"type":679,"value":1330,"toc":1334},[1331],[682,1332,1333],{},"A developer who loves to write code. Loves to write about his experiences \u002F opinions with tech and everything that goes with it.",{"title":830,"searchDepth":1296,"depth":1296,"links":1335},[],{},"\u002Fauthors\u002Fgaurav-pasarkar","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fauthors\u002Fgaurav-pasarkar.jpeg",{"title":674,"description":1333},"authors\u002Fgaurav-pasarkar","-ptraCqVgMs9SHD05mv3aLP4h65qu4Hr8RaGi7q-3Zk",{"left":1343,"top":1343,"width":1344,"height":1344,"rotate":1343,"vFlip":1318,"hFlip":1318,"body":1345},0,24,"\u003Cpath fill=\"currentColor\" d=\"m7.825 13l4.9 4.9q.3.3.288.7t-.313.7q-.3.275-.7.288t-.7-.288l-6.6-6.6q-.15-.15-.213-.325T4.426 12t.063-.375t.212-.325l6.6-6.6q.275-.275.688-.275t.712.275q.3.3.3.713t-.3.712L7.825 11H19q.425 0 .713.288T20 12t-.288.713T19 13z\"\u002F>"]