diff --git a/pkg/delivery/client/adapter.go b/pkg/delivery/client/adapter.go
new file mode 100644
index 0000000000000000000000000000000000000000..df4c1722cae2ee0abb3be12e58e9f5232bac2bb7
--- /dev/null
+++ b/pkg/delivery/client/adapter.go
@@ -0,0 +1,63 @@
+package client
+
+import (
+	"context"
+
+	"git.perx.ru/perxis/perxis-go/pkg/collections"
+	"git.perx.ru/perxis/perxis-go/pkg/delivery"
+	"git.perx.ru/perxis/perxis-go/pkg/environments"
+	"git.perx.ru/perxis/perxis-go/pkg/items"
+	"git.perx.ru/perxis/perxis-go/pkg/locales"
+)
+
+type envsAdapter struct {
+	environments.Environments
+	dv delivery.Delivery
+}
+
+func (a envsAdapter) Get(ctx context.Context, spaceId, envId string) (env *environments.Environment, err error) {
+	return a.dv.GetEnvironment(ctx, spaceId, envId)
+}
+
+func (a envsAdapter) List(ctx context.Context, spaceId string) (envs []*environments.Environment, err error) {
+	return a.dv.ListEnvironments(ctx, spaceId)
+}
+
+type localesAdapter struct {
+	locales.Locales
+	dv delivery.Delivery
+}
+
+func (a localesAdapter) List(ctx context.Context, spaceId string) (locales []*locales.Locale, err error) {
+	return a.dv.ListLocales(ctx, spaceId)
+}
+
+type collectionsAdapter struct {
+	collections.Collections
+	dv delivery.Delivery
+}
+
+func (a collectionsAdapter) Get(ctx context.Context, spaceId, envId, collectionId string, opts ...*collections.GetOptions) (collection *collections.Collection, err error) {
+	return a.dv.GetCollection(ctx, spaceId, envId, collectionId)
+}
+
+func (a collectionsAdapter) List(ctx context.Context, spaceId, envId string, filter *collections.Filter) (collections []*collections.Collection, err error) {
+	return a.dv.ListCollections(ctx, spaceId, envId)
+}
+
+type itemsAdapter struct {
+	items.Items
+	dv delivery.Delivery
+}
+
+func (a itemsAdapter) GetPublished(ctx context.Context, spaceId, envId, collectionId, itemId string, options ...*items.GetPublishedOptions) (item *items.Item, err error) {
+	return a.dv.GetItem(ctx, spaceId, envId, collectionId, itemId, options...)
+}
+
+func (a itemsAdapter) FindPublished(ctx context.Context, spaceId, envId, collectionId string, filter *items.Filter, options ...*items.FindPublishedOptions) (items []*items.Item, total int, err error) {
+	return a.dv.FindItems(ctx, spaceId, envId, collectionId, filter, options...)
+}
+
+func (a itemsAdapter) AggregatePublished(ctx context.Context, spaceId, envId, collectionId string, filter *items.Filter, options ...*items.AggregatePublishedOptions) (result map[string]interface{}, err error) {
+	return a.dv.Aggregate(ctx, spaceId, envId, collectionId, filter, options...)
+}
diff --git a/pkg/delivery/client/client.go b/pkg/delivery/client/client.go
new file mode 100644
index 0000000000000000000000000000000000000000..4f7d9a97ab4a978f3fd6c5708f6b5691067b64c0
--- /dev/null
+++ b/pkg/delivery/client/client.go
@@ -0,0 +1,67 @@
+package client
+
+import (
+	"context"
+	"time"
+
+	"git.perx.ru/perxis/perxis-go/pkg/cache"
+	collections "git.perx.ru/perxis/perxis-go/pkg/collections/middleware"
+	"git.perx.ru/perxis/perxis-go/pkg/delivery"
+	deliveryservice "git.perx.ru/perxis/perxis-go/pkg/delivery/service"
+	deliverytransportgrpc "git.perx.ru/perxis/perxis-go/pkg/delivery/transport/grpc"
+	environments "git.perx.ru/perxis/perxis-go/pkg/environments/middleware"
+	items "git.perx.ru/perxis/perxis-go/pkg/items/middleware"
+	locales "git.perx.ru/perxis/perxis-go/pkg/locales/middleware"
+	"google.golang.org/grpc"
+)
+
+func NewClient(addr string, opts ...Option) (delivery.Delivery, error) {
+	ctx := context.Background()
+
+	c := new(Config)
+	dialOpts := make([]grpc.DialOption, 0)
+
+	for _, o := range opts {
+		o(&c.Config)
+	}
+
+	authDialOpts, err := c.GetAuthDialOpts(ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	conn, err := grpc.Dial(addr, append(dialOpts, authDialOpts...)...)
+	if err != nil {
+		return nil, err
+	}
+
+	client := deliverytransportgrpc.NewGRPCClient(conn, "", c.ClientOptions...)
+
+	cfg := &deliveryservice.Config{
+		Locales:      localesAdapter{dv: client},
+		Environments: envsAdapter{dv: client},
+		Collections:  collectionsAdapter{dv: client},
+		Items:        itemsAdapter{dv: client},
+	}
+
+	if !c.NoDecode {
+		cfg.Items = items.ClientEncodeMiddleware(cfg.Collections)(cfg.Items)
+	}
+
+	if !c.NoCache {
+		cfg = WithCaching(cfg, 0, 0)
+	}
+
+	return deliveryservice.NewService(cfg), nil
+}
+
+func WithCaching(cfg *deliveryservice.Config, size int, ttl time.Duration) *deliveryservice.Config {
+	c := *cfg
+
+	c.Environments = environments.CachingMiddleware(cache.NewCache(size, ttl))(cfg.Environments)
+	c.Locales = locales.CachingMiddleware(cache.NewCache(size, ttl))(cfg.Locales)
+	c.Items = items.CachingMiddleware(cache.NewCache(size, ttl), cache.NewCache(size, ttl), c.Environments)(cfg.Items)
+	c.Collections = collections.CachingMiddleware(cache.NewCache(size, ttl), c.Environments)(cfg.Collections)
+
+	return &c
+}
diff --git a/pkg/delivery/client/config.go b/pkg/delivery/client/config.go
new file mode 100644
index 0000000000000000000000000000000000000000..27f34b0bef42e7ad5aa40093a2f4188f62d1c556
--- /dev/null
+++ b/pkg/delivery/client/config.go
@@ -0,0 +1,36 @@
+package client
+
+import (
+	contentclient "git.perx.ru/perxis/perxis-go/pkg/content"
+	"github.com/go-kit/kit/transport/grpc"
+)
+
+type Option contentclient.Option
+
+type Config struct {
+	contentclient.Config
+}
+
+func AuthOAuth2(tokenUrl, clientID, clientSecret, audience string) Option {
+	return Option(contentclient.AuthOAuth2(tokenUrl, clientID, clientSecret, audience))
+}
+
+func AuthTLS(cacert, cert, key []byte) Option {
+	return Option(contentclient.AuthTLS(cacert, cert, key))
+}
+
+func AuthAPIKey(key string) Option {
+	return Option(contentclient.AuthAPIKey(key))
+}
+
+func AuthInsecure() Option {
+	return Option(contentclient.AuthInsecure())
+}
+
+func GrpcClientOptions(opts ...grpc.ClientOption) Option {
+	return Option(contentclient.GrpcClientOptions(opts...))
+}
+
+func NoCache() Option {
+	return Option(contentclient.NoCache())
+}
diff --git a/pkg/delivery/service/service.go b/pkg/delivery/service/service.go
new file mode 100644
index 0000000000000000000000000000000000000000..ed1b5091c553853ec78f9f20bc3b54b3e0239834
--- /dev/null
+++ b/pkg/delivery/service/service.go
@@ -0,0 +1,67 @@
+package service
+
+import (
+	"context"
+
+	"git.perx.ru/perxis/perxis-go/pkg/collections"
+	"git.perx.ru/perxis/perxis-go/pkg/delivery"
+	"git.perx.ru/perxis/perxis-go/pkg/environments"
+	"git.perx.ru/perxis/perxis-go/pkg/items"
+	"git.perx.ru/perxis/perxis-go/pkg/locales"
+)
+
+type Config struct {
+	locales.Locales
+	environments.Environments
+	collections.Collections
+	items.Items
+}
+
+func NewService(config *Config) delivery.Delivery {
+	return &deliveryService{
+		Locales:      config.Locales,
+		Environments: config.Environments,
+		Collections:  config.Collections,
+		Items:        config.Items,
+	}
+}
+
+type deliveryService struct {
+	locales.Locales
+	environments.Environments
+	collections.Collections
+	items.Items
+}
+
+func (s deliveryService) ListLocales(ctx context.Context, spaceId string) (locales []*locales.Locale, err error) {
+	return s.Locales.List(ctx, spaceId)
+}
+
+func (s deliveryService) GetEnvironment(ctx context.Context, spaceId, envId string) (env *environments.Environment, err error) {
+	return s.Environments.Get(ctx, spaceId, envId)
+}
+
+func (s deliveryService) ListEnvironments(ctx context.Context, spaceId string) (envs []*environments.Environment, err error) {
+	return s.Environments.List(ctx, spaceId)
+}
+
+func (s deliveryService) GetCollection(ctx context.Context, spaceId, envId, collectionId string) (collection *collections.Collection, err error) {
+	// Для Delivery всегда загружается коллекция для последующего использования, так как нет кейсов использования незагруженной коллекции
+	return s.Collections.Get(ctx, spaceId, envId, collectionId)
+}
+
+func (s deliveryService) ListCollections(ctx context.Context, spaceId, envId string) (collections []*collections.Collection, err error) {
+	return s.Collections.List(ctx, spaceId, envId, nil)
+}
+
+func (s deliveryService) GetItem(ctx context.Context, spaceId, envId, collectionId, itemId string, options ...*items.GetPublishedOptions) (item *items.Item, err error) {
+	return s.Items.GetPublished(ctx, spaceId, envId, collectionId, itemId, options...)
+}
+
+func (s deliveryService) FindItems(ctx context.Context, spaceId, envId, collectionId string, filter *items.Filter, options ...*items.FindPublishedOptions) (items []*items.Item, total int, err error) {
+	return s.Items.FindPublished(ctx, spaceId, envId, collectionId, filter, options...)
+}
+
+func (s deliveryService) Aggregate(ctx context.Context, spaceId, envId, collectionId string, filter *items.Filter, options ...*items.AggregatePublishedOptions) (result map[string]interface{}, err error) {
+	return s.Items.AggregatePublished(ctx, spaceId, envId, collectionId, filter, options...)
+}