diff --git a/README.md b/README.md
index dcdf8227c76a..0af9e2e1267c 100644
--- a/README.md
+++ b/README.md
@@ -352,6 +352,7 @@ The directory layout conforms to OCI Image Spec v1.0.
 -   `mode=max`: export all the layers of all intermediate steps. Not supported for `inline` cache exporter.
 -   `ref=docker.io/user/image:tag`: reference for `registry` cache exporter
 -   `dest=path/to/output-dir`: directory for `local` cache exporter
+-   `oci-mediatypes=true|false`: whether to use OCI mediatypes in exported manifests for `local` and `registry` exporter. Since BuildKit `v0.8` defaults to true.
 
 #### `--import-cache` options
 -   `type`: `registry` or `local`. Use `registry` to import `inline` cache.
diff --git a/cache/remotecache/export.go b/cache/remotecache/export.go
index d9d5bab7fdf9..542aa760860f 100644
--- a/cache/remotecache/export.go
+++ b/cache/remotecache/export.go
@@ -12,6 +12,7 @@ import (
 	v1 "github.com/moby/buildkit/cache/remotecache/v1"
 	"github.com/moby/buildkit/session"
 	"github.com/moby/buildkit/solver"
+	"github.com/moby/buildkit/util/compression"
 	"github.com/moby/buildkit/util/contentutil"
 	"github.com/moby/buildkit/util/progress"
 	digest "github.com/opencontainers/go-digest"
@@ -55,20 +56,17 @@ type contentCacheExporter struct {
 	solver.CacheExporterTarget
 	chains   *v1.CacheChains
 	ingester content.Ingester
+	oci      bool
 }
 
-func NewExporter(ingester content.Ingester) Exporter {
+func NewExporter(ingester content.Ingester, oci bool) Exporter {
 	cc := v1.NewCacheChains()
-	return &contentCacheExporter{CacheExporterTarget: cc, chains: cc, ingester: ingester}
+	return &contentCacheExporter{CacheExporterTarget: cc, chains: cc, ingester: ingester, oci: oci}
 }
 
 func (ce *contentCacheExporter) Finalize(ctx context.Context) (map[string]string, error) {
-	return export(ctx, ce.ingester, ce.chains)
-}
-
-func export(ctx context.Context, ingester content.Ingester, cc *v1.CacheChains) (map[string]string, error) {
 	res := make(map[string]string)
-	config, descs, err := cc.Marshal()
+	config, descs, err := ce.chains.Marshal()
 	if err != nil {
 		return nil, err
 	}
@@ -86,6 +84,9 @@ func export(ctx context.Context, ingester content.Ingester, cc *v1.CacheChains)
 	var mfst manifestList
 	mfst.SchemaVersion = 2
 	mfst.MediaType = images.MediaTypeDockerSchema2ManifestList
+	if ce.oci {
+		mfst.MediaType = ocispec.MediaTypeImageIndex
+	}
 
 	for _, l := range config.Layers {
 		dgstPair, ok := descs[l.Blob]
@@ -93,13 +94,15 @@ func export(ctx context.Context, ingester content.Ingester, cc *v1.CacheChains)
 			return nil, errors.Errorf("missing blob %s", l.Blob)
 		}
 		layerDone := oneOffProgress(ctx, fmt.Sprintf("writing layer %s", l.Blob))
-		if err := contentutil.Copy(ctx, ingester, dgstPair.Provider, dgstPair.Descriptor); err != nil {
+		if err := contentutil.Copy(ctx, ce.ingester, dgstPair.Provider, dgstPair.Descriptor); err != nil {
 			return nil, layerDone(errors.Wrap(err, "error writing layer blob"))
 		}
 		layerDone(nil)
 		mfst.Manifests = append(mfst.Manifests, dgstPair.Descriptor)
 	}
 
+	mfst.Manifests = compression.ConvertAllLayerMediaTypes(ce.oci, mfst.Manifests...)
+
 	dt, err := json.Marshal(config)
 	if err != nil {
 		return nil, err
@@ -111,7 +114,7 @@ func export(ctx context.Context, ingester content.Ingester, cc *v1.CacheChains)
 		MediaType: v1.CacheConfigMediaTypeV0,
 	}
 	configDone := oneOffProgress(ctx, fmt.Sprintf("writing config %s", dgst))
-	if err := content.WriteBlob(ctx, ingester, dgst.String(), bytes.NewReader(dt), desc); err != nil {
+	if err := content.WriteBlob(ctx, ce.ingester, dgst.String(), bytes.NewReader(dt), desc); err != nil {
 		return nil, configDone(errors.Wrap(err, "error writing config blob"))
 	}
 	configDone(nil)
@@ -130,7 +133,7 @@ func export(ctx context.Context, ingester content.Ingester, cc *v1.CacheChains)
 		MediaType: mfst.MediaType,
 	}
 	mfstDone := oneOffProgress(ctx, fmt.Sprintf("writing manifest %s", dgst))
-	if err := content.WriteBlob(ctx, ingester, dgst.String(), bytes.NewReader(dt), desc); err != nil {
+	if err := content.WriteBlob(ctx, ce.ingester, dgst.String(), bytes.NewReader(dt), desc); err != nil {
 		return nil, mfstDone(errors.Wrap(err, "error writing manifest blob"))
 	}
 	descJSON, err := json.Marshal(desc)
diff --git a/cache/remotecache/local/local.go b/cache/remotecache/local/local.go
index 1e99ebbcafd9..2ee194afdfd0 100644
--- a/cache/remotecache/local/local.go
+++ b/cache/remotecache/local/local.go
@@ -2,6 +2,7 @@ package local
 
 import (
 	"context"
+	"strconv"
 	"time"
 
 	"github.com/containerd/containerd/content"
@@ -17,6 +18,7 @@ const (
 	attrDigest           = "digest"
 	attrSrc              = "src"
 	attrDest             = "dest"
+	attrOCIMediatypes    = "oci-mediatypes"
 	contentStoreIDPrefix = "local:"
 )
 
@@ -27,12 +29,20 @@ func ResolveCacheExporterFunc(sm *session.Manager) remotecache.ResolveCacheExpor
 		if store == "" {
 			return nil, errors.New("local cache exporter requires dest")
 		}
+		ociMediatypes := true
+		if v, ok := attrs[attrOCIMediatypes]; ok {
+			b, err := strconv.ParseBool(v)
+			if err != nil {
+				return nil, errors.Wrapf(err, "failed to parse %s", attrOCIMediatypes)
+			}
+			ociMediatypes = b
+		}
 		csID := contentStoreIDPrefix + store
 		cs, err := getContentStore(ctx, sm, g, csID)
 		if err != nil {
 			return nil, err
 		}
-		return remotecache.NewExporter(cs), nil
+		return remotecache.NewExporter(cs, ociMediatypes), nil
 	}
 }
 
diff --git a/cache/remotecache/registry/registry.go b/cache/remotecache/registry/registry.go
index f93d703fae69..281d9fa4a3f3 100644
--- a/cache/remotecache/registry/registry.go
+++ b/cache/remotecache/registry/registry.go
@@ -2,6 +2,7 @@ package registry
 
 import (
 	"context"
+	"strconv"
 
 	"github.com/containerd/containerd/content"
 	"github.com/containerd/containerd/remotes/docker"
@@ -28,7 +29,8 @@ func canonicalizeRef(rawRef string) (string, error) {
 }
 
 const (
-	attrRef = "ref"
+	attrRef           = "ref"
+	attrOCIMediatypes = "oci-mediatypes"
 )
 
 func ResolveCacheExporterFunc(sm *session.Manager, hosts docker.RegistryHosts) remotecache.ResolveCacheExporterFunc {
@@ -37,12 +39,20 @@ func ResolveCacheExporterFunc(sm *session.Manager, hosts docker.RegistryHosts) r
 		if err != nil {
 			return nil, err
 		}
+		ociMediatypes := true
+		if v, ok := attrs[attrOCIMediatypes]; ok {
+			b, err := strconv.ParseBool(v)
+			if err != nil {
+				return nil, errors.Wrapf(err, "failed to parse %s", attrOCIMediatypes)
+			}
+			ociMediatypes = b
+		}
 		remote := resolver.DefaultPool.GetResolver(hosts, ref, "push", sm, g)
 		pusher, err := remote.Pusher(ctx, ref)
 		if err != nil {
 			return nil, err
 		}
-		return remotecache.NewExporter(contentutil.FromPusher(pusher)), nil
+		return remotecache.NewExporter(contentutil.FromPusher(pusher), ociMediatypes), nil
 	}
 }