Skip to content

chore(refactor): use memdb for flag storage#1697

Merged
toddbaert merged 8 commits into
mainfrom
chore/go-memdb-store
Jul 30, 2025
Merged

chore(refactor): use memdb for flag storage#1697
toddbaert merged 8 commits into
mainfrom
chore/go-memdb-store

Conversation

@toddbaert

@toddbaert toddbaert commented Jul 28, 2025

Copy link
Copy Markdown
Member

This PR contains no behavioral changes, and no breaking changes.

It lays the groundwork for some of the upcoming improvements we want in flagd, as specified in recent ADRs. It does this by re-implementing our storage layer to use go-memdb, an open source in-memory database developed by Hashicorp and used in Consul (as well as MANY other projects).

Why?

This will allow us to easily support:

  • duplicate flag keys (namespaced by flagSetId), as mentioned in this ADR
  • robust flag selectors, as mentioned in this ADR, by supporting "watchers" which allow us to "listen" to change in flags returned by a given query 🕺
  • robust (and possibly, in the future, even customizable) indexing on arbitrary attributes (to easily support fetching "all boolean flags", or "flags with metadata = xyz", etc)
  • cross-"table" transactions

I have already PoC'd that these are all practical.

Changes in implementation

  • the store package's State is no longer just a struct; it's a object with methods wrapping the internal db
  • the store package's State was renamed to Store and the file was renamed from flags.go to store.go, since it's ceased to be a simple stateful object, and for consistency
  • a non-serialized (used only internally) Key field was added to the flag type (for indexing)
  • a new constructor for the Store was added which takes a logger and returns an error, the old was deprecated to avoid breaking changes in consumers (the Go flagd provider, mostly)

Note that the go-memdb dependency is MPL2, which is not allowed by the CNCF, however, go-memdb is already used in CNCF projects and has a special exception.

Perfromance

There was no significant change in performance, see benchmark diff vs main below:

Benchmark diff vs main
-BenchmarkFractionalEvaluation/test_c@faas.com-16         	  559051	     13832 ns/op	    7229 B/op	     135 allocs/op
-BenchmarkFractionalEvaluation/test_d@faas.com-16         	  611665	     13106 ns/op	    7229 B/op	     135 allocs/op
-BenchmarkFractionalEvaluation/test_a@faas.com-16         	  383074	     13433 ns/op	    7229 B/op	     135 allocs/op
-BenchmarkFractionalEvaluation/test_b@faas.com-16         	  529185	     12190 ns/op	    7229 B/op	     135 allocs/op
-BenchmarkResolveBooleanValue/test_staticBoolFlag-16      	 3929409	      1712 ns/op	    1008 B/op	      11 allocs/op
-BenchmarkResolveBooleanValue/test_targetingBoolFlag-16   	  812671	     10276 ns/op	    6065 B/op	      87 allocs/op
-BenchmarkResolveBooleanValue/test_staticObjectFlag-16    	 4398327	      1700 ns/op	    1008 B/op	      11 allocs/op
-BenchmarkResolveBooleanValue/test_missingFlag-16         	 4541409	      1494 ns/op	     784 B/op	      12 allocs/op
-BenchmarkResolveBooleanValue/test_disabledFlag-16        	 2998599	      1815 ns/op	    1072 B/op	      13 allocs/op
-BenchmarkResolveStringValue/test_staticStringFlag-16     	 4378830	      1698 ns/op	    1040 B/op	      13 allocs/op
-BenchmarkResolveStringValue/test_targetingStringFlag-16  	  849668	      9165 ns/op	    6097 B/op	      89 allocs/op
-BenchmarkResolveStringValue/test_staticObjectFlag-16     	 4560192	      1363 ns/op	    1008 B/op	      11 allocs/op
-BenchmarkResolveStringValue/test_missingFlag-16          	 5283511	      1196 ns/op	     784 B/op	      12 allocs/op
-BenchmarkResolveStringValue/test_disabledFlag-16         	 4393116	      1446 ns/op	    1072 B/op	      13 allocs/op
-BenchmarkResolveFloatValue/test:_staticFloatFlag-16      	 4264772	      1501 ns/op	    1024 B/op	      13 allocs/op
-BenchmarkResolveFloatValue/test:_targetingFloatFlag-16   	  776436	      8191 ns/op	    6081 B/op	      89 allocs/op
-BenchmarkResolveFloatValue/test:_staticObjectFlag-16     	 4685841	      1285 ns/op	    1008 B/op	      11 allocs/op
-BenchmarkResolveFloatValue/test:_missingFlag-16          	 5001636	      1376 ns/op	     784 B/op	      12 allocs/op
-BenchmarkResolveFloatValue/test:_disabledFlag-16         	 3707120	      1897 ns/op	    1072 B/op	      13 allocs/op
-BenchmarkResolveIntValue/test_staticIntFlag-16           	 3770362	      1677 ns/op	    1008 B/op	      11 allocs/op
-BenchmarkResolveIntValue/test_targetingNumberFlag-16     	  739861	     11142 ns/op	    6065 B/op	      87 allocs/op
-BenchmarkResolveIntValue/test_staticObjectFlag-16        	 4221418	      1913 ns/op	    1008 B/op	      11 allocs/op
-BenchmarkResolveIntValue/test_missingFlag-16             	 4289516	      1488 ns/op	     768 B/op	      12 allocs/op
-BenchmarkResolveIntValue/test_disabledFlag-16            	 4027533	      1829 ns/op	    1072 B/op	      13 allocs/op
-BenchmarkResolveObjectValue/test_staticObjectFlag-16     	 1588855	      3880 ns/op	    2243 B/op	      37 allocs/op
-BenchmarkResolveObjectValue/test_targetingObjectFlag-16  	  562364	     11580 ns/op	    7283 B/op	     109 allocs/op
-BenchmarkResolveObjectValue/test_staticBoolFlag-16       	 5026976	      1791 ns/op	    1008 B/op	      11 allocs/op
-BenchmarkResolveObjectValue/test_missingFlag-16          	 4254043	      1553 ns/op	     784 B/op	      12 allocs/op
-BenchmarkResolveObjectValue/test_disabledFlag-16         	 3051976	      2250 ns/op	    1072 B/op	      13 allocs/op
+BenchmarkFractionalEvaluation/test_a@faas.com-16         	  478593	     14527 ns/op	    7467 B/op	     143 allocs/op
+BenchmarkFractionalEvaluation/test_b@faas.com-16         	  429560	     14728 ns/op	    7467 B/op	     143 allocs/op
+BenchmarkFractionalEvaluation/test_c@faas.com-16         	  574078	     14230 ns/op	    7467 B/op	     143 allocs/op
+BenchmarkFractionalEvaluation/test_d@faas.com-16         	  411690	     15296 ns/op	    7467 B/op	     143 allocs/op
+BenchmarkResolveBooleanValue/test_staticBoolFlag-16      	 4133443	      1973 ns/op	     960 B/op	      18 allocs/op
+BenchmarkResolveBooleanValue/test_targetingBoolFlag-16   	  822934	     10981 ns/op	    6033 B/op	      94 allocs/op
+BenchmarkResolveBooleanValue/test_staticObjectFlag-16    	 3955728	      1964 ns/op	     976 B/op	      18 allocs/op
+BenchmarkResolveBooleanValue/test_missingFlag-16         	 3068791	      2294 ns/op	    1064 B/op	      21 allocs/op
+BenchmarkResolveBooleanValue/test_disabledFlag-16        	 3500334	      2225 ns/op	    1024 B/op	      20 allocs/op
+BenchmarkResolveStringValue/test_staticStringFlag-16     	 3935048	      1781 ns/op	    1008 B/op	      20 allocs/op
+BenchmarkResolveStringValue/test_targetingStringFlag-16  	  770565	     10765 ns/op	    6065 B/op	      96 allocs/op
+BenchmarkResolveStringValue/test_staticObjectFlag-16     	 3896060	      2084 ns/op	     976 B/op	      18 allocs/op
+BenchmarkResolveStringValue/test_missingFlag-16          	 3103950	      2141 ns/op	    1064 B/op	      21 allocs/op
+BenchmarkResolveStringValue/test_disabledFlag-16         	 3717013	      2092 ns/op	    1024 B/op	      20 allocs/op
+BenchmarkResolveFloatValue/test:_staticFloatFlag-16      	 3971438	      2003 ns/op	     976 B/op	      20 allocs/op
+BenchmarkResolveFloatValue/test:_targetingFloatFlag-16   	  782996	     10153 ns/op	    6049 B/op	      96 allocs/op
+BenchmarkResolveFloatValue/test:_staticObjectFlag-16     	 3469644	      2115 ns/op	     976 B/op	      18 allocs/op
+BenchmarkResolveFloatValue/test:_missingFlag-16          	 3376167	      2157 ns/op	    1064 B/op	      21 allocs/op
+BenchmarkResolveFloatValue/test:_disabledFlag-16         	 3610095	      2032 ns/op	    1024 B/op	      20 allocs/op
+BenchmarkResolveIntValue/test_staticIntFlag-16           	 3883299	      1941 ns/op	     960 B/op	      18 allocs/op
+BenchmarkResolveIntValue/test_targetingNumberFlag-16     	  823038	     10725 ns/op	    6033 B/op	      94 allocs/op
+BenchmarkResolveIntValue/test_staticObjectFlag-16        	 3697454	      2028 ns/op	     976 B/op	      18 allocs/op
+BenchmarkResolveIntValue/test_missingFlag-16             	 3326895	      1986 ns/op	    1048 B/op	      21 allocs/op
+BenchmarkResolveIntValue/test_disabledFlag-16            	 3327046	      2142 ns/op	    1024 B/op	      20 allocs/op
+BenchmarkResolveObjectValue/test_staticObjectFlag-16     	 1534627	      4885 ns/op	    2211 B/op	      44 allocs/op
+BenchmarkResolveObjectValue/test_targetingObjectFlag-16  	  509614	     14640 ns/op	    7251 B/op	     116 allocs/op
+BenchmarkResolveObjectValue/test_staticBoolFlag-16       	 3871867	      1978 ns/op	     960 B/op	      18 allocs/op
+BenchmarkResolveObjectValue/test_missingFlag-16          	 3484065	      2080 ns/op	    1064 B/op	      21 allocs/op
+BenchmarkResolveObjectValue/test_disabledFlag-16         	 4013230	      2158 ns/op	    1024 B/op	      20 allocs/op
 PASS
-ok  	github.com/open-feature/flagd/core/pkg/evaluator	233.286s
+ok  	github.com/open-feature/flagd/core/pkg/evaluator	261.212s
 ?   	github.com/open-feature/flagd/core/pkg/evaluator/mock	[no test files]
 PASS
-ok  	github.com/open-feature/flagd/core/pkg/logger	0.003s
+ok  	github.com/open-feature/flagd/core/pkg/logger	0.002s
 ?   	github.com/open-feature/flagd/core/pkg/model	[no test files]
 ?   	github.com/open-feature/flagd/core/pkg/service	[no test files]
 PASS
-ok  	github.com/open-feature/flagd/core/pkg/service/ofrep	0.003s
+ok  	github.com/open-feature/flagd/core/pkg/service/ofrep	0.002s
 PASS
 ok  	github.com/open-feature/flagd/core/pkg/store	0.002s
 ?   	github.com/open-feature/flagd/core/pkg/sync	[no test files]
@@ -51,9 +51,9 @@ PASS
 ok  	github.com/open-feature/flagd/core/pkg/sync/builder	0.020s
 ?   	github.com/open-feature/flagd/core/pkg/sync/builder/mock	[no test files]
 PASS
-ok  	github.com/open-feature/flagd/core/pkg/sync/file	1.007s
+ok  	github.com/open-feature/flagd/core/pkg/sync/file	1.006s
 PASS
-ok  	github.com/open-feature/flagd/core/pkg/sync/grpc	8.014s
+ok  	github.com/open-feature/flagd/core/pkg/sync/grpc	8.013s
 PASS
 ok  	github.com/open-feature/flagd/core/pkg/sync/grpc/credentials	0.004s
 ?   	github.com/open-feature/flagd/core/pkg/sync/grpc/credentials/mock	[no test files]
@@ -61,10 +61,10 @@ ok  	github.com/open-feature/flagd/core/pkg/sync/grpc/credentials	0.004s
 PASS
 ok  	github.com/open-feature/flagd/core/pkg/sync/grpc/nameresolvers	0.002s
 PASS
-ok  	github.com/open-feature/flagd/core/pkg/sync/http	4.008s
+ok  	github.com/open-feature/flagd/core/pkg/sync/http	4.007s
 ?   	github.com/open-feature/flagd/core/pkg/sync/http/mock	[no test files]
 PASS
-ok  	github.com/open-feature/flagd/core/pkg/sync/kubernetes	0.015s
+ok  	github.com/open-feature/flagd/core/pkg/sync/kubernetes	0.016s
 ?   	github.com/open-feature/flagd/core/pkg/sync/testing	[no test files]
 PASS
 ok  	github.com/open-feature/flagd/core/pkg/telemetry	0.016s

@toddbaert toddbaert requested a review from a team July 28, 2025 17:27
@toddbaert toddbaert requested a review from a team as a code owner July 28, 2025 17:27
@netlify

netlify Bot commented Jul 28, 2025

Copy link
Copy Markdown

Deploy Preview for polite-licorice-3db33c canceled.

Name Link
🔨 Latest commit 6a5760c
🔍 Latest deploy log https://app.netlify.com/projects/polite-licorice-3db33c/deploys/68891393495cf000081c827c

@dosubot dosubot Bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Jul 28, 2025
@toddbaert toddbaert force-pushed the chore/go-memdb-store branch 2 times, most recently from cf6b001 to d366b01 Compare July 28, 2025 17:29
Comment thread Makefile
go test -race -covermode=atomic -cover -short ./flagd-proxy/pkg/... -coverprofile=flagd-proxy-coverage.out
flagd-integration-test: # dependent on ./bin/flagd start -f file:test-harness/flags/testing-flags.json -f file:test-harness/flags/custom-ops.json -f file:test-harness/flags/evaluator-refs.json -f file:test-harness/flags/zero-flags.json
go test -cover ./test/integration $(ARGS)
flagd-integration-test-harness:

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just added to make local integration testing easier.

log := logger.NewLogger(nil, false)
je := NewJSON(log, store.NewFlags())
je.store.Flags = tt.flags.Flags
je.store.Update("", "", tt.flags.Flags, model.Metadata{})

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many tests have been updated to not directly mutate the State.

Comment thread core/pkg/model/flag.go
import "encoding/json"

type Flag struct {
Key string `json:"-"`

@toddbaert toddbaert Jul 28, 2025

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New field used for indexing (not serialized).

Any other fields we add here (copies of certain metadata, flag type, etc, etc) could be used for indexing.

@@ -0,0 +1,207 @@
package store

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, the large amount of changes here, plus the file rename from flags_test.go to store_test.go makes this look like a re-write - bot nothing has fundamentally changed - we are just using the public methods now instead of messing with the State struct directly.

@beeme1mr

Copy link
Copy Markdown
Member

/gemini summary

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

This pull request refactors the core flag storage layer to utilize go-memdb, an in-memory database, as a foundational change for future enhancements in flagd. This re-implementation aims to support advanced features like duplicate flag keys, robust flag selectors, and efficient indexing, without introducing any behavioral or breaking changes in the current functionality.

Highlights

  • Storage Layer Re-architecture: The internal flag storage mechanism has been re-implemented to leverage go-memdb, an in-memory database from HashiCorp, replacing the previous map-based State struct. This lays the groundwork for future features like duplicate flag keys, robust selectors, and efficient indexing.
  • API Evolution for Flag Store: The store.State struct has been renamed to store.Store and transformed into an object with methods wrapping the new internal database. A new constructor NewStore is introduced, taking a logger, while the old NewFlags is deprecated.
  • Flag Model Enhancement: A new, non-serialized Key field has been added to the model.Flag type to facilitate indexing within the go-memdb store.
  • Test Suite Adaptation: Existing tests, particularly those interacting with the flag store, have been updated to utilize the new store.Store methods (e.g., Update instead of direct map assignment) and reflect the new internal structure. The flags_test.go file was removed and its functionality migrated to store_test.go.
  • Build and Integration Test Updates: The Makefile includes new targets (flagd-integration-test-harness) to simplify local integration testing, and go.mod/go.sum have been updated to include the new go-memdb and related HashiCorp dependencies.
Changelog
  • Makefile
    • Added flagd-integration-test-harness target for easier local integration test setup.
    • Modified flagd-integration-test to depend on the new harness.
  • core/pkg/evaluator/fractional_test.go
    • Updated flag store initialization and update logic to use store.Update.
  • core/pkg/evaluator/json.go
    • Updated JSON evaluator's store field type from *store.State to *store.Store.
    • Changed NewJSON constructor to accept *store.Store.
    • Modified SetState method to call je.store.Update without passing the logger, as the logger is now part of the Store object.
  • core/pkg/evaluator/json_test.go
    • Adjusted reflect.DeepEqual comparison to match the new structure of gotOutputJSON.
  • core/pkg/evaluator/legacy_fractional_test.go
    • Updated flag store initialization and update logic to use store.Update.
  • core/pkg/evaluator/semver_test.go
    • Updated flag store initialization and update logic to use store.Update.
  • core/pkg/evaluator/string_comparison_test.go
    • Updated flag store initialization and update logic to use store.Update.
  • core/pkg/model/flag.go
    • Added Key field to model.Flag struct for internal indexing within go-memdb.
  • core/pkg/store/flags.go -> core/pkg/store/store.go
    • File renamed from flags.go to store.go.
    • The State struct was renamed to Store and refactored to encapsulate go-memdb.
    • Introduced NewStore constructor for initializing the go-memdb and deprecated NewFlags.
    • Implemented Get, GetAll, and Update methods to interact with the go-memdb.
    • Removed direct Set and Delete methods; these operations are now handled through Update and memdb transactions.
    • Updated method receivers from *State to *Store.
  • core/pkg/store/flags_test.go
    • File removed, as its functionality has been migrated to core/pkg/store/store_test.go.
  • core/pkg/store/store_test.go
    • New test file added to cover the store.Store functionality using go-memdb, including comprehensive tests for flag merging and updates.
  • flagd/go.mod
    • Added new dependencies: github.com/hashicorp/go-memdb, github.com/hashicorp/go-immutable-radix, and github.com/hashicorp/golang-lru.
  • flagd/go.sum
    • Updated checksums for new and modified dependencies.
  • flagd/pkg/runtime/from_config.go
    • Updated to use store.NewStore(logger) instead of store.NewFlags() and added error handling for store creation.
    • Refined error message for OFREP service creation.
  • flagd/pkg/service/flag-sync/sync-multiplexer.go
    • Updated Multiplexer's store field type from *store.State to *store.Store.
    • Changed NewMux constructor to accept *store.Store.
  • flagd/pkg/service/flag-sync/sync_service.go
    • Updated SvcConfigurations's Store field type from *store.State to *store.Store.
  • flagd/pkg/service/flag-sync/sync_service_test.go
    • Updated createAndStartSyncService helper function to accept *store.Store.
  • flagd/pkg/service/flag-sync/util_test.go
    • Updated getSimpleFlagStore helper function to return *store.Store and use store.NewStore and store.Update for flag population.
  • test/integration/README.md
    • Updated instructions for running integration tests to reflect new Makefile targets.
Activity
  • A deploy preview was canceled by netlify[bot].
  • beeme1mr requested a Gemini summary of the pull request.
  • The author, toddbaert, added a comment explaining that a new Makefile target was introduced to simplify local integration testing.
  • The author, toddbaert, clarified that many tests were updated to interact with the flag store via public methods rather than direct struct mutation.
  • The author, toddbaert, noted that the new Key field in the flag type is for internal indexing and is not serialized.
  • The author, toddbaert, explained that the file rename from flags_test.go to store_test.go and the associated changes are a refactor to use public methods, not a fundamental rewrite.

@beeme1mr

Copy link
Copy Markdown
Member

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

An excellent refactoring effort! Switching to go-memdb is a great move for the project's future, and I appreciate the detailed explanation in the pull request description. The changes are extensive, and I've focused my review on ensuring the new implementation is robust and thread-safe.

I've found a couple of critical issues related to error handling and concurrency in the new store.go that need to be addressed. I've also included a minor suggestion for improving a test helper.

Once these points are addressed, this will be a solid foundation for the upcoming features. Great work!

Comment thread core/pkg/store/store.go
Comment thread flagd/pkg/service/flag-sync/util_test.go Outdated
@toddbaert toddbaert requested a review from djosephsen July 28, 2025 18:19
@toddbaert toddbaert force-pushed the chore/go-memdb-store branch 3 times, most recently from 86b98c4 to 3600715 Compare July 28, 2025 18:41
@beeme1mr

Copy link
Copy Markdown
Member

gemini /review

Comment thread core/pkg/store/store.go
Comment on lines +63 to +67
"id": {
Name: "id",
Unique: true,
Indexer: &memdb.StringFieldIndex{Field: "Key", Lowercase: false},
},

@toddbaert toddbaert Jul 28, 2025

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently we just have a simple index on Key, to mimic the previous map behavior, but go-memdb supports all kinds of index types very useful to us, including compound indexes, numeric indexes, conditional indexes, etc. We can use these to great effect.

Note that Lowercase converts the field to lower before building the index - I've disabled this to maintain the previous, case-sensitive behavior, and for consistency with JSON map index behavior.

@toddbaert toddbaert force-pushed the chore/go-memdb-store branch 2 times, most recently from 204768d to 3600715 Compare July 28, 2025 19:29

@aepfli aepfli left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, this looks really cool, and i cant wait to use it. I think it will reduce our internal efforts heavily, as the memdb will offer a lot of flexibility. Thank you

Comment thread core/pkg/store/store.go Outdated
Comment thread core/pkg/store/store.go Outdated
Comment thread flagd/pkg/service/flag-sync/util_test.go Outdated
@toddbaert toddbaert requested a review from erka July 29, 2025 16:56
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
@toddbaert toddbaert force-pushed the chore/go-memdb-store branch from 753a92e to 53fbe0a Compare July 29, 2025 17:01
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
@toddbaert toddbaert force-pushed the chore/go-memdb-store branch from f646491 to 633107a Compare July 29, 2025 17:10
Comment thread core/pkg/store/store.go Outdated
@dosubot dosubot Bot added size:XXL This PR changes 1000+ lines, ignoring generated files. and removed size:XL This PR changes 500-999 lines, ignoring generated files. labels Jul 29, 2025
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
@toddbaert toddbaert force-pushed the chore/go-memdb-store branch from 084123c to 6a5760c Compare July 29, 2025 18:31
@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:XXL This PR changes 1000+ lines, ignoring generated files. labels Jul 29, 2025
@toddbaert toddbaert merged commit 5c5c1cf into main Jul 30, 2025
16 checks passed
@github-actions github-actions Bot mentioned this pull request Jul 30, 2025
toddbaert added a commit that referenced this pull request Dec 24, 2025
🤖 I have created a release *beep* *boop*
---


<details><summary>flagd: 0.13.0</summary>

##
[0.13.0](flagd/v0.12.9...flagd/v0.13.0)
(2025-12-23)


### 🐛 Bug Fixes

* fixing sync return format missing flag layer, adding full e2e suite
([#1827](#1827))
([570693d](570693d))
* **security:** update module github.com/go-viper/mapstructure/v2 to
v2.4.0 [security]
([#1784](#1784))
([037e30b](037e30b))
* **security:** update module golang.org/x/crypto to v0.45.0 [security]
([#1826](#1826))
([7e0762b](7e0762b))


### ✨ New Features

* add support for http-based ofrep metrics
([#1803](#1803))
([fcd19b3](fcd19b3))
* cleanup evaluator interface
([#1793](#1793))
([aa504f7](aa504f7))
* enable parsing of array flag configurations for flagd
([#1797](#1797))
([97c6ffa](97c6ffa))
* multi-project support via selectors and flagSetId namespacing
([#1702](#1702))
([f9ce46f](f9ce46f))
* normalize selector in sync (use header as in OFREP and RPC)
([#1815](#1815))
([c1f06cb](c1f06cb))


### 🧹 Chore

* **refactor:** use memdb for flag storage
([#1697](#1697))
([5c5c1cf](5c5c1cf))


### 🔄 Refactoring

* store cleanup
([#1705](#1705))
([bcff8d7](bcff8d7))
</details>

<details><summary>flagd-proxy: 0.8.1</summary>

##
[0.8.1](flagd-proxy/v0.8.0...flagd-proxy/v0.8.1)
(2025-12-23)


### 🐛 Bug Fixes

* **security:** update module github.com/go-viper/mapstructure/v2 to
v2.4.0 [security]
([#1784](#1784))
([037e30b](037e30b))
* **security:** update module golang.org/x/crypto to v0.45.0 [security]
([#1826](#1826))
([7e0762b](7e0762b))
</details>

<details><summary>core: 0.13.0</summary>

##
[0.13.0](core/v0.12.1...core/v0.13.0)
(2025-12-23)


### ⚠ BREAKING CHANGES

* enable parsing of array flag configurations for flagd
([#1797](#1797))
* cleanup evaluator interface
([#1793](#1793))
* removes the `fractionalEvaluation` operator since it has been replaced
with `fractional`.
([#1704](#1704))

### 🐛 Bug Fixes

* **security:** update module github.com/go-viper/mapstructure/v2 to
v2.4.0 [security]
([#1784](#1784))
([037e30b](037e30b))
* **security:** update module golang.org/x/crypto to v0.45.0 [security]
([#1825](#1825))
([44edcc9](44edcc9))
* **security:** update module golang.org/x/crypto to v0.45.0 [security]
([#1826](#1826))
([7e0762b](7e0762b))


### ✨ New Features

* Add OAuth support for HTTP Sync
([#1791](#1791))
([268fd75](268fd75))
* Add OTEL default variables
([#1812](#1812))
([c2e3fc6](c2e3fc6))
* allow null flagSetId Selector, restrict Selector to single
key-value-pairs
([#1708](#1708))
([#1811](#1811))
([c12a0ae](c12a0ae))
* change jsonschema parser
([#1794](#1794))
([bf3f722](bf3f722))
* cleanup evaluator interface
([#1793](#1793))
([aa504f7](aa504f7))
* enable parsing of array flag configurations for flagd
([#1797](#1797))
([97c6ffa](97c6ffa))
* multi-project support via selectors and flagSetId namespacing
([#1702](#1702))
([f9ce46f](f9ce46f))


### 🧹 Chore

* **refactor:** use memdb for flag storage
([#1697](#1697))
([5c5c1cf](5c5c1cf))
* removes the `fractionalEvaluation` operator since it has been replaced
with `fractional`.
([#1704](#1704))
([3228ad8](3228ad8))


### 🔄 Refactoring

* remove deprecated bearerToken option
([#1816](#1816))
([efda06a](efda06a))
* removed unused Selector from Flag and Store.
([#1747](#1747))
([1083005](1083005))
* store cleanup
([#1705](#1705))
([bcff8d7](bcff8d7))
</details>

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Signed-off-by: OpenFeature Bot <109696520+openfeaturebot@users.noreply.github.com>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Todd Baert <todd.baert@dynatrace.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants