---
title: "Helm Charts - Kubernetes Package Management"
lang: "en"
author: "Mohammad Abu Mattar"
canonical: https://mkabumattar.com/post/helm-charts-kubernetes-multi-environment
---

![Blog post image for Helm Charts: Templating & Multi-Environment Kubernetes Deployments - How Helm templates Kubernetes manifests for multi-environment deployments: values overrides per environment, conditional logic, chart dependencies, and GitOps rollout with ArgoCD.](/_astro/hero.C-pWunDw_1dskDY.webp)

[Home](/)›[Devtips](/devtips)›[All Categories](/devtips/categories)›[Kubernetes & DevOps](/devtips/categories/kubernetes--devops)

Devtips

[Kubernetes & DevOps](/devtips/categories/kubernetes--devops)

# Helm Charts: Templating & Multi-Environment Kubernetes Deployments

[Mohammad Abu Mattar](/authors/mohammad-abu-mattar)Published: 30 Mar 202604 Mins read04 Mins listen

[Markdown for AI(opens in a new tab)](/post/helm-charts-kubernetes-multi-environment/index.md "Open the plain-Markdown version of this page, for pasting into an AI tool")

TL;DR

How Helm templates Kubernetes manifests for multi-environment deployments: values overrides per environment, conditional logic, chart dependencies, and GitOps rollout with ArgoCD.

Series

[Kubernetes & Container Orchestration](/series/kubernetes--container-orchestration)1/1

All posts in this series (1)

DevTips1

1.  [Helm Charts: Templating & Multi-Environment Kubernetes DeploymentsYou are here](/devtips/post/helm-charts-kubernetes-multi-environment)

### Helm Charts: Templating & Multi-Environment Kubernetes Deployments

Contents

[Why Helm matters](#why-helm-matters)[The Kubernetes manifest problem](#the-kubernetes-manifest-problem)[Where hand-written YAML breaks down](#where-hand-written-yaml-breaks-down)[The fix: Helm charts](#the-fix-helm-charts)[What Helm is](#what-helm-is)[What you get](#what-you-get)[Chart structure](#chart-structure)[Directory layout](#directory-layout)[Chart.yaml](#chartyaml)[Templating](#templating)[Basic values templating](#basic-values-templating)[A templated deployment](#a-templated-deployment)[Conditional logic in templates](#conditional-logic-in-templates)[Environment-specific configuration](#environment-specific-configuration)[Resources that exist only in some environments](#resources-that-exist-only-in-some-environments)[Conditional security settings](#conditional-security-settings)[Managing multiple environments](#managing-multiple-environments)[Environment-specific values files](#environment-specific-values-files)[Values priority (the last one wins)](#values-priority-the-last-one-wins)[Chart dependencies](#chart-dependencies)[Depending on PostgreSQL](#depending-on-postgresql)[Installing dependencies](#installing-dependencies)[Values for a sub-chart](#values-for-a-sub-chart)[Release management](#release-management)[The basic commands](#the-basic-commands)[A deployment run, start to finish](#a-deployment-run-start-to-finish)[GitOps integration](#gitops-integration)[Storing charts in Git](#storing-charts-in-git)[GitOps with ArgoCD](#gitops-with-argocd)[Going further with templates](#going-further-with-templates)[Helper functions](#helper-functions)[Loops](#loops)[Best practices](#best-practices)[1\. Version charts semantically](#1-version-charts-semantically)[2\. Use namespaces](#2-use-namespaces)[3\. Lint before you deploy](#3-lint-before-you-deploy)[4\. Test charts](#4-test-charts)[5\. Validate values against a schema](#5-validate-values-against-a-schema)[A complete minimal example](#a-complete-minimal-example)[Chart structure](#chart-structure)[Deploying it](#deploying-it)[Wrapping up](#wrapping-up)[Resources](#resources)

## [Why Helm matters](#why-helm-matters)

### [The Kubernetes manifest problem](#the-kubernetes-manifest-problem)

**Managing Kubernetes manifests at scale becomes a nightmare.**

You have a deployment for dev, staging and production. Each one is 90% identical: same containers, same services, different replicas and resource limits and environment variables. Copy the YAML, edit a few lines, deploy. That works right up until someone edits dev and forgets staging, or a typo lands in production and nobody notices until users report the outage.

Helm packages a Kubernetes application as a chart with templates, values and a version number. The YAML you deploy is generated from one source instead of maintained in three places.

### [Where hand-written YAML breaks down](#where-hand-written-yaml-breaks-down)

```
1Environment Fragmentation:2prod-deployment.yaml  ← Different values hardcoded3staging-deployment.yaml  ← Needs 3 edits for prod4dev-deployment.yaml  ← Inconsistent structure5
6Result:7• Configurations drift8• Changes in one place aren't replicated9• Rollback = manually revert files10• New environments = copy-paste hell
```

## [The fix: Helm charts](#the-fix-helm-charts)

### [What Helm is](#what-helm-is)

**Helm is package management for Kubernetes**, like npm for Node.js or pip for Python.

-   **Charts**: Helm packages containing templated Kubernetes manifests
-   **Values**: Configuration that gets injected into templates (replicas, image tags, resources)
-   **Releases**: Deployed instances of charts, tracked with versions for easy rollback
-   **Repos**: Central repositories where teams share charts

### [What you get](#what-you-get)

-   **Single chart, multiple environments**: Use template variables instead of duplicating YAML
-   **Templating system**: `{{ .Values.replicas }}` → substituted with values from env-specific file
-   **Dependency management**: Charts can depend on other charts (PostgreSQL, Redis, etc.)
-   **Versioning & rollback**: Every deployment tracked, instant rollback to previous version
-   **Validation**: Helm validates charts before deployment
-   **GitOps ready**: Store charts in Git, deploy from Git

## [Chart structure](#chart-structure)

### [Directory layout](#directory-layout)

```
1my-app/2├── Chart.yaml                 # Chart metadata (name, version, description)3├── values.yaml                # Default values4├── values-dev.yaml            # Dev environment overrides5├── values-staging.yaml        # Staging overrides6├── values-prod.yaml           # Production overrides7├── templates/8│   ├── deployment.yaml        # Templated Kubernetes Deployment9│   ├── service.yaml           # Service manifest10│   ├── configmap.yaml         # ConfigMap for config11│   ├── hpa.yaml               # Horizontal Pod Autoscaler (prod only)12│   └── _helpers.tpl           # Template helpers/functions13└── README.md                  # Chart documentation
```

### [Chart.yaml](#chartyaml)

Chart.yaml

```
1apiVersion: v22name: my-app3description: A Helm chart for my microservice4type: application5version: 1.0.0 # Chart version6appVersion: '1.2.3' # Application version7maintainers:8  - name: Your Team9    email: team@example.com
```

## [Templating](#templating)

### [Basic values templating](#basic-values-templating)

values.yaml

```
1# Default values for all environments2replicaCount: 13
4image:5  repository: myregistry.azurecr.io/my-app6  tag: '1.2.3'7  pullPolicy: IfNotPresent8
9resources:10  requests:11    memory: '128Mi'12    cpu: '100m'13  limits:14    memory: '256Mi'15    cpu: '500m'16
17environment: 'dev'18debug: true
```

values-prod.yaml

```
1# Production overrides2replicaCount: 3 # More replicas for load3
4resources:5  requests:6    memory: '512Mi'7    cpu: '500m'8  limits:9    memory: '1Gi'10    cpu: '2000m'11
12environment: 'production'13debug: false # Disable debug logging
```

### [A templated deployment](#a-templated-deployment)

templates/deployment.yaml

```
1apiVersion: apps/v12kind: Deployment3metadata:4  name: {{.Release.Name}}5  namespace: {{.Release.Namespace}}6spec:7  replicas: {{.Values.replicaCount}} # Injected from values8  selector:9    matchLabels:10      app: {{.Chart.Name}}11  template:12    metadata:13      labels:14        app: {{.Chart.Name}}15    spec:16      containers:17        - name: {{.Chart.Name}}18          image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}'19          imagePullPolicy: {{.Values.image.pullPolicy}}20          env:21            - name: ENVIRONMENT22              value: {{.Values.environment}}23            - name: DEBUG24              value: '{{ .Values.debug }}'25          ports:26            - containerPort: 808027          resources:28            requests:29              memory: {{.Values.resources.requests.memory | quote}}30              cpu: {{.Values.resources.requests.cpu | quote}}31            limits:32              memory: {{.Values.resources.limits.memory | quote}}33              cpu: {{.Values.resources.limits.cpu | quote}}
```

## [Conditional logic in templates](#conditional-logic-in-templates)

### [Environment-specific configuration](#environment-specific-configuration)

templates/deployment.yaml

```
1spec:2  {{- if eq .Values.environment "production" }}3  replicas: 34  {{- else if eq .Values.environment "staging" }}5  replicas: 26  {{- else }}7  replicas: 18  {{- end }}
```

### [Resources that exist only in some environments](#resources-that-exist-only-in-some-environments)

templates/hpa.yaml

```
1{{- if eq .Values.environment "production" }}2apiVersion: autoscaling/v23kind: HorizontalPodAutoscaler4metadata:5  name: {{ .Release.Name }}6spec:7  scaleTargetRef:8    apiVersion: apps/v19    kind: Deployment10    name: {{ .Release.Name }}11  minReplicas: 312  maxReplicas: 1013  metrics:14  - type: Resource15    resource:16      name: cpu17      target:18        type: Utilization19        averageUtilization: 7020{{- end }}
```

### [Conditional security settings](#conditional-security-settings)

templates/deployment.yaml

```
1spec:2  {{- if eq .Values.environment "production" }}3  securityContext:4    runAsNonRoot: true5    runAsUser: 10006    fsReadOnlyRootFilesystem: true7  {{- end }}
```

## [Managing multiple environments](#managing-multiple-environments)

### [Environment-specific values files](#environment-specific-values-files)

```
1Deploy to dev:2helm install my-app . -f values.yaml -f values-dev.yaml3
4Deploy to staging:5helm install my-app . -f values.yaml -f values-staging.yaml6
7Deploy to prod:8helm install my-app . -f values.yaml -f values-prod.yaml
```

### [Values priority (the last one wins)](#values-priority-the-last-one-wins)

Terminal window

```
# Later files override earlier oneshelm install my-app \  -f values.yaml \           # Base defaults  -f values-prod.yaml \      # Override for prod  --set environment=production # Override from CLI (highest priority)
```

## [Chart dependencies](#chart-dependencies)

### [Depending on PostgreSQL](#depending-on-postgresql)

Chart.yaml

```
1dependencies:2  - name: postgresql3    version: '13.0.0'4    repository: https://charts.bitnami.com/bitnami
```

### [Installing dependencies](#installing-dependencies)

Terminal window

```
# Download dependencieshelm dependency update
# Then deploy (PostgreSQL chart auto-installs)helm install my-app . -f values-prod.yaml
```

### [Values for a sub-chart](#values-for-a-sub-chart)

values-prod.yaml

```
1# My app values2replicaCount: 33
4# PostgreSQL sub-chart values5postgresql:6  enabled: true7  auth:8    password: 'prod-secure-password'9  primary:10    persistence:11      size: 100Gi12  metrics:13    enabled: true
```

## [Release management](#release-management)

### [The basic commands](#the-basic-commands)

Terminal window

```
# Install a releasehelm install my-app ./chart -f values-prod.yaml
# Upgrade to new versionhelm upgrade my-app ./chart -f values-prod.yaml
# Check release historyhelm history my-app
# Rollback to previous version (instant!)helm rollback my-app 2
# Delete releasehelm uninstall my-app
```

### [A deployment run, start to finish](#a-deployment-run-start-to-finish)

Terminal window

```
# 1. Make changes to chart# 2. Test locallyhelm install test-release . -f values-dev.yaml
# 3. Test succeeded, upgradehelm uninstall test-release
# 4. Deploy to productionhelm upgrade my-app . -f values-prod.yaml
# 5. Verifykubectl get pods -l app=my-app
# 6. If something's wrong, instant rollbackhelm rollback my-app
```

## [GitOps integration](#gitops-integration)

### [Storing charts in Git](#storing-charts-in-git)

```
1git repository structure:2├── charts/3│   ├── my-app/4│   │   ├── Chart.yaml5│   │   ├── values.yaml6│   │   ├── values-dev.yaml7│   │   ├── values-prod.yaml8│   │   └── templates/9│   └── other-app/10├── .gitignore11└── README.md
```

### [GitOps with ArgoCD](#gitops-with-argocd)

ArgoCD watches your Git repo and automatically keeps your Kubernetes cluster in sync:

argocd-app.yaml

```
1apiVersion: argoproj.io/v1alpha12kind: Application3metadata:4  name: my-app-prod5spec:6  project: default7  source:8    repoURL: https://github.com/myteam/infrastructure9    targetRevision: main10    path: charts/my-app11    helm:12      values: |13        environment: production14        replicaCount: 315  destination:16    server: https://kubernetes.default.svc17    namespace: prod18  syncPolicy:19    automated:20      prune: true21      selfHeal: true
```

Deploy workflow:

```
11. Developer updates Chart in Git22. Commits and pushes33. ArgoCD detects change44. Automatically syncs to Kubernetes55. Helm applies new deployment66. Services updated with zero downtime
```

## [Going further with templates](#going-further-with-templates)

### [Helper functions](#helper-functions)

templates/\_helpers.tpl

```
1{{- define "my-app.labels" -}}2helm.sh/chart: {{ include "my-app.chart" . }}3app.kubernetes.io/name: {{ include "my-app.name" . }}4app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}5{{- end }}6
7{{- define "my-app.name" -}}8{{ .Chart.Name }}9{{- end }}
```

templates/deployment.yaml

```
1# Reuse helper2metadata:3  labels: {{- include "my-app.labels" . | nindent 4}}
```

### [Loops](#loops)

templates/deployment.yaml

```
1env:2{{- range $key, $value := .Values.env }}3- name: {{ $key }}4  value: {{ $value | quote }}5{{- end }}
```

## [Best practices](#best-practices)

### [1\. Version charts semantically](#1-version-charts-semantically)

```
1version: 2.1.0 # MAJOR.MINOR.PATCH2# MAJOR: Breaking changes3# MINOR: New features4# PATCH: Bug fixes
```

### [2\. Use namespaces](#2-use-namespaces)

Terminal window

```
# Deploy each environment to different namespacehelm install app . -n production -f values-prod.yamlhelm install app . -n staging -f values-staging.yamlhelm install app . -n dev -f values-dev.yaml
```

### [3\. Lint before you deploy](#3-lint-before-you-deploy)

Terminal window

```
# Validate chart syntaxhelm lint ./chart
# Dry-run to see what will be deployedhelm install --dry-run my-app ./chart -f values-prod.yaml
```

### [4\. Test charts](#4-test-charts)

Terminal window

```
helm test my-app  # Run chart tests
```

### [5\. Validate values against a schema](#5-validate-values-against-a-schema)

values.schema.json

```
1{2  '$schema': 'https://json-schema.org/draft-07/schema#',3  'type': 'object',4  'properties':5    {6      'replicaCount': {'type': 'integer', 'minimum': 1},7      'image': {'type': 'object', 'properties': {'tag': {'type': 'string'}}},8    },9}
```

## [A complete minimal example](#a-complete-minimal-example)

### [Chart structure](#chart-structure-1)

```
1my-service/2├── Chart.yaml3├── values.yaml4├── values-prod.yaml5└── templates/6    ├── deployment.yaml7    └── service.yaml
```

### [Deploying it](#deploying-it)

Terminal window

```
# Devhelm install my-service . -f values.yaml -f values-dev.yaml
# Productionhelm upgrade my-service . -f values.yaml -f values-prod.yaml --install
# Rollback if neededhelm rollback my-service
```

## [Wrapping up](#wrapping-up)

**Helm replaces four copies of a deployment with one chart and four values files.**

Templated manifests, values per environment and numbered releases mean a rollback is one command instead of an archaeology session in Git history. Pair it with ArgoCD and the cluster follows the repo. The templating language is the price of admission, and it is a real cost, but it buys you environments that actually match.

## [Resources](#resources)

-   [Helm Official Documentation](https://helm.sh/docs/)
-   [Chart Template Guide](https://helm.sh/docs/chart_template_guide/)
-   [Helm Best Practices](https://helm.sh/docs/chart_best_practices/)
-   [ArtifactHub: Pre-built Charts](https://artifacthub.io/)
-   [ArgoCD + Helm Integration](https://argo-cd.readthedocs.io/en/stable/user-guide/helm/)

Was this useful?

## Tags

[#Helm](/devtips/tags/helm)[#Kubernetes](/devtips/tags/kubernetes)[#Deployment](/devtips/tags/deployment)[#GitOps](/devtips/tags/gitops)[#Containerization](/devtips/tags/containerization)[#Microservices](/devtips/tags/microservices)[#Infrastructure](/devtips/tags/infrastructure)

## Share

[Facebook](https://facebook.com/sharer/sharer.php?u=https%3A%2F%2Fmkabumattar.com%2Fdevtips%2Fpost%2Fhelm-charts-kubernetes-multi-environment "Share on Facebook")[Twitter](https://twitter.com/intent/tweet/?text=Helm%20Charts%3A%20Templating%20%26%20Multi-Environment%20Kubernetes%20Deployments&url=https%3A%2F%2Fmkabumattar.com%2Fdevtips%2Fpost%2Fhelm-charts-kubernetes-multi-environment "Share on Twitter")[LinkedIn](https://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Fmkabumattar.com%2Fdevtips%2Fpost%2Fhelm-charts-kubernetes-multi-environment&title=Helm%20Charts%3A%20Templating%20%26%20Multi-Environment%20Kubernetes%20Deployments&summary=How%20Helm%20templates%20Kubernetes%20manifests%20for%20multi-environment%20deployments%3A%20values%20overrides%20per%20environment%2C%20conditional%20logic%2C%20chart%20dependencies%2C%20and%20GitOps%20rollout%20with%20ArgoCD.&source=https://mkabumattar.com "Share on LinkedIn")[WhatsApp](https://wa.me/?text=Helm%20Charts%3A%20Templating%20%26%20Multi-Environment%20Kubernetes%20Deployments%20https%3A%2F%2Fmkabumattar.com%2Fdevtips%2Fpost%2Fhelm-charts-kubernetes-multi-environment "Share on WhatsApp")[Telegram](https://t.me/share/url?url=https%3A%2F%2Fmkabumattar.com%2Fdevtips%2Fpost%2Fhelm-charts-kubernetes-multi-environment&text=Helm%20Charts%3A%20Templating%20%26%20Multi-Environment%20Kubernetes%20Deployments "Share on Telegram")[Reddit](https://www.reddit.com/submit?url=https%3A%2F%2Fmkabumattar.com%2Fdevtips%2Fpost%2Fhelm-charts-kubernetes-multi-environment&title=Helm%20Charts%3A%20Templating%20%26%20Multi-Environment%20Kubernetes%20Deployments "Share on Reddit")[Hacker News](http://news.ycombinator.com/submitlink?u=https%3A%2F%2Fmkabumattar.com%2Fdevtips%2Fpost%2Fhelm-charts-kubernetes-multi-environment&t=Helm%20Charts%3A%20Templating%20%26%20Multi-Environment%20Kubernetes%20Deployments "Share on Hacker News")[Pinterest](https://pinterest.com/pin/create/button/?url=https%3A%2F%2Fmkabumattar.com%2Fdevtips%2Fpost%2Fhelm-charts-kubernetes-multi-environment&media=&description=How%20Helm%20templates%20Kubernetes%20manifests%20for%20multi-environment%20deployments%3A%20values%20overrides%20per%20environment%2C%20conditional%20logic%2C%20chart%20dependencies%2C%20and%20GitOps%20rollout%20with%20ArgoCD. "Share on Pinterest")[Email](<mailto:?subject=Helm%20Charts%3A%20Templating%20%26%20Multi-Environment%20Kubernetes%20Deployments&body=Check out this article: https%3A%2F%2Fmkabumattar.com%2Fdevtips%2Fpost%2Fhelm-charts-kubernetes-multi-environment>)

## Comments

## You might also enjoy

More posts on similar topics

[![ArgoCD GitOps: Sync Kubernetes Deployments Automatically from Git](/_astro/hero.D4Pcicvc_VlKXt.webp)](/devtips/post/argocd-gitops-kubernetes-deployments-git-sync)

## [ArgoCD GitOps: Sync Kubernetes Deployments Automatically from Git](/devtips/post/argocd-gitops-kubernetes-deployments-git-sync)

-   [Mohammad Abu Mattar](/authors/mohammad-abu-mattar)
-   [Kubernetes & Containers](/devtips/categories/kubernetes--containers)

Why GitOps for Kubernetes? From kubectl apply to Git as the source of truth Hey, want to stop deploying to Kubernetes by hand? If your releases still come from someone running \`kubectl ap

[#ArgoCD](/devtips/tags/argocd)[#GitOps](/devtips/tags/gitops)[#Kubernetes](/devtips/tags/kubernetes)+4 tags

[read more](/devtips/post/argocd-gitops-kubernetes-deployments-git-sync)

[![Policy-as-Code Governance with OPA/Rego](/_astro/hero.CwAJ64Mi_1WeH9p.webp)](/devtips/post/policy-as-code-opa-rego)

## [Policy-as-Code Governance with OPA/Rego](/devtips/post/policy-as-code-opa-rego)

-   [Mohammad Abu Mattar](/authors/mohammad-abu-mattar)
-   [DevOps & DevSecOps](/devtips/categories/devops--devsecops)

Why policy-as-code matters The governance problem Managing infrastructure at scale gets complicated fast. As your infrastructure grows, keeping it consistent and compliant gets harder. M

[#Policy as Code](/devtips/tags/policy-as-code)[#OPA/Rego](/devtips/tags/oparego)[#Compliance](/devtips/tags/compliance)+4 tags

[read more](/devtips/post/policy-as-code-opa-rego)

[![Structured Logging & Log Aggregation with ELK Stack](/_astro/hero.w_mPuDHM_Z1SSNz9.webp)](/devtips/post/structured-logging-elk-stack)

## [Structured Logging & Log Aggregation with ELK Stack](/devtips/post/structured-logging-elk-stack)

-   [Mohammad Abu Mattar](/authors/mohammad-abu-mattar)
-   [DevOps & Observability](/devtips/categories/devops--observability)

Why centralized logging matters When services fail, where do you look first? In a distributed system, logs scatter across servers, containers and regions. One request might touch five service

[#Logging](/devtips/tags/logging)[#ELK Stack](/devtips/tags/elk-stack)[#Elasticsearch](/devtips/tags/elasticsearch)+4 tags

[read more](/devtips/post/structured-logging-elk-stack)

[![Kubernetes Namespaces: Organize, Isolate, and Secure Multi-Team Clusters](/_astro/hero.DwnjQnvN_Z1FaY8R.webp)](/devtips/post/kubernetes-namespaces-organize-isolate-multi-team)

## [Kubernetes Namespaces: Organize, Isolate, and Secure Multi-Team Clusters](/devtips/post/kubernetes-namespaces-organize-isolate-multi-team)

-   [Mohammad Abu Mattar](/authors/mohammad-abu-mattar)
-   [Kubernetes & Cloud Native](/devtips/categories/kubernetes--cloud-native)

Why cluster isolation matters The multi-tenant reality If you're running a separate cluster for every environment and every dev team, you have already seen the bill and the amount of upgrade

[#Kubernetes](/devtips/tags/kubernetes)[#Namespaces](/devtips/tags/namespaces)[#Multi Tenancy](/devtips/tags/multi-tenancy)+6 tags

[read more](/devtips/post/kubernetes-namespaces-organize-isolate-multi-team)

[![Understanding Kubernetes Services: ClusterIP vs NodePort vs LoadBalancer](/_astro/hero.DBNjupL__148EQW.webp)](/devtips/post/kubernetes-services-clusterip-nodeport-loadbalancer)

## [Understanding Kubernetes Services: ClusterIP vs NodePort vs LoadBalancer](/devtips/post/kubernetes-services-clusterip-nodeport-loadbalancer)

-   [Mohammad Abu Mattar](/authors/mohammad-abu-mattar)
-   [DevOps & Kubernetes](/devtips/categories/devops--kubernetes)

If you're working with Kubernetes, you've probably noticed that Pods come and go, and their IP addresses keep changing. That's where Services come in. They give you a stable way to keep your apps acce

[#Kubernetes](/devtips/tags/kubernetes)[#K8s Services](/devtips/tags/k8s-services)[#ClusterIP](/devtips/tags/clusterip)+5 tags

[read more](/devtips/post/kubernetes-services-clusterip-nodeport-loadbalancer)

[![Tracing Microservices with OpenTelemetry](/_astro/hero.BOHz8WyH_Z1IEpz3.webp)](/devtips/post/tracing-microservices-opentelemetry)

## [Tracing Microservices with OpenTelemetry](/devtips/post/tracing-microservices-opentelemetry)

-   [Mohammad Abu Mattar](/authors/mohammad-abu-mattar)
-   [Observability & Monitoring](/devtips/categories/observability--monitoring)

Why monitor your microservices? The complexity of distributed systems If you're juggling multiple services, it's hard to track how they work together. OpenTelemetry lets you follow one reques

[#OpenTelemetry](/devtips/tags/opentelemetry)[#Microservices](/devtips/tags/microservices)[#Distributed Tracing](/devtips/tags/distributed-tracing)+4 tags

[read more](/devtips/post/tracing-microservices-opentelemetry)

6 related posts
