diff --git a/cmd/compose/alpha.go b/cmd/compose/alpha.go
index 5eaeaa9e2..99359360c 100644
--- a/cmd/compose/alpha.go
+++ b/cmd/compose/alpha.go
@@ -32,6 +32,7 @@ func alphaCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
 	cmd.AddCommand(
 		watchCommand(p, backend),
 		vizCommand(p, backend),
+		publishCommand(p, backend),
 	)
 	return cmd
 }
diff --git a/cmd/compose/publish.go b/cmd/compose/publish.go
new file mode 100644
index 000000000..f7c202966
--- /dev/null
+++ b/cmd/compose/publish.go
@@ -0,0 +1,49 @@
+/*
+   Copyright 2020 Docker Compose CLI authors
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package compose
+
+import (
+	"context"
+
+	"github.com/spf13/cobra"
+
+	"github.com/docker/compose/v2/pkg/api"
+)
+
+func publishCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
+	opts := pushOptions{
+		ProjectOptions: p,
+	}
+	publishCmd := &cobra.Command{
+		Use:   "publish [OPTIONS] [REPOSITORY]",
+		Short: "Publish compose application",
+		RunE: Adapt(func(ctx context.Context, args []string) error {
+			return runPublish(ctx, backend, opts, args[0])
+		}),
+		Args: cobra.ExactArgs(1),
+	}
+	return publishCmd
+}
+
+func runPublish(ctx context.Context, backend api.Service, opts pushOptions, repository string) error {
+	project, err := opts.ToProject(nil)
+	if err != nil {
+		return err
+	}
+
+	return backend.Publish(ctx, project, repository)
+}
diff --git a/docs/reference/compose_alpha_publish.md b/docs/reference/compose_alpha_publish.md
new file mode 100644
index 000000000..056d211b0
--- /dev/null
+++ b/docs/reference/compose_alpha_publish.md
@@ -0,0 +1,14 @@
+# docker compose alpha publish
+
+<!---MARKER_GEN_START-->
+Publish compose application
+
+### Options
+
+| Name        | Type | Default | Description                     |
+|:------------|:-----|:--------|:--------------------------------|
+| `--dry-run` |      |         | Execute command in dry run mode |
+
+
+<!---MARKER_GEN_END-->
+
diff --git a/docs/reference/docker_compose_alpha.yaml b/docs/reference/docker_compose_alpha.yaml
index 2598c0e88..43994d80c 100644
--- a/docs/reference/docker_compose_alpha.yaml
+++ b/docs/reference/docker_compose_alpha.yaml
@@ -4,9 +4,11 @@ long: Experimental commands
 pname: docker compose
 plink: docker_compose.yaml
 cname:
+    - docker compose alpha publish
     - docker compose alpha viz
     - docker compose alpha watch
 clink:
+    - docker_compose_alpha_publish.yaml
     - docker_compose_alpha_viz.yaml
     - docker_compose_alpha_watch.yaml
 inherited_options:
diff --git a/docs/reference/docker_compose_alpha_publish.yaml b/docs/reference/docker_compose_alpha_publish.yaml
new file mode 100644
index 000000000..ba01e166a
--- /dev/null
+++ b/docs/reference/docker_compose_alpha_publish.yaml
@@ -0,0 +1,24 @@
+command: docker compose alpha publish
+short: Publish compose application
+long: Publish compose application
+usage: docker compose alpha publish [OPTIONS] [REPOSITORY]
+pname: docker compose alpha
+plink: docker_compose_alpha.yaml
+inherited_options:
+    - option: dry-run
+      value_type: bool
+      default_value: "false"
+      description: Execute command in dry run mode
+      deprecated: false
+      hidden: false
+      experimental: false
+      experimentalcli: false
+      kubernetes: false
+      swarm: false
+deprecated: false
+hidden: false
+experimental: false
+experimentalcli: true
+kubernetes: false
+swarm: false
+
diff --git a/pkg/api/api.go b/pkg/api/api.go
index 28595941b..3c2a4ef76 100644
--- a/pkg/api/api.go
+++ b/pkg/api/api.go
@@ -74,6 +74,8 @@ type Service interface {
 	Events(ctx context.Context, projectName string, options EventsOptions) error
 	// Port executes the equivalent to a `compose port`
 	Port(ctx context.Context, projectName string, service string, port uint16, options PortOptions) (string, int, error)
+	// Publish executes the equivalent to a `compose publish`
+	Publish(ctx context.Context, project *types.Project, repository string) error
 	// Images executes the equivalent of a `compose images`
 	Images(ctx context.Context, projectName string, options ImagesOptions) ([]ImageSummary, error)
 	// MaxConcurrency defines upper limit for concurrent operations against engine API
diff --git a/pkg/api/proxy.go b/pkg/api/proxy.go
index 4547cb266..b74fe098f 100644
--- a/pkg/api/proxy.go
+++ b/pkg/api/proxy.go
@@ -55,6 +55,7 @@ type ServiceProxy struct {
 	DryRunModeFn         func(ctx context.Context, dryRun bool) (context.Context, error)
 	VizFn                func(ctx context.Context, project *types.Project, options VizOptions) (string, error)
 	WaitFn               func(ctx context.Context, projectName string, options WaitOptions) (int64, error)
+	PublishFn            func(ctx context.Context, project *types.Project, repository string) error
 	interceptors         []Interceptor
 }
 
@@ -91,6 +92,7 @@ func (s *ServiceProxy) WithService(service Service) *ServiceProxy {
 	s.TopFn = service.Top
 	s.EventsFn = service.Events
 	s.PortFn = service.Port
+	s.PublishFn = service.Publish
 	s.ImagesFn = service.Images
 	s.WatchFn = service.Watch
 	s.MaxConcurrencyFn = service.MaxConcurrency
@@ -311,6 +313,10 @@ func (s *ServiceProxy) Port(ctx context.Context, projectName string, service str
 	return s.PortFn(ctx, projectName, service, port, options)
 }
 
+func (s *ServiceProxy) Publish(ctx context.Context, project *types.Project, repository string) error {
+	return s.PublishFn(ctx, project, repository)
+}
+
 // Images implements Service interface
 func (s *ServiceProxy) Images(ctx context.Context, project string, options ImagesOptions) ([]ImageSummary, error) {
 	if s.ImagesFn == nil {
diff --git a/pkg/compose/publish.go b/pkg/compose/publish.go
new file mode 100644
index 000000000..97d7aa614
--- /dev/null
+++ b/pkg/compose/publish.go
@@ -0,0 +1,41 @@
+/*
+   Copyright 2020 Docker Compose CLI authors
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package compose
+
+import (
+	"context"
+
+	"github.com/compose-spec/compose-go/types"
+	"github.com/distribution/distribution/v3/reference"
+	"github.com/docker/compose/v2/pkg/api"
+)
+
+func (s *composeService) Publish(ctx context.Context, project *types.Project, repository string) error {
+	err := s.Push(ctx, project, api.PushOptions{})
+	if err != nil {
+		return err
+	}
+
+	_, err = reference.ParseDockerRef(repository)
+	if err != nil {
+		return err
+	}
+
+	// TODO publish project.ComposeFiles
+
+	return api.ErrNotImplemented
+}
diff --git a/pkg/mocks/mock_docker_compose_api.go b/pkg/mocks/mock_docker_compose_api.go
index ffb62f3fb..428d2665a 100644
--- a/pkg/mocks/mock_docker_compose_api.go
+++ b/pkg/mocks/mock_docker_compose_api.go
@@ -266,6 +266,20 @@ func (mr *MockServiceMockRecorder) Ps(ctx, projectName, options interface{}) *go
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ps", reflect.TypeOf((*MockService)(nil).Ps), ctx, projectName, options)
 }
 
+// Publish mocks base method.
+func (m *MockService) Publish(ctx context.Context, project *types.Project, repository string) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Publish", ctx, project, repository)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// Publish indicates an expected call of Publish.
+func (mr *MockServiceMockRecorder) Publish(ctx, project, repository interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Publish", reflect.TypeOf((*MockService)(nil).Publish), ctx, project, repository)
+}
+
 // Pull mocks base method.
 func (m *MockService) Pull(ctx context.Context, project *types.Project, options api.PullOptions) error {
 	m.ctrl.T.Helper()