<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Obaseki Noruwa</title>
    <description>The latest articles on DEV Community by Obaseki Noruwa (@noruwa).</description>
    <link>https://dev.to/noruwa</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1045195%2F847f0567-ce97-4cc6-ba05-37d1fc9658d9.jpeg</url>
      <title>DEV Community: Obaseki Noruwa</title>
      <link>https://dev.to/noruwa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/noruwa"/>
    <language>en</language>
    <item>
      <title>Monitoring for Express.js Applications Using Prometheus and Node Exporter</title>
      <dc:creator>Obaseki Noruwa</dc:creator>
      <pubDate>Sun, 08 Jun 2025 00:48:56 +0000</pubDate>
      <link>https://dev.to/noruwa/monitoring-for-expressjs-applications-using-prometheus-and-node-exporter-2don</link>
      <guid>https://dev.to/noruwa/monitoring-for-expressjs-applications-using-prometheus-and-node-exporter-2don</guid>
      <description>&lt;p&gt;Monitoring isn't just about knowing when things break, it's about understanding how your systems behave under real-world conditions and making data-driven decisions before issues impact users. In this comprehensive guide, I will walk you through building a robust monitoring solution for Express.js applications using the industry standard Prometheus ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Monitoring Matters More Than You Think
&lt;/h2&gt;

&lt;p&gt;During my journey into DevOps practices, I discovered that monitoring is often treated as an afterthought after CI/CD pipeline deployment. Teams build amazing applications, deploy them to production, and then set up monitoring as a reactive measure. However, I believe that as part of the journey to become a DevOps engineer, after learning containerization, the next critical step should be gaining hands-on experience in setting up monitoring with open-source toolkits for system optimization.&lt;/p&gt;

&lt;p&gt;This approach transforms monitoring from a reactive necessity into a proactive strategy that enables better system understanding and performance optimization.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Monitoring Stack Architecture
&lt;/h2&gt;

&lt;p&gt;I chose the Prometheus ecosystem because it's become the de facto standard for container native monitoring. Here's why this combination works so well:&lt;/p&gt;

&lt;h3&gt;
  
  
  Prometheus: The Storage for Time-Series Data
&lt;/h3&gt;

&lt;p&gt;Prometheus serves as the storage layer for time-series data, exposing its metrics endpoint at &lt;code&gt;http://localhost:9090/metrics&lt;/code&gt; to be scraped by monitoring tools. The time-series database design excels at storing metrics with timestamps, enabling powerful queries and aggregations. When you need to understand how your application performed during last week's traffic spike, Prometheus gives you that historical context.&lt;/p&gt;

&lt;p&gt;In your &lt;code&gt;compose.monitoring.yml&lt;/code&gt; file, you can configure data retention in the command section by adding &lt;code&gt;--storage.tsdb.retention.time=30d&lt;/code&gt; to maintain 30 days of historical data for trend analysis.&lt;/p&gt;

&lt;h3&gt;
  
  
  Node Exporter: The Metrics Collector
&lt;/h3&gt;

&lt;p&gt;Node Exporter bridges the gap between application metrics and infrastructure health. It collects and exposes hardware statistics—CPU usage, memory consumption, disk I/O, and network activity—in Prometheus format. This integration means you can correlate application slowdowns with system resource constraints, making troubleshooting significantly more effective.&lt;/p&gt;

&lt;p&gt;The collector operates by reading system files and translating them into Prometheus-compatible metrics, providing comprehensive visibility into your infrastructure's health.&lt;/p&gt;

&lt;h3&gt;
  
  
  Grafana: From Data to Insights
&lt;/h3&gt;

&lt;p&gt;Raw metrics are meaningless without proper visualization. Grafana transforms Prometheus data into meaningful dashboards that tell the story of your application's health. The ability to create alerts based on metric thresholds means your monitoring system becomes proactive rather than reactive.&lt;/p&gt;

&lt;p&gt;With Grafana's extensive dashboard library, you can leverage pre-built visualizations or create custom dashboards tailored to your specific monitoring needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Repository Setup
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Clone the project repository&lt;/span&gt;
git clone https://github.com/noruwa03/express-js-nginx-lb
&lt;span class="nb"&gt;cd &lt;/span&gt;express-js-nginx-lb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Application Configuration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Navigate to application directory&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;app

&lt;span class="c"&gt;# Install Node.js dependencies&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Environment Configuration
&lt;/h3&gt;

&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file in the &lt;code&gt;app/&lt;/code&gt; directory with the following variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Port
PORT=8080

# Database Configuration for Neon DB or AWS RDS
DB_CONN_LINK=postgresql://username:password@host:port/database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Local Development (Optional)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start development server with hot reload to test&lt;/span&gt;
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Production Deployment
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Return to project root&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ..

&lt;span class="c"&gt;# Add name to compose.yml&lt;/span&gt;
name: monitoring-system

&lt;span class="c"&gt;# Change ports of nginx service in compose.yml from 3000:80 to 4000:80, port 3000 will be used by Grafana service&lt;/span&gt;
nginx:
   ports:
      - 4000:80
nginx:
   ports:
      - 4000:80

&lt;span class="c"&gt;# Add include option for compose.monitoring.yml&lt;/span&gt;
include:
  - compose.monitoring.yml

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create &lt;code&gt;compose.monitoring.yml&lt;/code&gt; file
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;node-exporter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prom/node-exporter&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node-exporter&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--path.procfs=/host/proc&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--path.rootfs=/rootfs&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--path.sysfs=/host/sys&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc|run/user)($|/)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--collector.filesystem.fs-types-exclude=^(autofs|binfmt_misc|bpf|cgroup2?|configfs|debugfs|devpts|devtmpfs|fusectl|hugetlbfs|iso9660|mqueue|nsfs|overlay|proc|procfs|pstore|rpc_pipefs|securityfs|selinuxfs|squashfs|sysfs|tracefs)$&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/proc:/host/proc:ro&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/sys:/host/sys:ro&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/:/rootfs:ro&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;9100:9100&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;monitoring&lt;/span&gt;

  &lt;span class="na"&gt;prometheus&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prom/prometheus&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prometheus&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;9090:9090&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--config.file=/etc/prometheus/prometheus.yml&lt;/span&gt;
      &lt;span class="c1"&gt;# - --storage.tsdb.retention.time=30d&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;monitoring&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node-exporter&lt;/span&gt;

  &lt;span class="na"&gt;grafana&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;grafana/grafana&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;grafana&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;3000:3000&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;monitoring&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GF_SECURITY_ADMIN_USER=admin&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GF_SECURITY_ADMIN_PASSWORD=admin&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GF_SERVER_ROOT_URL=http://localhost:3000/grafana/&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GF_SERVER_SERVE_FROM_SUB_PATH=true&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;grafana-storage:/var/lib/grafana&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;prometheus&lt;/span&gt;


&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;monitoring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bridge&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;grafana-storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add monitoring directory and create monitoring.yml file
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;
&lt;span class="na"&gt;global&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scrape_interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;15s&lt;/span&gt;
  &lt;span class="na"&gt;evaluation_interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;15s&lt;/span&gt;

&lt;span class="na"&gt;scrape_configs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;job_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node-exporter&lt;/span&gt;
    &lt;span class="na"&gt;static_configs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;targets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node-exporter:9100&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;job_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prometheus&lt;/span&gt;
    &lt;span class="na"&gt;static_configs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;targets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;prometheus:9090&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Architecture Overview
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Application Structure (Before Monitoring)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;express-js-nginx-lb/
├── app/                          # [Unchanged] app source code
├── nginx/                        # [Unchanged] Load balancer config
├── compose.yml                   # [Updated] Core application services
└── README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Enhanced Structure (With Monitoring Stack)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;express-js-nginx-lb/
├── app/                          # [Updated] .env file added with PORT and DB_CONN_LINK
├── nginx/                        # [Unchanged] Load balancer config
├── monitoring/                   # [New] Monitoring configurations
│   └── prometheus.yml              # Metrics collection rules
├── compose.monitoring.yml        # [New] Monitoring stack services
├── compose.yml                   # [Updated] Core application services
└── README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Launch complete monitoring stack&lt;/span&gt;
docker compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Accessing Your Monitoring Stack
&lt;/h2&gt;

&lt;p&gt;Once your stack is running, you can access the different components through these endpoints:&lt;/p&gt;

&lt;h3&gt;
  
  
  Prometheus Query Interface
&lt;/h3&gt;

&lt;p&gt;Access Prometheus at &lt;code&gt;http://localhost:9090/query&lt;/code&gt; to explore your metrics and run PromQL queries. The interface allows you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Execute queries to retrieve specific metrics&lt;/li&gt;
&lt;li&gt;Visualize data trends over time&lt;/li&gt;
&lt;li&gt;Monitor the health of your scrape targets&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Prometheus Targets Monitoring
&lt;/h3&gt;

&lt;p&gt;Navigate to the targets section at &lt;code&gt;http://localhost:9090/targets&lt;/code&gt; to verify that Prometheus is successfully scraping metrics from Node Exporter and other configured endpoints. This view shows the status of each target and helps troubleshoot connectivity issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  Grafana Dashboard Configuration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Initial Login
&lt;/h3&gt;

&lt;p&gt;Access Grafana at &lt;code&gt;http://localhost:3000&lt;/code&gt; using the default credentials:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Username&lt;/strong&gt;: admin&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Password&lt;/strong&gt;: admin&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These credentials are configured in your Docker Compose file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GF_SECURITY_ADMIN_USER=admin&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GF_SECURITY_ADMIN_PASSWORD=admin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding Prometheus as a Data Source
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to Configuration → Data Sources&lt;/li&gt;
&lt;li&gt;Click "Add data source"&lt;/li&gt;
&lt;li&gt;Select Prometheus&lt;/li&gt;
&lt;li&gt;Set the URL to &lt;code&gt;http://prometheus:9090&lt;/code&gt; (using Docker service name)&lt;/li&gt;
&lt;li&gt;Click "Save &amp;amp; Test" to verify the connection&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Importing Pre-built Dashboards
&lt;/h3&gt;

&lt;p&gt;Grafana's community provides excellent pre-built dashboards:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Visit &lt;code&gt;https://grafana.com/grafana/dashboards/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Search for "Node Exporter Full" dashboard&lt;/li&gt;
&lt;li&gt;Copy the dashboard ID (1860)&lt;/li&gt;
&lt;li&gt;In Grafana, navigate to Dashboards → Import&lt;/li&gt;
&lt;li&gt;Paste the ID and click "Load"&lt;/li&gt;
&lt;li&gt;Select Prometheus as your data source&lt;/li&gt;
&lt;li&gt;Click "Import" to complete the setup&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This dashboard provides comprehensive system monitoring including CPU, memory, disk, and network metrics with professional visualizations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaway
&lt;/h2&gt;

&lt;p&gt;The combination of Prometheus, Node Exporter, and Grafana provides a solid foundation that scales from development environments to enterprise production systems. By implementing this stack early in your development process, you build reliability practices into your application lifecycle rather than retrofitting them later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Future Enhancements
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Advanced Monitoring
&lt;/h3&gt;

&lt;p&gt;Implement container-specific monitoring using &lt;strong&gt;cAdvisor&lt;/strong&gt; for granular insights into Docker container resource usage, complementing the current system-level monitoring approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  Centralized Logging
&lt;/h3&gt;

&lt;p&gt;Integrate &lt;strong&gt;OpenTelemetry&lt;/strong&gt; or &lt;strong&gt;Promtail&lt;/strong&gt; as log collectors, &lt;strong&gt;Loki&lt;/strong&gt; for log aggregation, and enhance Grafana dashboards with log correlation capabilities for comprehensive observability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Distributed Tracing
&lt;/h3&gt;

&lt;p&gt;Add &lt;strong&gt;Jaeger&lt;/strong&gt; or &lt;strong&gt;Zipkin&lt;/strong&gt; integration to trace request flows through the microservice architecture, Tempo as storage and Grafana for visualization to enable detailed performance analysis and bottleneck identification across service boundaries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Production Deployment
&lt;/h3&gt;

&lt;p&gt;Implement &lt;strong&gt;GitHub Actions&lt;/strong&gt; CI/CD pipeline for automated testing, building, and deployment to cloud infrastructure (AWS ECS, Google Cloud Run, or Azure Container Instances).&lt;/p&gt;

&lt;p&gt;You can find the full project of this article at &lt;a href="https://github.com/noruwa03/express.js-monitoring" rel="noopener noreferrer"&gt;Github link&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>softwaredevelopment</category>
      <category>monitoring</category>
      <category>docker</category>
    </item>
    <item>
      <title>Scaling Express.js with Nginx Load Balancing: A Dockerized Approach</title>
      <dc:creator>Obaseki Noruwa</dc:creator>
      <pubDate>Fri, 23 May 2025 21:22:01 +0000</pubDate>
      <link>https://dev.to/noruwa/scaling-expressjs-with-nginx-load-balancing-a-dockerized-approach-4fhn</link>
      <guid>https://dev.to/noruwa/scaling-expressjs-with-nginx-load-balancing-a-dockerized-approach-4fhn</guid>
      <description>&lt;p&gt;Modern web applications need to be scalable, resilient, and maintainable. One of the most effective ways to achieve this is by using Docker to containerize your application and Nginx as a load balancer. In this post, I will walk you through how I built a scalable Express.js backend API, balanced with Nginx and orchestrated using Docker Compose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Load Balancing Matters
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Improved performance&lt;/strong&gt; – by sharing the workload.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Increased availability&lt;/strong&gt; – through redundancy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Easier horizontal scaling&lt;/strong&gt; – as demand grows, you can spin up more containers.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Project Overview
&lt;/h2&gt;

&lt;p&gt;This project demonstrates how to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Containerize an Express.js API using Docker.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scale the API across multiple containers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use Nginx as a reverse proxy and load balancer more containers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implement round-robin request distribution.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Before you read pass this point please clone the Express.Js project, Or you can develop your own Express.Js backend API and expose the port in the compose.yml file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Clone the repository:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   git clone https://github.com/noruwa03/express-js-nginx-lb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Navigate to the project directory:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;cd &lt;/span&gt;express-js-nginx-lb/app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Install dependencies:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Set up environment variables:&lt;/strong&gt;&lt;br&gt;
   Create a &lt;code&gt;.env&lt;/code&gt; file inside the &lt;code&gt;app&lt;/code&gt; directory with the following variables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;PORT&lt;/code&gt; - Port number for the Express.js server&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DB_CONN_LINK&lt;/code&gt; - PostgreSQL connection string from Neon DB. To create Database and Tables please open the &lt;strong&gt;express-test-db.sql&lt;/strong&gt; file at &lt;code&gt;app/src/db/express-test-db.sql&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Start the development server:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Project Structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;express-js-nginx-lb/
├── app/
│   ├── src/
│   │   ├── controllers/
│   │   │   ├── create-post.ts
│   │   │   ├── delete-post.ts
│   │   │   ├── get-post-by-id.ts
│   │   │   ├── get-posts.ts
│   │   │   └── update-post.ts
│   │   ├── db/
│   │   │   ├── express-test-db.sql
│   │   │   └── index.ts
│   │   ├── middlewares/
│   │   │   └── post-validation.ts
│   │   ├── routes/
│   │   │   └── index.ts
│   │   └── app.ts
│   ├── .dockerignore
│   ├── package-lock.json
│   ├── package.json
│   └── tsconfig.json
├── nginx/
│   └── nginx.conf
├── compose.yml
└── README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Key Components
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Express.js API&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The backend API handles basic CRUD operations for posts, with these endpoints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;GET /post&lt;/code&gt; - Retrieve all posts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;GET /post/:id&lt;/code&gt; - Get a specific post.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;POST /create-post&lt;/code&gt; - Create a new post.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;PATCH/update-post/:id&lt;/code&gt; - Update a post.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;DELETE/post/:id&lt;/code&gt; - Delete a post.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Docker Configuration&lt;/strong&gt;: compose.yml&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;myapp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./app&lt;/span&gt;
    &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
    &lt;span class="na"&gt;expose&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./app/.env:/etc/express_env/.env&lt;/span&gt;

  &lt;span class="na"&gt;nginx&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:alpine&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;3000:80&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./nginx/nginx.conf:/etc/nginx/nginx.conf&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;myapp&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;If you are developing your own Express.Js backend API, remember to change the port in the expose list&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nginx Configuration&lt;/strong&gt;: nginx.conf located at &lt;code&gt;nginx&lt;/code&gt; directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;events {}&lt;/span&gt;

&lt;span class="s"&gt;http {&lt;/span&gt;
  &lt;span class="s"&gt;include mime.types;&lt;/span&gt;

  &lt;span class="s"&gt;upstream myapp {&lt;/span&gt;
    &lt;span class="s"&gt;server myapp:8080;&lt;/span&gt;
  &lt;span class="s"&gt;}&lt;/span&gt;

  &lt;span class="s"&gt;server {&lt;/span&gt;
    &lt;span class="s"&gt;listen 80;&lt;/span&gt;
    &lt;span class="s"&gt;location / {&lt;/span&gt;
      &lt;span class="s"&gt;proxy_pass http://myapp;&lt;/span&gt;
      &lt;span class="s"&gt;proxy_set_header Host $host;&lt;/span&gt;
      &lt;span class="s"&gt;proxy_set_header X-Real-IP $remote_addr;&lt;/span&gt;
    &lt;span class="s"&gt;}&lt;/span&gt;
  &lt;span class="s"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Implementation Details
&lt;/h2&gt;

&lt;p&gt;Docker commands and snapshots is provided below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsrdj1wn48fnrlf2cldah.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsrdj1wn48fnrlf2cldah.PNG" alt="Docker Compose Build" width="800" height="324"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftiliepcz43vstsw6wq96.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftiliepcz43vstsw6wq96.PNG" alt="Docker Compose Up" width="800" height="341"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhqi8ru7vus4anq144kq3.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhqi8ru7vus4anq144kq3.PNG" alt="Docker PS" width="800" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Container Identification
&lt;/h3&gt;

&lt;p&gt;To verify load balancing was working, I added a /ping endpoint that returns the hostname of the container serving the request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;os&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;os&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/ping&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Served by: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Server running at port &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.....`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Served by: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdxqlgfejmcqh8loxy93.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdxqlgfejmcqh8loxy93.PNG" alt="Container One" width="800" height="309"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9hnkindxvlj8dx18sbrj.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9hnkindxvlj8dx18sbrj.PNG" alt="Container two" width="800" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Environment Variable Management
&lt;/h3&gt;

&lt;p&gt;I wanted to securely handle the &lt;code&gt;.env&lt;/code&gt; file using &lt;code&gt;secrets&lt;/code&gt; and map &lt;code&gt;.env&lt;/code&gt; file in a volume to the secrets in the Docker Compose configuration. However, when running &lt;code&gt;docker compose -f compose.yml config&lt;/code&gt; for the compose.yml file validation, I encountered an error. I didn't want to copy the &lt;code&gt;.env&lt;/code&gt; file directly into the Docker container, so I used Docker volumes to map the &lt;code&gt;app/.env&lt;/code&gt; file to the &lt;code&gt;/etc/express_env/.env&lt;/code&gt; directory inside the container. This approach keeps sensitive data out of the container image while still making it accessible at runtime.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;volumes:
  - ./app/.env:/etc/express_env/.env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's how to inspect the environment variables inside a running container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &amp;lt;container_id&amp;gt; /bin/sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;etc/express_env
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;span class="nb"&gt;exit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8v1gwlrsnlffcm516wnk.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8v1gwlrsnlffcm516wnk.PNG" alt="Container Info" width="800" height="228"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  API Response Snapshot
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;/api/v1/&lt;/code&gt; - root route&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ue6a75uhxdg33r685nj.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ue6a75uhxdg33r685nj.PNG" alt="Root Route" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/api/v1/create-post&lt;/code&gt; - create post route&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1b7901rsiud19gpqsvwe.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1b7901rsiud19gpqsvwe.PNG" alt="Create Post" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/api/v1/post/:id&lt;/code&gt; - get post by id&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0k5rnv8qioi4uddsdkku.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0k5rnv8qioi4uddsdkku.PNG" alt="Get Post By ID" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges and Solutions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Environment Variable Security
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Challenge&lt;/strong&gt;: Initially, I wanted to use Docker's secrets but encountered configuration errors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Using volumes provided a secure way to inject environment variables at runtime without baking them into the container image.&lt;/p&gt;

&lt;h3&gt;
  
  
  Load Balancing Verification
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Challenge&lt;/strong&gt;: Confirming that requests were actually being distributed across containers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Implementing the /ping endpoint that returns the container hostname provided clear visual confirmation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recommendations for Future Improvements
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Monitoring and Observability:&lt;/strong&gt; Implement comprehensive monitoring for the backend API including metrics collection, centralized logging, and distributed tracing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CI/CD Pipeline:&lt;/strong&gt; Deploy to cloud infrastructure using automated CI/CD pipelines with GitHub Actions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security Enhancements:&lt;/strong&gt; Add SSL/TLS termination at the Nginx layer to secure API communications&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>express</category>
      <category>nginx</category>
      <category>docker</category>
      <category>api</category>
    </item>
    <item>
      <title>Networking: The Essential Foundation for DevOps Engineering</title>
      <dc:creator>Obaseki Noruwa</dc:creator>
      <pubDate>Wed, 07 May 2025 10:20:30 +0000</pubDate>
      <link>https://dev.to/noruwa/networking-the-essential-foundation-for-devops-engineering-14d1</link>
      <guid>https://dev.to/noruwa/networking-the-essential-foundation-for-devops-engineering-14d1</guid>
      <description>&lt;h2&gt;
  
  
  Understanding the Networking Basics
&lt;/h2&gt;

&lt;p&gt;Have you ever wondered what truly separates exceptional DevOps engineers from the rest? Networking. Yes, Basic understanding of Networking, it isn't just helpful—it's absolutely essential. In today's interconnected world where microservices, containers, and distributed systems dominate the landscape, a solid understanding of networking principles is required.&lt;/p&gt;

&lt;p&gt;Before diving into the technical depths of networking for DevOps, let me share why this knowledge has become non-negotiable in our field, Networking knowledge is crucial in DevOps for several key reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure Management:&lt;/strong&gt; DevOps engineers need to design, deploy, and maintain network architectures that support modern cloud and hybrid applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Troubleshooting:&lt;/strong&gt; When issues arise in complex systems, understanding network connectivity, protocols, and routing is essential for rapid diagnosis and resolution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security Implementation:&lt;/strong&gt; DevOps professionals must implement proper network security controls, including firewalls, VPNs, and proper subnet isolation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD Pipeline Configuration:&lt;/strong&gt; Ensuring your build and deployment pipelines have proper network connectivity and security.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before diving into DevOps-specific networking, I have found that mastering the fundamentals is crucial. Let me explain the key components and concepts I have come to understand:&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Hardware Components:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hubs:&lt;/strong&gt; Hardware networking devices that transmit data to all devices connected to them, regardless of the intended recipient&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Switches:&lt;/strong&gt; Intelligent networking devices that transmit data to specific devices using MAC addresses, making them more efficient than hubs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adapters:&lt;/strong&gt; Used for connecting devices to a network, converting data between the device and the network&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ethernet:&lt;/strong&gt; The most standard method of wired data transfer in local networks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Media - Cable or WAP:&lt;/strong&gt; Data transferred through physical cables or wireless medium (Wireless Access Point - a device that allows other devices to connect using WiFi; Wireless Fidelity)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Essential Networking Concepts:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data:&lt;/strong&gt; Information transmitted across networks that enables usage by various applications and services&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nodes:&lt;/strong&gt; End devices in a network, such as computers, servers, printers, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frames:&lt;/strong&gt; Data packets that exist on the data link layer of the OSI model, containing addressing and error-checking information&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client:&lt;/strong&gt; A computer, device, or software that requests resources from a server&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server:&lt;/strong&gt; A computer or device that provides resources to clients&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Peer:&lt;/strong&gt; A device that acts as either a client or server, sharing resources without a centralized server (common in P2P networks)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IP Addresses:&lt;/strong&gt; Unique numerical identifiers assigned to devices on a network (explained further below)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MAC Addresses:&lt;/strong&gt; Hardware-based addresses permanently assigned to network interfaces (detailed later)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Firewalls:&lt;/strong&gt; Sets of rules that secure and monitor incoming and outgoing traffic on a device or network&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intranet:&lt;/strong&gt; An internal network where devices within an organization have access to shared resources&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extranet:&lt;/strong&gt; A controlled network that allows authorized external users to access an organization's internal network&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With these fundamentals in mind, I have identified eight key networking concepts that every DevOps Engineer should thoroughly understand:&lt;/p&gt;

&lt;h2&gt;
  
  
  The Eight Critical Networking Pillars for DevOps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Open System Interconnection (OSI) Models
&lt;/h3&gt;

&lt;p&gt;I have learned that the OSI model explains how computers communicate through seven distinct layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Physical Layer:&lt;/strong&gt; Transmits raw bit streams through physical media like hubs, switches, adapters, Ethernet, and cables&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Link Layer:&lt;/strong&gt; Manages packet transmission between network devices using frames that contain paths, source/destination information via MAC addresses, payload data, and error-checking information&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network Layer:&lt;/strong&gt; Determines the optimal path for data to follow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transport Layer:&lt;/strong&gt; Handles data transmission using protocols like TCP and UDP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Session Layer:&lt;/strong&gt; Maintains connections between devices, handling authentication and permissions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Presentation Layer:&lt;/strong&gt; Prepares data in a format applications can use&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application Layer:&lt;/strong&gt; Enables data usage by various applications and services&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Protocols: The Language of Networks
&lt;/h3&gt;

&lt;p&gt;Protocols are essential rule sets that govern network communication. Protocols types below:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TCP (Transmission Control Protocol):&lt;/strong&gt; Establishes a reliable connection with the destination device before sending data, ensuring everything arrives correctly. This is the foundation for most web applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UDP (User Datagram Protocol):&lt;/strong&gt; This is a connectionless protocol, it follows a "fire and forget" approach. While less reliable than TCP, it offers lower latency—perfect for applications like gaming and streaming services (Netflix, Twitch).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IP (Internet Protocol):&lt;/strong&gt; Assigns unique addresses to devices, enabling internet connectivity. Understanding both IPv4 (32-bit, four decimal format separated by periods) and IPv6 (128-bit, hexadecimal format separated by colons) has been crucial in my work.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Ports: The Doorways for Application Communication
&lt;/h3&gt;

&lt;p&gt;Ports function as communication endpoints that allow devices to send and receive data across various services. If you are reading this article, have you ever wondered why we can spin up multiple ports of frontend, backend, databases all at once? Say we have five React.js frontend projects on our local machine and we run the dev script from package.json 'npm run dev' - the first port will be localhost:3000, second will be localhost:3001, ... to localhost:3004. Here we have ports 3000, 3001, 3002, 3003, 3004 sending and receiving data in our system seamlessly. And then if we want to spin up a backend project with port 3000, it will give an error of 'Port in use' and then probably use a port available will be used or you as a user will assign it an unused port, say 3005.&lt;/p&gt;

&lt;p&gt;Some critical standard ports include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;FTP: File Transfer Protocol - 20, SFTP - Secure File Transfer Protocol 21 (for secure file transfers)&lt;/li&gt;
&lt;li&gt;SSH: Secure Shell - 22 (for secure remote access)&lt;/li&gt;
&lt;li&gt;SMTP: Simple Mail Transfer Protocol - 25 (for email transmission)&lt;/li&gt;
&lt;li&gt;DNS: Domain Name Systems - 53 (AWS named their service Route 53 for this reason, i think 😄)&lt;/li&gt;
&lt;li&gt;HTTP: Hyper Text Transfer Protocol - 80 (standard web traffic)&lt;/li&gt;
&lt;li&gt;HTTPS: Hyper Text Transfer Protocol Secure - 443 (secure web traffic)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Routers: The Traffic Directors
&lt;/h3&gt;

&lt;p&gt;Routers connect network devices and manage data transmission between them. They perform routing operations using routing tables—specialized databases stored in the router that contain paths, source/destination information, and optimal data travel routes.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Domain Name Systems (DNS): Making the Internet Human-Friendly
&lt;/h3&gt;

&lt;p&gt;DNS translates human-readable domain names (like google.com) into machine-readable IP addresses. As humans, we can't easily remember complex IP formats like 192.168.1.1 (IPv4) or 2001:0db8:85a3:0000:0000:8a2e:0370:7334 (IPv6), making DNS essential for usability.&lt;/p&gt;

&lt;p&gt;DNS offers additional benefits like caching (faster response times) and request redirection. A deep understanding of DNS system record types is required for a DevOps Engineer: A, AAAA, CName, DName, NS, MX records:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A Record:&lt;/strong&gt; Maps a domain name to an IPv4 address&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AAAA Record:&lt;/strong&gt; Maps a domain name to an IPv6 address&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CNAME Record:&lt;/strong&gt; Creates an alias from one domain to another, e.g myweb.com will redirect to web.com.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DNAME Record:&lt;/strong&gt; Redirects all subdomains of one domain to another domain&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NS Record:&lt;/strong&gt; Specifies the authoritative nameservers for a domain&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MX Record:&lt;/strong&gt; Directs email to the appropriate mail servers&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. Subnetting: Organizing IP Space Efficiently
&lt;/h3&gt;

&lt;p&gt;I have learned that subnetting divides larger IP address blocks into smaller, more manageable segments. This practice improves network organization, security, and performance—all critical aspects of DevOps infrastructure management.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Virtual Private Networks (VPNs): Securing Connections
&lt;/h3&gt;

&lt;p&gt;VPNs create secure tunnels for internet connections, encrypting data as it travels through servers. This technology is crucial in DevOps Engineering, for instance a work with teams distribute globally and require secure access to sensitive resources.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Essential Networking Tools
&lt;/h3&gt;

&lt;p&gt;The diagnostic tools I rely on daily include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ipconfig&lt;/strong&gt; (Windows) and &lt;strong&gt;ifconfig&lt;/strong&gt; (Linux) for viewing network interface configurations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;netstat&lt;/strong&gt; for examining network connections and routing tables&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ping&lt;/strong&gt; for testing basic connectivity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;curl&lt;/strong&gt; for transferring data with URLs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;nslookup&lt;/strong&gt; for querying DNS servers&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Putting It All Together
&lt;/h2&gt;

&lt;p&gt;Understanding these networking concepts hasn't just expanded my knowledge—it's transformed how I approach DevOps engineering. Each component interconnects with others to create the foundation upon which our modern cloud infrastructure runs.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>cloudcomputing</category>
      <category>networking</category>
      <category>continuouslearning</category>
    </item>
    <item>
      <title>My Understanding of DevOps Engineering</title>
      <dc:creator>Obaseki Noruwa</dc:creator>
      <pubDate>Fri, 02 May 2025 14:35:15 +0000</pubDate>
      <link>https://dev.to/noruwa/my-understanding-of-devops-engineering-383f</link>
      <guid>https://dev.to/noruwa/my-understanding-of-devops-engineering-383f</guid>
      <description>&lt;h2&gt;
  
  
  What is DevOps?
&lt;/h2&gt;

&lt;p&gt;DevOps, as the name suggests, combines Development and Operations into a unified approach. A DevOps Engineer orchestrates the entire journey of an application: planning, coding, building, testing, releasing, deploying, and monitoring. This comprehensive process ensures applications work seamlessly for end-users and integrate properly with other services.&lt;/p&gt;

&lt;p&gt;I see DevOps Engineers as master planners who understand the complete Software Development Life Cycle (SDLC). Success in this role requires both technical expertise and strong communication skills. Communication becomes crucial especially when coordinating across different teams – from developers to stakeholders.&lt;/p&gt;

&lt;h2&gt;
  
  
  The DevOps Lifecycle
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Planning
&lt;/h3&gt;

&lt;p&gt;Planning begins with constructive thinking about the development and production environments where code will be built. For example, imagine a client named Alex who needs a web-based analytical platform for Business Intelligence. The DevOps Engineer would need to carefully consider all technical components.&lt;/p&gt;

&lt;p&gt;Drawing on development knowledge, the engineer would select appropriate libraries and services for Alex's project specific needs. This means evaluating both private and open-source packages, and choosing between established cloud platforms like AWS, Azure, GCP, DigitalOcean, Linode, and Oracle.&lt;/p&gt;

&lt;p&gt;After this critical thinking phase, development can move forward confidently. For Alex's theoretical project, React.js might be ideal for the frontend (a robust and popular library), FastAPI for the backend (which offers flexibility as an unopinionated framework), along with essential services including storage, databases, compute resources, networking, and Content Delivery Network (CDN) capabilities. This thorough planning establishes the foundation for the entire SDLC.&lt;/p&gt;

&lt;h3&gt;
  
  
  Coding
&lt;/h3&gt;

&lt;p&gt;During the coding stage, development teams work collaboratively to create the components that form the business logic of the application. This typically involves frontend developers, backend developers, and database administrators working in concert. Additional team members often include project managers, data analysts, and data scientists who provide specialized expertise.&lt;/p&gt;

&lt;p&gt;The DevOps Engineer's role during this phase involves ensuring these diverse teams can work efficiently within well-structured environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building, Testing, Releasing, and Deploying
&lt;/h3&gt;

&lt;p&gt;These phases represent the core of the SDLC, where source code is transformed through validation and formatting into a production-ready application that serves end-users. This process, known as the CI/CD Pipeline (Continuous Integration/Continuous Delivery or Deployment), is where significant automation occurs.&lt;/p&gt;

&lt;p&gt;By automating the software development workflow, DevOps makes development less stressful and reduces complexity for the entire team. During this process, testing protocols identify potential issues before they reach production, significantly improving code quality.&lt;/p&gt;

&lt;p&gt;Various CI/CD tools can be utilized depending on project requirements. These include GitHub Actions, GitLab, BitBucket, Jenkins, CircleCI, and ArgoCD. Major cloud platforms also offer their own solutions like AWS Pipeline and Azure Pipeline. Some platforms, such as GitLab and BitBucket, provide built-in CI/CD capabilities that streamline the process by reducing integration complexity.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Mechanics of CI/CD
&lt;/h4&gt;

&lt;p&gt;Continuous Integration involves merging all code committed to a shared repository (like GitHub or GitLab). Each time a developer commits or merges code, automated tests verify its quality. This Continuous Testing approach includes four critical testing types:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unit Testing&lt;/strong&gt; – Verifies individual code units and methods function as expected. For frontend code, tools like Jest or Mocha test specific components within the source repository.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integration Testing&lt;/strong&gt; – Confirms that modules, services, and components work together correctly. This testing ensures different parts of the application communicate and function cohesively.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Regression Testing&lt;/strong&gt; – When a build test fails (whether unit or integration), regression testing determines if errors from previous builds persist. This prevents old bugs from reappearing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Code Quality Testing&lt;/strong&gt; – Evaluates code against established standards. For example, if a junior developer uses 'var' instead of 'const' for a scoped variable, tools like SonarQube or Qodana can automatically flag this issue without requiring senior developers to manually review every line of code, Checkout &lt;a href="https://thectoclub.com/tools/best-code-analysis-tools" rel="noopener noreferrer"&gt;thectoclub&lt;/a&gt; for other code quality tools.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The final stage of the CI/CD Pipeline is Continuous Deployment/Delivery (CD). At this point, successful builds are published to an Artifact registry (Docker Hub, Nexus, AWS ECS - Elastic Container Service), Testing environment, or Production environment. This constitutes the actual application release that users will experience.&lt;/p&gt;

&lt;p&gt;During this phase, Infrastructure Provisioning is implemented using tools like Terraform or Pulumi. This creates and configures the precise environment and services needed to run the application efficiently. This infrastructure-as-code (IaC) approach allows for upgrading resources or removing unused services as required.&lt;/p&gt;

&lt;h3&gt;
  
  
  Monitoring
&lt;/h3&gt;

&lt;p&gt;Continuous monitoring of both the production environment and application is essential to DevOps practice. This vigilance helps detect anomalies and analyze traffic patterns before they impact users.&lt;/p&gt;

&lt;p&gt;The consequences of inadequate monitoring can be severe: service downtime, customer loss, and unexpectedly high cloud infrastructure costs. To prevent these issues, specialized tools simplify the monitoring process like CloudWatch service from AWS.&lt;/p&gt;

&lt;p&gt;Prometheus collects critical metrics like CPU and memory usage, while Grafana transforms this data into intuitive visualizations. Combining these tools creates a powerful system for tracking application resource usage. For more detailed analysis, the Elastic Logstash Kibana (ELK) stack provides comprehensive metrics with advanced search capabilities. Kibana serves as the visualization layer for this rich data.&lt;/p&gt;

&lt;h2&gt;
  
  
  The DevOps Impact
&lt;/h2&gt;

&lt;p&gt;Through my understanding of these DevOps practices, I can see how proper planning, automation, and monitoring can transform application development and deployment. This systematic approach not only improves technical operations but also delivers tangible business benefits through faster, more reliable software delivery.&lt;/p&gt;

&lt;p&gt;What aspects of DevOps do you find most valuable in your work? I would love to connect with fellow professionals interested in this field!&lt;/p&gt;

</description>
      <category>devops</category>
      <category>cloudcomputing</category>
      <category>cicd</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Animated Hamburger Menu with Tailwindcss</title>
      <dc:creator>Obaseki Noruwa</dc:creator>
      <pubDate>Sun, 02 Apr 2023 12:43:30 +0000</pubDate>
      <link>https://dev.to/noruwa/animated-hamburger-menu-with-tailwindcss-1j0b</link>
      <guid>https://dev.to/noruwa/animated-hamburger-menu-with-tailwindcss-1j0b</guid>
      <description>&lt;p&gt;Most developer use svg hamburger menu icon when developing hamburger menu for their frontend web project, in this post i will show you how to build hamburger menu with animation in tailwindcss.&lt;/p&gt;

&lt;p&gt;We are to create three horizontal line stacked vertically, to resemble an hamburger. Below is a graphical representation of the hamburger menu with animation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn0m1bpi2bgsr5d51d9vs.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn0m1bpi2bgsr5d51d9vs.PNG" alt="Hamburger Menu Image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSS&lt;/strong&gt;&lt;br&gt;
Create two div tags, one outer and the other inner div. we focus on the inner div tag by giving a width of 4rems &lt;code&gt;w-16&lt;/code&gt;, height &lt;code&gt;h-2&lt;/code&gt;, background-color &lt;code&gt;bg-black&lt;/code&gt; and border-radius &lt;code&gt;rounded-full&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2qzk49ckj0k2afk4yc6r.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2qzk49ckj0k2afk4yc6r.PNG" alt="Div Class"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhhhy94eolcktklbvl3kt.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhhhy94eolcktklbvl3kt.PNG" alt="Div Width &amp;amp; Height"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next step will be to create the div pseudo-elements (&amp;amp;::before, &amp;amp;::after). &lt;/p&gt;

&lt;p&gt;To create the div ::before pseudo-element, we write the following tailwindcss utility classes &lt;code&gt;before:content-[‘’]&lt;/code&gt;, &lt;code&gt;before:absolute&lt;/code&gt;, &lt;code&gt;before:w-16&lt;/code&gt;, &lt;code&gt;before:h-2&lt;/code&gt;, &lt;code&gt;before:bg-black&lt;/code&gt;, &lt;code&gt;before:rounded-full&lt;/code&gt;, &lt;code&gt;before:-translate-y-4&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnhvo3z7nnsu3bzxkidde.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnhvo3z7nnsu3bzxkidde.PNG" alt="Before Pseudo-Element"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxh68xw1ylk0u023b2f76.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxh68xw1ylk0u023b2f76.PNG" alt="Before Pseudo-Element Image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the ::after pseudo element, we copy the code from the ::before pseudo element above, but this time we remove the negative sign from the start of the translate-y-4 tailwindcss utility class: We replace &lt;code&gt;before:-translate-y-4&lt;/code&gt; with &lt;code&gt;after:translate-y-4&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ngfr097xmy9f41ms3rc.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ngfr097xmy9f41ms3rc.PNG" alt="After Pseudo-Element Image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feqbickael9e7qopv3sjw.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feqbickael9e7qopv3sjw.PNG" alt="After Pseudo-Element Image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JavaScript&lt;/strong&gt;&lt;br&gt;
We add an id to our outer div to enable us have a mouseEvent (click) and have a reference to the outer div.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgblvn47ccla4vxr06ryy.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgblvn47ccla4vxr06ryy.PNG" alt="Outer div id"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzzu9izqvhytfe8xqfota.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzzu9izqvhytfe8xqfota.PNG" alt="JavaScript Code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We add the following tailwindcss utility class to be applied to the hamburger-toggle class: &lt;code&gt;[&amp;amp;&amp;gt;div]:h-0 [&amp;amp;&amp;gt;div]:bg-white [&amp;amp;&amp;gt;div::before]:before:translate-y-0 [&amp;amp;&amp;gt;div::before]:before:rotate-45 [&amp;amp;&amp;gt;div::before]:after:translate-y-0 [&amp;amp;&amp;gt;div::before]:after:-rotate-45&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9w7vmtgun7o4w9c9sjts.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9w7vmtgun7o4w9c9sjts.PNG" alt="ToggleMenu Utility Class"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, we add some transition properties to the div and div pseudo-elements (&amp;amp;::before, &amp;amp;::after) for smooth animation, &lt;code&gt;transition-all duration-150&lt;/code&gt;, &lt;code&gt;before:transition-all before:duration-150&lt;/code&gt;, &lt;code&gt;after:transition-all after:duration-150&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8wibnzzrfsslx0t8ao66.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8wibnzzrfsslx0t8ao66.PNG" alt="Full Code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdotgvqze2zw4sqnproke.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdotgvqze2zw4sqnproke.PNG" alt="Final Image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope this tutorial helped you understand how to create an hamburger menu with tailwindcss. If you do not understand the concept and the utility classes of tailwindcss, please visit &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;tailwindcss&lt;/a&gt; website for better understanding and best practices when using the css framework. &lt;/p&gt;

&lt;p&gt;Here is the link to the hamburger menu code on stackblitz: &lt;a href="https://stackblitz.com/edit/web-platform-bsycn4?file=index.html" rel="noopener noreferrer"&gt;click me&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>Folder Structure for Modern Web Applications</title>
      <dc:creator>Obaseki Noruwa</dc:creator>
      <pubDate>Sat, 01 Apr 2023 15:52:01 +0000</pubDate>
      <link>https://dev.to/noruwa/folder-structure-for-modern-web-applications-4d11</link>
      <guid>https://dev.to/noruwa/folder-structure-for-modern-web-applications-4d11</guid>
      <description>&lt;p&gt;It is critical to create a maintainable folder structure while developing web apps, having the right files in the correct folder helps organize your code and makes other developers have an idea of how the architecture of your web application is or will be during development. In this post, I am going to explain some folder names when building your modern web project.&lt;/p&gt;

&lt;p&gt;Maintaining a well-organized folder structure is crucial when developing web applications, even though it may not be the first thing that comes to mind when working alone or with few resources. If not, you run the risk of coming across as unprofessional.&lt;/p&gt;

&lt;h4&gt;
  
  
  Some Tips In Designing Your Folder Structure
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Understand the purpose of your web project: In order to figure out how to organize your web project, you will need to establish a good understanding of what you have, depending on how many assets you are trying to organize and the features in your web applications.&lt;/li&gt;
&lt;li&gt;Use proper naming convention for your folders and files, they should be descriptive of the purpose in your web application.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Folder Structures and their explanation
&lt;/h4&gt;

&lt;p&gt;&lt;u&gt;Assets&lt;/u&gt;&lt;br&gt;
The assets folder contains all images, icons, css files, font files, etc. that will be used in your web application. Custom images, icons, paid fonts are being placed inside this folder. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbosdpni04f4rhoscokrl.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbosdpni04f4rhoscokrl.PNG" alt="Assets" width="141" height="129"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Context&lt;/u&gt;&lt;br&gt;
When using React Js as your preferred frontend ui library, the context folder stores all your react context files that are used across components and multiple pages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F34ah8q7qbthfe5pbkcbf.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F34ah8q7qbthfe5pbkcbf.PNG" alt="Context" width="232" height="81"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Components&lt;/u&gt;&lt;br&gt;
The components folder holds the UI for your application. It contains all our UI components like navbar, footer, buttons, modals, cards, etc. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0fsm5cd609kxc1ydcv4b.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0fsm5cd609kxc1ydcv4b.PNG" alt="Components" width="174" height="228"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Composables&lt;/u&gt; &lt;br&gt;
In the context of Vue applications, a "composable" is a function that leverages Vue's Composition API to encapsulate and reuse stateful logic.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Data&lt;/u&gt;&lt;br&gt;
The data folder is used for storing text data which will be used in different sections and pages as JSON files. Doing this will enable updating of information easier.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F74ey2c253fveerw4ox3y.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F74ey2c253fveerw4ox3y.PNG" alt="Data JSON" width="234" height="60"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmybd8n92pxns26feb6qt.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmybd8n92pxns26feb6qt.PNG" alt="Data" width="252" height="344"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Features&lt;/u&gt;&lt;br&gt;
This folder contains individual folder feature for each page (authentication, theme, modals). For example each page might have a modal feature.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgljjlh0jgarivzabdamm.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgljjlh0jgarivzabdamm.PNG" alt="Features" width="221" height="130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Hooks&lt;/u&gt;&lt;br&gt;
Hooks are functions that let you “hook into” React state and lifecycle features from function components. Also we can create custom hooks whose name starts with 'use' and can be used to call other hooks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa84dq8pahtjgff63ru7e.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa84dq8pahtjgff63ru7e.PNG" alt="Hooks" width="233" height="63"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Layouts&lt;/u&gt;&lt;br&gt;
When defining the general look and feel of the web page, the Layouts folder comes in handy. It is used to place layout-based components such as the sidebar, navbar, and footer. If your web application has many layouts, this folder is a fantastic place to save them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6h73gy0uruci8qlq5sjl.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6h73gy0uruci8qlq5sjl.PNG" alt="Layouts" width="229" height="102"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Modules&lt;/u&gt;&lt;br&gt;
Modules folder handles specific tasks in your application. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fboeni6zfudcg14201s87.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fboeni6zfudcg14201s87.PNG" alt="Modules" width="224" height="111"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Pages&lt;/u&gt;&lt;br&gt;
The pages directory contains your web application views. Pages directory in frontend frameworks like Next Js and Nuxt Js reads all files inside the directory and automatically creates the router configuration for you.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Public&lt;/u&gt;&lt;br&gt;
The public directory is directly served at the server root and contains public files that won't change e.g favicon.ico.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Routes&lt;/u&gt;&lt;br&gt;
The routes folder is just a place in your web application to store the routes path to different screens.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Utility/Utils&lt;/u&gt;&lt;br&gt;
This folder is for storing all utility functions, such as auth, theme, handleApiError, etc.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Views&lt;/u&gt;&lt;br&gt;
Views folder are like the pages folder, The views are used to represent your pages properly, that users can navigate back and forth.&lt;/p&gt;

&lt;h4&gt;
  
  
  Conclusion
&lt;/h4&gt;

&lt;p&gt;A good folder structure allows you and other developers to find files faster and manage them more easily. A well-organized folder structure makes you appear professional.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Understanding Errors In JavaScript: Error Objects</title>
      <dc:creator>Obaseki Noruwa</dc:creator>
      <pubDate>Wed, 22 Mar 2023 11:13:18 +0000</pubDate>
      <link>https://dev.to/noruwa/understanding-errors-in-javascript-error-objects-3db4</link>
      <guid>https://dev.to/noruwa/understanding-errors-in-javascript-error-objects-3db4</guid>
      <description>&lt;p&gt;When executing JavaScript code, different errors can occur, understanding errors in javascript cannot be overstated. Errors can occur due to wrong input, and other unforeseeable things. Error objects are in-built in javascript to enable coders/programmers know and understand their errors for easier debugging where necessary. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What are Error Objects&lt;/strong&gt;&lt;br&gt;
An error object provides error information when an error occurs. Error object has a collection of properties: name, message, file name, line number. These properties helps us have a better understanding of the problem.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mOCCpNdL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jfw0q7qtnwditbacc06r.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mOCCpNdL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jfw0q7qtnwditbacc06r.PNG" alt="Image description" width="248" height="60"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G7RD5JuV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fdvag7a2l6jsbrou163m.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G7RD5JuV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fdvag7a2l6jsbrou163m.PNG" alt="Image description" width="671" height="17"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the image above, SyntaxError is the error name, Invalid or unexpected token is the error description. At the right hand side we have the file name and line number.&lt;/p&gt;

&lt;p&gt;Understanding error object properties helps you understand the problem faster for easier debugging. Below are some errors you will likely run into while executing javascript code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EvalError&lt;/strong&gt;: This occurs when the eval() inbuilt function is used in a way that is not allowed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ioBRn9ww--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cykon7qtgsq1sj88pj72.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ioBRn9ww--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cykon7qtgsq1sj88pj72.PNG" alt="Image description" width="384" height="136"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Hp1pxd4e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lviu1grnb53zpid1cam6.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Hp1pxd4e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lviu1grnb53zpid1cam6.PNG" alt="Image description" width="664" height="30"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An Error object; EvalError is thrown in the try block. The error is caught in the catch block and its stack trace is logged to the console using our ultimate debugger method (console.log). The output is produced with the name, description, file name and line number.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ReferenceError&lt;/strong&gt;: This occurs when referencing a variable that does not exist or has not yet been initialized in the current scope.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--44xqhCNv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y6qmw401ggsk3wd5hjg2.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--44xqhCNv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y6qmw401ggsk3wd5hjg2.PNG" alt="Image description" width="289" height="80"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gI9psvNM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qmafx3fmvboys5dojbch.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gI9psvNM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qmafx3fmvboys5dojbch.PNG" alt="Image description" width="670" height="33"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the above example, the variable fulname does not exist. Fixing an error like this, is to cross check the spellings and analyze the code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TypeError&lt;/strong&gt;: This error occurs when a variable or parameter is not of a valid type or is not of the expected data type.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--C75ysaLJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gn7c1hz6q7nd34qreyfh.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--C75ysaLJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gn7c1hz6q7nd34qreyfh.PNG" alt="Image description" width="206" height="83"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SUrn8UiQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vuih5et3zbu5sllus2p9.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SUrn8UiQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vuih5et3zbu5sllus2p9.PNG" alt="Image description" width="671" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RangeError&lt;/strong&gt;: An RangeError is thrown when a numeric variable or parameter is outside its valid range.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YtRhSkuA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/czpm8oeeftak9wcshb7y.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YtRhSkuA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/czpm8oeeftak9wcshb7y.PNG" alt="Image description" width="262" height="78"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aij3Fy2f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9bdj6evwymjhk3ry0wnt.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aij3Fy2f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9bdj6evwymjhk3ry0wnt.PNG" alt="Image description" width="670" height="36"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;URIError&lt;/strong&gt;: A URIError error object is thrown if you use illegal characters in a URI function, The error occurs due to the use of an invalid character in encoding the url.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7n1TSWCL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tvxmrp29lucak8vetavc.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7n1TSWCL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tvxmrp29lucak8vetavc.PNG" alt="Image description" width="458" height="74"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PEmqyxwG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gir1kctl7xdfgmxz44lp.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PEmqyxwG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gir1kctl7xdfgmxz44lp.PNG" alt="Image description" width="670" height="49"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
When you understand the concepts of error objects, debugging and fixing your error will be simple and this will spare you from spending hours online looking for solutions.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
