diff --git a/apis/core.oam.dev/common/types.go b/apis/core.oam.dev/common/types.go
index c0437a35ecb6815162829302a142a2f964d3103a..473cf4c7d014d36e2bd58d70ce5d86e08d8fb783 100644
--- a/apis/core.oam.dev/common/types.go
+++ b/apis/core.oam.dev/common/types.go
@@ -268,8 +268,8 @@ type RawComponent struct {
 	Raw runtime.RawExtension `json:"raw"`
 }
 
-// WorkflowStepStatus record the status of a workflow step
-type WorkflowStepStatus struct {
+// StepStatus record the base status of workflow step, which could be workflow step or subStep
+type StepStatus struct {
 	ID    string            `json:"id"`
 	Name  string            `json:"name,omitempty"`
 	Type  string            `json:"type,omitempty"`
@@ -277,24 +277,22 @@ type WorkflowStepStatus struct {
 	// A human readable message indicating details about why the workflowStep is in this state.
 	Message string `json:"message,omitempty"`
 	// A brief CamelCase message indicating details about why the workflowStep is in this state.
-	Reason   string          `json:"reason,omitempty"`
-	SubSteps *SubStepsStatus `json:"subSteps,omitempty"`
+	Reason string `json:"reason,omitempty"`
 	// FirstExecuteTime is the first time this step execution.
 	FirstExecuteTime metav1.Time `json:"firstExecuteTime,omitempty"`
 	// LastExecuteTime is the last time this step execution.
 	LastExecuteTime metav1.Time `json:"lastExecuteTime,omitempty"`
 }
 
-// WorkflowSubStepStatus record the status of a workflow step
+// WorkflowStepStatus record the status of a workflow step, include step status and subStep status
+type WorkflowStepStatus struct {
+	StepStatus     `json:",inline"`
+	SubStepsStatus []WorkflowSubStepStatus `json:"subSteps,omitempty"`
+}
+
+// WorkflowSubStepStatus record the status of a workflow subStep
 type WorkflowSubStepStatus struct {
-	ID    string            `json:"id"`
-	Name  string            `json:"name,omitempty"`
-	Type  string            `json:"type,omitempty"`
-	Phase WorkflowStepPhase `json:"phase,omitempty"`
-	// A human readable message indicating details about why the workflowStep is in this state.
-	Message string `json:"message,omitempty"`
-	// A brief CamelCase message indicating details about why the workflowStep is in this state.
-	Reason string `json:"reason,omitempty"`
+	StepStatus `json:",inline"`
 }
 
 // AppStatus defines the observed state of Application
@@ -347,6 +345,25 @@ type WorkflowStep struct {
 	// +kubebuilder:pruning:PreserveUnknownFields
 	Properties *runtime.RawExtension `json:"properties,omitempty"`
 
+	SubSteps []WorkflowSubStep `json:"subSteps,omitempty"`
+
+	DependsOn []string `json:"dependsOn,omitempty"`
+
+	Inputs StepInputs `json:"inputs,omitempty"`
+
+	Outputs StepOutputs `json:"outputs,omitempty"`
+}
+
+// WorkflowSubStep defines how to execute a workflow subStep.
+type WorkflowSubStep struct {
+	// Name is the unique name of the workflow step.
+	Name string `json:"name"`
+
+	Type string `json:"type"`
+
+	// +kubebuilder:pruning:PreserveUnknownFields
+	Properties *runtime.RawExtension `json:"properties,omitempty"`
+
 	DependsOn []string `json:"dependsOn,omitempty"`
 
 	Inputs StepInputs `json:"inputs,omitempty"`
@@ -372,13 +389,6 @@ type WorkflowStatus struct {
 	StartTime metav1.Time `json:"startTime,omitempty"`
 }
 
-// SubStepsStatus record the status of workflow steps.
-type SubStepsStatus struct {
-	StepIndex int                     `json:"stepIndex,omitempty"`
-	Mode      WorkflowMode            `json:"mode,omitempty"`
-	Steps     []WorkflowSubStepStatus `json:"steps,omitempty"`
-}
-
 // WorkflowStepPhase describes the phase of a workflow step.
 type WorkflowStepPhase string
 
diff --git a/apis/core.oam.dev/common/zz_generated.deepcopy.go b/apis/core.oam.dev/common/zz_generated.deepcopy.go
index fec9023f25924133158cf6ec7c725063b172a73f..cfeb8347920a7ed7a0d2285c17cd487d4fc355b9 100644
--- a/apis/core.oam.dev/common/zz_generated.deepcopy.go
+++ b/apis/core.oam.dev/common/zz_generated.deepcopy.go
@@ -612,21 +612,18 @@ func (in StepOutputs) DeepCopy() StepOutputs {
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *SubStepsStatus) DeepCopyInto(out *SubStepsStatus) {
+func (in *StepStatus) DeepCopyInto(out *StepStatus) {
 	*out = *in
-	if in.Steps != nil {
-		in, out := &in.Steps, &out.Steps
-		*out = make([]WorkflowSubStepStatus, len(*in))
-		copy(*out, *in)
-	}
+	in.FirstExecuteTime.DeepCopyInto(&out.FirstExecuteTime)
+	in.LastExecuteTime.DeepCopyInto(&out.LastExecuteTime)
 }
 
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubStepsStatus.
-func (in *SubStepsStatus) DeepCopy() *SubStepsStatus {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StepStatus.
+func (in *StepStatus) DeepCopy() *StepStatus {
 	if in == nil {
 		return nil
 	}
-	out := new(SubStepsStatus)
+	out := new(StepStatus)
 	in.DeepCopyInto(out)
 	return out
 }
@@ -692,6 +689,13 @@ func (in *WorkflowStep) DeepCopyInto(out *WorkflowStep) {
 		*out = new(runtime.RawExtension)
 		(*in).DeepCopyInto(*out)
 	}
+	if in.SubSteps != nil {
+		in, out := &in.SubSteps, &out.SubSteps
+		*out = make([]WorkflowSubStep, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
 	if in.DependsOn != nil {
 		in, out := &in.DependsOn, &out.DependsOn
 		*out = make([]string, len(*in))
@@ -722,13 +726,14 @@ func (in *WorkflowStep) DeepCopy() *WorkflowStep {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *WorkflowStepStatus) DeepCopyInto(out *WorkflowStepStatus) {
 	*out = *in
-	if in.SubSteps != nil {
-		in, out := &in.SubSteps, &out.SubSteps
-		*out = new(SubStepsStatus)
-		(*in).DeepCopyInto(*out)
+	in.StepStatus.DeepCopyInto(&out.StepStatus)
+	if in.SubStepsStatus != nil {
+		in, out := &in.SubStepsStatus, &out.SubStepsStatus
+		*out = make([]WorkflowSubStepStatus, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
 	}
-	in.FirstExecuteTime.DeepCopyInto(&out.FirstExecuteTime)
-	in.LastExecuteTime.DeepCopyInto(&out.LastExecuteTime)
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowStepStatus.
@@ -741,9 +746,45 @@ func (in *WorkflowStepStatus) DeepCopy() *WorkflowStepStatus {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *WorkflowSubStep) DeepCopyInto(out *WorkflowSubStep) {
+	*out = *in
+	if in.Properties != nil {
+		in, out := &in.Properties, &out.Properties
+		*out = new(runtime.RawExtension)
+		(*in).DeepCopyInto(*out)
+	}
+	if in.DependsOn != nil {
+		in, out := &in.DependsOn, &out.DependsOn
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
+	if in.Inputs != nil {
+		in, out := &in.Inputs, &out.Inputs
+		*out = make(StepInputs, len(*in))
+		copy(*out, *in)
+	}
+	if in.Outputs != nil {
+		in, out := &in.Outputs, &out.Outputs
+		*out = make(StepOutputs, len(*in))
+		copy(*out, *in)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowSubStep.
+func (in *WorkflowSubStep) DeepCopy() *WorkflowSubStep {
+	if in == nil {
+		return nil
+	}
+	out := new(WorkflowSubStep)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *WorkflowSubStepStatus) DeepCopyInto(out *WorkflowSubStepStatus) {
 	*out = *in
+	in.StepStatus.DeepCopyInto(&out.StepStatus)
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowSubStepStatus.
diff --git a/apis/core.oam.dev/v1beta1/zz_generated.deepcopy.go b/apis/core.oam.dev/v1beta1/zz_generated.deepcopy.go
index 4bba8da4a5c924cda3ccdce26e2beda10b388852..acb2d5211b34b59252e36d390e68f669683c18b6 100644
--- a/apis/core.oam.dev/v1beta1/zz_generated.deepcopy.go
+++ b/apis/core.oam.dev/v1beta1/zz_generated.deepcopy.go
@@ -954,6 +954,13 @@ func (in *WorkflowStep) DeepCopyInto(out *WorkflowStep) {
 		*out = new(runtime.RawExtension)
 		(*in).DeepCopyInto(*out)
 	}
+	if in.SubSteps != nil {
+		in, out := &in.SubSteps, &out.SubSteps
+		*out = make([]common.WorkflowSubStep, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
 	if in.DependsOn != nil {
 		in, out := &in.DependsOn, &out.DependsOn
 		*out = make([]string, len(*in))
diff --git a/charts/vela-core/crds/core.oam.dev_applicationrevisions.yaml b/charts/vela-core/crds/core.oam.dev_applicationrevisions.yaml
index b99b42a1260df0ea9bb789660c6b8b56935c3dab..cfbeb0b7243a5b63df901fb9474b56409f5d17e3 100644
--- a/charts/vela-core/crds/core.oam.dev_applicationrevisions.yaml
+++ b/charts/vela-core/crds/core.oam.dev_applicationrevisions.yaml
@@ -856,7 +856,7 @@ spec:
                           steps:
                             items:
                               description: WorkflowStepStatus record the status of
-                                a workflow step
+                                a workflow step, include step status and subStep status
                               properties:
                                 firstExecuteTime:
                                   description: FirstExecuteTime is the first time
@@ -887,45 +887,44 @@ spec:
                                     state.
                                   type: string
                                 subSteps:
-                                  description: SubStepsStatus record the status of
-                                    workflow steps.
-                                  properties:
-                                    mode:
-                                      description: WorkflowMode describes the mode
-                                        of workflow
-                                      type: string
-                                    stepIndex:
-                                      type: integer
-                                    steps:
-                                      items:
-                                        description: WorkflowSubStepStatus record
-                                          the status of a workflow step
-                                        properties:
-                                          id:
-                                            type: string
-                                          message:
-                                            description: A human readable message
-                                              indicating details about why the workflowStep
-                                              is in this state.
-                                            type: string
-                                          name:
-                                            type: string
-                                          phase:
-                                            description: WorkflowStepPhase describes
-                                              the phase of a workflow step.
-                                            type: string
-                                          reason:
-                                            description: A brief CamelCase message
-                                              indicating details about why the workflowStep
-                                              is in this state.
-                                            type: string
-                                          type:
-                                            type: string
-                                        required:
-                                        - id
-                                        type: object
-                                      type: array
-                                  type: object
+                                  items:
+                                    description: WorkflowSubStepStatus record the
+                                      status of a workflow subStep
+                                    properties:
+                                      firstExecuteTime:
+                                        description: FirstExecuteTime is the first
+                                          time this step execution.
+                                        format: date-time
+                                        type: string
+                                      id:
+                                        type: string
+                                      lastExecuteTime:
+                                        description: LastExecuteTime is the last time
+                                          this step execution.
+                                        format: date-time
+                                        type: string
+                                      message:
+                                        description: A human readable message indicating
+                                          details about why the workflowStep is in
+                                          this state.
+                                        type: string
+                                      name:
+                                        type: string
+                                      phase:
+                                        description: WorkflowStepPhase describes the
+                                          phase of a workflow step.
+                                        type: string
+                                      reason:
+                                        description: A brief CamelCase message indicating
+                                          details about why the workflowStep is in
+                                          this state.
+                                        type: string
+                                      type:
+                                        type: string
+                                    required:
+                                    - id
+                                    type: object
+                                  type: array
                                 type:
                                   type: string
                               required:
@@ -2245,6 +2244,57 @@ spec:
                                 properties:
                                   type: object
                                   x-kubernetes-preserve-unknown-fields: true
+                                subSteps:
+                                  items:
+                                    description: WorkflowSubStep defines how to execute
+                                      a workflow subStep.
+                                    properties:
+                                      dependsOn:
+                                        items:
+                                          type: string
+                                        type: array
+                                      inputs:
+                                        description: StepInputs defines variable input
+                                          of WorkflowStep
+                                        items:
+                                          properties:
+                                            from:
+                                              type: string
+                                            parameterKey:
+                                              type: string
+                                          required:
+                                          - from
+                                          - parameterKey
+                                          type: object
+                                        type: array
+                                      name:
+                                        description: Name is the unique name of the
+                                          workflow step.
+                                        type: string
+                                      outputs:
+                                        description: StepOutputs defines output variable
+                                          of WorkflowStep
+                                        items:
+                                          properties:
+                                            name:
+                                              type: string
+                                            valueFrom:
+                                              type: string
+                                          required:
+                                          - name
+                                          - valueFrom
+                                          type: object
+                                        type: array
+                                      properties:
+                                        type: object
+                                        x-kubernetes-preserve-unknown-fields: true
+                                      type:
+                                        type: string
+                                    required:
+                                    - name
+                                    - type
+                                    type: object
+                                  type: array
                                 type:
                                   type: string
                               required:
@@ -2667,7 +2717,7 @@ spec:
                           steps:
                             items:
                               description: WorkflowStepStatus record the status of
-                                a workflow step
+                                a workflow step, include step status and subStep status
                               properties:
                                 firstExecuteTime:
                                   description: FirstExecuteTime is the first time
@@ -2698,45 +2748,44 @@ spec:
                                     state.
                                   type: string
                                 subSteps:
-                                  description: SubStepsStatus record the status of
-                                    workflow steps.
-                                  properties:
-                                    mode:
-                                      description: WorkflowMode describes the mode
-                                        of workflow
-                                      type: string
-                                    stepIndex:
-                                      type: integer
-                                    steps:
-                                      items:
-                                        description: WorkflowSubStepStatus record
-                                          the status of a workflow step
-                                        properties:
-                                          id:
-                                            type: string
-                                          message:
-                                            description: A human readable message
-                                              indicating details about why the workflowStep
-                                              is in this state.
-                                            type: string
-                                          name:
-                                            type: string
-                                          phase:
-                                            description: WorkflowStepPhase describes
-                                              the phase of a workflow step.
-                                            type: string
-                                          reason:
-                                            description: A brief CamelCase message
-                                              indicating details about why the workflowStep
-                                              is in this state.
-                                            type: string
-                                          type:
-                                            type: string
-                                        required:
-                                        - id
-                                        type: object
-                                      type: array
-                                  type: object
+                                  items:
+                                    description: WorkflowSubStepStatus record the
+                                      status of a workflow subStep
+                                    properties:
+                                      firstExecuteTime:
+                                        description: FirstExecuteTime is the first
+                                          time this step execution.
+                                        format: date-time
+                                        type: string
+                                      id:
+                                        type: string
+                                      lastExecuteTime:
+                                        description: LastExecuteTime is the last time
+                                          this step execution.
+                                        format: date-time
+                                        type: string
+                                      message:
+                                        description: A human readable message indicating
+                                          details about why the workflowStep is in
+                                          this state.
+                                        type: string
+                                      name:
+                                        type: string
+                                      phase:
+                                        description: WorkflowStepPhase describes the
+                                          phase of a workflow step.
+                                        type: string
+                                      reason:
+                                        description: A brief CamelCase message indicating
+                                          details about why the workflowStep is in
+                                          this state.
+                                        type: string
+                                      type:
+                                        type: string
+                                    required:
+                                    - id
+                                    type: object
+                                  type: array
                                 type:
                                   type: string
                               required:
@@ -3937,6 +3986,57 @@ spec:
                         properties:
                           type: object
                           x-kubernetes-preserve-unknown-fields: true
+                        subSteps:
+                          items:
+                            description: WorkflowSubStep defines how to execute a
+                              workflow subStep.
+                            properties:
+                              dependsOn:
+                                items:
+                                  type: string
+                                type: array
+                              inputs:
+                                description: StepInputs defines variable input of
+                                  WorkflowStep
+                                items:
+                                  properties:
+                                    from:
+                                      type: string
+                                    parameterKey:
+                                      type: string
+                                  required:
+                                  - from
+                                  - parameterKey
+                                  type: object
+                                type: array
+                              name:
+                                description: Name is the unique name of the workflow
+                                  step.
+                                type: string
+                              outputs:
+                                description: StepOutputs defines output variable of
+                                  WorkflowStep
+                                items:
+                                  properties:
+                                    name:
+                                      type: string
+                                    valueFrom:
+                                      type: string
+                                  required:
+                                  - name
+                                  - valueFrom
+                                  type: object
+                                type: array
+                              properties:
+                                type: object
+                                x-kubernetes-preserve-unknown-fields: true
+                              type:
+                                type: string
+                            required:
+                            - name
+                            - type
+                            type: object
+                          type: array
                         type:
                           type: string
                       required:
@@ -4619,7 +4719,7 @@ spec:
                   steps:
                     items:
                       description: WorkflowStepStatus record the status of a workflow
-                        step
+                        step, include step status and subStep status
                       properties:
                         firstExecuteTime:
                           description: FirstExecuteTime is the first time this step
@@ -4648,44 +4748,42 @@ spec:
                             about why the workflowStep is in this state.
                           type: string
                         subSteps:
-                          description: SubStepsStatus record the status of workflow
-                            steps.
-                          properties:
-                            mode:
-                              description: WorkflowMode describes the mode of workflow
-                              type: string
-                            stepIndex:
-                              type: integer
-                            steps:
-                              items:
-                                description: WorkflowSubStepStatus record the status
-                                  of a workflow step
-                                properties:
-                                  id:
-                                    type: string
-                                  message:
-                                    description: A human readable message indicating
-                                      details about why the workflowStep is in this
-                                      state.
-                                    type: string
-                                  name:
-                                    type: string
-                                  phase:
-                                    description: WorkflowStepPhase describes the phase
-                                      of a workflow step.
-                                    type: string
-                                  reason:
-                                    description: A brief CamelCase message indicating
-                                      details about why the workflowStep is in this
-                                      state.
-                                    type: string
-                                  type:
-                                    type: string
-                                required:
-                                - id
-                                type: object
-                              type: array
-                          type: object
+                          items:
+                            description: WorkflowSubStepStatus record the status of
+                              a workflow subStep
+                            properties:
+                              firstExecuteTime:
+                                description: FirstExecuteTime is the first time this
+                                  step execution.
+                                format: date-time
+                                type: string
+                              id:
+                                type: string
+                              lastExecuteTime:
+                                description: LastExecuteTime is the last time this
+                                  step execution.
+                                format: date-time
+                                type: string
+                              message:
+                                description: A human readable message indicating details
+                                  about why the workflowStep is in this state.
+                                type: string
+                              name:
+                                type: string
+                              phase:
+                                description: WorkflowStepPhase describes the phase
+                                  of a workflow step.
+                                type: string
+                              reason:
+                                description: A brief CamelCase message indicating
+                                  details about why the workflowStep is in this state.
+                                type: string
+                              type:
+                                type: string
+                            required:
+                            - id
+                            type: object
+                          type: array
                         type:
                           type: string
                       required:
diff --git a/charts/vela-core/crds/core.oam.dev_applications.yaml b/charts/vela-core/crds/core.oam.dev_applications.yaml
index bd9ea725a40519d2a3912297ba3dc46e3db57d7d..c63283bc99768d525ae3b291804414b6789671ad 100644
--- a/charts/vela-core/crds/core.oam.dev_applications.yaml
+++ b/charts/vela-core/crds/core.oam.dev_applications.yaml
@@ -779,7 +779,7 @@ spec:
                   steps:
                     items:
                       description: WorkflowStepStatus record the status of a workflow
-                        step
+                        step, include step status and subStep status
                       properties:
                         firstExecuteTime:
                           description: FirstExecuteTime is the first time this step
@@ -808,44 +808,42 @@ spec:
                             about why the workflowStep is in this state.
                           type: string
                         subSteps:
-                          description: SubStepsStatus record the status of workflow
-                            steps.
-                          properties:
-                            mode:
-                              description: WorkflowMode describes the mode of workflow
-                              type: string
-                            stepIndex:
-                              type: integer
-                            steps:
-                              items:
-                                description: WorkflowSubStepStatus record the status
-                                  of a workflow step
-                                properties:
-                                  id:
-                                    type: string
-                                  message:
-                                    description: A human readable message indicating
-                                      details about why the workflowStep is in this
-                                      state.
-                                    type: string
-                                  name:
-                                    type: string
-                                  phase:
-                                    description: WorkflowStepPhase describes the phase
-                                      of a workflow step.
-                                    type: string
-                                  reason:
-                                    description: A brief CamelCase message indicating
-                                      details about why the workflowStep is in this
-                                      state.
-                                    type: string
-                                  type:
-                                    type: string
-                                required:
-                                - id
-                                type: object
-                              type: array
-                          type: object
+                          items:
+                            description: WorkflowSubStepStatus record the status of
+                              a workflow subStep
+                            properties:
+                              firstExecuteTime:
+                                description: FirstExecuteTime is the first time this
+                                  step execution.
+                                format: date-time
+                                type: string
+                              id:
+                                type: string
+                              lastExecuteTime:
+                                description: LastExecuteTime is the last time this
+                                  step execution.
+                                format: date-time
+                                type: string
+                              message:
+                                description: A human readable message indicating details
+                                  about why the workflowStep is in this state.
+                                type: string
+                              name:
+                                type: string
+                              phase:
+                                description: WorkflowStepPhase describes the phase
+                                  of a workflow step.
+                                type: string
+                              reason:
+                                description: A brief CamelCase message indicating
+                                  details about why the workflowStep is in this state.
+                                type: string
+                              type:
+                                type: string
+                            required:
+                            - id
+                            type: object
+                          type: array
                         type:
                           type: string
                       required:
@@ -1054,6 +1052,57 @@ spec:
                         properties:
                           type: object
                           x-kubernetes-preserve-unknown-fields: true
+                        subSteps:
+                          items:
+                            description: WorkflowSubStep defines how to execute a
+                              workflow subStep.
+                            properties:
+                              dependsOn:
+                                items:
+                                  type: string
+                                type: array
+                              inputs:
+                                description: StepInputs defines variable input of
+                                  WorkflowStep
+                                items:
+                                  properties:
+                                    from:
+                                      type: string
+                                    parameterKey:
+                                      type: string
+                                  required:
+                                  - from
+                                  - parameterKey
+                                  type: object
+                                type: array
+                              name:
+                                description: Name is the unique name of the workflow
+                                  step.
+                                type: string
+                              outputs:
+                                description: StepOutputs defines output variable of
+                                  WorkflowStep
+                                items:
+                                  properties:
+                                    name:
+                                      type: string
+                                    valueFrom:
+                                      type: string
+                                  required:
+                                  - name
+                                  - valueFrom
+                                  type: object
+                                type: array
+                              properties:
+                                type: object
+                                x-kubernetes-preserve-unknown-fields: true
+                              type:
+                                type: string
+                            required:
+                            - name
+                            - type
+                            type: object
+                          type: array
                         type:
                           type: string
                       required:
@@ -1446,7 +1495,7 @@ spec:
                   steps:
                     items:
                       description: WorkflowStepStatus record the status of a workflow
-                        step
+                        step, include step status and subStep status
                       properties:
                         firstExecuteTime:
                           description: FirstExecuteTime is the first time this step
@@ -1475,44 +1524,42 @@ spec:
                             about why the workflowStep is in this state.
                           type: string
                         subSteps:
-                          description: SubStepsStatus record the status of workflow
-                            steps.
-                          properties:
-                            mode:
-                              description: WorkflowMode describes the mode of workflow
-                              type: string
-                            stepIndex:
-                              type: integer
-                            steps:
-                              items:
-                                description: WorkflowSubStepStatus record the status
-                                  of a workflow step
-                                properties:
-                                  id:
-                                    type: string
-                                  message:
-                                    description: A human readable message indicating
-                                      details about why the workflowStep is in this
-                                      state.
-                                    type: string
-                                  name:
-                                    type: string
-                                  phase:
-                                    description: WorkflowStepPhase describes the phase
-                                      of a workflow step.
-                                    type: string
-                                  reason:
-                                    description: A brief CamelCase message indicating
-                                      details about why the workflowStep is in this
-                                      state.
-                                    type: string
-                                  type:
-                                    type: string
-                                required:
-                                - id
-                                type: object
-                              type: array
-                          type: object
+                          items:
+                            description: WorkflowSubStepStatus record the status of
+                              a workflow subStep
+                            properties:
+                              firstExecuteTime:
+                                description: FirstExecuteTime is the first time this
+                                  step execution.
+                                format: date-time
+                                type: string
+                              id:
+                                type: string
+                              lastExecuteTime:
+                                description: LastExecuteTime is the last time this
+                                  step execution.
+                                format: date-time
+                                type: string
+                              message:
+                                description: A human readable message indicating details
+                                  about why the workflowStep is in this state.
+                                type: string
+                              name:
+                                type: string
+                              phase:
+                                description: WorkflowStepPhase describes the phase
+                                  of a workflow step.
+                                type: string
+                              reason:
+                                description: A brief CamelCase message indicating
+                                  details about why the workflowStep is in this state.
+                                type: string
+                              type:
+                                type: string
+                            required:
+                            - id
+                            type: object
+                          type: array
                         type:
                           type: string
                       required:
diff --git a/charts/vela-core/crds/core.oam.dev_workflows.yaml b/charts/vela-core/crds/core.oam.dev_workflows.yaml
index b0413fc5127d6aef1436101ec888b1b9631e5b94..155367c3ddfa165abfd7911a8995a1a6a923105e 100644
--- a/charts/vela-core/crds/core.oam.dev_workflows.yaml
+++ b/charts/vela-core/crds/core.oam.dev_workflows.yaml
@@ -74,6 +74,54 @@ spec:
                 properties:
                   type: object
                   x-kubernetes-preserve-unknown-fields: true
+                subSteps:
+                  items:
+                    description: WorkflowSubStep defines how to execute a workflow
+                      subStep.
+                    properties:
+                      dependsOn:
+                        items:
+                          type: string
+                        type: array
+                      inputs:
+                        description: StepInputs defines variable input of WorkflowStep
+                        items:
+                          properties:
+                            from:
+                              type: string
+                            parameterKey:
+                              type: string
+                          required:
+                          - from
+                          - parameterKey
+                          type: object
+                        type: array
+                      name:
+                        description: Name is the unique name of the workflow step.
+                        type: string
+                      outputs:
+                        description: StepOutputs defines output variable of WorkflowStep
+                        items:
+                          properties:
+                            name:
+                              type: string
+                            valueFrom:
+                              type: string
+                          required:
+                          - name
+                          - valueFrom
+                          type: object
+                        type: array
+                      properties:
+                        type: object
+                        x-kubernetes-preserve-unknown-fields: true
+                      type:
+                        type: string
+                    required:
+                    - name
+                    - type
+                    type: object
+                  type: array
                 type:
                   type: string
               required:
@@ -131,6 +179,54 @@ spec:
                 properties:
                   type: object
                   x-kubernetes-preserve-unknown-fields: true
+                subSteps:
+                  items:
+                    description: WorkflowSubStep defines how to execute a workflow
+                      subStep.
+                    properties:
+                      dependsOn:
+                        items:
+                          type: string
+                        type: array
+                      inputs:
+                        description: StepInputs defines variable input of WorkflowStep
+                        items:
+                          properties:
+                            from:
+                              type: string
+                            parameterKey:
+                              type: string
+                          required:
+                          - from
+                          - parameterKey
+                          type: object
+                        type: array
+                      name:
+                        description: Name is the unique name of the workflow step.
+                        type: string
+                      outputs:
+                        description: StepOutputs defines output variable of WorkflowStep
+                        items:
+                          properties:
+                            name:
+                              type: string
+                            valueFrom:
+                              type: string
+                          required:
+                          - name
+                          - valueFrom
+                          type: object
+                        type: array
+                      properties:
+                        type: object
+                        x-kubernetes-preserve-unknown-fields: true
+                      type:
+                        type: string
+                    required:
+                    - name
+                    - type
+                    type: object
+                  type: array
                 type:
                   type: string
               required:
diff --git a/charts/vela-core/templates/defwithtemplate/step-group.yaml b/charts/vela-core/templates/defwithtemplate/step-group.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..91768971ea8d4b1255534d16add56891f8af3599
--- /dev/null
+++ b/charts/vela-core/templates/defwithtemplate/step-group.yaml
@@ -0,0 +1,16 @@
+# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
+# Definition source cue file: vela-templates/definitions/internal/step-group.cue
+apiVersion: core.oam.dev/v1beta1
+kind: WorkflowStepDefinition
+metadata:
+  annotations:
+    definition.oam.dev/description: step group
+  name: step-group
+  namespace: {{ include "systemDefinitionNamespace" . }}
+spec:
+  schematic:
+    cue:
+      template: |
+        // no parameters
+        parameter: {}
+
diff --git a/charts/vela-minimal/crds/core.oam.dev_applicationrevisions.yaml b/charts/vela-minimal/crds/core.oam.dev_applicationrevisions.yaml
index b99b42a1260df0ea9bb789660c6b8b56935c3dab..cfbeb0b7243a5b63df901fb9474b56409f5d17e3 100644
--- a/charts/vela-minimal/crds/core.oam.dev_applicationrevisions.yaml
+++ b/charts/vela-minimal/crds/core.oam.dev_applicationrevisions.yaml
@@ -856,7 +856,7 @@ spec:
                           steps:
                             items:
                               description: WorkflowStepStatus record the status of
-                                a workflow step
+                                a workflow step, include step status and subStep status
                               properties:
                                 firstExecuteTime:
                                   description: FirstExecuteTime is the first time
@@ -887,45 +887,44 @@ spec:
                                     state.
                                   type: string
                                 subSteps:
-                                  description: SubStepsStatus record the status of
-                                    workflow steps.
-                                  properties:
-                                    mode:
-                                      description: WorkflowMode describes the mode
-                                        of workflow
-                                      type: string
-                                    stepIndex:
-                                      type: integer
-                                    steps:
-                                      items:
-                                        description: WorkflowSubStepStatus record
-                                          the status of a workflow step
-                                        properties:
-                                          id:
-                                            type: string
-                                          message:
-                                            description: A human readable message
-                                              indicating details about why the workflowStep
-                                              is in this state.
-                                            type: string
-                                          name:
-                                            type: string
-                                          phase:
-                                            description: WorkflowStepPhase describes
-                                              the phase of a workflow step.
-                                            type: string
-                                          reason:
-                                            description: A brief CamelCase message
-                                              indicating details about why the workflowStep
-                                              is in this state.
-                                            type: string
-                                          type:
-                                            type: string
-                                        required:
-                                        - id
-                                        type: object
-                                      type: array
-                                  type: object
+                                  items:
+                                    description: WorkflowSubStepStatus record the
+                                      status of a workflow subStep
+                                    properties:
+                                      firstExecuteTime:
+                                        description: FirstExecuteTime is the first
+                                          time this step execution.
+                                        format: date-time
+                                        type: string
+                                      id:
+                                        type: string
+                                      lastExecuteTime:
+                                        description: LastExecuteTime is the last time
+                                          this step execution.
+                                        format: date-time
+                                        type: string
+                                      message:
+                                        description: A human readable message indicating
+                                          details about why the workflowStep is in
+                                          this state.
+                                        type: string
+                                      name:
+                                        type: string
+                                      phase:
+                                        description: WorkflowStepPhase describes the
+                                          phase of a workflow step.
+                                        type: string
+                                      reason:
+                                        description: A brief CamelCase message indicating
+                                          details about why the workflowStep is in
+                                          this state.
+                                        type: string
+                                      type:
+                                        type: string
+                                    required:
+                                    - id
+                                    type: object
+                                  type: array
                                 type:
                                   type: string
                               required:
@@ -2245,6 +2244,57 @@ spec:
                                 properties:
                                   type: object
                                   x-kubernetes-preserve-unknown-fields: true
+                                subSteps:
+                                  items:
+                                    description: WorkflowSubStep defines how to execute
+                                      a workflow subStep.
+                                    properties:
+                                      dependsOn:
+                                        items:
+                                          type: string
+                                        type: array
+                                      inputs:
+                                        description: StepInputs defines variable input
+                                          of WorkflowStep
+                                        items:
+                                          properties:
+                                            from:
+                                              type: string
+                                            parameterKey:
+                                              type: string
+                                          required:
+                                          - from
+                                          - parameterKey
+                                          type: object
+                                        type: array
+                                      name:
+                                        description: Name is the unique name of the
+                                          workflow step.
+                                        type: string
+                                      outputs:
+                                        description: StepOutputs defines output variable
+                                          of WorkflowStep
+                                        items:
+                                          properties:
+                                            name:
+                                              type: string
+                                            valueFrom:
+                                              type: string
+                                          required:
+                                          - name
+                                          - valueFrom
+                                          type: object
+                                        type: array
+                                      properties:
+                                        type: object
+                                        x-kubernetes-preserve-unknown-fields: true
+                                      type:
+                                        type: string
+                                    required:
+                                    - name
+                                    - type
+                                    type: object
+                                  type: array
                                 type:
                                   type: string
                               required:
@@ -2667,7 +2717,7 @@ spec:
                           steps:
                             items:
                               description: WorkflowStepStatus record the status of
-                                a workflow step
+                                a workflow step, include step status and subStep status
                               properties:
                                 firstExecuteTime:
                                   description: FirstExecuteTime is the first time
@@ -2698,45 +2748,44 @@ spec:
                                     state.
                                   type: string
                                 subSteps:
-                                  description: SubStepsStatus record the status of
-                                    workflow steps.
-                                  properties:
-                                    mode:
-                                      description: WorkflowMode describes the mode
-                                        of workflow
-                                      type: string
-                                    stepIndex:
-                                      type: integer
-                                    steps:
-                                      items:
-                                        description: WorkflowSubStepStatus record
-                                          the status of a workflow step
-                                        properties:
-                                          id:
-                                            type: string
-                                          message:
-                                            description: A human readable message
-                                              indicating details about why the workflowStep
-                                              is in this state.
-                                            type: string
-                                          name:
-                                            type: string
-                                          phase:
-                                            description: WorkflowStepPhase describes
-                                              the phase of a workflow step.
-                                            type: string
-                                          reason:
-                                            description: A brief CamelCase message
-                                              indicating details about why the workflowStep
-                                              is in this state.
-                                            type: string
-                                          type:
-                                            type: string
-                                        required:
-                                        - id
-                                        type: object
-                                      type: array
-                                  type: object
+                                  items:
+                                    description: WorkflowSubStepStatus record the
+                                      status of a workflow subStep
+                                    properties:
+                                      firstExecuteTime:
+                                        description: FirstExecuteTime is the first
+                                          time this step execution.
+                                        format: date-time
+                                        type: string
+                                      id:
+                                        type: string
+                                      lastExecuteTime:
+                                        description: LastExecuteTime is the last time
+                                          this step execution.
+                                        format: date-time
+                                        type: string
+                                      message:
+                                        description: A human readable message indicating
+                                          details about why the workflowStep is in
+                                          this state.
+                                        type: string
+                                      name:
+                                        type: string
+                                      phase:
+                                        description: WorkflowStepPhase describes the
+                                          phase of a workflow step.
+                                        type: string
+                                      reason:
+                                        description: A brief CamelCase message indicating
+                                          details about why the workflowStep is in
+                                          this state.
+                                        type: string
+                                      type:
+                                        type: string
+                                    required:
+                                    - id
+                                    type: object
+                                  type: array
                                 type:
                                   type: string
                               required:
@@ -3937,6 +3986,57 @@ spec:
                         properties:
                           type: object
                           x-kubernetes-preserve-unknown-fields: true
+                        subSteps:
+                          items:
+                            description: WorkflowSubStep defines how to execute a
+                              workflow subStep.
+                            properties:
+                              dependsOn:
+                                items:
+                                  type: string
+                                type: array
+                              inputs:
+                                description: StepInputs defines variable input of
+                                  WorkflowStep
+                                items:
+                                  properties:
+                                    from:
+                                      type: string
+                                    parameterKey:
+                                      type: string
+                                  required:
+                                  - from
+                                  - parameterKey
+                                  type: object
+                                type: array
+                              name:
+                                description: Name is the unique name of the workflow
+                                  step.
+                                type: string
+                              outputs:
+                                description: StepOutputs defines output variable of
+                                  WorkflowStep
+                                items:
+                                  properties:
+                                    name:
+                                      type: string
+                                    valueFrom:
+                                      type: string
+                                  required:
+                                  - name
+                                  - valueFrom
+                                  type: object
+                                type: array
+                              properties:
+                                type: object
+                                x-kubernetes-preserve-unknown-fields: true
+                              type:
+                                type: string
+                            required:
+                            - name
+                            - type
+                            type: object
+                          type: array
                         type:
                           type: string
                       required:
@@ -4619,7 +4719,7 @@ spec:
                   steps:
                     items:
                       description: WorkflowStepStatus record the status of a workflow
-                        step
+                        step, include step status and subStep status
                       properties:
                         firstExecuteTime:
                           description: FirstExecuteTime is the first time this step
@@ -4648,44 +4748,42 @@ spec:
                             about why the workflowStep is in this state.
                           type: string
                         subSteps:
-                          description: SubStepsStatus record the status of workflow
-                            steps.
-                          properties:
-                            mode:
-                              description: WorkflowMode describes the mode of workflow
-                              type: string
-                            stepIndex:
-                              type: integer
-                            steps:
-                              items:
-                                description: WorkflowSubStepStatus record the status
-                                  of a workflow step
-                                properties:
-                                  id:
-                                    type: string
-                                  message:
-                                    description: A human readable message indicating
-                                      details about why the workflowStep is in this
-                                      state.
-                                    type: string
-                                  name:
-                                    type: string
-                                  phase:
-                                    description: WorkflowStepPhase describes the phase
-                                      of a workflow step.
-                                    type: string
-                                  reason:
-                                    description: A brief CamelCase message indicating
-                                      details about why the workflowStep is in this
-                                      state.
-                                    type: string
-                                  type:
-                                    type: string
-                                required:
-                                - id
-                                type: object
-                              type: array
-                          type: object
+                          items:
+                            description: WorkflowSubStepStatus record the status of
+                              a workflow subStep
+                            properties:
+                              firstExecuteTime:
+                                description: FirstExecuteTime is the first time this
+                                  step execution.
+                                format: date-time
+                                type: string
+                              id:
+                                type: string
+                              lastExecuteTime:
+                                description: LastExecuteTime is the last time this
+                                  step execution.
+                                format: date-time
+                                type: string
+                              message:
+                                description: A human readable message indicating details
+                                  about why the workflowStep is in this state.
+                                type: string
+                              name:
+                                type: string
+                              phase:
+                                description: WorkflowStepPhase describes the phase
+                                  of a workflow step.
+                                type: string
+                              reason:
+                                description: A brief CamelCase message indicating
+                                  details about why the workflowStep is in this state.
+                                type: string
+                              type:
+                                type: string
+                            required:
+                            - id
+                            type: object
+                          type: array
                         type:
                           type: string
                       required:
diff --git a/charts/vela-minimal/crds/core.oam.dev_applications.yaml b/charts/vela-minimal/crds/core.oam.dev_applications.yaml
index bd9ea725a40519d2a3912297ba3dc46e3db57d7d..c63283bc99768d525ae3b291804414b6789671ad 100644
--- a/charts/vela-minimal/crds/core.oam.dev_applications.yaml
+++ b/charts/vela-minimal/crds/core.oam.dev_applications.yaml
@@ -779,7 +779,7 @@ spec:
                   steps:
                     items:
                       description: WorkflowStepStatus record the status of a workflow
-                        step
+                        step, include step status and subStep status
                       properties:
                         firstExecuteTime:
                           description: FirstExecuteTime is the first time this step
@@ -808,44 +808,42 @@ spec:
                             about why the workflowStep is in this state.
                           type: string
                         subSteps:
-                          description: SubStepsStatus record the status of workflow
-                            steps.
-                          properties:
-                            mode:
-                              description: WorkflowMode describes the mode of workflow
-                              type: string
-                            stepIndex:
-                              type: integer
-                            steps:
-                              items:
-                                description: WorkflowSubStepStatus record the status
-                                  of a workflow step
-                                properties:
-                                  id:
-                                    type: string
-                                  message:
-                                    description: A human readable message indicating
-                                      details about why the workflowStep is in this
-                                      state.
-                                    type: string
-                                  name:
-                                    type: string
-                                  phase:
-                                    description: WorkflowStepPhase describes the phase
-                                      of a workflow step.
-                                    type: string
-                                  reason:
-                                    description: A brief CamelCase message indicating
-                                      details about why the workflowStep is in this
-                                      state.
-                                    type: string
-                                  type:
-                                    type: string
-                                required:
-                                - id
-                                type: object
-                              type: array
-                          type: object
+                          items:
+                            description: WorkflowSubStepStatus record the status of
+                              a workflow subStep
+                            properties:
+                              firstExecuteTime:
+                                description: FirstExecuteTime is the first time this
+                                  step execution.
+                                format: date-time
+                                type: string
+                              id:
+                                type: string
+                              lastExecuteTime:
+                                description: LastExecuteTime is the last time this
+                                  step execution.
+                                format: date-time
+                                type: string
+                              message:
+                                description: A human readable message indicating details
+                                  about why the workflowStep is in this state.
+                                type: string
+                              name:
+                                type: string
+                              phase:
+                                description: WorkflowStepPhase describes the phase
+                                  of a workflow step.
+                                type: string
+                              reason:
+                                description: A brief CamelCase message indicating
+                                  details about why the workflowStep is in this state.
+                                type: string
+                              type:
+                                type: string
+                            required:
+                            - id
+                            type: object
+                          type: array
                         type:
                           type: string
                       required:
@@ -1054,6 +1052,57 @@ spec:
                         properties:
                           type: object
                           x-kubernetes-preserve-unknown-fields: true
+                        subSteps:
+                          items:
+                            description: WorkflowSubStep defines how to execute a
+                              workflow subStep.
+                            properties:
+                              dependsOn:
+                                items:
+                                  type: string
+                                type: array
+                              inputs:
+                                description: StepInputs defines variable input of
+                                  WorkflowStep
+                                items:
+                                  properties:
+                                    from:
+                                      type: string
+                                    parameterKey:
+                                      type: string
+                                  required:
+                                  - from
+                                  - parameterKey
+                                  type: object
+                                type: array
+                              name:
+                                description: Name is the unique name of the workflow
+                                  step.
+                                type: string
+                              outputs:
+                                description: StepOutputs defines output variable of
+                                  WorkflowStep
+                                items:
+                                  properties:
+                                    name:
+                                      type: string
+                                    valueFrom:
+                                      type: string
+                                  required:
+                                  - name
+                                  - valueFrom
+                                  type: object
+                                type: array
+                              properties:
+                                type: object
+                                x-kubernetes-preserve-unknown-fields: true
+                              type:
+                                type: string
+                            required:
+                            - name
+                            - type
+                            type: object
+                          type: array
                         type:
                           type: string
                       required:
@@ -1446,7 +1495,7 @@ spec:
                   steps:
                     items:
                       description: WorkflowStepStatus record the status of a workflow
-                        step
+                        step, include step status and subStep status
                       properties:
                         firstExecuteTime:
                           description: FirstExecuteTime is the first time this step
@@ -1475,44 +1524,42 @@ spec:
                             about why the workflowStep is in this state.
                           type: string
                         subSteps:
-                          description: SubStepsStatus record the status of workflow
-                            steps.
-                          properties:
-                            mode:
-                              description: WorkflowMode describes the mode of workflow
-                              type: string
-                            stepIndex:
-                              type: integer
-                            steps:
-                              items:
-                                description: WorkflowSubStepStatus record the status
-                                  of a workflow step
-                                properties:
-                                  id:
-                                    type: string
-                                  message:
-                                    description: A human readable message indicating
-                                      details about why the workflowStep is in this
-                                      state.
-                                    type: string
-                                  name:
-                                    type: string
-                                  phase:
-                                    description: WorkflowStepPhase describes the phase
-                                      of a workflow step.
-                                    type: string
-                                  reason:
-                                    description: A brief CamelCase message indicating
-                                      details about why the workflowStep is in this
-                                      state.
-                                    type: string
-                                  type:
-                                    type: string
-                                required:
-                                - id
-                                type: object
-                              type: array
-                          type: object
+                          items:
+                            description: WorkflowSubStepStatus record the status of
+                              a workflow subStep
+                            properties:
+                              firstExecuteTime:
+                                description: FirstExecuteTime is the first time this
+                                  step execution.
+                                format: date-time
+                                type: string
+                              id:
+                                type: string
+                              lastExecuteTime:
+                                description: LastExecuteTime is the last time this
+                                  step execution.
+                                format: date-time
+                                type: string
+                              message:
+                                description: A human readable message indicating details
+                                  about why the workflowStep is in this state.
+                                type: string
+                              name:
+                                type: string
+                              phase:
+                                description: WorkflowStepPhase describes the phase
+                                  of a workflow step.
+                                type: string
+                              reason:
+                                description: A brief CamelCase message indicating
+                                  details about why the workflowStep is in this state.
+                                type: string
+                              type:
+                                type: string
+                            required:
+                            - id
+                            type: object
+                          type: array
                         type:
                           type: string
                       required:
diff --git a/charts/vela-minimal/templates/defwithtemplate/step-group.yaml b/charts/vela-minimal/templates/defwithtemplate/step-group.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..91768971ea8d4b1255534d16add56891f8af3599
--- /dev/null
+++ b/charts/vela-minimal/templates/defwithtemplate/step-group.yaml
@@ -0,0 +1,16 @@
+# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
+# Definition source cue file: vela-templates/definitions/internal/step-group.cue
+apiVersion: core.oam.dev/v1beta1
+kind: WorkflowStepDefinition
+metadata:
+  annotations:
+    definition.oam.dev/description: step group
+  name: step-group
+  namespace: {{ include "systemDefinitionNamespace" . }}
+spec:
+  schematic:
+    cue:
+      template: |
+        // no parameters
+        parameter: {}
+
diff --git a/design/vela-core/workflow_policy.md b/design/vela-core/workflow_policy.md
index de4a5d60298f95897c08247b4ee8d37a5110cfcc..57c7dca106cf8710216c4fd07cc2164b7c8c28f7 100644
--- a/design/vela-core/workflow_policy.md
+++ b/design/vela-core/workflow_policy.md
@@ -652,7 +652,7 @@ The process goes as:
 - The HelmTemplate/KustomizePatch controller would read the template from specified source, render the final config. It will compare the config with the Application object -- if there is difference, it will write back to the Application object per se.
 - The update of Application will trigger another event, the app controller will apply the HelmTemplate/KustomizePatch objects with new context. But this time, the HelmTemplate/KustomizePatch controller will find no diff after the rendering. So it will skip this time.
 
-### Case 5: Conditional Check
+### Case 6: Conditional Check
 
 In this case, users want to execute different steps based on the responseCode. When the `if` condition is not met, the step will be skipped.
 
@@ -684,6 +684,28 @@ steps:
      type: notification
 ```
 
+### Case 7: step group
+
+In this case, the user runs multiple workflow steps in the `step-group` workflow type. subSteps in a step group will be executed in dag mode.
+```yaml
+workflow:
+  steps:
+  - type: step-group
+    name: run-step-group1
+    subSteps: 
+    - name: sub-step1
+      type: ...
+      ...
+    - name: sub-step2
+      type: ...
+      ...
+
+```
+
+The process is as follows:
+
+- When executing a `step-group` step, the subSteps in the step group are executed in dag mode. A step group will only complete when all subSteps have been executed to completion.
+
 ## Considerations
 
 ### Comparison with Argo Workflow/Tekton
diff --git a/docs/examples/workflow/step-group/app.yaml b/docs/examples/workflow/step-group/app.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..0e47d6f07a250087a33367df399904fd1789b8ca
--- /dev/null
+++ b/docs/examples/workflow/step-group/app.yaml
@@ -0,0 +1,22 @@
+apiVersion: core.oam.dev/v1beta1
+kind: Application
+metadata:
+  name: step-group-example
+  namespace: default
+spec:
+  components:
+    - name: express-server
+      type: webservice
+      properties:
+        image: crccheck/hello-world
+        port: 8000
+
+  workflow:
+    steps:
+      - name: step
+        type: step-group
+        subSteps:
+          - name: apply-server
+            type: apply-component
+            properties:
+              component: express-server
diff --git a/legacy/charts/vela-core-legacy/crds/core.oam.dev_applicationrevisions.yaml b/legacy/charts/vela-core-legacy/crds/core.oam.dev_applicationrevisions.yaml
index 22f8d1223dd663f05df51d1f5571907b59bb70a4..f0f4d208553279e79b0423ced380c9649ab77c0a 100644
--- a/legacy/charts/vela-core-legacy/crds/core.oam.dev_applicationrevisions.yaml
+++ b/legacy/charts/vela-core-legacy/crds/core.oam.dev_applicationrevisions.yaml
@@ -856,7 +856,7 @@ spec:
                           steps:
                             items:
                               description: WorkflowStepStatus record the status of
-                                a workflow step
+                                a workflow step, include step status and subStep status
                               properties:
                                 firstExecuteTime:
                                   description: FirstExecuteTime is the first time
@@ -887,45 +887,44 @@ spec:
                                     state.
                                   type: string
                                 subSteps:
-                                  description: SubStepsStatus record the status of
-                                    workflow steps.
-                                  properties:
-                                    mode:
-                                      description: WorkflowMode describes the mode
-                                        of workflow
-                                      type: string
-                                    stepIndex:
-                                      type: integer
-                                    steps:
-                                      items:
-                                        description: WorkflowSubStepStatus record
-                                          the status of a workflow step
-                                        properties:
-                                          id:
-                                            type: string
-                                          message:
-                                            description: A human readable message
-                                              indicating details about why the workflowStep
-                                              is in this state.
-                                            type: string
-                                          name:
-                                            type: string
-                                          phase:
-                                            description: WorkflowStepPhase describes
-                                              the phase of a workflow step.
-                                            type: string
-                                          reason:
-                                            description: A brief CamelCase message
-                                              indicating details about why the workflowStep
-                                              is in this state.
-                                            type: string
-                                          type:
-                                            type: string
-                                        required:
-                                        - id
-                                        type: object
-                                      type: array
-                                  type: object
+                                  items:
+                                    description: WorkflowSubStepStatus record the
+                                      status of a workflow subStep
+                                    properties:
+                                      firstExecuteTime:
+                                        description: FirstExecuteTime is the first
+                                          time this step execution.
+                                        format: date-time
+                                        type: string
+                                      id:
+                                        type: string
+                                      lastExecuteTime:
+                                        description: LastExecuteTime is the last time
+                                          this step execution.
+                                        format: date-time
+                                        type: string
+                                      message:
+                                        description: A human readable message indicating
+                                          details about why the workflowStep is in
+                                          this state.
+                                        type: string
+                                      name:
+                                        type: string
+                                      phase:
+                                        description: WorkflowStepPhase describes the
+                                          phase of a workflow step.
+                                        type: string
+                                      reason:
+                                        description: A brief CamelCase message indicating
+                                          details about why the workflowStep is in
+                                          this state.
+                                        type: string
+                                      type:
+                                        type: string
+                                    required:
+                                    - id
+                                    type: object
+                                  type: array
                                 type:
                                   type: string
                               required:
@@ -2245,6 +2244,57 @@ spec:
                                 properties:
                                   type: object
                                   
+                                subSteps:
+                                  items:
+                                    description: WorkflowSubStep defines how to execute
+                                      a workflow subStep.
+                                    properties:
+                                      dependsOn:
+                                        items:
+                                          type: string
+                                        type: array
+                                      inputs:
+                                        description: StepInputs defines variable input
+                                          of WorkflowStep
+                                        items:
+                                          properties:
+                                            from:
+                                              type: string
+                                            parameterKey:
+                                              type: string
+                                          required:
+                                          - from
+                                          - parameterKey
+                                          type: object
+                                        type: array
+                                      name:
+                                        description: Name is the unique name of the
+                                          workflow step.
+                                        type: string
+                                      outputs:
+                                        description: StepOutputs defines output variable
+                                          of WorkflowStep
+                                        items:
+                                          properties:
+                                            name:
+                                              type: string
+                                            valueFrom:
+                                              type: string
+                                          required:
+                                          - name
+                                          - valueFrom
+                                          type: object
+                                        type: array
+                                      properties:
+                                        type: object
+                                        
+                                      type:
+                                        type: string
+                                    required:
+                                    - name
+                                    - type
+                                    type: object
+                                  type: array
                                 type:
                                   type: string
                               required:
@@ -2667,7 +2717,7 @@ spec:
                           steps:
                             items:
                               description: WorkflowStepStatus record the status of
-                                a workflow step
+                                a workflow step, include step status and subStep status
                               properties:
                                 firstExecuteTime:
                                   description: FirstExecuteTime is the first time
@@ -2698,45 +2748,44 @@ spec:
                                     state.
                                   type: string
                                 subSteps:
-                                  description: SubStepsStatus record the status of
-                                    workflow steps.
-                                  properties:
-                                    mode:
-                                      description: WorkflowMode describes the mode
-                                        of workflow
-                                      type: string
-                                    stepIndex:
-                                      type: integer
-                                    steps:
-                                      items:
-                                        description: WorkflowSubStepStatus record
-                                          the status of a workflow step
-                                        properties:
-                                          id:
-                                            type: string
-                                          message:
-                                            description: A human readable message
-                                              indicating details about why the workflowStep
-                                              is in this state.
-                                            type: string
-                                          name:
-                                            type: string
-                                          phase:
-                                            description: WorkflowStepPhase describes
-                                              the phase of a workflow step.
-                                            type: string
-                                          reason:
-                                            description: A brief CamelCase message
-                                              indicating details about why the workflowStep
-                                              is in this state.
-                                            type: string
-                                          type:
-                                            type: string
-                                        required:
-                                        - id
-                                        type: object
-                                      type: array
-                                  type: object
+                                  items:
+                                    description: WorkflowSubStepStatus record the
+                                      status of a workflow subStep
+                                    properties:
+                                      firstExecuteTime:
+                                        description: FirstExecuteTime is the first
+                                          time this step execution.
+                                        format: date-time
+                                        type: string
+                                      id:
+                                        type: string
+                                      lastExecuteTime:
+                                        description: LastExecuteTime is the last time
+                                          this step execution.
+                                        format: date-time
+                                        type: string
+                                      message:
+                                        description: A human readable message indicating
+                                          details about why the workflowStep is in
+                                          this state.
+                                        type: string
+                                      name:
+                                        type: string
+                                      phase:
+                                        description: WorkflowStepPhase describes the
+                                          phase of a workflow step.
+                                        type: string
+                                      reason:
+                                        description: A brief CamelCase message indicating
+                                          details about why the workflowStep is in
+                                          this state.
+                                        type: string
+                                      type:
+                                        type: string
+                                    required:
+                                    - id
+                                    type: object
+                                  type: array
                                 type:
                                   type: string
                               required:
@@ -3937,6 +3986,57 @@ spec:
                         properties:
                           type: object
                           
+                        subSteps:
+                          items:
+                            description: WorkflowSubStep defines how to execute a
+                              workflow subStep.
+                            properties:
+                              dependsOn:
+                                items:
+                                  type: string
+                                type: array
+                              inputs:
+                                description: StepInputs defines variable input of
+                                  WorkflowStep
+                                items:
+                                  properties:
+                                    from:
+                                      type: string
+                                    parameterKey:
+                                      type: string
+                                  required:
+                                  - from
+                                  - parameterKey
+                                  type: object
+                                type: array
+                              name:
+                                description: Name is the unique name of the workflow
+                                  step.
+                                type: string
+                              outputs:
+                                description: StepOutputs defines output variable of
+                                  WorkflowStep
+                                items:
+                                  properties:
+                                    name:
+                                      type: string
+                                    valueFrom:
+                                      type: string
+                                  required:
+                                  - name
+                                  - valueFrom
+                                  type: object
+                                type: array
+                              properties:
+                                type: object
+                                
+                              type:
+                                type: string
+                            required:
+                            - name
+                            - type
+                            type: object
+                          type: array
                         type:
                           type: string
                       required:
@@ -4619,7 +4719,7 @@ spec:
                   steps:
                     items:
                       description: WorkflowStepStatus record the status of a workflow
-                        step
+                        step, include step status and subStep status
                       properties:
                         firstExecuteTime:
                           description: FirstExecuteTime is the first time this step
@@ -4648,44 +4748,42 @@ spec:
                             about why the workflowStep is in this state.
                           type: string
                         subSteps:
-                          description: SubStepsStatus record the status of workflow
-                            steps.
-                          properties:
-                            mode:
-                              description: WorkflowMode describes the mode of workflow
-                              type: string
-                            stepIndex:
-                              type: integer
-                            steps:
-                              items:
-                                description: WorkflowSubStepStatus record the status
-                                  of a workflow step
-                                properties:
-                                  id:
-                                    type: string
-                                  message:
-                                    description: A human readable message indicating
-                                      details about why the workflowStep is in this
-                                      state.
-                                    type: string
-                                  name:
-                                    type: string
-                                  phase:
-                                    description: WorkflowStepPhase describes the phase
-                                      of a workflow step.
-                                    type: string
-                                  reason:
-                                    description: A brief CamelCase message indicating
-                                      details about why the workflowStep is in this
-                                      state.
-                                    type: string
-                                  type:
-                                    type: string
-                                required:
-                                - id
-                                type: object
-                              type: array
-                          type: object
+                          items:
+                            description: WorkflowSubStepStatus record the status of
+                              a workflow subStep
+                            properties:
+                              firstExecuteTime:
+                                description: FirstExecuteTime is the first time this
+                                  step execution.
+                                format: date-time
+                                type: string
+                              id:
+                                type: string
+                              lastExecuteTime:
+                                description: LastExecuteTime is the last time this
+                                  step execution.
+                                format: date-time
+                                type: string
+                              message:
+                                description: A human readable message indicating details
+                                  about why the workflowStep is in this state.
+                                type: string
+                              name:
+                                type: string
+                              phase:
+                                description: WorkflowStepPhase describes the phase
+                                  of a workflow step.
+                                type: string
+                              reason:
+                                description: A brief CamelCase message indicating
+                                  details about why the workflowStep is in this state.
+                                type: string
+                              type:
+                                type: string
+                            required:
+                            - id
+                            type: object
+                          type: array
                         type:
                           type: string
                       required:
diff --git a/legacy/charts/vela-core-legacy/crds/core.oam.dev_applications.yaml b/legacy/charts/vela-core-legacy/crds/core.oam.dev_applications.yaml
index d003fb58203a5335fd23a402667625ffbc8e1c7a..8a398661ace1fa1f2694218306b803ff352f7458 100644
--- a/legacy/charts/vela-core-legacy/crds/core.oam.dev_applications.yaml
+++ b/legacy/charts/vela-core-legacy/crds/core.oam.dev_applications.yaml
@@ -780,7 +780,7 @@ spec:
                   steps:
                     items:
                       description: WorkflowStepStatus record the status of a workflow
-                        step
+                        step, include step status and subStep status
                       properties:
                         firstExecuteTime:
                           description: FirstExecuteTime is the first time this step
@@ -809,44 +809,42 @@ spec:
                             about why the workflowStep is in this state.
                           type: string
                         subSteps:
-                          description: SubStepsStatus record the status of workflow
-                            steps.
-                          properties:
-                            mode:
-                              description: WorkflowMode describes the mode of workflow
-                              type: string
-                            stepIndex:
-                              type: integer
-                            steps:
-                              items:
-                                description: WorkflowSubStepStatus record the status
-                                  of a workflow step
-                                properties:
-                                  id:
-                                    type: string
-                                  message:
-                                    description: A human readable message indicating
-                                      details about why the workflowStep is in this
-                                      state.
-                                    type: string
-                                  name:
-                                    type: string
-                                  phase:
-                                    description: WorkflowStepPhase describes the phase
-                                      of a workflow step.
-                                    type: string
-                                  reason:
-                                    description: A brief CamelCase message indicating
-                                      details about why the workflowStep is in this
-                                      state.
-                                    type: string
-                                  type:
-                                    type: string
-                                required:
-                                - id
-                                type: object
-                              type: array
-                          type: object
+                          items:
+                            description: WorkflowSubStepStatus record the status of
+                              a workflow subStep
+                            properties:
+                              firstExecuteTime:
+                                description: FirstExecuteTime is the first time this
+                                  step execution.
+                                format: date-time
+                                type: string
+                              id:
+                                type: string
+                              lastExecuteTime:
+                                description: LastExecuteTime is the last time this
+                                  step execution.
+                                format: date-time
+                                type: string
+                              message:
+                                description: A human readable message indicating details
+                                  about why the workflowStep is in this state.
+                                type: string
+                              name:
+                                type: string
+                              phase:
+                                description: WorkflowStepPhase describes the phase
+                                  of a workflow step.
+                                type: string
+                              reason:
+                                description: A brief CamelCase message indicating
+                                  details about why the workflowStep is in this state.
+                                type: string
+                              type:
+                                type: string
+                            required:
+                            - id
+                            type: object
+                          type: array
                         type:
                           type: string
                       required:
@@ -1055,6 +1053,57 @@ spec:
                         properties:
                           type: object
                           
+                        subSteps:
+                          items:
+                            description: WorkflowSubStep defines how to execute a
+                              workflow subStep.
+                            properties:
+                              dependsOn:
+                                items:
+                                  type: string
+                                type: array
+                              inputs:
+                                description: StepInputs defines variable input of
+                                  WorkflowStep
+                                items:
+                                  properties:
+                                    from:
+                                      type: string
+                                    parameterKey:
+                                      type: string
+                                  required:
+                                  - from
+                                  - parameterKey
+                                  type: object
+                                type: array
+                              name:
+                                description: Name is the unique name of the workflow
+                                  step.
+                                type: string
+                              outputs:
+                                description: StepOutputs defines output variable of
+                                  WorkflowStep
+                                items:
+                                  properties:
+                                    name:
+                                      type: string
+                                    valueFrom:
+                                      type: string
+                                  required:
+                                  - name
+                                  - valueFrom
+                                  type: object
+                                type: array
+                              properties:
+                                type: object
+                                
+                              type:
+                                type: string
+                            required:
+                            - name
+                            - type
+                            type: object
+                          type: array
                         type:
                           type: string
                       required:
@@ -1447,7 +1496,7 @@ spec:
                   steps:
                     items:
                       description: WorkflowStepStatus record the status of a workflow
-                        step
+                        step, include step status and subStep status
                       properties:
                         firstExecuteTime:
                           description: FirstExecuteTime is the first time this step
@@ -1476,44 +1525,42 @@ spec:
                             about why the workflowStep is in this state.
                           type: string
                         subSteps:
-                          description: SubStepsStatus record the status of workflow
-                            steps.
-                          properties:
-                            mode:
-                              description: WorkflowMode describes the mode of workflow
-                              type: string
-                            stepIndex:
-                              type: integer
-                            steps:
-                              items:
-                                description: WorkflowSubStepStatus record the status
-                                  of a workflow step
-                                properties:
-                                  id:
-                                    type: string
-                                  message:
-                                    description: A human readable message indicating
-                                      details about why the workflowStep is in this
-                                      state.
-                                    type: string
-                                  name:
-                                    type: string
-                                  phase:
-                                    description: WorkflowStepPhase describes the phase
-                                      of a workflow step.
-                                    type: string
-                                  reason:
-                                    description: A brief CamelCase message indicating
-                                      details about why the workflowStep is in this
-                                      state.
-                                    type: string
-                                  type:
-                                    type: string
-                                required:
-                                - id
-                                type: object
-                              type: array
-                          type: object
+                          items:
+                            description: WorkflowSubStepStatus record the status of
+                              a workflow subStep
+                            properties:
+                              firstExecuteTime:
+                                description: FirstExecuteTime is the first time this
+                                  step execution.
+                                format: date-time
+                                type: string
+                              id:
+                                type: string
+                              lastExecuteTime:
+                                description: LastExecuteTime is the last time this
+                                  step execution.
+                                format: date-time
+                                type: string
+                              message:
+                                description: A human readable message indicating details
+                                  about why the workflowStep is in this state.
+                                type: string
+                              name:
+                                type: string
+                              phase:
+                                description: WorkflowStepPhase describes the phase
+                                  of a workflow step.
+                                type: string
+                              reason:
+                                description: A brief CamelCase message indicating
+                                  details about why the workflowStep is in this state.
+                                type: string
+                              type:
+                                type: string
+                            required:
+                            - id
+                            type: object
+                          type: array
                         type:
                           type: string
                       required:
diff --git a/legacy/charts/vela-core-legacy/crds/core.oam.dev_workflows.yaml b/legacy/charts/vela-core-legacy/crds/core.oam.dev_workflows.yaml
index ef80e8f57968a08de1c4d76f0644192afb67c9c8..0f0b9a14f5600b70bf53335af4e59f9d5cbd2165 100644
--- a/legacy/charts/vela-core-legacy/crds/core.oam.dev_workflows.yaml
+++ b/legacy/charts/vela-core-legacy/crds/core.oam.dev_workflows.yaml
@@ -74,6 +74,54 @@ spec:
                 properties:
                   type: object
                   
+                subSteps:
+                  items:
+                    description: WorkflowSubStep defines how to execute a workflow
+                      subStep.
+                    properties:
+                      dependsOn:
+                        items:
+                          type: string
+                        type: array
+                      inputs:
+                        description: StepInputs defines variable input of WorkflowStep
+                        items:
+                          properties:
+                            from:
+                              type: string
+                            parameterKey:
+                              type: string
+                          required:
+                          - from
+                          - parameterKey
+                          type: object
+                        type: array
+                      name:
+                        description: Name is the unique name of the workflow step.
+                        type: string
+                      outputs:
+                        description: StepOutputs defines output variable of WorkflowStep
+                        items:
+                          properties:
+                            name:
+                              type: string
+                            valueFrom:
+                              type: string
+                          required:
+                          - name
+                          - valueFrom
+                          type: object
+                        type: array
+                      properties:
+                        type: object
+                        
+                      type:
+                        type: string
+                    required:
+                    - name
+                    - type
+                    type: object
+                  type: array
                 type:
                   type: string
               required:
@@ -131,6 +179,54 @@ spec:
                 properties:
                   type: object
                   
+                subSteps:
+                  items:
+                    description: WorkflowSubStep defines how to execute a workflow
+                      subStep.
+                    properties:
+                      dependsOn:
+                        items:
+                          type: string
+                        type: array
+                      inputs:
+                        description: StepInputs defines variable input of WorkflowStep
+                        items:
+                          properties:
+                            from:
+                              type: string
+                            parameterKey:
+                              type: string
+                          required:
+                          - from
+                          - parameterKey
+                          type: object
+                        type: array
+                      name:
+                        description: Name is the unique name of the workflow step.
+                        type: string
+                      outputs:
+                        description: StepOutputs defines output variable of WorkflowStep
+                        items:
+                          properties:
+                            name:
+                              type: string
+                            valueFrom:
+                              type: string
+                          required:
+                          - name
+                          - valueFrom
+                          type: object
+                        type: array
+                      properties:
+                        type: object
+                        
+                      type:
+                        type: string
+                    required:
+                    - name
+                    - type
+                    type: object
+                  type: array
                 type:
                   type: string
               required:
diff --git a/pkg/appfile/parser.go b/pkg/appfile/parser.go
index 283bca8d6c9553afc3ae8b9ee69d413293a5c582..c51f46ca2e167e2f85e2a54c1e122ba25e675ff7 100644
--- a/pkg/appfile/parser.go
+++ b/pkg/appfile/parser.go
@@ -444,21 +444,37 @@ func (p *Parser) parseWorkflowSteps(ctx context.Context, af *Appfile) error {
 		return err
 	}
 	for _, workflowStep := range af.WorkflowSteps {
-		if wftypes.IsBuiltinWorkflowStepType(workflowStep.Type) {
-			continue
-		}
-		if _, found := af.RelatedWorkflowStepDefinitions[workflowStep.Type]; found {
-			continue
+		err := p.parseWorkflowStep(ctx, af, workflowStep.Type)
+		if err != nil {
+			return err
 		}
-		def := &v1beta1.WorkflowStepDefinition{}
-		if err := util.GetCapabilityDefinition(ctx, p.client, def, workflowStep.Type); err != nil {
-			return errors.Wrapf(err, "failed to get workflow step definition %s", workflowStep.Type)
+
+		if workflowStep.SubSteps != nil {
+			for _, workflowSubStep := range workflowStep.SubSteps {
+				err := p.parseWorkflowStep(ctx, af, workflowSubStep.Type)
+				if err != nil {
+					return err
+				}
+			}
 		}
-		af.RelatedWorkflowStepDefinitions[workflowStep.Type] = def
 	}
 	return nil
 }
 
+func (p *Parser) parseWorkflowStep(ctx context.Context, af *Appfile, workflowStepType string) error {
+	if wftypes.IsBuiltinWorkflowStepType(workflowStepType) {
+		return nil
+	}
+	if _, found := af.RelatedWorkflowStepDefinitions[workflowStepType]; found {
+		return nil
+	}
+	def := &v1beta1.WorkflowStepDefinition{}
+	if err := util.GetCapabilityDefinition(ctx, p.client, def, workflowStepType); err != nil {
+		return errors.Wrapf(err, "failed to get workflow step definition %s", workflowStepType)
+	}
+	af.RelatedWorkflowStepDefinitions[workflowStepType] = def
+	return nil
+}
 func (p *Parser) makeWorkload(ctx context.Context, name, typ string, capType types.CapType, props *runtime.RawExtension) (*Workload, error) {
 	templ, err := p.tmplLoader.LoadTemplate(ctx, p.dm, p.client, typ, capType)
 	if err != nil {
diff --git a/pkg/controller/core.oam.dev/v1alpha2/application/generator.go b/pkg/controller/core.oam.dev/v1alpha2/application/generator.go
index e595186823728ddb801ed4bca72358e3935e1966..00e21ae59b973f4ca567e4e6ea8e2448193ec62b 100644
--- a/pkg/controller/core.oam.dev/v1alpha2/application/generator.go
+++ b/pkg/controller/core.oam.dev/v1alpha2/application/generator.go
@@ -83,27 +83,7 @@ func (h *AppHandler) GenerateApplicationSteps(ctx monitorContext.Context,
 
 	var tasks []wfTypes.TaskRunner
 	for _, step := range af.WorkflowSteps {
-		options := &wfTypes.GeneratorOptions{
-			ID: generateStepID(step.Name, app.Status.Workflow),
-		}
-		generatorName := step.Type
-		if generatorName == wfTypes.WorkflowStepTypeApplyComponent {
-			generatorName = wfTypes.WorkflowStepTypeBuiltinApplyComponent
-			options.StepConvertor = func(lstep v1beta1.WorkflowStep) (v1beta1.WorkflowStep, error) {
-				copierStep := lstep.DeepCopy()
-				if err := convertStepProperties(copierStep, app); err != nil {
-					return lstep, errors.WithMessage(err, "convert [apply-component]")
-				}
-				return *copierStep, nil
-			}
-		}
-
-		genTask, err := taskDiscover.GetTaskGenerator(ctx, generatorName)
-		if err != nil {
-			return nil, err
-		}
-
-		task, err := genTask(step, options)
+		task, err := generateStep(ctx, app, step, taskDiscover, "")
 		if err != nil {
 			return nil, err
 		}
@@ -112,6 +92,57 @@ func (h *AppHandler) GenerateApplicationSteps(ctx monitorContext.Context,
 	return tasks, nil
 }
 
+func generateStep(ctx context.Context,
+	app *v1beta1.Application,
+	step v1beta1.WorkflowStep,
+	taskDiscover wfTypes.TaskDiscover,
+	parentStepName string) (wfTypes.TaskRunner, error) {
+	options := &wfTypes.GeneratorOptions{
+		ID: generateStepID(step.Name, app.Status.Workflow, parentStepName),
+	}
+	generatorName := step.Type
+	switch {
+	case generatorName == wfTypes.WorkflowStepTypeApplyComponent:
+		generatorName = wfTypes.WorkflowStepTypeBuiltinApplyComponent
+		options.StepConvertor = func(lstep v1beta1.WorkflowStep) (v1beta1.WorkflowStep, error) {
+			copierStep := lstep.DeepCopy()
+			if err := convertStepProperties(copierStep, app); err != nil {
+				return lstep, errors.WithMessage(err, "convert [apply-component]")
+			}
+			return *copierStep, nil
+		}
+	case generatorName == wfTypes.WorkflowStepTypeStepGroup:
+		var subTaskRunners []wfTypes.TaskRunner
+		for _, subStep := range step.SubSteps {
+			workflowStep := v1beta1.WorkflowStep{
+				Name:       subStep.Name,
+				Type:       subStep.Type,
+				Properties: subStep.Properties,
+				DependsOn:  subStep.DependsOn,
+				Inputs:     subStep.Inputs,
+				Outputs:    subStep.Outputs,
+			}
+			subTask, err := generateStep(ctx, app, workflowStep, taskDiscover, step.Name)
+			if err != nil {
+				return nil, err
+			}
+			subTaskRunners = append(subTaskRunners, subTask)
+		}
+		options.SubTaskRunners = subTaskRunners
+	}
+
+	genTask, err := taskDiscover.GetTaskGenerator(ctx, generatorName)
+	if err != nil {
+		return nil, err
+	}
+
+	task, err := genTask(step, options)
+	if err != nil {
+		return nil, err
+	}
+	return task, nil
+}
+
 func convertStepProperties(step *v1beta1.WorkflowStep, app *v1beta1.Application) error {
 	o := struct {
 		Component string `json:"component"`
@@ -360,15 +391,38 @@ func getComponentResources(ctx context.Context, manifest *types.ComponentManifes
 	return workload, traits, nil
 }
 
-func generateStepID(stepName string, wfStatus *common.WorkflowStatus) string {
+func getStepID(stepName string, stepsStatus []common.StepStatus) string {
+	for _, status := range stepsStatus {
+		if status.Name == stepName {
+			return status.ID
+		}
+	}
+	return ""
+}
+
+func generateStepID(stepName string, workflowStatus *common.WorkflowStatus, parentStepName string) string {
 	var id string
-	if wfStatus != nil {
-		for _, status := range wfStatus.Steps {
-			if status.Name == stepName {
-				id = status.ID
+	if workflowStatus != nil {
+		workflowStepsStatus := workflowStatus.Steps
+		if parentStepName != "" {
+			for _, status := range workflowStepsStatus {
+				if status.Name == parentStepName {
+					var stepsStatus []common.StepStatus
+					for _, status := range status.SubStepsStatus {
+						stepsStatus = append(stepsStatus, status.StepStatus)
+					}
+					id = getStepID(stepName, stepsStatus)
+				}
 			}
+		} else {
+			var stepsStatus []common.StepStatus
+			for _, status := range workflowStepsStatus {
+				stepsStatus = append(stepsStatus, status.StepStatus)
+			}
+			id = getStepID(stepName, stepsStatus)
 		}
 	}
+
 	if id == "" {
 		id = utils.RandomString(10)
 	}
diff --git a/pkg/workflow/tasks/custom/task.go b/pkg/workflow/tasks/custom/task.go
index cc3af3535ed494d531885388bfc8efa358eb8351..a25e5dccee2523aa43b4c136bc221d7f4ce3069a 100644
--- a/pkg/workflow/tasks/custom/task.go
+++ b/pkg/workflow/tasks/custom/task.go
@@ -84,7 +84,7 @@ func (t *TaskLoader) GetTaskGenerator(ctx context.Context, name string) (wfTypes
 
 type taskRunner struct {
 	name         string
-	run          func(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.WorkflowStepStatus, *wfTypes.Operation, error)
+	run          func(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.StepStatus, *wfTypes.Operation, error)
 	checkPending func(ctx wfContext.Context) bool
 }
 
@@ -94,7 +94,7 @@ func (tr *taskRunner) Name() string {
 }
 
 // Run execute task.
-func (tr *taskRunner) Run(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.WorkflowStepStatus, *wfTypes.Operation, error) {
+func (tr *taskRunner) Run(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.StepStatus, *wfTypes.Operation, error) {
 	return tr.run(ctx, options)
 }
 
@@ -103,12 +103,17 @@ func (tr *taskRunner) Pending(ctx wfContext.Context) bool {
 	return tr.checkPending(ctx)
 }
 
+// SubTaskRunners return child step names. it could be null if the step have no sub-step
+func (tr *taskRunner) SubTaskRunners() []wfTypes.TaskRunner {
+	return nil
+}
+
 func (t *TaskLoader) makeTaskGenerator(templ string) (wfTypes.TaskGenerator, error) {
 	return func(wfStep v1beta1.WorkflowStep, genOpt *wfTypes.GeneratorOptions) (wfTypes.TaskRunner, error) {
 
 		exec := &executor{
 			handlers: t.handlers,
-			wfStatus: common.WorkflowStepStatus{
+			wfStatus: common.StepStatus{
 				Name:  wfStep.Name,
 				Type:  wfStep.Type,
 				Phase: common.WorkflowStepPhaseSucceeded,
@@ -154,7 +159,7 @@ func (t *TaskLoader) makeTaskGenerator(templ string) (wfTypes.TaskGenerator, err
 			}
 			return false
 		}
-		tRunner.run = func(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.WorkflowStepStatus, *wfTypes.Operation, error) {
+		tRunner.run = func(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.StepStatus, *wfTypes.Operation, error) {
 			if options.GetTracer == nil {
 				options.GetTracer = func(id string, step v1beta1.WorkflowStep) monitorContext.Context {
 					return monitorContext.NewTraceContext(context.Background(), "")
@@ -177,13 +182,13 @@ func (t *TaskLoader) makeTaskGenerator(templ string) (wfTypes.TaskGenerator, err
 			paramsValue, err := ctx.MakeParameter(params)
 			if err != nil {
 				tracer.Error(err, "make parameter")
-				return common.WorkflowStepStatus{}, nil, errors.WithMessage(err, "make parameter")
+				return common.StepStatus{}, nil, errors.WithMessage(err, "make parameter")
 			}
 
 			for _, hook := range options.PreStartHooks {
 				if err := hook(ctx, paramsValue, wfStep); err != nil {
 					tracer.Error(err, "do preStartHook")
-					return common.WorkflowStepStatus{}, nil, errors.WithMessage(err, "do preStartHook")
+					return common.StepStatus{}, nil, errors.WithMessage(err, "do preStartHook")
 				}
 			}
 
@@ -196,7 +201,7 @@ func (t *TaskLoader) makeTaskGenerator(templ string) (wfTypes.TaskGenerator, err
 			if params != nil {
 				ps, err := paramsValue.String()
 				if err != nil {
-					return common.WorkflowStepStatus{}, nil, errors.WithMessage(err, "params encode")
+					return common.StepStatus{}, nil, errors.WithMessage(err, "params encode")
 				}
 				paramFile = fmt.Sprintf(model.ParameterFieldName+": {%s}\n", ps)
 			}
@@ -256,7 +261,7 @@ func (t *TaskLoader) makeValue(ctx wfContext.Context, templ string, id string, p
 type executor struct {
 	handlers providers.Providers
 
-	wfStatus           common.WorkflowStepStatus
+	wfStatus           common.StepStatus
 	suspend            bool
 	terminated         bool
 	failedAfterRetries bool
@@ -314,7 +319,7 @@ func (exec *executor) operation() *wfTypes.Operation {
 	}
 }
 
-func (exec *executor) status() common.WorkflowStepStatus {
+func (exec *executor) status() common.StepStatus {
 	return exec.wfStatus
 }
 
diff --git a/pkg/workflow/tasks/discover.go b/pkg/workflow/tasks/discover.go
index 98cb4dfe93aeda0b3b41551e978eb3a264aeb8ac..05a5a26f6bb6183f24044163d4e369177d46a43a 100644
--- a/pkg/workflow/tasks/discover.go
+++ b/pkg/workflow/tasks/discover.go
@@ -87,6 +87,14 @@ func suspend(step v1beta1.WorkflowStep, opt *types.GeneratorOptions) (types.Task
 	return tr, nil
 }
 
+func stepGroup(step v1beta1.WorkflowStep, opt *types.GeneratorOptions) (types.TaskRunner, error) {
+	return &stepGroupTaskRunner{
+		id:             opt.ID,
+		name:           step.Name,
+		subTaskRunners: opt.SubTaskRunners,
+	}, nil
+}
+
 func newTaskDiscover(ctx monitorContext.Context, providerHandlers providers.Providers, pd *packages.PackageDiscover, pCtx process.Context, templateLoader template.Loader) types.TaskDiscover {
 	// install builtin provider
 	workspace.Install(providerHandlers)
@@ -95,7 +103,8 @@ func newTaskDiscover(ctx monitorContext.Context, providerHandlers providers.Prov
 
 	return &taskDiscover{
 		builtins: map[string]types.TaskGenerator{
-			types.WorkflowStepTypeSuspend: suspend,
+			types.WorkflowStepTypeSuspend:   suspend,
+			types.WorkflowStepTypeStepGroup: stepGroup,
 		},
 		remoteTaskDiscover: custom.NewTaskLoader(templateLoader.LoadTaskTemplate, pd, providerHandlers, 0, pCtx),
 		templateLoader:     templateLoader,
@@ -120,8 +129,8 @@ func (tr *suspendTaskRunner) Name() string {
 }
 
 // Run make workflow suspend.
-func (tr *suspendTaskRunner) Run(ctx wfContext.Context, options *types.TaskRunOptions) (common.WorkflowStepStatus, *types.Operation, error) {
-	stepStatus := common.WorkflowStepStatus{
+func (tr *suspendTaskRunner) Run(ctx wfContext.Context, options *types.TaskRunOptions) (common.StepStatus, *types.Operation, error) {
+	stepStatus := common.StepStatus{
 		ID:    tr.id,
 		Name:  tr.name,
 		Type:  types.WorkflowStepTypeSuspend,
@@ -140,6 +149,46 @@ func (tr *suspendTaskRunner) Pending(ctx wfContext.Context) bool {
 	return false
 }
 
+// SubTaskRunners return child step names. it could be null if the step have no sub-step
+func (tr *suspendTaskRunner) SubTaskRunners() []types.TaskRunner {
+	return nil
+}
+
+type stepGroupTaskRunner struct {
+	id             string
+	name           string
+	subTaskRunners []types.TaskRunner
+}
+
+// Name return suspend step name.
+func (tr *stepGroupTaskRunner) Name() string {
+	return tr.name
+}
+
+// SubTaskRunners return child step runners. it could be null if the step have no sub-step
+func (tr *stepGroupTaskRunner) SubTaskRunners() []types.TaskRunner {
+	return tr.subTaskRunners
+}
+
+// Run make workflow step group.
+func (tr *stepGroupTaskRunner) Run(ctx wfContext.Context, options *types.TaskRunOptions) (common.StepStatus, *types.Operation, error) {
+	phase := common.WorkflowStepPhaseRunning
+	if tr.subTaskRunners == nil {
+		phase = common.WorkflowStepPhaseSucceeded
+	}
+	return common.StepStatus{
+		ID:    tr.id,
+		Name:  tr.name,
+		Type:  types.WorkflowStepTypeStepGroup,
+		Phase: phase,
+	}, &types.Operation{}, nil
+}
+
+// Pending check task should be executed or not.
+func (tr *stepGroupTaskRunner) Pending(ctx wfContext.Context) bool {
+	return false
+}
+
 // NewViewTaskDiscover will create a client for load task generator.
 func NewViewTaskDiscover(pd *packages.PackageDiscover, cli client.Client, cfg *rest.Config, apply kube.Dispatcher, delete kube.Deleter, viewNs string, logLevel int, pCtx process.Context) types.TaskDiscover {
 	handlerProviders := providers.NewProviders()
diff --git a/pkg/workflow/tasks/discover_test.go b/pkg/workflow/tasks/discover_test.go
index 7e8d170871581189a31ca248d5f706156763187f..f36312e08ccc6453e88925ffd0402d14b86b7415 100644
--- a/pkg/workflow/tasks/discover_test.go
+++ b/pkg/workflow/tasks/discover_test.go
@@ -55,13 +55,16 @@ func TestDiscover(t *testing.T) {
 	})
 	discover := &taskDiscover{
 		builtins: map[string]types.TaskGenerator{
-			"suspend": suspend,
+			"suspend":   suspend,
+			"stepGroup": stepGroup,
 		},
 		remoteTaskDiscover: custom.NewTaskLoader(loadTemplate, nil, nil, 0, pCtx),
 	}
 
 	_, err := discover.GetTaskGenerator(context.Background(), "suspend")
 	assert.NilError(t, err)
+	_, err = discover.GetTaskGenerator(context.Background(), "stepGroup")
+	assert.NilError(t, err)
 	_, err = discover.GetTaskGenerator(context.Background(), "foo")
 	assert.NilError(t, err)
 	_, err = discover.GetTaskGenerator(context.Background(), "crazy")
@@ -90,3 +93,23 @@ func TestSuspendStep(t *testing.T) {
 	assert.Equal(t, status.Name, "test")
 	assert.Equal(t, status.Phase, common.WorkflowStepPhaseSucceeded)
 }
+
+func TestStepGroupStep(t *testing.T) {
+	discover := &taskDiscover{
+		builtins: map[string]types.TaskGenerator{
+			"stepGroup": stepGroup,
+		},
+	}
+	gen, err := discover.GetTaskGenerator(context.Background(), "stepGroup")
+	assert.NilError(t, err)
+	runner, err := gen(v1beta1.WorkflowStep{Name: "test"}, &types.GeneratorOptions{ID: "124"})
+	assert.NilError(t, err)
+	assert.Equal(t, runner.Name(), "test")
+	assert.Equal(t, runner.Pending(nil), false)
+	status, act, err := runner.Run(nil, nil)
+	assert.NilError(t, err)
+	assert.Equal(t, act.Suspend, false)
+	assert.Equal(t, status.ID, "124")
+	assert.Equal(t, status.Name, "test")
+	assert.Equal(t, status.Phase, common.WorkflowStepPhaseSucceeded)
+}
diff --git a/pkg/workflow/types/types.go b/pkg/workflow/types/types.go
index ebcd38fff564a9529f8cc421b6fb8fe12316817f..349cb0b47aa3d34865e4401aecd2ffb764249a71 100644
--- a/pkg/workflow/types/types.go
+++ b/pkg/workflow/types/types.go
@@ -30,8 +30,9 @@ import (
 // TaskRunner is a task runner.
 type TaskRunner interface {
 	Name() string
+	SubTaskRunners() []TaskRunner
 	Pending(ctx wfContext.Context) bool
-	Run(ctx wfContext.Context, options *TaskRunOptions) (common.WorkflowStepStatus, *Operation, error)
+	Run(ctx wfContext.Context, options *TaskRunOptions) (common.StepStatus, *Operation, error)
 }
 
 // TaskDiscover is the interface to obtain the TaskGenerator。
@@ -69,9 +70,10 @@ type TaskGenerator func(wfStep v1beta1.WorkflowStep, options *GeneratorOptions)
 
 // GeneratorOptions is the options for generate task.
 type GeneratorOptions struct {
-	ID            string
-	PrePhase      common.WorkflowStepPhase
-	StepConvertor func(step v1beta1.WorkflowStep) (v1beta1.WorkflowStep, error)
+	ID             string
+	PrePhase       common.WorkflowStepPhase
+	StepConvertor  func(step v1beta1.WorkflowStep) (v1beta1.WorkflowStep, error)
+	SubTaskRunners []TaskRunner
 }
 
 // Action is that workflow provider can do.
@@ -103,4 +105,6 @@ const (
 	WorkflowStepTypeApplyComponent = "apply-component"
 	// WorkflowStepTypeBuiltinApplyComponent type builtin-apply-component
 	WorkflowStepTypeBuiltinApplyComponent = "builtin-apply-component"
+	// WorkflowStepTypeStepGroup type step-group
+	WorkflowStepTypeStepGroup = "step-group"
 )
diff --git a/pkg/workflow/types/utils.go b/pkg/workflow/types/utils.go
index 72ab8571b344734383922166c435c8e24d87a9ee..1a7a5e9d96eeb605960d4ce63ebca05fd1b4cd69 100644
--- a/pkg/workflow/types/utils.go
+++ b/pkg/workflow/types/utils.go
@@ -22,6 +22,7 @@ func IsBuiltinWorkflowStepType(wfType string) bool {
 		WorkflowStepTypeSuspend,
 		WorkflowStepTypeApplyComponent,
 		WorkflowStepTypeBuiltinApplyComponent,
+		WorkflowStepTypeStepGroup,
 	} {
 		if _type == wfType {
 			return true
diff --git a/pkg/workflow/workflow.go b/pkg/workflow/workflow.go
index 93a92a0791a0693f240421545919f08e751c1f85..f27549079665bc64e36660b6244228cfb3fc4786 100644
--- a/pkg/workflow/workflow.go
+++ b/pkg/workflow/workflow.go
@@ -351,22 +351,37 @@ func (w *workflow) setMetadataToContext(wfCtx wfContext.Context) error {
 	return wfCtx.SetVar(metadata, wfTypes.ContextKeyMetadata)
 }
 
+func (e *engine) getBackoffTimes(stepID string) (success bool, backoffTimes int) {
+	if v, ok := e.wfCtx.GetValueInMemory(wfTypes.ContextPrefixBackoffTimes, stepID); ok {
+		times, ok := v.(int)
+		if ok {
+			return true, times
+		}
+	}
+	return false, 0
+}
+
 func (e *engine) getBackoffWaitTime() int {
 	// the default value of min times reaches the max workflow backoff wait time
 	minTimes := 15
 	found := false
 	for _, step := range e.status.Steps {
-		if v, ok := e.wfCtx.GetValueInMemory(wfTypes.ContextPrefixBackoffTimes, step.ID); ok {
+		success, backoffTimes := e.getBackoffTimes(step.ID)
+		if success && backoffTimes < minTimes {
+			minTimes = backoffTimes
 			found = true
-			times, ok := v.(int)
-			if !ok {
-				times = 0
-			}
-			if times < minTimes {
-				minTimes = times
+		}
+		if step.SubStepsStatus != nil {
+			for _, subStep := range step.SubStepsStatus {
+				success, backoffTimes := e.getBackoffTimes(subStep.ID)
+				if success && backoffTimes < minTimes {
+					minTimes = backoffTimes
+					found = true
+				}
 			}
 		}
 	}
+
 	if !found {
 		return minWorkflowBackoffWaitTime
 	}
@@ -460,12 +475,16 @@ func (e *engine) runAsDAG(taskRunners []wfTypes.TaskRunner) error {
 
 }
 
+func (e *engine) runAsStepByStep(taskRunners []wfTypes.TaskRunner) error {
+	return e.steps(e.todoByIndex(taskRunners))
+}
+
 func (e *engine) run(taskRunners []wfTypes.TaskRunner) error {
 	var err error
 	if e.dagMode {
 		err = e.runAsDAG(taskRunners)
 	} else {
-		err = e.steps(e.todoByIndex(taskRunners))
+		err = e.runAsStepByStep(taskRunners)
 	}
 
 	e.setNextExecuteTime()
@@ -500,64 +519,135 @@ func (e *engine) todoByIndex(taskRunners []wfTypes.TaskRunner) []wfTypes.TaskRun
 	}
 	return taskRunners[index:]
 }
-
 func (e *engine) steps(taskRunners []wfTypes.TaskRunner) error {
-	wfCtx := e.wfCtx
 	for _, runner := range taskRunners {
-		options := &wfTypes.TaskRunOptions{
-			GetTracer: func(id string, stepStatus oamcore.WorkflowStep) monitorContext.Context {
-				return e.monitorCtx.Fork(id, monitorContext.DurationMetric(func(v float64) {
-					metrics.StepDurationHistogram.WithLabelValues("application", stepStatus.Type).Observe(v)
-				}))
-			},
-		}
-		if e.debug {
-			options.Debug = func(step string, v *value.Value) error {
-				debugContext := debug.NewContext(e.cli, e.rk, e.app, step)
-				if err := debugContext.Set(v); err != nil {
-					return err
-				}
-				return nil
-			}
+		var err error
+		var needStop bool
+		if runner.SubTaskRunners() == nil {
+			needStop, err = e.step(runner, e.isDag(), "")
+		} else {
+			needStop, err = e.stepWithSubSteps(runner)
 		}
-		status, operation, err := runner.Run(wfCtx, options)
-		if err != nil {
+		if needStop || err != nil {
 			return err
 		}
+	}
+	return nil
+}
 
-		e.updateStepStatus(status)
-
-		e.failedAfterRetries = e.failedAfterRetries || operation.FailedAfterRetries
-		e.waiting = e.waiting || operation.Waiting
-		if status.Phase == common.WorkflowStepPhaseSucceeded || (status.Phase == common.WorkflowStepPhaseRunning && status.Type == wfTypes.WorkflowStepTypeSuspend) {
-			wfCtx.DeleteValueInMemory(wfTypes.ContextPrefixBackoffTimes, status.ID)
-			wfCtx.DeleteValueInMemory(wfTypes.ContextPrefixBackoffReason, status.ID)
-			if err := wfCtx.Commit(); err != nil {
-				return errors.WithMessage(err, "commit workflow context")
-			}
-
-			e.finishStep(operation)
-			if e.needStop() {
-				return nil
+func (e *engine) step(runner wfTypes.TaskRunner, dag bool, parentStepName string) (bool, error) {
+	wfCtx := e.wfCtx
+	options := &wfTypes.TaskRunOptions{
+		GetTracer: func(id string, stepStatus oamcore.WorkflowStep) monitorContext.Context {
+			return e.monitorCtx.Fork(id, monitorContext.DurationMetric(func(v float64) {
+				metrics.StepDurationHistogram.WithLabelValues("application", stepStatus.Type).Observe(v)
+			}))
+		},
+	}
+	if e.debug {
+		options.Debug = func(step string, v *value.Value) error {
+			debugContext := debug.NewContext(e.cli, e.rk, e.app, step)
+			if err := debugContext.Set(v); err != nil {
+				return err
 			}
-			continue
+			return nil
 		}
-
-		if val, exists := wfCtx.GetValueInMemory(wfTypes.ContextPrefixBackoffReason, status.ID); !exists || val != status.Message {
-			wfCtx.SetValueInMemory(status.Message, wfTypes.ContextPrefixBackoffReason, status.ID)
-			wfCtx.DeleteValueInMemory(wfTypes.ContextPrefixBackoffTimes, status.ID)
+	}
+	status, operation, err := runner.Run(wfCtx, options)
+	if err != nil {
+		return true, err
+	}
+	if parentStepName != "" {
+		subStepStatus := common.WorkflowSubStepStatus{
+			StepStatus: status,
+		}
+		e.updateSubStepStatus(parentStepName, subStepStatus)
+	} else {
+		workflowStepStatus := common.WorkflowStepStatus{
+			StepStatus: status,
 		}
-		wfCtx.IncreaseCountValueInMemory(wfTypes.ContextPrefixBackoffTimes, status.ID)
+		e.updateStepStatus(workflowStepStatus)
+	}
+
+	e.failedAfterRetries = e.failedAfterRetries || operation.FailedAfterRetries
+	e.waiting = e.waiting || operation.Waiting
+	if status.Phase == common.WorkflowStepPhaseSucceeded || (status.Phase == common.WorkflowStepPhaseRunning && status.Type == wfTypes.WorkflowStepTypeSuspend) {
+		wfCtx.DeleteValueInMemory(wfTypes.ContextPrefixBackoffTimes, status.ID)
+		wfCtx.DeleteValueInMemory(wfTypes.ContextPrefixBackoffReason, status.ID)
 		if err := wfCtx.Commit(); err != nil {
-			return errors.WithMessage(err, "commit workflow context")
+			return true, errors.WithMessage(err, "commit workflow context")
 		}
-		if e.isDag() {
-			continue
+
+		e.finishStep(operation)
+		if e.needStop() {
+			return true, nil
 		}
-		e.checkFailedAfterRetries()
-		return nil
+		return false, nil
 	}
-	return nil
+
+	if val, exists := wfCtx.GetValueInMemory(wfTypes.ContextPrefixBackoffReason, status.ID); !exists || val != status.Message {
+		wfCtx.SetValueInMemory(status.Message, wfTypes.ContextPrefixBackoffReason, status.ID)
+		wfCtx.DeleteValueInMemory(wfTypes.ContextPrefixBackoffTimes, status.ID)
+	}
+	wfCtx.IncreaseCountValueInMemory(wfTypes.ContextPrefixBackoffTimes, status.ID)
+	if err := wfCtx.Commit(); err != nil {
+		return true, errors.WithMessage(err, "commit workflow context")
+	}
+	if dag {
+		return false, nil
+	}
+	e.checkFailedAfterRetries()
+	return true, nil
+}
+
+func (e *engine) stepWithSubSteps(runner wfTypes.TaskRunner) (bool, error) {
+	stepName := runner.Name()
+	var err error
+	var needStop bool
+	var status common.StepStatus
+	status, _, err = runner.Run(e.wfCtx, &wfTypes.TaskRunOptions{})
+	if err != nil {
+		return true, err
+	}
+	workflowStepStatus := common.WorkflowStepStatus{
+		StepStatus:     status,
+		SubStepsStatus: e.getStepStatus(stepName).SubStepsStatus,
+	}
+	e.updateStepStatus(workflowStepStatus)
+
+	todoSubTaskRunners, pendingSubTaskRunners := e.getTodoSubTaskRunners(runner)
+	for _, todoSubTaskRunner := range todoSubTaskRunners {
+		// subStep only use dag mode
+		dag := true
+		needStop, err = e.step(todoSubTaskRunner, dag, stepName)
+	}
+
+	stepStatus := e.getStepStatus(stepName)
+	subStepPhaseToCount := make(map[common.WorkflowStepPhase]int)
+	for _, subStepsStatus := range stepStatus.SubStepsStatus {
+		subStepPhaseToCount[subStepsStatus.Phase]++
+	}
+	switch {
+	case subStepPhaseToCount[common.WorkflowStepPhaseRunning] != 0:
+		stepStatus.Phase = common.WorkflowStepPhaseRunning
+	case subStepPhaseToCount[common.WorkflowStepPhaseStopped] != 0:
+		stepStatus.Phase = common.WorkflowStepPhaseStopped
+	case subStepPhaseToCount[common.WorkflowStepPhaseFailed] != 0:
+		stepStatus.Phase = common.WorkflowStepPhaseFailed
+	case len(pendingSubTaskRunners) != 0:
+		stepStatus.Phase = common.WorkflowStepPhaseRunning
+	default:
+		stepStatus.Phase = common.WorkflowStepPhaseSucceeded
+	}
+	e.updateStepStatus(stepStatus)
+	e.checkFailedAfterRetries()
+	if needStop || err != nil {
+		return true, err
+	}
+	if stepStatus.Phase == common.WorkflowStepPhaseSucceeded {
+		return false, nil
+	}
+	return true, nil
 }
 
 type engine struct {
@@ -585,25 +675,60 @@ func (e *engine) finishStep(operation *wfTypes.Operation) {
 }
 
 func (e *engine) updateStepStatus(status common.WorkflowStepStatus) {
+	var now = metav1.NewTime(time.Now())
+	e.wfCtx.SetValueInMemory(now.Unix(), wfTypes.ContextKeyLastExecuteTime)
+	e.status.Steps = updateStepStatusByName(e.status.Steps, status, now)
+}
+
+func updateStepStatusByName(stepStatus []common.WorkflowStepStatus, status common.WorkflowStepStatus, now metav1.Time) []common.WorkflowStepStatus {
 	var (
 		conditionUpdated bool
-		now              = metav1.NewTime(time.Now())
 	)
 
-	e.wfCtx.SetValueInMemory(now.Unix(), wfTypes.ContextKeyLastExecuteTime)
 	status.LastExecuteTime = now
+	for i := range stepStatus {
+		if stepStatus[i].Name == status.Name {
+			status.FirstExecuteTime = stepStatus[i].FirstExecuteTime
+			stepStatus[i] = status
+			conditionUpdated = true
+			break
+		}
+	}
+	if !conditionUpdated {
+		status.FirstExecuteTime = now
+		stepStatus = append(stepStatus, status)
+	}
+	return stepStatus
+}
+
+func (e *engine) updateSubStepStatus(stepName string, subStepStatus common.WorkflowSubStepStatus) {
+	var now = metav1.NewTime(time.Now())
 	for i := range e.status.Steps {
-		if e.status.Steps[i].Name == status.Name {
-			status.FirstExecuteTime = e.status.Steps[i].FirstExecuteTime
-			e.status.Steps[i] = status
+		if e.status.Steps[i].Name == stepName {
+			e.status.Steps[i].SubStepsStatus = updateSubStepStatusByName(e.status.Steps[i].SubStepsStatus, subStepStatus, now)
+		}
+	}
+}
+
+func updateSubStepStatusByName(stepStatus []common.WorkflowSubStepStatus, status common.WorkflowSubStepStatus, now metav1.Time) []common.WorkflowSubStepStatus {
+	var (
+		conditionUpdated bool
+	)
+
+	status.LastExecuteTime = now
+	for i := range stepStatus {
+		if stepStatus[i].Name == status.Name {
+			status.FirstExecuteTime = stepStatus[i].FirstExecuteTime
+			stepStatus[i] = status
 			conditionUpdated = true
 			break
 		}
 	}
 	if !conditionUpdated {
 		status.FirstExecuteTime = now
-		e.status.Steps = append(e.status.Steps, status)
+		stepStatus = append(stepStatus, status)
 	}
+	return stepStatus
 }
 
 func (e *engine) checkFailedAfterRetries() {
@@ -637,3 +762,53 @@ func ComputeWorkflowRevisionHash(rev string, app *oamcore.Application) (string,
 func IsFailedAfterRetry(app *oamcore.Application) bool {
 	return app.Status.Workflow != nil && app.Status.Workflow.Message == MessageFailedAfterRetries
 }
+
+func (e *engine) getTodoSubTaskRunners(taskRunner wfTypes.TaskRunner) ([]wfTypes.TaskRunner, []wfTypes.TaskRunner) {
+	wfCtx := e.wfCtx
+	var (
+		todoSubTasks    []wfTypes.TaskRunner
+		pendingSubTasks []wfTypes.TaskRunner
+	)
+	for _, subTRunner := range taskRunner.SubTaskRunners() {
+		ready := false
+		var stepID string
+		subStepStatus := e.getSubStepStatus(taskRunner.Name(), subTRunner.Name())
+		ready = subStepStatus.Phase == common.WorkflowStepPhaseSucceeded
+		stepID = subStepStatus.ID
+
+		if !ready {
+			if subTRunner.Pending(wfCtx) {
+				pendingSubTasks = append(pendingSubTasks, subTRunner)
+				continue
+			}
+			todoSubTasks = append(todoSubTasks, subTRunner)
+		} else {
+			wfCtx.DeleteValueInMemory(wfTypes.ContextPrefixBackoffTimes, stepID)
+		}
+	}
+	return todoSubTasks, pendingSubTasks
+}
+
+func (e *engine) getSubStepStatus(stepName string, subStepName string) common.WorkflowSubStepStatus {
+	// ss is step status
+	for _, ss := range e.status.Steps {
+		if ss.Name == stepName {
+			// sss is subStepStatus
+			for _, sss := range ss.SubStepsStatus {
+				if sss.Name == subStepName {
+					return sss
+				}
+			}
+		}
+	}
+	return common.WorkflowSubStepStatus{}
+}
+func (e *engine) getStepStatus(stepName string) common.WorkflowStepStatus {
+	// ss is step status
+	for _, ss := range e.status.Steps {
+		if ss.Name == stepName {
+			return ss
+		}
+	}
+	return common.WorkflowStepStatus{}
+}
diff --git a/pkg/workflow/workflow_test.go b/pkg/workflow/workflow_test.go
index b22608d6dde18cd78816edf37bedb037e0768b44..55e3b34f547664cde3ce08a77f946b4a0f14f209 100644
--- a/pkg/workflow/workflow_test.go
+++ b/pkg/workflow/workflow_test.go
@@ -84,15 +84,21 @@ var _ = Describe("Test Workflow", func() {
 			AppRevision: workflowStatus.AppRevision,
 			Mode:        common.WorkflowModeStep,
 			Message:     string(common.WorkflowStateExecuting),
-			Steps: []common.WorkflowStepStatus{{
-				Name:  "s1",
-				Type:  "success",
-				Phase: common.WorkflowStepPhaseSucceeded,
-			}, {
-				Name:  "s2",
-				Type:  "failed",
-				Phase: common.WorkflowStepPhaseFailed,
-			}},
+			Steps: []common.WorkflowStepStatus{
+				{
+					StepStatus: common.StepStatus{
+						Name:  "s1",
+						Type:  "success",
+						Phase: common.WorkflowStepPhaseSucceeded,
+					},
+				}, {
+					StepStatus: common.StepStatus{
+						Name:  "s2",
+						Type:  "failed",
+						Phase: common.WorkflowStepPhaseFailed,
+					},
+				},
+			},
 		})).Should(BeEquivalentTo(""))
 
 		app, runners = makeTestCase([]oamcore.WorkflowStep{
@@ -129,17 +135,214 @@ var _ = Describe("Test Workflow", func() {
 			Mode:        common.WorkflowModeStep,
 			Message:     string(common.WorkflowStateSucceeded),
 			Steps: []common.WorkflowStepStatus{{
-				Name:  "s1",
-				Type:  "success",
-				Phase: common.WorkflowStepPhaseSucceeded,
+				StepStatus: common.StepStatus{
+					Name:  "s1",
+					Type:  "success",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
 			}, {
-				Name:  "s2",
-				Type:  "success",
-				Phase: common.WorkflowStepPhaseSucceeded,
+				StepStatus: common.StepStatus{
+					Name:  "s2",
+					Type:  "success",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
 			}, {
-				Name:  "s3",
-				Type:  "success",
-				Phase: common.WorkflowStepPhaseSucceeded,
+				StepStatus: common.StepStatus{
+					Name:  "s3",
+					Type:  "success",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
+			}},
+		})).Should(BeEquivalentTo(""))
+
+		By("Test failed with step group")
+		app, runners = makeTestCase([]oamcore.WorkflowStep{
+			{
+				Name: "s1",
+				Type: "success",
+			},
+			{
+				Name: "s2",
+				Type: "step-group",
+				SubSteps: []common.WorkflowSubStep{
+					{
+						Name: "s2-sub1",
+						Type: "success",
+					},
+					{
+						Name: "s2-sub2",
+						Type: "failed",
+					},
+				},
+			},
+			{
+				Name: "s3",
+				Type: "success",
+			},
+		})
+		wf = NewWorkflow(app, k8sClient, common.WorkflowModeStep, false, nil)
+		ctx = monitorContext.NewTraceContext(context.Background(), "test-app")
+		state, err = wf.ExecuteSteps(ctx, revision, runners)
+		Expect(err).ToNot(HaveOccurred())
+		Expect(state).Should(BeEquivalentTo(common.WorkflowStateInitializing))
+		state, err = wf.ExecuteSteps(ctx, revision, runners)
+		Expect(err).ToNot(HaveOccurred())
+		Expect(state).Should(BeEquivalentTo(common.WorkflowStateExecuting))
+		app.Status.Workflow.ContextBackend = nil
+		cleanStepTimeStamp(app.Status.Workflow)
+		Expect(cmp.Diff(*app.Status.Workflow, common.WorkflowStatus{
+			AppRevision: app.Status.Workflow.AppRevision,
+			Mode:        common.WorkflowModeStep,
+			Message:     string(common.WorkflowStateExecuting),
+			Steps: []common.WorkflowStepStatus{{
+				StepStatus: common.StepStatus{
+					Name:  "s1",
+					Type:  "success",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
+			}, {
+				StepStatus: common.StepStatus{
+					Name:  "s2",
+					Type:  "step-group",
+					Phase: common.WorkflowStepPhaseFailed,
+				},
+				SubStepsStatus: []common.WorkflowSubStepStatus{{
+					StepStatus: common.StepStatus{
+						Name:  "s2-sub1",
+						Type:  "success",
+						Phase: common.WorkflowStepPhaseSucceeded,
+					},
+				}, {
+					StepStatus: common.StepStatus{
+						Name:  "s2-sub2",
+						Type:  "failed",
+						Phase: common.WorkflowStepPhaseFailed,
+					},
+				}},
+			}},
+		})).Should(BeEquivalentTo(""))
+
+		By("Test success with step group")
+		app, runners = makeTestCase([]oamcore.WorkflowStep{
+			{
+				Name: "s1",
+				Type: "success",
+			},
+			{
+				Name: "s2",
+				Type: "step-group",
+				SubSteps: []common.WorkflowSubStep{
+					{
+						Name: "s2-sub1",
+						Type: "success",
+					},
+					{
+						Name: "s2-sub2",
+						Type: "success",
+					},
+				},
+			},
+			{
+				Name: "s3",
+				Type: "success",
+			},
+		})
+		wf = NewWorkflow(app, k8sClient, common.WorkflowModeStep, false, nil)
+		ctx = monitorContext.NewTraceContext(context.Background(), "test-app")
+		state, err = wf.ExecuteSteps(ctx, revision, runners)
+		Expect(err).ToNot(HaveOccurred())
+		Expect(state).Should(BeEquivalentTo(common.WorkflowStateInitializing))
+		state, err = wf.ExecuteSteps(ctx, revision, runners)
+		Expect(err).ToNot(HaveOccurred())
+		Expect(state).Should(BeEquivalentTo(common.WorkflowStateSucceeded))
+		app.Status.Workflow.ContextBackend = nil
+		cleanStepTimeStamp(app.Status.Workflow)
+		Expect(cmp.Diff(*app.Status.Workflow, common.WorkflowStatus{
+			AppRevision: app.Status.Workflow.AppRevision,
+			Mode:        common.WorkflowModeStep,
+			Message:     string(common.WorkflowStateSucceeded),
+			Steps: []common.WorkflowStepStatus{{
+				StepStatus: common.StepStatus{
+					Name:  "s1",
+					Type:  "success",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
+			}, {
+				StepStatus: common.StepStatus{
+					Name:  "s2",
+					Type:  "step-group",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
+				SubStepsStatus: []common.WorkflowSubStepStatus{{
+					StepStatus: common.StepStatus{
+						Name:  "s2-sub1",
+						Type:  "success",
+						Phase: common.WorkflowStepPhaseSucceeded,
+					},
+				}, {
+					StepStatus: common.StepStatus{
+						Name:  "s2-sub2",
+						Type:  "success",
+						Phase: common.WorkflowStepPhaseSucceeded,
+					},
+				}},
+			}, {
+				StepStatus: common.StepStatus{
+					Name:  "s3",
+					Type:  "success",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
+			}},
+		})).Should(BeEquivalentTo(""))
+
+		By("Test success with step group and empty subSteps")
+		app, runners = makeTestCase([]oamcore.WorkflowStep{
+			{
+				Name: "s1",
+				Type: "success",
+			},
+			{
+				Name:     "s2",
+				Type:     "step-group",
+				SubSteps: []common.WorkflowSubStep{},
+			},
+			{
+				Name: "s3",
+				Type: "success",
+			},
+		})
+		wf = NewWorkflow(app, k8sClient, common.WorkflowModeStep, false, nil)
+		ctx = monitorContext.NewTraceContext(context.Background(), "test-app")
+		state, err = wf.ExecuteSteps(ctx, revision, runners)
+		Expect(err).ToNot(HaveOccurred())
+		Expect(state).Should(BeEquivalentTo(common.WorkflowStateInitializing))
+		state, err = wf.ExecuteSteps(ctx, revision, runners)
+		Expect(err).ToNot(HaveOccurred())
+		Expect(state).Should(BeEquivalentTo(common.WorkflowStateSucceeded))
+		app.Status.Workflow.ContextBackend = nil
+		cleanStepTimeStamp(app.Status.Workflow)
+		Expect(cmp.Diff(*app.Status.Workflow, common.WorkflowStatus{
+			AppRevision: app.Status.Workflow.AppRevision,
+			Mode:        common.WorkflowModeStep,
+			Message:     string(common.WorkflowStateSucceeded),
+			Steps: []common.WorkflowStepStatus{{
+				StepStatus: common.StepStatus{
+					Name:  "s1",
+					Type:  "success",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
+			}, {
+				StepStatus: common.StepStatus{
+					Name:  "s2",
+					Type:  "step-group",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
+			}, {
+				StepStatus: common.StepStatus{
+					Name:  "s3",
+					Type:  "success",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
 			}},
 		})).Should(BeEquivalentTo(""))
 	})
@@ -179,13 +382,17 @@ var _ = Describe("Test Workflow", func() {
 			Message:     MessageFailedAfterRetries,
 			Suspend:     true,
 			Steps: []common.WorkflowStepStatus{{
-				Name:  "s1",
-				Type:  "success",
-				Phase: common.WorkflowStepPhaseSucceeded,
+				StepStatus: common.StepStatus{
+					Name:  "s1",
+					Type:  "success",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
 			}, {
-				Name:  "s2",
-				Type:  "failed-after-retries",
-				Phase: common.WorkflowStepPhaseFailed,
+				StepStatus: common.StepStatus{
+					Name:  "s2",
+					Type:  "failed-after-retries",
+					Phase: common.WorkflowStepPhaseFailed,
+				},
 			}},
 		})).Should(BeEquivalentTo(""))
 
@@ -223,17 +430,91 @@ var _ = Describe("Test Workflow", func() {
 			Message:     MessageFailedAfterRetries,
 			Suspend:     true,
 			Steps: []common.WorkflowStepStatus{{
-				Name:  "s1",
-				Type:  "success",
-				Phase: common.WorkflowStepPhaseSucceeded,
+				StepStatus: common.StepStatus{
+					Name:  "s1",
+					Type:  "success",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
 			}, {
-				Name:  "s2",
-				Type:  "failed-after-retries",
-				Phase: common.WorkflowStepPhaseFailed,
+				StepStatus: common.StepStatus{
+					Name:  "s2",
+					Type:  "failed-after-retries",
+					Phase: common.WorkflowStepPhaseFailed,
+				},
 			}, {
-				Name:  "s3",
-				Type:  "success",
-				Phase: common.WorkflowStepPhaseSucceeded,
+				StepStatus: common.StepStatus{
+					Name:  "s3",
+					Type:  "success",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
+			}},
+		})).Should(BeEquivalentTo(""))
+
+		By("Test failed-after-retries with step group in StepByStep mode")
+		app, runners = makeTestCase([]oamcore.WorkflowStep{
+			{
+				Name: "s1",
+				Type: "success",
+			},
+			{
+				Name: "s2",
+				Type: "step-group",
+				SubSteps: []common.WorkflowSubStep{
+					{
+						Name: "s2-sub1",
+						Type: "success",
+					},
+					{
+						Name: "s2-sub2",
+						Type: "failed-after-retries",
+					},
+				},
+			},
+			{
+				Name: "s3",
+				Type: "success",
+			},
+		})
+		wf = NewWorkflow(app, k8sClient, common.WorkflowModeStep, false, nil)
+		ctx = monitorContext.NewTraceContext(context.Background(), "test-app")
+		state, err = wf.ExecuteSteps(ctx, revision, runners)
+		Expect(err).ToNot(HaveOccurred())
+		Expect(state).Should(BeEquivalentTo(common.WorkflowStateInitializing))
+		state, err = wf.ExecuteSteps(ctx, revision, runners)
+		Expect(err).ToNot(HaveOccurred())
+		Expect(state).Should(BeEquivalentTo(common.WorkflowStateSuspended))
+		app.Status.Workflow.ContextBackend = nil
+		cleanStepTimeStamp(app.Status.Workflow)
+		Expect(cmp.Diff(*app.Status.Workflow, common.WorkflowStatus{
+			AppRevision: app.Status.Workflow.AppRevision,
+			Mode:        common.WorkflowModeStep,
+			Message:     MessageFailedAfterRetries,
+			Suspend:     true,
+			Steps: []common.WorkflowStepStatus{{
+				StepStatus: common.StepStatus{
+					Name:  "s1",
+					Type:  "success",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
+			}, {
+				StepStatus: common.StepStatus{
+					Name:  "s2",
+					Type:  "step-group",
+					Phase: common.WorkflowStepPhaseFailed,
+				},
+				SubStepsStatus: []common.WorkflowSubStepStatus{{
+					StepStatus: common.StepStatus{
+						Name:  "s2-sub1",
+						Type:  "success",
+						Phase: common.WorkflowStepPhaseSucceeded,
+					},
+				}, {
+					StepStatus: common.StepStatus{
+						Name:  "s2-sub2",
+						Type:  "failed-after-retries",
+						Phase: common.WorkflowStepPhaseFailed,
+					},
+				}},
 			}},
 		})).Should(BeEquivalentTo(""))
 	})
@@ -326,13 +607,17 @@ var _ = Describe("Test Workflow", func() {
 			Suspend:     true,
 			Message:     string(common.WorkflowStateSuspended),
 			Steps: []common.WorkflowStepStatus{{
-				Name:  "s1",
-				Type:  "success",
-				Phase: common.WorkflowStepPhaseSucceeded,
+				StepStatus: common.StepStatus{
+					Name:  "s1",
+					Type:  "success",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
 			}, {
-				Name:  "s2",
-				Type:  "suspend",
-				Phase: common.WorkflowStepPhaseSucceeded,
+				StepStatus: common.StepStatus{
+					Name:  "s2",
+					Type:  "suspend",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
 			}},
 		})).Should(BeEquivalentTo(""))
 
@@ -355,23 +640,97 @@ var _ = Describe("Test Workflow", func() {
 			Mode:        common.WorkflowModeStep,
 			Message:     string(common.WorkflowStateSucceeded),
 			Steps: []common.WorkflowStepStatus{{
-				Name:  "s1",
-				Type:  "success",
-				Phase: common.WorkflowStepPhaseSucceeded,
+				StepStatus: common.StepStatus{
+					Name:  "s1",
+					Type:  "success",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
 			}, {
-				Name:  "s2",
-				Type:  "suspend",
-				Phase: common.WorkflowStepPhaseSucceeded,
+				StepStatus: common.StepStatus{
+					Name:  "s2",
+					Type:  "suspend",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
 			}, {
-				Name:  "s3",
-				Type:  "success",
-				Phase: common.WorkflowStepPhaseSucceeded,
+				StepStatus: common.StepStatus{
+					Name:  "s3",
+					Type:  "success",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
 			}},
 		})).Should(BeEquivalentTo(""))
 
 		state, err = wf.ExecuteSteps(ctx, revision, runners)
 		Expect(err).ToNot(HaveOccurred())
 		Expect(state).Should(BeEquivalentTo(common.WorkflowStateSucceeded))
+
+		By("Test suspend with step group")
+		app, runners = makeTestCase([]oamcore.WorkflowStep{
+			{
+				Name: "s1",
+				Type: "success",
+			},
+			{
+				Name: "s2",
+				Type: "step-group",
+				SubSteps: []common.WorkflowSubStep{
+					{
+						Name: "s2-sub1",
+						Type: "success",
+					},
+					{
+						Name: "s2-sub2",
+						Type: "suspend",
+					},
+				},
+			},
+			{
+				Name: "s3",
+				Type: "success",
+			},
+		})
+		wf = NewWorkflow(app, k8sClient, common.WorkflowModeStep, false, nil)
+		ctx = monitorContext.NewTraceContext(context.Background(), "test-app")
+		state, err = wf.ExecuteSteps(ctx, revision, runners)
+		Expect(err).ToNot(HaveOccurred())
+		Expect(state).Should(BeEquivalentTo(common.WorkflowStateInitializing))
+		state, err = wf.ExecuteSteps(ctx, revision, runners)
+		Expect(err).ToNot(HaveOccurred())
+		Expect(state).Should(BeEquivalentTo(common.WorkflowStateSuspended))
+		app.Status.Workflow.ContextBackend = nil
+		cleanStepTimeStamp(app.Status.Workflow)
+		Expect(cmp.Diff(*app.Status.Workflow, common.WorkflowStatus{
+			AppRevision: app.Status.Workflow.AppRevision,
+			Mode:        common.WorkflowModeStep,
+			Suspend:     true,
+			Message:     string(common.WorkflowStateSuspended),
+			Steps: []common.WorkflowStepStatus{{
+				StepStatus: common.StepStatus{
+					Name:  "s1",
+					Type:  "success",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
+			}, {
+				StepStatus: common.StepStatus{
+					Name:  "s2",
+					Type:  "step-group",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
+				SubStepsStatus: []common.WorkflowSubStepStatus{{
+					StepStatus: common.StepStatus{
+						Name:  "s2-sub1",
+						Type:  "success",
+						Phase: common.WorkflowStepPhaseSucceeded,
+					},
+				}, {
+					StepStatus: common.StepStatus{
+						Name:  "s2-sub2",
+						Type:  "suspend",
+						Phase: common.WorkflowStepPhaseSucceeded,
+					},
+				}},
+			}},
+		})).Should(BeEquivalentTo(""))
 	})
 
 	It("test for terminate", func() {
@@ -401,13 +760,85 @@ var _ = Describe("Test Workflow", func() {
 			Terminated:  true,
 			Message:     string(common.WorkflowStateTerminated),
 			Steps: []common.WorkflowStepStatus{{
-				Name:  "s1",
-				Type:  "success",
-				Phase: common.WorkflowStepPhaseSucceeded,
+				StepStatus: common.StepStatus{
+					Name:  "s1",
+					Type:  "success",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
 			}, {
-				Name:  "s2",
-				Type:  "terminate",
-				Phase: common.WorkflowStepPhaseSucceeded,
+				StepStatus: common.StepStatus{
+					Name:  "s2",
+					Type:  "terminate",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
+			}},
+		})).Should(BeEquivalentTo(""))
+
+		state, err = wf.ExecuteSteps(ctx, revision, runners)
+		Expect(err).ToNot(HaveOccurred())
+		Expect(state).Should(BeEquivalentTo(common.WorkflowStateTerminated))
+
+		By("Test terminate with step group")
+		app, runners = makeTestCase([]oamcore.WorkflowStep{
+			{
+				Name: "s1",
+				Type: "success",
+			},
+			{
+				Name: "s2",
+				Type: "step-group",
+				SubSteps: []common.WorkflowSubStep{
+					{
+						Name: "s2-sub1",
+						Type: "success",
+					},
+					{
+						Name: "s2-sub2",
+						Type: "terminate",
+					},
+				},
+			},
+		})
+		ctx = monitorContext.NewTraceContext(context.Background(), "test-app")
+		wf = NewWorkflow(app, k8sClient, common.WorkflowModeStep, false, nil)
+		state, err = wf.ExecuteSteps(ctx, revision, runners)
+		Expect(err).ToNot(HaveOccurred())
+		Expect(state).Should(BeEquivalentTo(common.WorkflowStateInitializing))
+		state, err = wf.ExecuteSteps(ctx, revision, runners)
+		Expect(err).ToNot(HaveOccurred())
+		Expect(state).Should(BeEquivalentTo(common.WorkflowStateTerminated))
+		app.Status.Workflow.ContextBackend = nil
+		cleanStepTimeStamp(app.Status.Workflow)
+		Expect(cmp.Diff(*app.Status.Workflow, common.WorkflowStatus{
+			AppRevision: app.Status.Workflow.AppRevision,
+			Mode:        common.WorkflowModeStep,
+			Terminated:  true,
+			Message:     string(common.WorkflowStateTerminated),
+			Steps: []common.WorkflowStepStatus{{
+				StepStatus: common.StepStatus{
+					Name:  "s1",
+					Type:  "success",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
+			}, {
+				StepStatus: common.StepStatus{
+					Name:  "s2",
+					Type:  "step-group",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
+				SubStepsStatus: []common.WorkflowSubStepStatus{{
+					StepStatus: common.StepStatus{
+						Name:  "s2-sub1",
+						Type:  "success",
+						Phase: common.WorkflowStepPhaseSucceeded,
+					},
+				}, {
+					StepStatus: common.StepStatus{
+						Name:  "s2-sub2",
+						Type:  "terminate",
+						Phase: common.WorkflowStepPhaseSucceeded,
+					},
+				}},
 			}},
 		})).Should(BeEquivalentTo(""))
 
@@ -442,9 +873,11 @@ var _ = Describe("Test Workflow", func() {
 			Mode:        common.WorkflowModeStep,
 			Message:     string(common.WorkflowStateExecuting),
 			Steps: []common.WorkflowStepStatus{{
-				Name:  "s1",
-				Type:  "success",
-				Phase: common.WorkflowStepPhaseSucceeded,
+				StepStatus: common.StepStatus{
+					Name:  "s1",
+					Type:  "success",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
 			}},
 		})).Should(BeEquivalentTo(""))
 	})
@@ -489,13 +922,17 @@ var _ = Describe("Test Workflow", func() {
 			Mode:        common.WorkflowModeDAG,
 			Message:     string(common.WorkflowStateExecuting),
 			Steps: []common.WorkflowStepStatus{{
-				Name:  "s1",
-				Type:  "success",
-				Phase: common.WorkflowStepPhaseSucceeded,
+				StepStatus: common.StepStatus{
+					Name:  "s1",
+					Type:  "success",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
 			}, {
-				Name:  "s3",
-				Type:  "success",
-				Phase: common.WorkflowStepPhaseSucceeded,
+				StepStatus: common.StepStatus{
+					Name:  "s3",
+					Type:  "success",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
 			}},
 		})).Should(BeEquivalentTo(""))
 
@@ -514,17 +951,23 @@ var _ = Describe("Test Workflow", func() {
 			Mode:        common.WorkflowModeDAG,
 			Message:     string(common.WorkflowStateSucceeded),
 			Steps: []common.WorkflowStepStatus{{
-				Name:  "s1",
-				Type:  "success",
-				Phase: common.WorkflowStepPhaseSucceeded,
+				StepStatus: common.StepStatus{
+					Name:  "s1",
+					Type:  "success",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
 			}, {
-				Name:  "s3",
-				Type:  "success",
-				Phase: common.WorkflowStepPhaseSucceeded,
+				StepStatus: common.StepStatus{
+					Name:  "s3",
+					Type:  "success",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
 			}, {
-				Name:  "s2",
-				Type:  "pending",
-				Phase: common.WorkflowStepPhaseSucceeded,
+				StepStatus: common.StepStatus{
+					Name:  "s2",
+					Type:  "pending",
+					Phase: common.WorkflowStepPhaseSucceeded,
+				},
 			}},
 		})).Should(BeEquivalentTo(""))
 	})
@@ -573,19 +1016,27 @@ func makeTestCase(steps []oamcore.WorkflowStep) (*oamcore.Application, []wfTypes
 	app.Name = "app"
 	runners := []wfTypes.TaskRunner{}
 	for _, step := range steps {
-		runners = append(runners, makeRunner(step.Name, step.Type))
+		if step.SubSteps != nil {
+			subStepRunners := []wfTypes.TaskRunner{}
+			for _, subStep := range step.SubSteps {
+				subStepRunners = append(subStepRunners, makeRunner(subStep.Name, subStep.Type, nil))
+			}
+			runners = append(runners, makeRunner(step.Name, step.Type, subStepRunners))
+		} else {
+			runners = append(runners, makeRunner(step.Name, step.Type, nil))
+		}
 	}
 	return app, runners
 }
 
 var pending bool
 
-func makeRunner(name string, tpy string) wfTypes.TaskRunner {
-	var run func(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.WorkflowStepStatus, *wfTypes.Operation, error)
+func makeRunner(name string, tpy string, subTaskRunners []wfTypes.TaskRunner) wfTypes.TaskRunner {
+	var run func(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.StepStatus, *wfTypes.Operation, error)
 	switch tpy {
 	case "suspend":
-		run = func(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.WorkflowStepStatus, *wfTypes.Operation, error) {
-			return common.WorkflowStepStatus{
+		run = func(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.StepStatus, *wfTypes.Operation, error) {
+			return common.StepStatus{
 					Name:  name,
 					Type:  "suspend",
 					Phase: common.WorkflowStepPhaseSucceeded,
@@ -594,8 +1045,8 @@ func makeRunner(name string, tpy string) wfTypes.TaskRunner {
 				}, nil
 		}
 	case "terminate":
-		run = func(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.WorkflowStepStatus, *wfTypes.Operation, error) {
-			return common.WorkflowStepStatus{
+		run = func(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.StepStatus, *wfTypes.Operation, error) {
+			return common.StepStatus{
 					Name:  name,
 					Type:  "terminate",
 					Phase: common.WorkflowStepPhaseSucceeded,
@@ -604,24 +1055,24 @@ func makeRunner(name string, tpy string) wfTypes.TaskRunner {
 				}, nil
 		}
 	case "success":
-		run = func(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.WorkflowStepStatus, *wfTypes.Operation, error) {
-			return common.WorkflowStepStatus{
+		run = func(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.StepStatus, *wfTypes.Operation, error) {
+			return common.StepStatus{
 				Name:  name,
 				Type:  "success",
 				Phase: common.WorkflowStepPhaseSucceeded,
 			}, &wfTypes.Operation{}, nil
 		}
 	case "failed":
-		run = func(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.WorkflowStepStatus, *wfTypes.Operation, error) {
-			return common.WorkflowStepStatus{
+		run = func(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.StepStatus, *wfTypes.Operation, error) {
+			return common.StepStatus{
 				Name:  name,
 				Type:  "failed",
 				Phase: common.WorkflowStepPhaseFailed,
 			}, &wfTypes.Operation{}, nil
 		}
 	case "failed-after-retries":
-		run = func(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.WorkflowStepStatus, *wfTypes.Operation, error) {
-			return common.WorkflowStepStatus{
+		run = func(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.StepStatus, *wfTypes.Operation, error) {
+			return common.StepStatus{
 					Name:  name,
 					Type:  "failed-after-retries",
 					Phase: common.WorkflowStepPhaseFailed,
@@ -630,27 +1081,34 @@ func makeRunner(name string, tpy string) wfTypes.TaskRunner {
 				}, nil
 		}
 	case "error":
-		run = func(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.WorkflowStepStatus, *wfTypes.Operation, error) {
-			return common.WorkflowStepStatus{
+		run = func(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.StepStatus, *wfTypes.Operation, error) {
+			return common.StepStatus{
 				Name:  name,
 				Type:  "error",
 				Phase: common.WorkflowStepPhaseRunning,
 			}, &wfTypes.Operation{}, errors.New("error for test")
 		}
 	case "wait-with-set-var":
-		run = func(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.WorkflowStepStatus, *wfTypes.Operation, error) {
+		run = func(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.StepStatus, *wfTypes.Operation, error) {
 			v, _ := value.NewValue(`saved: true`, nil, "")
 			err := ctx.SetVar(v)
-			return common.WorkflowStepStatus{
+			return common.StepStatus{
 				Name:  name,
 				Type:  "wait-with-set-var",
 				Phase: common.WorkflowStepPhaseRunning,
 			}, &wfTypes.Operation{}, err
 		}
-
+	case "step-group":
+		run = func(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.StepStatus, *wfTypes.Operation, error) {
+			return common.StepStatus{
+				Name:  name,
+				Type:  "step-group",
+				Phase: common.WorkflowStepPhaseRunning,
+			}, &wfTypes.Operation{}, nil
+		}
 	default:
-		run = func(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.WorkflowStepStatus, *wfTypes.Operation, error) {
-			return common.WorkflowStepStatus{
+		run = func(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.StepStatus, *wfTypes.Operation, error) {
+			return common.StepStatus{
 				Name:  name,
 				Type:  tpy,
 				Phase: common.WorkflowStepPhaseSucceeded,
@@ -670,6 +1128,7 @@ func makeRunner(name string, tpy string) wfTypes.TaskRunner {
 			}
 			return false
 		},
+		subTaskRunners: subTaskRunners,
 	}
 }
 
@@ -690,9 +1149,10 @@ metadata:
 )
 
 type testTaskRunner struct {
-	name         string
-	run          func(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.WorkflowStepStatus, *wfTypes.Operation, error)
-	checkPending func(ctx wfContext.Context) bool
+	name           string
+	run            func(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.StepStatus, *wfTypes.Operation, error)
+	checkPending   func(ctx wfContext.Context) bool
+	subTaskRunners []wfTypes.TaskRunner
 }
 
 // Name return step name.
@@ -701,7 +1161,7 @@ func (tr *testTaskRunner) Name() string {
 }
 
 // Run execute task.
-func (tr *testTaskRunner) Run(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.WorkflowStepStatus, *wfTypes.Operation, error) {
+func (tr *testTaskRunner) Run(ctx wfContext.Context, options *wfTypes.TaskRunOptions) (common.StepStatus, *wfTypes.Operation, error) {
 	return tr.run(ctx, nil)
 }
 
@@ -710,10 +1170,20 @@ func (tr *testTaskRunner) Pending(ctx wfContext.Context) bool {
 	return tr.checkPending(ctx)
 }
 
+func (tr *testTaskRunner) SubTaskRunners() []wfTypes.TaskRunner {
+	return tr.subTaskRunners
+}
+
 func cleanStepTimeStamp(wfStatus *common.WorkflowStatus) {
 	wfStatus.StartTime = metav1.Time{}
-	for index := range wfStatus.Steps {
+	for index, step := range wfStatus.Steps {
 		wfStatus.Steps[index].FirstExecuteTime = metav1.Time{}
 		wfStatus.Steps[index].LastExecuteTime = metav1.Time{}
+		if step.SubStepsStatus != nil {
+			for indexSubStep := range step.SubStepsStatus {
+				wfStatus.Steps[index].SubStepsStatus[indexSubStep].FirstExecuteTime = metav1.Time{}
+				wfStatus.Steps[index].SubStepsStatus[indexSubStep].LastExecuteTime = metav1.Time{}
+			}
+		}
 	}
 }
diff --git a/vela-templates/definitions/internal/workflowstep/step-group.cue b/vela-templates/definitions/internal/workflowstep/step-group.cue
new file mode 100644
index 0000000000000000000000000000000000000000..558548af7a1b0df9c06ea766d3145fec55896f62
--- /dev/null
+++ b/vela-templates/definitions/internal/workflowstep/step-group.cue
@@ -0,0 +1,10 @@
+"step-group": {
+	type: "workflow-step"
+	annotations: {}
+	labels: {}
+	description: "step group"
+}
+template: {
+	// no parameters
+	parameter: {}
+}