diff --git a/go.mod b/go.mod
index 0564d83750563587252c4c190bc10c030a072a58..d0e1df79114c59810d2c315e1ffc1275bfec78a0 100644
--- a/go.mod
+++ b/go.mod
@@ -3,8 +3,7 @@ module github.com/iotaledger/goshimmer
 go 1.13
 
 require (
-	github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect
-	github.com/dgraph-io/badger v1.6.0
+	github.com/dgraph-io/badger/v2 v2.0.1
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible
 	github.com/dgryski/go-farm v0.0.0-20191112170834-c2139c5d712b // indirect
 	github.com/gdamore/tcell v1.3.0
@@ -13,7 +12,7 @@ require (
 	github.com/googollee/go-engine.io v1.4.3-0.20190924125625-798118fc0dd2
 	github.com/googollee/go-socket.io v1.4.3-0.20191204093753-683f8725b6d0
 	github.com/gorilla/websocket v1.4.1
-	github.com/iotaledger/hive.go v0.0.0-20200120092048-f168257b6ccc
+	github.com/iotaledger/hive.go v0.0.0-20200120174440-057de3927083
 	github.com/iotaledger/iota.go v1.0.0-beta.14
 	github.com/labstack/echo v3.3.10+incompatible
 	github.com/labstack/gommon v0.3.0 // indirect
diff --git a/go.sum b/go.sum
index 6cba4d494385fe85e220a35a9c3824cd03edc7bd..3664b27905c74ce03f34db0ca1e2e8ad939f2f08 100644
--- a/go.sum
+++ b/go.sum
@@ -7,12 +7,12 @@ dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1
 dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
 git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
 github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
-github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M=
-github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
 github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
+github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM=
 github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
+github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -36,10 +36,11 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgraph-io/badger v1.5.4 h1:gVTrpUTbbr/T24uvoCaqY2KSHfNLVGm0w+hbee2HMeg=
 github.com/dgraph-io/badger v1.5.4/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ=
-github.com/dgraph-io/badger v1.6.0 h1:DshxFxZWXUcO0xX476VJC07Xsr6ZCBVRHKZ93Oh7Evo=
-github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
-github.com/dgraph-io/badger/v2 v2.0.0/go.mod h1:YoRSIp1LmAJ7zH7tZwRvjNMUYLxB4wl3ebYkaIruZ04=
+github.com/dgraph-io/badger/v2 v2.0.1 h1:+D6dhIqC6jIeCclnxMHqk4HPuXgrRN5UfBsLR4dNQ3A=
+github.com/dgraph-io/badger/v2 v2.0.1/go.mod h1:YoRSIp1LmAJ7zH7tZwRvjNMUYLxB4wl3ebYkaIruZ04=
+github.com/dgraph-io/ristretto v0.0.0-20191025175511-c1f00be0418e h1:aeUNgwup7PnDOBAD1BOKAqzb/W/NksOj6r3dwKKuqfg=
 github.com/dgraph-io/ristretto v0.0.0-20191025175511-c1f00be0418e/go.mod h1:edzKIzGvqUCMzhTVWbiTSe75zD9Xxq0GtSBtFmaUTZs=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
@@ -79,6 +80,7 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
 github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
 github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@@ -116,8 +118,8 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T
 github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/iotaledger/hive.go v0.0.0-20200120092048-f168257b6ccc h1:7SZQ3+4EvMd/iSOONrvD7Sa7qCm712KqTTKh8CK/9TU=
-github.com/iotaledger/hive.go v0.0.0-20200120092048-f168257b6ccc/go.mod h1:obs07gqna53/Yw1ltzLsQzJBMyA6lGu7Fb/ltjqWMnQ=
+github.com/iotaledger/hive.go v0.0.0-20200120174440-057de3927083 h1:dQx6NHouYh3KBStOuYrgMm6wYNnf4L+grKWQV4iBxNI=
+github.com/iotaledger/hive.go v0.0.0-20200120174440-057de3927083/go.mod h1:S+v90R3u4Rqe4VoOg4DhiZrAKlKZhz2UFKuK/Neqa2o=
 github.com/iotaledger/iota.go v1.0.0-beta.9/go.mod h1:F6WBmYd98mVjAmmPVYhnxg8NNIWCjjH8VWT9qvv3Rc8=
 github.com/iotaledger/iota.go v1.0.0-beta.14 h1:Oeb28MfBuJEeXcGrLhTCJFtbsnc8y1u7xidsAmiOD5A=
 github.com/iotaledger/iota.go v1.0.0-beta.14/go.mod h1:F6WBmYd98mVjAmmPVYhnxg8NNIWCjjH8VWT9qvv3Rc8=
@@ -239,6 +241,7 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k
 github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
 github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
 github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
 github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
diff --git a/packages/autopeering/peer/peerdb.go b/packages/autopeering/peer/peerdb.go
index def6344b4f270d140c121e50a5504cb0101b5aba..b20fcd052b304c5dc9b4fac5b09a3ca31dce8fa5 100644
--- a/packages/autopeering/peer/peerdb.go
+++ b/packages/autopeering/peer/peerdb.go
@@ -74,7 +74,7 @@ const (
 
 // NewPersistentDB creates a new persistent DB.
 func NewPersistentDB(log *logger.Logger) DB {
-	db, err := database.Get("peer")
+	db, err := database.Get(database.DBPrefixAutoPeering, database.GetBadgerInstance())
 	if err != nil {
 		panic(err)
 	}
@@ -157,26 +157,26 @@ func parseInt64(blob []byte) int64 {
 
 // getInt64 retrieves an integer associated with a particular key.
 func (db *persistentDB) getInt64(key []byte) int64 {
-	blob, err := db.db.Get(key)
+	entry, err := db.db.Get(key)
 	if err != nil {
 		return 0
 	}
-	return parseInt64(blob)
+	return parseInt64(entry.Value)
 }
 
 // setInt64 stores an integer in the given key.
 func (db *persistentDB) setInt64(key []byte, n int64) error {
 	blob := make([]byte, binary.MaxVarintLen64)
 	blob = blob[:binary.PutVarint(blob, n)]
-	return db.db.SetWithTTL(key, blob, peerExpiration)
+	return db.db.Set(database.Entry{Key: key, Value: blob, TTL: peerExpiration})
 }
 
 // LocalPrivateKey returns the private key stored in the database or creates a new one.
 func (db *persistentDB) LocalPrivateKey() (PrivateKey, error) {
-	key, err := db.db.Get(localFieldKey(dbLocalKey))
+	entry, err := db.db.Get(localFieldKey(dbLocalKey))
 	if err == database.ErrKeyNotFound {
-		key, err = generatePrivateKey()
-		if err == nil {
+		key, genErr := generatePrivateKey()
+		if genErr == nil {
 			err = db.UpdateLocalPrivateKey(key)
 		}
 		return key, err
@@ -184,13 +184,12 @@ func (db *persistentDB) LocalPrivateKey() (PrivateKey, error) {
 	if err != nil {
 		return nil, err
 	}
-
-	return key, nil
+	return PrivateKey(entry.Value), nil
 }
 
 // UpdateLocalPrivateKey stores the provided key in the database.
 func (db *persistentDB) UpdateLocalPrivateKey(key PrivateKey) error {
-	return db.db.Set(localFieldKey(dbLocalKey), key)
+	return db.db.Set(database.Entry{Key: localFieldKey(dbLocalKey), Value: []byte(key)})
 }
 
 // LastPing returns that property for the given peer ID and address.
@@ -218,7 +217,7 @@ func (db *persistentDB) setPeerWithTTL(p *Peer, ttl time.Duration) error {
 	if err != nil {
 		return err
 	}
-	return db.db.SetWithTTL(nodeKey(p.ID()), data, ttl)
+	return db.db.Set(database.Entry{Key: nodeKey(p.ID()), Value: data, TTL: ttl})
 }
 
 func (db *persistentDB) UpdatePeer(p *Peer) error {
@@ -238,7 +237,7 @@ func (db *persistentDB) Peer(id ID) *Peer {
 	if err != nil {
 		return nil
 	}
-	return parsePeer(data)
+	return parsePeer(data.Value)
 }
 
 func randomSubset(peers []*Peer, m int) []*Peer {
@@ -259,21 +258,22 @@ func (db *persistentDB) getPeers(maxAge time.Duration) []*Peer {
 	peers := make([]*Peer, 0)
 	now := time.Now()
 
-	err := db.db.ForEachWithPrefix([]byte(dbNodePrefix), func(key []byte, value []byte) {
-		id, rest := splitNodeKey(key)
+	err := db.db.StreamForEachPrefix([]byte(dbNodePrefix), func(entry database.Entry) error {
+		id, rest := splitNodeKey(entry.Key)
 		if len(rest) > 0 {
-			return
+			return nil
 		}
 
-		p := parsePeer(value)
+		p := parsePeer(entry.Value)
 		if p == nil || p.ID() != id {
-			return
+			return nil
 		}
 		if maxAge > 0 && now.Sub(db.LastPong(p.ID(), p.Address())) > maxAge {
-			return
+			return nil
 		}
 
 		peers = append(peers, p)
+		return nil
 	})
 	if err != nil {
 		return []*Peer{}
diff --git a/packages/database/badger_instance.go b/packages/database/badger_instance.go
deleted file mode 100644
index 439aa4727db7bd7f56c29bbc46896cbba7ae7b7e..0000000000000000000000000000000000000000
--- a/packages/database/badger_instance.go
+++ /dev/null
@@ -1,69 +0,0 @@
-package database
-
-import (
-	"fmt"
-	"os"
-	"sync"
-
-	"github.com/dgraph-io/badger"
-	"github.com/dgraph-io/badger/options"
-	"github.com/iotaledger/goshimmer/packages/parameter"
-)
-
-var instance *badger.DB
-var once sync.Once
-
-// Returns whether the given file or directory exists.
-func exists(path string) (bool, error) {
-	_, err := os.Stat(path)
-	if err == nil {
-		return true, nil
-	}
-	if os.IsNotExist(err) {
-		return false, nil
-	}
-	return false, err
-}
-
-func checkDir(dir string) error {
-	exists, err := exists(dir)
-	if err != nil {
-		return err
-	}
-
-	if !exists {
-		return os.Mkdir(dir, 0700)
-	}
-	return nil
-}
-
-func createDB() (*badger.DB, error) {
-	directory := parameter.NodeConfig.GetString(CFG_DIRECTORY)
-	if err := checkDir(directory); err != nil {
-		return nil, fmt.Errorf("could not check directory: %w", err)
-	}
-
-	opts := badger.DefaultOptions(directory)
-	opts.Logger = &logger{}
-	opts.Truncate = true
-	opts.TableLoadingMode = options.MemoryMap
-
-	db, err := badger.Open(opts)
-	if err != nil {
-		return nil, fmt.Errorf("could not open new DB: %w", err)
-	}
-
-	return db, nil
-}
-
-func GetBadgerInstance() *badger.DB {
-	once.Do(func() {
-		db, err := createDB()
-		if err != nil {
-			// errors should cause a panic to avoid singleton deadlocks
-			panic(err)
-		}
-		instance = db
-	})
-	return instance
-}
diff --git a/packages/database/database.go b/packages/database/database.go
index 913ffc3f91589637dddc22272a4e8ee45cb56214..4da5818cd93cde477656d97f9d069267d0f2ccba 100644
--- a/packages/database/database.go
+++ b/packages/database/database.go
@@ -1,134 +1,78 @@
 package database
 
 import (
+	"io/ioutil"
+	"os"
+	"runtime"
 	"sync"
-	"time"
 
-	"github.com/dgraph-io/badger"
+	"github.com/dgraph-io/badger/v2"
+	"github.com/iotaledger/goshimmer/packages/parameter"
+	"github.com/iotaledger/hive.go/database"
+	"github.com/iotaledger/hive.go/logger"
 )
 
 var (
-	ErrKeyNotFound = badger.ErrKeyNotFound
-
-	dbMap = make(map[string]*prefixDb)
-	mu    sync.Mutex
+	instance       *badger.DB
+	once           sync.Once
+	ErrKeyNotFound = database.ErrKeyNotFound
 )
 
-type prefixDb struct {
-	db     *badger.DB
-	name   string
-	prefix []byte
-}
-
-func getPrefix(name string) []byte {
-	return []byte(name + "_")
-}
-
-func Get(name string) (Database, error) {
-	mu.Lock()
-	defer mu.Unlock()
-
-	if db, exists := dbMap[name]; exists {
-		return db, nil
-	}
-
-	badger := GetBadgerInstance()
-	db := &prefixDb{
-		db:     badger,
-		name:   name,
-		prefix: getPrefix(name),
-	}
-
-	dbMap[name] = db
-
-	return db, nil
-}
-
-func (this *prefixDb) setEntry(e *badger.Entry) error {
-	err := this.db.Update(func(txn *badger.Txn) error {
-		return txn.SetEntry(e)
-	})
-	return err
-}
-
-func (this *prefixDb) Set(key []byte, value []byte) error {
-	e := badger.NewEntry(append(this.prefix, key...), value)
-	return this.setEntry(e)
-}
+type (
+	Database     = database.Database
+	Entry        = database.Entry
+	KeyOnlyEntry = database.KeyOnlyEntry
+	KeyPrefix    = database.KeyPrefix
+	Value        = database.Value
+)
 
-func (this *prefixDb) SetWithTTL(key []byte, value []byte, ttl time.Duration) error {
-	e := badger.NewEntry(append(this.prefix, key...), value).WithTTL(ttl)
-	return this.setEntry(e)
+func Get(dbPrefix byte, optionalBadger ...*badger.DB) (Database, error) {
+	return database.Get(dbPrefix, optionalBadger...)
 }
 
-func (this *prefixDb) Contains(key []byte) (bool, error) {
-	err := this.db.View(func(txn *badger.Txn) error {
-		_, err := txn.Get(append(this.prefix, key...))
-		return err
-	})
-
-	if err == ErrKeyNotFound {
-		return false, nil
-	} else {
-		return err == nil, err
-	}
-}
+func GetBadgerInstance() *badger.DB {
+	once.Do(func() {
+		dbDir := parameter.NodeConfig.GetString(CFG_DIRECTORY)
 
-func (this *prefixDb) Get(key []byte) ([]byte, error) {
-	var result []byte = nil
-
-	err := this.db.View(func(txn *badger.Txn) error {
-		item, err := txn.Get(append(this.prefix, key...))
+		var dbDirClear bool
+		// check whether the database is new, by checking whether any file exists within
+		// the database directory
+		fileInfos, err := ioutil.ReadDir(dbDir)
 		if err != nil {
-			return err
+			// panic on other errors, for example permission related
+			if !os.IsNotExist(err) {
+				panic(err)
+			}
+			dbDirClear = true
+		}
+		if len(fileInfos) == 0 {
+			dbDirClear = true
 		}
 
-		return item.Value(func(val []byte) error {
-			result = append([]byte{}, val...)
-
-			return nil
-		})
-	})
-
-	return result, err
-}
-
-func (this *prefixDb) Delete(key []byte) error {
-	err := this.db.Update(func(txn *badger.Txn) error {
-		return txn.Delete(append(this.prefix, key...))
-	})
-	return err
-}
-
-func (this *prefixDb) forEach(prefix []byte, consumer func([]byte, []byte)) error {
-	err := this.db.View(func(txn *badger.Txn) error {
-		iteratorOptions := badger.DefaultIteratorOptions
-		iteratorOptions.Prefix = prefix // filter by prefix
-
-		// create an iterator the default options
-		it := txn.NewIterator(iteratorOptions)
-		defer it.Close()
-
-		// loop through every key-value-pair and call the function
-		for it.Rewind(); it.Valid(); it.Next() {
-			item := it.Item()
-
-			value, err := item.ValueCopy(nil)
-			if err != nil {
-				return err
-			}
+		opts := badger.DefaultOptions(dbDir)
+		opts.Logger = nil
+		if runtime.GOOS == "windows" {
+			opts = opts.WithTruncate(true)
+		}
 
-			consumer(item.Key()[len(this.prefix):], value)
+		db, err := database.CreateDB(dbDir, opts)
+		if err != nil {
+			// errors should cause a panic to avoid singleton deadlocks
+			panic(err)
 		}
-		return nil
-	})
-	return err
-}
+		instance = db
 
-func (this *prefixDb) ForEachWithPrefix(prefix []byte, consumer func([]byte, []byte)) error {
-	return this.forEach(append(this.prefix, prefix...), consumer)
+		// up on the first caller, check whether the version of the database is compatible
+		checkDatabaseVersion(dbDirClear)
+	})
+	return instance
 }
 
-func (this *prefixDb) ForEach(consumer func([]byte, []byte)) error {
-	return this.forEach(this.prefix, consumer)
+func CleanupBadgerInstance(log *logger.Logger) {
+	db := GetBadgerInstance()
+	log.Info("Running Badger database garbage collection")
+	var err error
+	for err == nil {
+		err = db.RunValueLogGC(0.7)
+	}
 }
diff --git a/packages/database/interfaces.go b/packages/database/interfaces.go
deleted file mode 100644
index 56d2b9573836153e1b487802510ce0d7953c13ca..0000000000000000000000000000000000000000
--- a/packages/database/interfaces.go
+++ /dev/null
@@ -1,13 +0,0 @@
-package database
-
-import "time"
-
-type Database interface {
-	Set(key []byte, value []byte) error
-	SetWithTTL(key []byte, value []byte, ttl time.Duration) error
-	Contains(key []byte) (bool, error)
-	Get(key []byte) ([]byte, error)
-	ForEach(consumer func(key []byte, value []byte)) error
-	ForEachWithPrefix(prefix []byte, consumer func(key []byte, value []byte)) error
-	Delete(key []byte) error
-}
diff --git a/packages/database/logger.go b/packages/database/logger.go
deleted file mode 100644
index ac1de091452794ddb04857acd94df5ff87df72d7..0000000000000000000000000000000000000000
--- a/packages/database/logger.go
+++ /dev/null
@@ -1,19 +0,0 @@
-package database
-
-type logger struct{}
-
-func (this *logger) Errorf(string, ...interface{}) {
-	// disable logging
-}
-
-func (this *logger) Infof(string, ...interface{}) {
-	// disable logging
-}
-
-func (this *logger) Warningf(string, ...interface{}) {
-	// disable logging
-}
-
-func (this *logger) Debugf(string, ...interface{}) {
-	// disable logging
-}
diff --git a/packages/database/prefixes.go b/packages/database/prefixes.go
new file mode 100644
index 0000000000000000000000000000000000000000..c9dc488d40b5fbe557467e1be275e6aa56052aec
--- /dev/null
+++ b/packages/database/prefixes.go
@@ -0,0 +1,11 @@
+package database
+
+const (
+	DBPrefixApprovers byte = iota
+	DBPrefixTransaction
+	DBPrefixBundle
+	DBPrefixTransactionMetadata
+	DBPrefixAddressTransactions
+	DBPrefixAutoPeering
+	DBPrefixDatabaseVersion
+)
diff --git a/packages/database/versioning.go b/packages/database/versioning.go
new file mode 100644
index 0000000000000000000000000000000000000000..a848eb0e508a7ecbf3b9c61773700fdfdaa79b1c
--- /dev/null
+++ b/packages/database/versioning.go
@@ -0,0 +1,47 @@
+package database
+
+import (
+	"errors"
+	"fmt"
+)
+
+const (
+	// DBVersion defines the version of the database schema this version of GoShimmer supports.
+	// everytime there's a breaking change regarding the stored data, this version flag should be adjusted.
+	DBVersion = 1
+)
+
+var (
+	ErrDBVersionIncompatible = errors.New("database version is not compatible. please delete your database folder and restart")
+	// the key under which the database is stored
+	dbVersionKey = []byte{0}
+)
+
+// checks whether the database is compatible with the current schema version.
+// also automatically sets the version if the database is new.
+func checkDatabaseVersion(dbIsNew bool) {
+	dbInstance, err := Get(DBPrefixDatabaseVersion, instance)
+	if err != nil {
+		panic(err)
+	}
+
+	if dbIsNew {
+		// store db version for the first time in the new database
+		if err = dbInstance.Set(Entry{Key: dbVersionKey, Value: []byte{DBVersion}}); err != nil {
+			panic(fmt.Sprintf("unable to persist db version number: %s", err.Error()))
+		}
+		return
+	}
+
+	// db version must be available
+	entry, err := dbInstance.Get(dbVersionKey)
+	if err != nil {
+		if err == ErrKeyNotFound {
+			panic(err)
+		}
+		panic(fmt.Errorf("%w: no database version was persisted", ErrDBVersionIncompatible))
+	}
+	if entry.Value[0] != DBVersion {
+		panic(fmt.Errorf("%w: supported version: %d, version of database: %d", ErrDBVersionIncompatible, DBVersion, entry.Value[0]))
+	}
+}
diff --git a/packages/shutdown/order.go b/packages/shutdown/order.go
index b16bc91e04b45b2e9744555ae229ab359d9cb18e..51ed31ec8d11251d947628842d80542e7f05d7dd 100644
--- a/packages/shutdown/order.go
+++ b/packages/shutdown/order.go
@@ -14,5 +14,6 @@ const (
 	ShutdownPriorityUI
 	ShutdownPriorityDashboard
 	ShutdownPriorityTangleSpammer
+	ShutdownPriorityBadgerGarbageCollection
 	ShutdownPriorityStatusScreen
 )
diff --git a/plugins/bundleprocessor/bundleprocessor_test.go b/plugins/bundleprocessor/bundleprocessor_test.go
index 6505583f451516b7db36c7d5a0c20d90d56fa490..e7b90366bd676bf6a0ba3d284ba6e241a368b3f9 100644
--- a/plugins/bundleprocessor/bundleprocessor_test.go
+++ b/plugins/bundleprocessor/bundleprocessor_test.go
@@ -1,10 +1,13 @@
 package bundleprocessor
 
 import (
+	"io/ioutil"
+	"os"
 	"sync"
 	"testing"
 
 	"github.com/iotaledger/goshimmer/packages/client"
+	"github.com/iotaledger/goshimmer/packages/database"
 	"github.com/iotaledger/goshimmer/packages/model/bundle"
 	"github.com/iotaledger/goshimmer/packages/model/value_transaction"
 	"github.com/iotaledger/goshimmer/packages/parameter"
@@ -16,6 +19,7 @@ import (
 	"github.com/iotaledger/iota.go/consts"
 	"github.com/magiconair/properties/assert"
 	"github.com/spf13/viper"
+	"github.com/stretchr/testify/require"
 )
 
 var seed = client.NewSeed("YFHQWAUPCXC9S9DSHP9NDF9RLNPMZVCMSJKUKQP9SWUSUCPRQXCMDVDVZ9SHHESHIQNCXWBJF9UJSWE9Z", consts.SecurityLevelMedium)
@@ -69,6 +73,12 @@ func TestValidateSignatures(t *testing.T) {
 }
 
 func TestProcessSolidBundleHead(t *testing.T) {
+	dir, err := ioutil.TempDir("", t.Name())
+	require.NoError(t, err)
+	defer os.Remove(dir)
+	// use the tempdir for the database
+	parameter.NodeConfig.Set(database.CFG_DIRECTORY, dir)
+
 	// start a test node
 	node.Start(node.Plugins(tangle.PLUGIN, PLUGIN))
 	defer node.Shutdown()
diff --git a/plugins/tangle/approvers.go b/plugins/tangle/approvers.go
index 10073c39435df28a04fefc943518312582ab5eee..3e50c29caec97397832490d911ca3989ebe3be6b 100644
--- a/plugins/tangle/approvers.go
+++ b/plugins/tangle/approvers.go
@@ -82,7 +82,7 @@ const (
 var approversDatabase database.Database
 
 func configureApproversDatabase() {
-	if db, err := database.Get("approvers"); err != nil {
+	if db, err := database.Get(database.DBPrefixApprovers, database.GetBadgerInstance()); err != nil {
 		panic(err)
 	} else {
 		approversDatabase = db
@@ -91,10 +91,9 @@ func configureApproversDatabase() {
 
 func storeApproversInDatabase(approvers *approvers.Approvers) error {
 	if approvers.GetModified() {
-		if err := approversDatabase.Set(typeutils.StringToBytes(approvers.GetHash()), approvers.Marshal()); err != nil {
+		if err := approversDatabase.Set(database.Entry{Key: typeutils.StringToBytes(approvers.GetHash()), Value: approvers.Marshal()}); err != nil {
 			return fmt.Errorf("%w: failed to store approvers: %s", ErrDatabaseError, err)
 		}
-
 		approvers.SetModified(false)
 	}
 
@@ -111,7 +110,7 @@ func getApproversFromDatabase(transactionHash trinary.Trytes) (*approvers.Approv
 	}
 
 	var result approvers.Approvers
-	if err = result.Unmarshal(approversData); err != nil {
+	if err = result.Unmarshal(approversData.Value); err != nil {
 		panic(err)
 	}
 
diff --git a/plugins/tangle/bundle.go b/plugins/tangle/bundle.go
index 55411764a2eacc04b73122a86b119352bc0d1cbd..2cb1fb896ae5cd5a8d6152a0e2398ef4651f4a87 100644
--- a/plugins/tangle/bundle.go
+++ b/plugins/tangle/bundle.go
@@ -86,7 +86,7 @@ const (
 var bundleDatabase database.Database
 
 func configureBundleDatabase() {
-	if db, err := database.Get("bundle"); err != nil {
+	if db, err := database.Get(database.DBPrefixBundle, database.GetBadgerInstance()); err != nil {
 		panic(err)
 	} else {
 		bundleDatabase = db
@@ -95,10 +95,9 @@ func configureBundleDatabase() {
 
 func storeBundleInDatabase(bundle *bundle.Bundle) error {
 	if bundle.GetModified() {
-		if err := bundleDatabase.Set(typeutils.StringToBytes(bundle.GetHash()), bundle.Marshal()); err != nil {
+		if err := bundleDatabase.Set(database.Entry{Key: typeutils.StringToBytes(bundle.GetHash()), Value: bundle.Marshal()}); err != nil {
 			return fmt.Errorf("%w: failed to store bundle: %s", ErrDatabaseError, err)
 		}
-
 		bundle.SetModified(false)
 	}
 
@@ -116,7 +115,7 @@ func getBundleFromDatabase(transactionHash trinary.Trytes) (*bundle.Bundle, erro
 	}
 
 	var result bundle.Bundle
-	if err = result.Unmarshal(bundleData); err != nil {
+	if err = result.Unmarshal(bundleData.Value); err != nil {
 		panic(err)
 	}
 
diff --git a/plugins/tangle/plugin.go b/plugins/tangle/plugin.go
index 252c2b987da1db3774e0def97e65582f879a8c6c..6c6bc09015f462d137784c7c9c5fad2a26c59929 100644
--- a/plugins/tangle/plugin.go
+++ b/plugins/tangle/plugin.go
@@ -1,11 +1,14 @@
 package tangle
 
 import (
+	"time"
+
 	"github.com/iotaledger/goshimmer/packages/database"
 	"github.com/iotaledger/goshimmer/packages/shutdown"
 	"github.com/iotaledger/hive.go/daemon"
 	"github.com/iotaledger/hive.go/logger"
 	"github.com/iotaledger/hive.go/node"
+	"github.com/iotaledger/hive.go/timeutil"
 	"github.com/iotaledger/iota.go/trinary"
 )
 
@@ -42,6 +45,13 @@ func configure(*node.Plugin) {
 }
 
 func run(*node.Plugin) {
+
+	daemon.BackgroundWorker("Badger garbage collection", func(shutdownSignal <-chan struct{}) {
+		timeutil.Ticker(func() {
+			database.CleanupBadgerInstance(log)
+		}, 5*time.Minute, shutdownSignal)
+	}, shutdown.ShutdownPriorityBadgerGarbageCollection)
+
 	runSolidifier()
 }
 
diff --git a/plugins/tangle/solidifier_test.go b/plugins/tangle/solidifier_test.go
index 850f87501e8dc43fccc6fddb55a74cf834e9ee8d..28a63bc25a1fdcd79f16fb2f82d2b66380088ae5 100644
--- a/plugins/tangle/solidifier_test.go
+++ b/plugins/tangle/solidifier_test.go
@@ -33,7 +33,7 @@ func init() {
 }
 
 func TestTangle(t *testing.T) {
-	dir, err := ioutil.TempDir("", "example")
+	dir, err := ioutil.TempDir("", t.Name())
 	require.NoError(t, err)
 	defer os.Remove(dir)
 	// use the tempdir for the database
diff --git a/plugins/tangle/transaction.go b/plugins/tangle/transaction.go
index fc2e2f02dd7cd3b18739eeb232f6b27b4bd791ae..bff7b6b726d8bda3b4f3fdc4278f0a3bbe80a254 100644
--- a/plugins/tangle/transaction.go
+++ b/plugins/tangle/transaction.go
@@ -83,7 +83,7 @@ const (
 var transactionDatabase database.Database
 
 func configureTransactionDatabase() {
-	if db, err := database.Get("transaction"); err != nil {
+	if db, err := database.Get(database.DBPrefixTransaction, database.GetBadgerInstance()); err != nil {
 		panic(err)
 	} else {
 		transactionDatabase = db
@@ -92,10 +92,9 @@ func configureTransactionDatabase() {
 
 func storeTransactionInDatabase(transaction *value_transaction.ValueTransaction) error {
 	if transaction.GetModified() {
-		if err := transactionDatabase.Set(typeutils.StringToBytes(transaction.GetHash()), transaction.MetaTransaction.GetBytes()); err != nil {
+		if err := transactionDatabase.Set(database.Entry{Key: typeutils.StringToBytes(transaction.GetHash()), Value: transaction.MetaTransaction.GetBytes()}); err != nil {
 			return fmt.Errorf("%w: failed to store transaction: %s", ErrDatabaseError, err.Error())
 		}
-
 		transaction.SetModified(false)
 	}
 
@@ -111,7 +110,7 @@ func getTransactionFromDatabase(transactionHash trinary.Trytes) (*value_transact
 		return nil, fmt.Errorf("%w: failed to retrieve transaction: %s", ErrDatabaseError, err)
 	}
 
-	return value_transaction.FromBytes(txData), nil
+	return value_transaction.FromBytes(txData.Value), nil
 }
 
 func databaseContainsTransaction(transactionHash trinary.Trytes) (bool, error) {
diff --git a/plugins/tangle/transaction_metadata.go b/plugins/tangle/transaction_metadata.go
index 94d6177af989c666a75d2b1c1e75bd1c252166bc..152f0126da1f00dd741d2c9953743a8010e9f764 100644
--- a/plugins/tangle/transaction_metadata.go
+++ b/plugins/tangle/transaction_metadata.go
@@ -83,7 +83,7 @@ const (
 var transactionMetadataDatabase database.Database
 
 func configureTransactionMetaDataDatabase() {
-	if db, err := database.Get("transactionMetadata"); err != nil {
+	if db, err := database.Get(database.DBPrefixTransactionMetadata, database.GetBadgerInstance()); err != nil {
 		panic(err)
 	} else {
 		transactionMetadataDatabase = db
@@ -95,7 +95,7 @@ func storeTransactionMetadataInDatabase(metadata *transactionmetadata.Transactio
 		if marshaledMetadata, err := metadata.Marshal(); err != nil {
 			return err
 		} else {
-			if err := transactionMetadataDatabase.Set(typeutils.StringToBytes(metadata.GetHash()), marshaledMetadata); err != nil {
+			if err := transactionMetadataDatabase.Set(database.Entry{Key: typeutils.StringToBytes(metadata.GetHash()), Value: marshaledMetadata}); err != nil {
 				return fmt.Errorf("%w: failed to store transaction metadata: %s", ErrDatabaseError, err)
 			}
 
@@ -116,7 +116,7 @@ func getTransactionMetadataFromDatabase(transactionHash trinary.Trytes) (*transa
 	}
 
 	var result transactionmetadata.TransactionMetadata
-	if err := result.Unmarshal(txMetadata); err != nil {
+	if err := result.Unmarshal(txMetadata.Value); err != nil {
 		panic(err)
 	}
 
diff --git a/plugins/tangle/tx_per_address.go b/plugins/tangle/tx_per_address.go
index 1ab4950e6c79405e99e4acf3242f4ebc6591eb94..092a75248419251137c6205be0abf108b9b495df 100644
--- a/plugins/tangle/tx_per_address.go
+++ b/plugins/tangle/tx_per_address.go
@@ -13,7 +13,7 @@ var (
 )
 
 func configureTransactionHashesForAddressDatabase() {
-	if db, err := database.Get("transactionsHashesForAddress"); err != nil {
+	if db, err := database.Get(database.DBPrefixAddressTransactions, database.GetBadgerInstance()); err != nil {
 		panic(err)
 	} else {
 		transactionsHashesForAddressDatabase = db
@@ -26,10 +26,10 @@ type TxHashForAddress struct {
 }
 
 func StoreTransactionHashForAddressInDatabase(address *TxHashForAddress) error {
-	if err := transactionsHashesForAddressDatabase.Set(
-		databaseKeyForHashPrefixedHash(address.Address, address.TxHash),
-		[]byte{},
-	); err != nil {
+	if err := transactionsHashesForAddressDatabase.Set(database.Entry{
+		Key:   databaseKeyForHashPrefixedHash(address.Address, address.TxHash),
+		Value: []byte{},
+	}); err != nil {
 		return fmt.Errorf("%w: failed to store tx for address in database: %s", ErrDatabaseError, err)
 	}
 	return nil
@@ -47,11 +47,9 @@ func DeleteTransactionHashForAddressInDatabase(address *TxHashForAddress) error
 
 func ReadTransactionHashesForAddressFromDatabase(address trinary.Hash) ([]trinary.Hash, error) {
 	var transactionHashes []trinary.Hash
-	err := transactionsHashesForAddressDatabase.ForEachWithPrefix(databaseKeyForHashPrefix(address), func(key []byte, value []byte) {
-		k := typeutils.BytesToString(key)
-		if len(k) > 81 {
-			transactionHashes = append(transactionHashes, k[81:])
-		}
+	err := transactionsHashesForAddressDatabase.StreamForEachPrefixKeyOnly(databaseKeyForHashPrefix(address), func(key database.KeyOnlyEntry) error {
+		transactionHashes = append(transactionHashes, typeutils.BytesToString(key.Key))
+		return nil
 	})
 
 	if err != nil {