Kiwi Logo

A minimalistic in-memory key value store.

Go CI Docs CI Docs CD PkgGoDev


You can think of Kiwi as thread safe global variables. This kind of library comes in helpful when you need to manage state accross your application which can be mutated with multiple threads. Kiwi protects your keys with mutex locks so you don't have to.

Head over to for more details and documentation.


Kiwi requires Go >= 1.14

Kiwi can be integrated with your application just like any other go library.

go get -u

Now you can import kiwi any where in your code.

import ""

Basic usage

Create a store, add key and play with it. It's that easy!

store := stdkiwi.NewStore()

if err := store.AddKey("my_string", "str"); err != nil {
  // handle error

myString := store.Str("my_string")

if err := myString.Update("Hello, World!"); err != nil {
  // handle error

str, err := myString.Get()
if err != nil {
  // handle error

fmt.Println(str) // Hello, World!

Check out the tutorial to learn how to use Kiwi.


Following are the benchmarks comparing Kiwi with BuntDB on a MacBook Pro (8th gen Intel i5 2.4GHz processor, 8GB RAM).

❯ go test -bench=. -test.benchmem ./benchmark
goos: darwin
goarch: amd64
BenchmarkBuntDB_Update-8        11777931                96.6 ns/op            48 B/op          1 allocs/op
BenchmarkBuntDB_View-8          23310963                47.1 ns/op            48 B/op          1 allocs/op
BenchmarkKiwi_Update-8          10356004               115 ns/op              48 B/op          3 allocs/op
BenchmarkKiwi_Get-8             21910110                53.2 ns/op             0 B/op          0 allocs/op
ok       6.216s

Following are the key differences due to which Kiwi is a little slow:

  1. BuntDB supports transactions, i.e., it locks the database once to apply all the operations (and this is what is tested).
  2. Kiwi supports dynamic data-types, which means, allocation on heap at runtime (interface{}) whereas BuntDB is statically typed.

The above two differences are what makes Kiwi unique and suitable to use on many occasions. Due to the aforementioned reasons, Kiwi can support typed values and not everything is just another "string".

There are places where we could improve more. Some performance issues also lie in the implementation of values. For example, when updating a string, not returning the updated string avoids an extra allocation.


We are always open for contributions. If you find any feature missing, or just want to report a bug, feel free to open an issue and/or submit a pull request regarding the same.

For more information on contribution, check out our docs.


If you have a query regarding the product or just want to say hello then feel free to visit or drop a mail at

Made by SDSLabs

Expand ▾ Collapse ▴



Package kiwi implements a minimalistic in-memory key value store.

Each key is thread safe as it is protected by its own mutex, though different keys can be accessed by various threads.

To get started, create a store with the NewStore function and add keys to it using AddKey. Each key is associated with a value which has a specific type. These types are extendible and can be created by implementing the Value interface.

Store can also be initialized with a schema, which is basically a map of keys and value types.

Get Started

Create a store, add key and play with it. It's that easy!

store := kiwi.NewStore()

if err := store.AddKey("my_string", "str"); err != nil {
  // handle error

if _, err := store.Do("my_string", "UPDATE", "Hello, World!"); err != nil {
  // handle error

v, err := store.Do("my_string", "GET")
if err != nil {
  // handle error

fmt.Println(v.(string)) // Hello, World!

For documentation visit



This section is empty.


View Source
var (
	ErrKeyExists   = fmt.Errorf("key already exists")
	ErrKeyNotExist = fmt.Errorf("key does not exist")

Various errors related to keys.

View Source
var (
	ErrValueRegistered    = fmt.Errorf("value already registered")
	ErrValueNotRegistered = fmt.Errorf("value not registered")

Errors related to values.

View Source
var (
	ErrInvalidAction = fmt.Errorf("invalid action")

Errors related to actions.


func ListRegisteredValues

func ListRegisteredValues() []string

ListRegisteredValues lists all the values registered with the package.

func RegisterValue

func RegisterValue(newFn func() Value)

RegisterValue registers a new value type with the package.

It takes in two params: the type of the value and a function to create a new value.


type Action

type Action string

Action is required to invoke (or "Do") an action.

type DoFunc

type DoFunc func(params ...interface{}) (interface{}, error)

DoFunc is a function that can be executed when an action is invoked.

type ImportOpts

type ImportOpts struct {
	// AddKeys specifies whether to add keys that do not exist.
	AddKeys bool

	// UpdateTypes specifies if the type of key in JSON doesn't match the one
	// with already-defined key, should the type of key be updated or not.
	UpdateTypes bool

	// ErrOnInvalidKey specifies whether to throw error if the key in the JSON
	// does not exist in the actual schema of the Store.
	// This option is considered only when `AddKeys` is false.
	ErrOnInvalidKey bool

ImportOpts are the options that can be used to configure how to import data into the store from raw JSON.

type Schema

type Schema map[string]ValueType

Schema contains the value types corresponding to their keys.

func (Schema) String

func (s Schema) String() string

String implements the fmt.Stringer interface.

type Store

type Store struct {

	// contains filtered or unexported fields


Store is the main element that contains and manages all the key value pairs.

func NewStore

func NewStore() *Store

NewStore creates an empty store without any key value pairs initialized.

func NewStoreFromSchema

func NewStoreFromSchema(schema Schema) (*Store, error)

NewStoreFromSchema creates a new store from the provided schema.

func (*Store) AddKey

func (s *Store) AddKey(key string, typ ValueType) error

AddKey adds a new key to the store. It throws an error if the key already exists.

func (*Store) DeleteKey

func (s *Store) DeleteKey(key string) error

DeleteKey deletes the key if it exists. Throws an error if it doesn't.

func (*Store) Do

func (s *Store) Do(key string, action Action, params ...interface{}) (interface{}, error)

Do executes the action for the value associated with the key.

func (*Store) Export

func (s *Store) Export() (json.RawMessage, error)

Export returns JSON data for the store.

The data is in the format (StoreJSON):

	"key_1": {
		"type": "str",
		"data": "hello"
	"key_2": {
		"type": "hash",
		"data": {
			"a": "b",
			"c": "d"

func (*Store) FromJSON

func (s *Store) FromJSON(key string, rawmessage json.RawMessage) error

FromJSON takes the raw JSON form of data and loads it into the value.

func (*Store) GetSchema

func (s *Store) GetSchema() Schema

GetSchema returns the schema of the store.

func (*Store) GetValueType

func (s *Store) GetValueType(key string) (ValueType, error)

GetValueType returns the type of value corresponding to the key.

func (*Store) Import

func (s *Store) Import(rawmessage json.RawMessage, opts ImportOpts) error

Import loads store from the data.

The default behavior is that the store takes the data from the JSON and if an unknown key exists, i.e., a key that is not already added to the store, it silently skips the value associated with it. This can be configured using the ImportOpts.

The data is in the format (StoreJSON):

	"key_1": {
		"type": "str",
		"data": "hello"
	"key_2": {
		"type": "hash",
		"data": {
			"a": "b",
			"c": "d"

func (*Store) KeyExists

func (s *Store) KeyExists(key string) bool

KeyExists tells if the key exists or not.

func (*Store) ToJSON

func (s *Store) ToJSON(key string) (json.RawMessage, error)

ToJSON converts the data associated with the value into JSON format.

func (*Store) UpdateKey

func (s *Store) UpdateKey(key string, typ ValueType) error

UpdateKey updates the key if it exists. Throws an error if it doesn't.

type StoreJSON

type StoreJSON = map[string]ValJSON

StoreJSON is the type which includes all the data for the store.

type ValJSON

type ValJSON struct {
	Type string          `json:"type"`
	Data json.RawMessage `json:"data"`

ValJSON is the JSON object for each value.

type Value

type Value interface {
	// Type returns the type of the value.
	Type() ValueType

	// DoMap returns a map which associates actions with a do function.
	DoMap() map[Action]DoFunc

	// ToJSON returns a raw byte array of the data.
	ToJSON() (json.RawMessage, error)

	// FromJSON returns the data in golang from a raw byte array.
	FromJSON(json.RawMessage) error

Value is something that can be associated with a "key".

A value implements its own methods and can be accessed by type assertion. To add a value type to the register simply call RegisterValue. All the default values are already registered with the package.

type ValueType

type ValueType string

ValueType is the name of type of value.


Path Synopsis
stdkiwi Package stdkiwi implements an API with standard values.
values/hash Package hash implements a kiwi.Value which can store a string-string hashmap.
values/list Package list implements a kiwi.Value which can store an array of strings.
values/set Package set implements a kiwi.Value which can store a set of strings.
values/str Package str implements a kiwi.Value which can store a simple string.
values/zhash Package zhash implements a kiwi.Value which can store a hash with each element having a value and a score.
values/zset Package zset implements a kiwi.Value which can store a set with each element having score.