diff --git a/engine/browser.go b/engine/browser.go
index 123c7f24e..df551b1b1 100644
--- a/engine/browser.go
+++ b/engine/browser.go
@@ -32,11 +32,11 @@ type browser struct {
 }
 
 func (b *browser) MediaFolders(ctx context.Context) (model.MediaFolders, error) {
-	return b.ds.MediaFolder().GetAll()
+	return b.ds.MediaFolder(ctx).GetAll()
 }
 
 func (b *browser) Indexes(ctx context.Context, ifModifiedSince time.Time) (model.ArtistIndexes, time.Time, error) {
-	l, err := b.ds.Property().DefaultGet(model.PropLastScan, "-1")
+	l, err := b.ds.Property(ctx).DefaultGet(model.PropLastScan, "-1")
 	ms, _ := strconv.ParseInt(l, 10, 64)
 	lastModified := utils.ToTime(ms)
 
@@ -45,7 +45,7 @@ func (b *browser) Indexes(ctx context.Context, ifModifiedSince time.Time) (model
 	}
 
 	if lastModified.After(ifModifiedSince) {
-		indexes, err := b.ds.Artist().GetIndex()
+		indexes, err := b.ds.Artist(ctx).GetIndex()
 		return indexes, lastModified, err
 	}
 
@@ -72,7 +72,7 @@ type DirectoryInfo struct {
 }
 
 func (b *browser) Artist(ctx context.Context, id string) (*DirectoryInfo, error) {
-	a, albums, err := b.retrieveArtist(id)
+	a, albums, err := b.retrieveArtist(ctx, id)
 	if err != nil {
 		return nil, err
 	}
@@ -81,12 +81,12 @@ func (b *browser) Artist(ctx context.Context, id string) (*DirectoryInfo, error)
 	for _, al := range albums {
 		albumIds = append(albumIds, al.ID)
 	}
-	annMap, err := b.ds.Annotation().GetMap(getUserID(ctx), model.AlbumItemType, albumIds)
+	annMap, err := b.ds.Annotation(ctx).GetMap(getUserID(ctx), model.AlbumItemType, albumIds)
 	return b.buildArtistDir(a, albums, annMap), nil
 }
 
 func (b *browser) Album(ctx context.Context, id string) (*DirectoryInfo, error) {
-	al, tracks, err := b.retrieveAlbum(id)
+	al, tracks, err := b.retrieveAlbum(ctx, id)
 	if err != nil {
 		return nil, err
 	}
@@ -97,11 +97,11 @@ func (b *browser) Album(ctx context.Context, id string) (*DirectoryInfo, error)
 	}
 
 	userID := getUserID(ctx)
-	trackAnnMap, err := b.ds.Annotation().GetMap(userID, model.MediaItemType, mfIds)
+	trackAnnMap, err := b.ds.Annotation(ctx).GetMap(userID, model.MediaItemType, mfIds)
 	if err != nil {
 		return nil, err
 	}
-	ann, err := b.ds.Annotation().Get(userID, model.AlbumItemType, al.ID)
+	ann, err := b.ds.Annotation(ctx).Get(userID, model.AlbumItemType, al.ID)
 	if err != nil {
 		return nil, err
 	}
@@ -121,13 +121,13 @@ func (b *browser) Directory(ctx context.Context, id string) (*DirectoryInfo, err
 }
 
 func (b *browser) GetSong(ctx context.Context, id string) (*Entry, error) {
-	mf, err := b.ds.MediaFile().Get(id)
+	mf, err := b.ds.MediaFile(ctx).Get(id)
 	if err != nil {
 		return nil, err
 	}
 
 	userId := getUserID(ctx)
-	ann, err := b.ds.Annotation().Get(userId, model.MediaItemType, id)
+	ann, err := b.ds.Annotation(ctx).Get(userId, model.MediaItemType, id)
 	if err != nil {
 		return nil, err
 	}
@@ -137,7 +137,7 @@ func (b *browser) GetSong(ctx context.Context, id string) (*Entry, error) {
 }
 
 func (b *browser) GetGenres(ctx context.Context) (model.Genres, error) {
-	genres, err := b.ds.Genre().GetAll()
+	genres, err := b.ds.Genre(ctx).GetAll()
 	for i, g := range genres {
 		if strings.TrimSpace(g.Name) == "" {
 			genres[i].Name = "<Empty>"
@@ -195,7 +195,7 @@ func (b *browser) buildAlbumDir(al *model.Album, albumAnn *model.Annotation, tra
 }
 
 func (b *browser) isArtist(ctx context.Context, id string) bool {
-	found, err := b.ds.Artist().Exists(id)
+	found, err := b.ds.Artist(ctx).Exists(id)
 	if err != nil {
 		log.Debug(ctx, "Error searching for Artist", "id", id, err)
 		return false
@@ -204,7 +204,7 @@ func (b *browser) isArtist(ctx context.Context, id string) bool {
 }
 
 func (b *browser) isAlbum(ctx context.Context, id string) bool {
-	found, err := b.ds.Album().Exists(id)
+	found, err := b.ds.Album(ctx).Exists(id)
 	if err != nil {
 		log.Debug(ctx, "Error searching for Album", "id", id, err)
 		return false
@@ -212,27 +212,27 @@ func (b *browser) isAlbum(ctx context.Context, id string) bool {
 	return found
 }
 
-func (b *browser) retrieveArtist(id string) (a *model.Artist, as model.Albums, err error) {
-	a, err = b.ds.Artist().Get(id)
+func (b *browser) retrieveArtist(ctx context.Context, id string) (a *model.Artist, as model.Albums, err error) {
+	a, err = b.ds.Artist(ctx).Get(id)
 	if err != nil {
 		err = fmt.Errorf("Error reading Artist %s from DB: %v", id, err)
 		return
 	}
 
-	if as, err = b.ds.Album().FindByArtist(id); err != nil {
+	if as, err = b.ds.Album(ctx).FindByArtist(id); err != nil {
 		err = fmt.Errorf("Error reading %s's albums from DB: %v", a.Name, err)
 	}
 	return
 }
 
-func (b *browser) retrieveAlbum(id string) (al *model.Album, mfs model.MediaFiles, err error) {
-	al, err = b.ds.Album().Get(id)
+func (b *browser) retrieveAlbum(ctx context.Context, id string) (al *model.Album, mfs model.MediaFiles, err error) {
+	al, err = b.ds.Album(ctx).Get(id)
 	if err != nil {
 		err = fmt.Errorf("Error reading Album %s from DB: %v", id, err)
 		return
 	}
 
-	if mfs, err = b.ds.MediaFile().FindByAlbum(id); err != nil {
+	if mfs, err = b.ds.MediaFile(ctx).FindByAlbum(id); err != nil {
 		err = fmt.Errorf("Error reading %s's tracks from DB: %v", al.Name, err)
 	}
 	return
diff --git a/engine/cover.go b/engine/cover.go
index 4dd59d21f..ecc418759 100644
--- a/engine/cover.go
+++ b/engine/cover.go
@@ -31,17 +31,17 @@ func NewCover(ds model.DataStore) Cover {
 	return &cover{ds}
 }
 
-func (c *cover) getCoverPath(id string) (string, error) {
+func (c *cover) getCoverPath(ctx context.Context, id string) (string, error) {
 	switch {
 	case strings.HasPrefix(id, "al-"):
 		id = id[3:]
-		al, err := c.ds.Album().Get(id)
+		al, err := c.ds.Album(ctx).Get(id)
 		if err != nil {
 			return "", err
 		}
 		return al.CoverArtPath, nil
 	default:
-		mf, err := c.ds.MediaFile().Get(id)
+		mf, err := c.ds.MediaFile(ctx).Get(id)
 		if err != nil {
 			return "", err
 		}
@@ -53,7 +53,7 @@ func (c *cover) getCoverPath(id string) (string, error) {
 }
 
 func (c *cover) Get(ctx context.Context, id string, size int, out io.Writer) error {
-	path, err := c.getCoverPath(id)
+	path, err := c.getCoverPath(ctx, id)
 	if err != nil && err != model.ErrNotFound {
 		return err
 	}
diff --git a/engine/cover_test.go b/engine/cover_test.go
index 5253955b4..91caad922 100644
--- a/engine/cover_test.go
+++ b/engine/cover_test.go
@@ -17,8 +17,8 @@ func TestCover(t *testing.T) {
 	Init(t, false)
 
 	ds := &persistence.MockDataStore{}
-	mockMediaFileRepo := ds.MediaFile().(*persistence.MockMediaFile)
-	mockAlbumRepo := ds.Album().(*persistence.MockAlbum)
+	mockMediaFileRepo := ds.MediaFile(nil).(*persistence.MockMediaFile)
+	mockAlbumRepo := ds.Album(nil).(*persistence.MockAlbum)
 
 	cover := engine.NewCover(ds)
 	out := new(bytes.Buffer)
diff --git a/engine/list_generator.go b/engine/list_generator.go
index d83c060c6..69d424948 100644
--- a/engine/list_generator.go
+++ b/engine/list_generator.go
@@ -31,7 +31,7 @@ type listGenerator struct {
 }
 
 func (g *listGenerator) query(ctx context.Context, qo model.QueryOptions) (Entries, error) {
-	albums, err := g.ds.Album().GetAll(qo)
+	albums, err := g.ds.Album(ctx).GetAll(qo)
 	if err != nil {
 		return nil, err
 	}
@@ -39,7 +39,7 @@ func (g *listGenerator) query(ctx context.Context, qo model.QueryOptions) (Entri
 	for i, al := range albums {
 		albumIds[i] = al.ID
 	}
-	annMap, err := g.ds.Annotation().GetMap(getUserID(ctx), model.AlbumItemType, albumIds)
+	annMap, err := g.ds.Annotation(ctx).GetMap(getUserID(ctx), model.AlbumItemType, albumIds)
 	if err != nil {
 		return nil, err
 	}
@@ -47,7 +47,7 @@ func (g *listGenerator) query(ctx context.Context, qo model.QueryOptions) (Entri
 }
 
 func (g *listGenerator) queryByAnnotation(ctx context.Context, qo model.QueryOptions) (Entries, error) {
-	annotations, err := g.ds.Annotation().GetAll(getUserID(ctx), model.AlbumItemType, qo)
+	annotations, err := g.ds.Annotation(ctx).GetAll(getUserID(ctx), model.AlbumItemType, qo)
 	if err != nil {
 		return nil, err
 	}
@@ -56,7 +56,7 @@ func (g *listGenerator) queryByAnnotation(ctx context.Context, qo model.QueryOpt
 		albumIds[i] = ann.ItemID
 	}
 
-	albumMap, err := g.ds.Album().GetMap(albumIds)
+	albumMap, err := g.ds.Album(ctx).GetMap(albumIds)
 	if err != nil {
 		return nil, err
 	}
@@ -103,7 +103,7 @@ func (g *listGenerator) GetByArtist(ctx context.Context, offset int, size int) (
 }
 
 func (g *listGenerator) GetRandom(ctx context.Context, offset int, size int) (Entries, error) {
-	albums, err := g.ds.Album().GetRandom(model.QueryOptions{Max: size, Offset: offset})
+	albums, err := g.ds.Album(ctx).GetRandom(model.QueryOptions{Max: size, Offset: offset})
 	if err != nil {
 		return nil, err
 	}
@@ -120,7 +120,7 @@ func (g *listGenerator) getAnnotationsForAlbums(ctx context.Context, albums mode
 	for i, al := range albums {
 		albumIds[i] = al.ID
 	}
-	return g.ds.Annotation().GetMap(getUserID(ctx), model.AlbumItemType, albumIds)
+	return g.ds.Annotation(ctx).GetMap(getUserID(ctx), model.AlbumItemType, albumIds)
 }
 
 func (g *listGenerator) GetRandomSongs(ctx context.Context, size int, genre string) (Entries, error) {
@@ -128,14 +128,14 @@ func (g *listGenerator) GetRandomSongs(ctx context.Context, size int, genre stri
 	if genre != "" {
 		options.Filters = map[string]interface{}{"genre": genre}
 	}
-	mediaFiles, err := g.ds.MediaFile().GetRandom(options)
+	mediaFiles, err := g.ds.MediaFile(ctx).GetRandom(options)
 	if err != nil {
 		return nil, err
 	}
 
 	r := make(Entries, len(mediaFiles))
 	for i, mf := range mediaFiles {
-		ann, err := g.ds.Annotation().Get(getUserID(ctx), model.MediaItemType, mf.ID)
+		ann, err := g.ds.Annotation(ctx).Get(getUserID(ctx), model.MediaItemType, mf.ID)
 		if err != nil {
 			return nil, err
 		}
@@ -146,7 +146,7 @@ func (g *listGenerator) GetRandomSongs(ctx context.Context, size int, genre stri
 
 func (g *listGenerator) GetStarred(ctx context.Context, offset int, size int) (Entries, error) {
 	qo := model.QueryOptions{Offset: offset, Max: size, Sort: "starred_at", Order: "desc"}
-	albums, err := g.ds.Album().GetStarred(getUserID(ctx), qo)
+	albums, err := g.ds.Album(ctx).GetStarred(getUserID(ctx), qo)
 	if err != nil {
 		return nil, err
 	}
@@ -161,17 +161,17 @@ func (g *listGenerator) GetStarred(ctx context.Context, offset int, size int) (E
 func (g *listGenerator) GetAllStarred(ctx context.Context) (artists Entries, albums Entries, mediaFiles Entries, err error) {
 	options := model.QueryOptions{Sort: "starred_at", Order: "desc"}
 
-	ars, err := g.ds.Artist().GetStarred(getUserID(ctx), options)
+	ars, err := g.ds.Artist(ctx).GetStarred(getUserID(ctx), options)
 	if err != nil {
 		return nil, nil, nil, err
 	}
 
-	als, err := g.ds.Album().GetStarred(getUserID(ctx), options)
+	als, err := g.ds.Album(ctx).GetStarred(getUserID(ctx), options)
 	if err != nil {
 		return nil, nil, nil, err
 	}
 
-	mfs, err := g.ds.MediaFile().GetStarred(getUserID(ctx), options)
+	mfs, err := g.ds.MediaFile(ctx).GetStarred(getUserID(ctx), options)
 	if err != nil {
 		return nil, nil, nil, err
 	}
@@ -180,7 +180,7 @@ func (g *listGenerator) GetAllStarred(ctx context.Context) (artists Entries, alb
 	for _, mf := range mfs {
 		mfIds = append(mfIds, mf.ID)
 	}
-	trackAnnMap, err := g.ds.Annotation().GetMap(getUserID(ctx), model.MediaItemType, mfIds)
+	trackAnnMap, err := g.ds.Annotation(ctx).GetMap(getUserID(ctx), model.MediaItemType, mfIds)
 	if err != nil {
 		return nil, nil, nil, err
 	}
@@ -194,7 +194,7 @@ func (g *listGenerator) GetAllStarred(ctx context.Context) (artists Entries, alb
 	for _, ar := range ars {
 		artistIds = append(artistIds, ar.ID)
 	}
-	artistAnnMap, err := g.ds.Annotation().GetMap(getUserID(ctx), model.MediaItemType, artistIds)
+	artistAnnMap, err := g.ds.Annotation(ctx).GetMap(getUserID(ctx), model.MediaItemType, artistIds)
 	if err != nil {
 		return nil, nil, nil, err
 	}
@@ -213,11 +213,11 @@ func (g *listGenerator) GetNowPlaying(ctx context.Context) (Entries, error) {
 	}
 	entries := make(Entries, len(npInfo))
 	for i, np := range npInfo {
-		mf, err := g.ds.MediaFile().Get(np.TrackID)
+		mf, err := g.ds.MediaFile(ctx).Get(np.TrackID)
 		if err != nil {
 			return nil, err
 		}
-		ann, err := g.ds.Annotation().Get(getUserID(ctx), model.MediaItemType, mf.ID)
+		ann, err := g.ds.Annotation(ctx).Get(getUserID(ctx), model.MediaItemType, mf.ID)
 		entries[i] = FromMediaFile(mf, ann)
 		entries[i].UserName = np.Username
 		entries[i].MinutesAgo = int(time.Now().Sub(np.Start).Minutes())
diff --git a/engine/playlists.go b/engine/playlists.go
index 1a5fb9091..d05323de2 100644
--- a/engine/playlists.go
+++ b/engine/playlists.go
@@ -30,7 +30,7 @@ func (p *playlists) Create(ctx context.Context, playlistId, name string, ids []s
 	var err error
 	// If playlistID is present, override tracks
 	if playlistId != "" {
-		pls, err = p.ds.Playlist().Get(playlistId)
+		pls, err = p.ds.Playlist(ctx).Get(playlistId)
 		if err != nil {
 			return err
 		}
@@ -48,7 +48,7 @@ func (p *playlists) Create(ctx context.Context, playlistId, name string, ids []s
 		pls.Tracks = append(pls.Tracks, model.MediaFile{ID: id})
 	}
 
-	return p.ds.Playlist().Put(pls)
+	return p.ds.Playlist(ctx).Put(pls)
 }
 
 func (p *playlists) getUser(ctx context.Context) string {
@@ -61,7 +61,7 @@ func (p *playlists) getUser(ctx context.Context) string {
 }
 
 func (p *playlists) Delete(ctx context.Context, playlistId string) error {
-	pls, err := p.ds.Playlist().Get(playlistId)
+	pls, err := p.ds.Playlist(ctx).Get(playlistId)
 	if err != nil {
 		return err
 	}
@@ -70,11 +70,11 @@ func (p *playlists) Delete(ctx context.Context, playlistId string) error {
 	if owner != pls.Owner {
 		return model.ErrNotAuthorized
 	}
-	return p.ds.Playlist().Delete(playlistId)
+	return p.ds.Playlist(nil).Delete(playlistId)
 }
 
 func (p *playlists) Update(ctx context.Context, playlistId string, name *string, idsToAdd []string, idxToRemove []int) error {
-	pls, err := p.ds.Playlist().Get(playlistId)
+	pls, err := p.ds.Playlist(ctx).Get(playlistId)
 
 	owner := p.getUser(ctx)
 	if owner != pls.Owner {
@@ -100,11 +100,11 @@ func (p *playlists) Update(ctx context.Context, playlistId string, name *string,
 	}
 	pls.Tracks = newTracks
 
-	return p.ds.Playlist().Put(pls)
+	return p.ds.Playlist(ctx).Put(pls)
 }
 
 func (p *playlists) GetAll(ctx context.Context) (model.Playlists, error) {
-	return p.ds.Playlist().GetAll(model.QueryOptions{})
+	return p.ds.Playlist(ctx).GetAll(model.QueryOptions{})
 }
 
 type PlaylistInfo struct {
@@ -119,7 +119,7 @@ type PlaylistInfo struct {
 }
 
 func (p *playlists) Get(ctx context.Context, id string) (*PlaylistInfo, error) {
-	pl, err := p.ds.Playlist().GetWithTracks(id)
+	pl, err := p.ds.Playlist(ctx).GetWithTracks(id)
 	if err != nil {
 		return nil, err
 	}
@@ -141,7 +141,7 @@ func (p *playlists) Get(ctx context.Context, id string) (*PlaylistInfo, error) {
 		mfIds = append(mfIds, mf.ID)
 	}
 
-	annMap, err := p.ds.Annotation().GetMap(getUserID(ctx), model.MediaItemType, mfIds)
+	annMap, err := p.ds.Annotation(ctx).GetMap(getUserID(ctx), model.MediaItemType, mfIds)
 
 	for i, mf := range pl.Tracks {
 		ann := annMap[mf.ID]
diff --git a/engine/ratings.go b/engine/ratings.go
index 4f968ef6e..a2702bfa8 100644
--- a/engine/ratings.go
+++ b/engine/ratings.go
@@ -21,14 +21,14 @@ type ratings struct {
 }
 
 func (r ratings) SetRating(ctx context.Context, id string, rating int) error {
-	exist, err := r.ds.Album().Exists(id)
+	exist, err := r.ds.Album(ctx).Exists(id)
 	if err != nil {
 		return err
 	}
 	if exist {
-		return r.ds.Annotation().SetRating(rating, getUserID(ctx), model.AlbumItemType, id)
+		return r.ds.Annotation(ctx).SetRating(rating, getUserID(ctx), model.AlbumItemType, id)
 	}
-	return r.ds.Annotation().SetRating(rating, getUserID(ctx), model.MediaItemType, id)
+	return r.ds.Annotation(ctx).SetRating(rating, getUserID(ctx), model.MediaItemType, id)
 }
 
 func (r ratings) SetStar(ctx context.Context, star bool, ids ...string) error {
@@ -40,29 +40,29 @@ func (r ratings) SetStar(ctx context.Context, star bool, ids ...string) error {
 
 	return r.ds.WithTx(func(tx model.DataStore) error {
 		for _, id := range ids {
-			exist, err := r.ds.Album().Exists(id)
+			exist, err := r.ds.Album(ctx).Exists(id)
 			if err != nil {
 				return err
 			}
 			if exist {
-				err = tx.Annotation().SetStar(star, userId, model.AlbumItemType, ids...)
+				err = tx.Annotation(ctx).SetStar(star, userId, model.AlbumItemType, ids...)
 				if err != nil {
 					return err
 				}
 				continue
 			}
-			exist, err = r.ds.Artist().Exists(id)
+			exist, err = r.ds.Artist(ctx).Exists(id)
 			if err != nil {
 				return err
 			}
 			if exist {
-				err = tx.Annotation().SetStar(star, userId, model.ArtistItemType, ids...)
+				err = tx.Annotation(ctx).SetStar(star, userId, model.ArtistItemType, ids...)
 				if err != nil {
 					return err
 				}
 				continue
 			}
-			err = tx.Annotation().SetStar(star, userId, model.MediaItemType, ids...)
+			err = tx.Annotation(ctx).SetStar(star, userId, model.MediaItemType, ids...)
 			if err != nil {
 				return err
 			}
diff --git a/engine/scrobbler.go b/engine/scrobbler.go
index b65533b6f..d3d874365 100644
--- a/engine/scrobbler.go
+++ b/engine/scrobbler.go
@@ -29,15 +29,15 @@ func (s *scrobbler) Register(ctx context.Context, playerId int, trackId string,
 	var mf *model.MediaFile
 	var err error
 	err = s.ds.WithTx(func(tx model.DataStore) error {
-		mf, err = s.ds.MediaFile().Get(trackId)
+		mf, err = s.ds.MediaFile(ctx).Get(trackId)
 		if err != nil {
 			return err
 		}
-		err = s.ds.Annotation().IncPlayCount(userId, model.MediaItemType, trackId, playTime)
+		err = s.ds.Annotation(ctx).IncPlayCount(userId, model.MediaItemType, trackId, playTime)
 		if err != nil {
 			return err
 		}
-		err = s.ds.Annotation().IncPlayCount(userId, model.AlbumItemType, mf.AlbumID, playTime)
+		err = s.ds.Annotation(ctx).IncPlayCount(userId, model.AlbumItemType, mf.AlbumID, playTime)
 		return err
 	})
 	return mf, err
@@ -45,7 +45,7 @@ func (s *scrobbler) Register(ctx context.Context, playerId int, trackId string,
 
 // TODO Validate if NowPlaying still works after all refactorings
 func (s *scrobbler) NowPlaying(ctx context.Context, playerId int, playerName, trackId, username string) (*model.MediaFile, error) {
-	mf, err := s.ds.MediaFile().Get(trackId)
+	mf, err := s.ds.MediaFile(ctx).Get(trackId)
 	if err != nil {
 		return nil, err
 	}
diff --git a/engine/search.go b/engine/search.go
index 6a913d456..8d7ae5e33 100644
--- a/engine/search.go
+++ b/engine/search.go
@@ -25,7 +25,7 @@ func NewSearch(ds model.DataStore) Search {
 
 func (s *search) SearchArtist(ctx context.Context, q string, offset int, size int) (Entries, error) {
 	q = sanitize.Accents(strings.ToLower(strings.TrimSuffix(q, "*")))
-	artists, err := s.ds.Artist().Search(q, offset, size)
+	artists, err := s.ds.Artist(ctx).Search(q, offset, size)
 	if len(artists) == 0 || err != nil {
 		return nil, nil
 	}
@@ -34,7 +34,7 @@ func (s *search) SearchArtist(ctx context.Context, q string, offset int, size in
 	for i, al := range artists {
 		artistIds[i] = al.ID
 	}
-	annMap, err := s.ds.Annotation().GetMap(getUserID(ctx), model.ArtistItemType, artistIds)
+	annMap, err := s.ds.Annotation(ctx).GetMap(getUserID(ctx), model.ArtistItemType, artistIds)
 	if err != nil {
 		return nil, nil
 	}
@@ -44,7 +44,7 @@ func (s *search) SearchArtist(ctx context.Context, q string, offset int, size in
 
 func (s *search) SearchAlbum(ctx context.Context, q string, offset int, size int) (Entries, error) {
 	q = sanitize.Accents(strings.ToLower(strings.TrimSuffix(q, "*")))
-	albums, err := s.ds.Album().Search(q, offset, size)
+	albums, err := s.ds.Album(ctx).Search(q, offset, size)
 	if len(albums) == 0 || err != nil {
 		return nil, nil
 	}
@@ -53,7 +53,7 @@ func (s *search) SearchAlbum(ctx context.Context, q string, offset int, size int
 	for i, al := range albums {
 		albumIds[i] = al.ID
 	}
-	annMap, err := s.ds.Annotation().GetMap(getUserID(ctx), model.AlbumItemType, albumIds)
+	annMap, err := s.ds.Annotation(ctx).GetMap(getUserID(ctx), model.AlbumItemType, albumIds)
 	if err != nil {
 		return nil, nil
 	}
@@ -63,7 +63,7 @@ func (s *search) SearchAlbum(ctx context.Context, q string, offset int, size int
 
 func (s *search) SearchSong(ctx context.Context, q string, offset int, size int) (Entries, error) {
 	q = sanitize.Accents(strings.ToLower(strings.TrimSuffix(q, "*")))
-	mediaFiles, err := s.ds.MediaFile().Search(q, offset, size)
+	mediaFiles, err := s.ds.MediaFile(ctx).Search(q, offset, size)
 	if len(mediaFiles) == 0 || err != nil {
 		return nil, nil
 	}
@@ -72,7 +72,7 @@ func (s *search) SearchSong(ctx context.Context, q string, offset int, size int)
 	for i, mf := range mediaFiles {
 		trackIds[i] = mf.ID
 	}
-	annMap, err := s.ds.Annotation().GetMap(getUserID(ctx), model.MediaItemType, trackIds)
+	annMap, err := s.ds.Annotation(ctx).GetMap(getUserID(ctx), model.MediaItemType, trackIds)
 	if err != nil {
 		return nil, nil
 	}
diff --git a/engine/users.go b/engine/users.go
index 120d90751..fde6fd04b 100644
--- a/engine/users.go
+++ b/engine/users.go
@@ -24,7 +24,7 @@ type users struct {
 }
 
 func (u *users) Authenticate(ctx context.Context, username, pass, token, salt string) (*model.User, error) {
-	user, err := u.ds.User().FindByUsername(username)
+	user, err := u.ds.User(ctx).FindByUsername(username)
 	if err == model.ErrNotFound {
 		return nil, model.ErrInvalidAuth
 	}
@@ -50,7 +50,7 @@ func (u *users) Authenticate(ctx context.Context, username, pass, token, salt st
 		return nil, model.ErrInvalidAuth
 	}
 	go func() {
-		err := u.ds.User().UpdateLastAccessAt(user.ID)
+		err := u.ds.User(ctx).UpdateLastAccessAt(user.ID)
 		if err != nil {
 			log.Error(ctx, "Could not update user's lastAccessAt", "user", user.UserName)
 		}
diff --git a/model/datastore.go b/model/datastore.go
index 493a8cb69..61f1ce862 100644
--- a/model/datastore.go
+++ b/model/datastore.go
@@ -1,6 +1,8 @@
 package model
 
 import (
+	"context"
+
 	"github.com/deluan/rest"
 )
 
@@ -22,17 +24,17 @@ type ResourceRepository interface {
 }
 
 type DataStore interface {
-	Album() AlbumRepository
-	Artist() ArtistRepository
-	MediaFile() MediaFileRepository
-	MediaFolder() MediaFolderRepository
-	Genre() GenreRepository
-	Playlist() PlaylistRepository
-	Property() PropertyRepository
-	User() UserRepository
-	Annotation() AnnotationRepository
+	Album(ctx context.Context) AlbumRepository
+	Artist(ctx context.Context) ArtistRepository
+	MediaFile(ctx context.Context) MediaFileRepository
+	MediaFolder(ctx context.Context) MediaFolderRepository
+	Genre(ctx context.Context) GenreRepository
+	Playlist(ctx context.Context) PlaylistRepository
+	Property(ctx context.Context) PropertyRepository
+	User(ctx context.Context) UserRepository
+	Annotation(ctx context.Context) AnnotationRepository
 
-	Resource(model interface{}) ResourceRepository
+	Resource(ctx context.Context, model interface{}) ResourceRepository
 
 	WithTx(func(tx DataStore) error) error
 }
diff --git a/persistence/mock_persistence.go b/persistence/mock_persistence.go
index ab268cbb1..ac021a526 100644
--- a/persistence/mock_persistence.go
+++ b/persistence/mock_persistence.go
@@ -1,6 +1,10 @@
 package persistence
 
-import "github.com/deluan/navidrome/model"
+import (
+	"context"
+
+	"github.com/deluan/navidrome/model"
+)
 
 type MockDataStore struct {
 	MockedGenre     model.GenreRepository
@@ -10,54 +14,54 @@ type MockDataStore struct {
 	MockedUser      model.UserRepository
 }
 
-func (db *MockDataStore) Album() model.AlbumRepository {
+func (db *MockDataStore) Album(context.Context) model.AlbumRepository {
 	if db.MockedAlbum == nil {
 		db.MockedAlbum = CreateMockAlbumRepo()
 	}
 	return db.MockedAlbum
 }
 
-func (db *MockDataStore) Artist() model.ArtistRepository {
+func (db *MockDataStore) Artist(context.Context) model.ArtistRepository {
 	if db.MockedArtist == nil {
 		db.MockedArtist = CreateMockArtistRepo()
 	}
 	return db.MockedArtist
 }
 
-func (db *MockDataStore) MediaFile() model.MediaFileRepository {
+func (db *MockDataStore) MediaFile(context.Context) model.MediaFileRepository {
 	if db.MockedMediaFile == nil {
 		db.MockedMediaFile = CreateMockMediaFileRepo()
 	}
 	return db.MockedMediaFile
 }
 
-func (db *MockDataStore) MediaFolder() model.MediaFolderRepository {
+func (db *MockDataStore) MediaFolder(context.Context) model.MediaFolderRepository {
 	return struct{ model.MediaFolderRepository }{}
 }
 
-func (db *MockDataStore) Genre() model.GenreRepository {
+func (db *MockDataStore) Genre(context.Context) model.GenreRepository {
 	if db.MockedGenre != nil {
 		return db.MockedGenre
 	}
 	return struct{ model.GenreRepository }{}
 }
 
-func (db *MockDataStore) Playlist() model.PlaylistRepository {
+func (db *MockDataStore) Playlist(context.Context) model.PlaylistRepository {
 	return struct{ model.PlaylistRepository }{}
 }
 
-func (db *MockDataStore) Property() model.PropertyRepository {
+func (db *MockDataStore) Property(context.Context) model.PropertyRepository {
 	return struct{ model.PropertyRepository }{}
 }
 
-func (db *MockDataStore) User() model.UserRepository {
+func (db *MockDataStore) User(context.Context) model.UserRepository {
 	if db.MockedUser == nil {
 		db.MockedUser = &mockedUserRepo{}
 	}
 	return db.MockedUser
 }
 
-func (db *MockDataStore) Annotation() model.AnnotationRepository {
+func (db *MockDataStore) Annotation(context.Context) model.AnnotationRepository {
 	return struct{ model.AnnotationRepository }{}
 }
 
@@ -65,7 +69,7 @@ func (db *MockDataStore) WithTx(block func(db model.DataStore) error) error {
 	return block(db)
 }
 
-func (db *MockDataStore) Resource(m interface{}) model.ResourceRepository {
+func (db *MockDataStore) Resource(ctx context.Context, m interface{}) model.ResourceRepository {
 	return struct{ model.ResourceRepository }{}
 }
 
diff --git a/persistence/persistence.go b/persistence/persistence.go
index f53728214..1b19a9113 100644
--- a/persistence/persistence.go
+++ b/persistence/persistence.go
@@ -1,6 +1,7 @@
 package persistence
 
 import (
+	"context"
 	"reflect"
 	"strings"
 	"sync"
@@ -41,43 +42,43 @@ func New() model.DataStore {
 	return &SQLStore{}
 }
 
-func (db *SQLStore) Album() model.AlbumRepository {
+func (db *SQLStore) Album(context.Context) model.AlbumRepository {
 	return NewAlbumRepository(db.getOrmer())
 }
 
-func (db *SQLStore) Artist() model.ArtistRepository {
+func (db *SQLStore) Artist(context.Context) model.ArtistRepository {
 	return NewArtistRepository(db.getOrmer())
 }
 
-func (db *SQLStore) MediaFile() model.MediaFileRepository {
+func (db *SQLStore) MediaFile(context.Context) model.MediaFileRepository {
 	return NewMediaFileRepository(db.getOrmer())
 }
 
-func (db *SQLStore) MediaFolder() model.MediaFolderRepository {
+func (db *SQLStore) MediaFolder(context.Context) model.MediaFolderRepository {
 	return NewMediaFolderRepository(db.getOrmer())
 }
 
-func (db *SQLStore) Genre() model.GenreRepository {
+func (db *SQLStore) Genre(context.Context) model.GenreRepository {
 	return NewGenreRepository(db.getOrmer())
 }
 
-func (db *SQLStore) Playlist() model.PlaylistRepository {
+func (db *SQLStore) Playlist(context.Context) model.PlaylistRepository {
 	return NewPlaylistRepository(db.getOrmer())
 }
 
-func (db *SQLStore) Property() model.PropertyRepository {
+func (db *SQLStore) Property(context.Context) model.PropertyRepository {
 	return NewPropertyRepository(db.getOrmer())
 }
 
-func (db *SQLStore) User() model.UserRepository {
+func (db *SQLStore) User(context.Context) model.UserRepository {
 	return NewUserRepository(db.getOrmer())
 }
 
-func (db *SQLStore) Annotation() model.AnnotationRepository {
+func (db *SQLStore) Annotation(context.Context) model.AnnotationRepository {
 	return NewAnnotationRepository(db.getOrmer())
 }
 
-func (db *SQLStore) Resource(model interface{}) model.ResourceRepository {
+func (db *SQLStore) Resource(ctx context.Context, model interface{}) model.ResourceRepository {
 	return NewResource(db.getOrmer(), model, getMappedModel(model))
 }
 
diff --git a/persistence/persistence_suite_test.go b/persistence/persistence_suite_test.go
index d4f50b7a1..cd3dd10a6 100644
--- a/persistence/persistence_suite_test.go
+++ b/persistence/persistence_suite_test.go
@@ -63,21 +63,21 @@ var _ = Describe("Initialize test DB", func() {
 	BeforeSuite(func() {
 		conf.Server.DbPath = ":memory:"
 		ds := New()
-		artistRepo := ds.Artist()
+		artistRepo := ds.Artist(nil)
 		for _, a := range testArtists {
 			err := artistRepo.Put(&a)
 			if err != nil {
 				panic(err)
 			}
 		}
-		albumRepository := ds.Album()
+		albumRepository := ds.Album(nil)
 		for _, a := range testAlbums {
 			err := albumRepository.Put(&a)
 			if err != nil {
 				panic(err)
 			}
 		}
-		mediaFileRepository := ds.MediaFile()
+		mediaFileRepository := ds.MediaFile(nil)
 		for _, s := range testSongs {
 			err := mediaFileRepository.Put(&s)
 			if err != nil {
diff --git a/scanner/scanner.go b/scanner/scanner.go
index 7c03e9b10..5b1d8212e 100644
--- a/scanner/scanner.go
+++ b/scanner/scanner.go
@@ -60,7 +60,7 @@ func (s *Scanner) RescanAll(fullRescan bool) error {
 func (s *Scanner) Status() []StatusInfo { return nil }
 
 func (s *Scanner) getLastModifiedSince(folder string) time.Time {
-	ms, err := s.ds.Property().Get(model.PropLastScan + "-" + folder)
+	ms, err := s.ds.Property(nil).Get(model.PropLastScan + "-" + folder)
 	if err != nil {
 		return time.Time{}
 	}
@@ -73,11 +73,11 @@ func (s *Scanner) getLastModifiedSince(folder string) time.Time {
 
 func (s *Scanner) updateLastModifiedSince(folder string, t time.Time) {
 	millis := t.UnixNano() / int64(time.Millisecond)
-	s.ds.Property().Put(model.PropLastScan+"-"+folder, fmt.Sprint(millis))
+	s.ds.Property(nil).Put(model.PropLastScan+"-"+folder, fmt.Sprint(millis))
 }
 
 func (s *Scanner) loadFolders() {
-	fs, _ := s.ds.MediaFolder().GetAll()
+	fs, _ := s.ds.MediaFolder(nil).GetAll()
 	for _, f := range fs {
 		log.Info("Configuring Media Folder", "name", f.Name, "path", f.Path)
 		s.folders[f.Path] = NewTagScanner(f.Path, s.ds)
diff --git a/scanner/tag_scanner.go b/scanner/tag_scanner.go
index 2fb053f33..60f6621f1 100644
--- a/scanner/tag_scanner.go
+++ b/scanner/tag_scanner.go
@@ -58,16 +58,16 @@ func (s *TagScanner) Scan(ctx context.Context, lastModifiedSince time.Time) erro
 	updatedAlbums := map[string]bool{}
 
 	for _, c := range changed {
-		err := s.processChangedDir(c, updatedArtists, updatedAlbums)
+		err := s.processChangedDir(ctx, c, updatedArtists, updatedAlbums)
 		if err != nil {
 			return err
 		}
 		if len(updatedAlbums)+len(updatedArtists) > 100 {
-			err = s.refreshAlbums(updatedAlbums)
+			err = s.refreshAlbums(ctx, updatedAlbums)
 			if err != nil {
 				return err
 			}
-			err = s.refreshArtists(updatedArtists)
+			err = s.refreshArtists(ctx, updatedArtists)
 			if err != nil {
 				return err
 			}
@@ -76,16 +76,16 @@ func (s *TagScanner) Scan(ctx context.Context, lastModifiedSince time.Time) erro
 		}
 	}
 	for _, c := range deleted {
-		err := s.processDeletedDir(c, updatedArtists, updatedAlbums)
+		err := s.processDeletedDir(ctx, c, updatedArtists, updatedAlbums)
 		if err != nil {
 			return err
 		}
 		if len(updatedAlbums)+len(updatedArtists) > 100 {
-			err = s.refreshAlbums(updatedAlbums)
+			err = s.refreshAlbums(ctx, updatedAlbums)
 			if err != nil {
 				return err
 			}
-			err = s.refreshArtists(updatedArtists)
+			err = s.refreshArtists(ctx, updatedArtists)
 			if err != nil {
 				return err
 			}
@@ -94,22 +94,22 @@ func (s *TagScanner) Scan(ctx context.Context, lastModifiedSince time.Time) erro
 		}
 	}
 
-	err = s.refreshAlbums(updatedAlbums)
+	err = s.refreshAlbums(ctx, updatedAlbums)
 	if err != nil {
 		return err
 	}
 
-	err = s.refreshArtists(updatedArtists)
+	err = s.refreshArtists(ctx, updatedArtists)
 	if err != nil {
 		return err
 	}
 
-	err = s.ds.Album().PurgeEmpty()
+	err = s.ds.Album(ctx).PurgeEmpty()
 	if err != nil {
 		return err
 	}
 
-	err = s.ds.Artist().PurgeEmpty()
+	err = s.ds.Artist(ctx).PurgeEmpty()
 	if err != nil {
 		return err
 	}
@@ -117,30 +117,30 @@ func (s *TagScanner) Scan(ctx context.Context, lastModifiedSince time.Time) erro
 	return nil
 }
 
-func (s *TagScanner) refreshAlbums(updatedAlbums map[string]bool) error {
+func (s *TagScanner) refreshAlbums(ctx context.Context, updatedAlbums map[string]bool) error {
 	var ids []string
 	for id := range updatedAlbums {
 		ids = append(ids, id)
 	}
-	return s.ds.Album().Refresh(ids...)
+	return s.ds.Album(ctx).Refresh(ids...)
 }
 
-func (s *TagScanner) refreshArtists(updatedArtists map[string]bool) error {
+func (s *TagScanner) refreshArtists(ctx context.Context, updatedArtists map[string]bool) error {
 	var ids []string
 	for id := range updatedArtists {
 		ids = append(ids, id)
 	}
-	return s.ds.Artist().Refresh(ids...)
+	return s.ds.Artist(ctx).Refresh(ids...)
 }
 
-func (s *TagScanner) processChangedDir(dir string, updatedArtists map[string]bool, updatedAlbums map[string]bool) error {
+func (s *TagScanner) processChangedDir(ctx context.Context, dir string, updatedArtists map[string]bool, updatedAlbums map[string]bool) error {
 	dir = path.Join(s.rootFolder, dir)
 
 	start := time.Now()
 
 	// Load folder's current tracks from DB into a map
 	currentTracks := map[string]model.MediaFile{}
-	ct, err := s.ds.MediaFile().FindByPath(dir)
+	ct, err := s.ds.MediaFile(ctx).FindByPath(dir)
 	if err != nil {
 		return err
 	}
@@ -168,7 +168,7 @@ func (s *TagScanner) processChangedDir(dir string, updatedArtists map[string]boo
 	for _, n := range newTracks {
 		c, ok := currentTracks[n.ID]
 		if !ok || (ok && n.UpdatedAt.After(c.UpdatedAt)) {
-			err := s.ds.MediaFile().Put(&n)
+			err := s.ds.MediaFile(ctx).Put(&n)
 			updatedArtists[n.ArtistID] = true
 			updatedAlbums[n.AlbumID] = true
 			numUpdatedTracks++
@@ -182,7 +182,7 @@ func (s *TagScanner) processChangedDir(dir string, updatedArtists map[string]boo
 	// Remaining tracks from DB that are not in the folder are deleted
 	for id := range currentTracks {
 		numPurgedTracks++
-		if err := s.ds.MediaFile().Delete(id); err != nil {
+		if err := s.ds.MediaFile(ctx).Delete(id); err != nil {
 			return err
 		}
 	}
@@ -191,10 +191,10 @@ func (s *TagScanner) processChangedDir(dir string, updatedArtists map[string]boo
 	return nil
 }
 
-func (s *TagScanner) processDeletedDir(dir string, updatedArtists map[string]bool, updatedAlbums map[string]bool) error {
+func (s *TagScanner) processDeletedDir(ctx context.Context, dir string, updatedArtists map[string]bool, updatedAlbums map[string]bool) error {
 	dir = path.Join(s.rootFolder, dir)
 
-	ct, err := s.ds.MediaFile().FindByPath(dir)
+	ct, err := s.ds.MediaFile(ctx).FindByPath(dir)
 	if err != nil {
 		return err
 	}
@@ -203,7 +203,7 @@ func (s *TagScanner) processDeletedDir(dir string, updatedArtists map[string]boo
 		updatedAlbums[t.AlbumID] = true
 	}
 
-	return s.ds.MediaFile().DeleteByPath(dir)
+	return s.ds.MediaFile(ctx).DeleteByPath(dir)
 }
 
 func (s *TagScanner) loadTracks(dirPath string) (model.MediaFiles, error) {
diff --git a/server/app/app.go b/server/app/app.go
index fe9f49114..1ed9eb4e6 100644
--- a/server/app/app.go
+++ b/server/app/app.go
@@ -64,7 +64,7 @@ func (app *Router) routes() http.Handler {
 
 func (app *Router) R(r chi.Router, pathPrefix string, model interface{}) {
 	constructor := func(ctx context.Context) rest.Repository {
-		return app.ds.Resource(model)
+		return app.ds.Resource(ctx, model)
 	}
 	r.Route(pathPrefix, func(r chi.Router) {
 		r.Get("/", rest.GetAll(constructor))
diff --git a/server/app/auth.go b/server/app/auth.go
index c70a93c24..4a9f53585 100644
--- a/server/app/auth.go
+++ b/server/app/auth.go
@@ -41,7 +41,7 @@ func Login(ds model.DataStore) func(w http.ResponseWriter, r *http.Request) {
 }
 
 func handleLogin(ds model.DataStore, username string, password string, w http.ResponseWriter, r *http.Request) {
-	user, err := validateLogin(ds.User(), username, password)
+	user, err := validateLogin(ds.User(r.Context()), username, password)
 	if err != nil {
 		rest.RespondWithError(w, http.StatusInternalServerError, "Unknown error authentication user. Please try again")
 		return
@@ -89,7 +89,7 @@ func CreateAdmin(ds model.DataStore) func(w http.ResponseWriter, r *http.Request
 			rest.RespondWithError(w, http.StatusUnprocessableEntity, err.Error())
 			return
 		}
-		c, err := ds.User().CountAll()
+		c, err := ds.User(r.Context()).CountAll()
 		if err != nil {
 			rest.RespondWithError(w, http.StatusInternalServerError, err.Error())
 			return
@@ -98,7 +98,7 @@ func CreateAdmin(ds model.DataStore) func(w http.ResponseWriter, r *http.Request
 			rest.RespondWithError(w, http.StatusForbidden, "Cannot create another first admin")
 			return
 		}
-		err = createDefaultUser(ds, username, password)
+		err = createDefaultUser(r.Context(), ds, username, password)
 		if err != nil {
 			rest.RespondWithError(w, http.StatusInternalServerError, err.Error())
 			return
@@ -107,7 +107,7 @@ func CreateAdmin(ds model.DataStore) func(w http.ResponseWriter, r *http.Request
 	}
 }
 
-func createDefaultUser(ds model.DataStore, username, password string) error {
+func createDefaultUser(ctx context.Context, ds model.DataStore, username, password string) error {
 	id, _ := uuid.NewRandom()
 	log.Warn("Creating initial user", "user", consts.InitialUserName)
 	initialUser := model.User{
@@ -118,7 +118,7 @@ func createDefaultUser(ds model.DataStore, username, password string) error {
 		Password: password,
 		IsAdmin:  true,
 	}
-	err := ds.User().Put(&initialUser)
+	err := ds.User(ctx).Put(&initialUser)
 	if err != nil {
 		log.Error("Could not create initial user", "user", initialUser, err)
 	}
@@ -127,7 +127,7 @@ func createDefaultUser(ds model.DataStore, username, password string) error {
 
 func initTokenAuth(ds model.DataStore) {
 	once.Do(func() {
-		secret, err := ds.Property().DefaultGet(consts.JWTSecretKey, "not so secret")
+		secret, err := ds.Property(nil).DefaultGet(consts.JWTSecretKey, "not so secret")
 		if err != nil {
 			log.Error("No JWT secret found in DB. Setting a temp one, but please report this error", err)
 		}
@@ -190,7 +190,7 @@ func getToken(ds model.DataStore, ctx context.Context) (*jwt.Token, error) {
 		return token, nil
 	}
 
-	c, err := ds.User().CountAll()
+	c, err := ds.User(ctx).CountAll()
 	firstTime := c == 0 && err == nil
 	if firstTime {
 		return nil, ErrFirstTime
diff --git a/server/initial_setup.go b/server/initial_setup.go
index d1b47aa0a..437859871 100644
--- a/server/initial_setup.go
+++ b/server/initial_setup.go
@@ -11,7 +11,7 @@ import (
 
 func initialSetup(ds model.DataStore) {
 	_ = ds.WithTx(func(tx model.DataStore) error {
-		_, err := ds.Property().Get(consts.InitialSetupFlagKey)
+		_, err := ds.Property(nil).Get(consts.InitialSetupFlagKey)
 		if err == nil {
 			return nil
 		}
@@ -20,19 +20,19 @@ func initialSetup(ds model.DataStore) {
 			return err
 		}
 
-		err = ds.Property().Put(consts.InitialSetupFlagKey, time.Now().String())
+		err = ds.Property(nil).Put(consts.InitialSetupFlagKey, time.Now().String())
 		return err
 	})
 }
 
 func createJWTSecret(ds model.DataStore) error {
-	_, err := ds.Property().Get(consts.JWTSecretKey)
+	_, err := ds.Property(nil).Get(consts.JWTSecretKey)
 	if err == nil {
 		return nil
 	}
 	jwtSecret, _ := uuid.NewRandom()
 	log.Warn("Creating JWT secret, used for encrypting UI sessions")
-	err = ds.Property().Put(consts.JWTSecretKey, jwtSecret.String())
+	err = ds.Property(nil).Put(consts.JWTSecretKey, jwtSecret.String())
 	if err != nil {
 		log.Error("Could not save JWT secret in DB", err)
 	}