<?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: Erik Santana</title>
    <description>The latest articles on DEV Community by Erik Santana (@imerik).</description>
    <link>https://dev.to/imerik</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%2F2750418%2F043859bf-20ff-4ebe-be49-0c10a2da8ab8.jpg</url>
      <title>DEV Community: Erik Santana</title>
      <link>https://dev.to/imerik</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/imerik"/>
    <language>en</language>
    <item>
      <title>Creating a reverse proxy and load balancer in 2 minutes using Caddy</title>
      <dc:creator>Erik Santana</dc:creator>
      <pubDate>Fri, 24 Jan 2025 22:13:29 +0000</pubDate>
      <link>https://dev.to/imerik/creating-a-reverse-proxy-and-load-balancer-in-10-minutes-using-caddy-4ppd</link>
      <guid>https://dev.to/imerik/creating-a-reverse-proxy-and-load-balancer-in-10-minutes-using-caddy-4ppd</guid>
      <description>&lt;h2&gt;
  
  
  Setting Up Your Computer:
&lt;/h2&gt;

&lt;p&gt;To perform what will be demonstrated in this example, you'll need these tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node 22: &lt;a href="https://nodejs.org/pt/blog/release/v22.11.0" rel="noopener noreferrer"&gt;https://nodejs.org/pt/blog/release/v22.11.0&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Caddy: &lt;a href="https://caddyserver.com/docs/install" rel="noopener noreferrer"&gt;https://caddyserver.com/docs/install&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction:
&lt;/h2&gt;

&lt;p&gt;Two well-known approaches in DevOps are reverse proxy and load balancer. Let's understand them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reverse proxy:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A Reverse Proxy is an approach where a server receives requests and acts as middleware with conditions and overrides to forward to a specific server. After the server responds, the reverse proxy is responsible for responding to the end user.&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%2Fay62893ipfnl54dt7hdy.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%2Fay62893ipfnl54dt7hdy.png" alt="Image description" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the example above, the user makes a request to localhost:8080 or service2.com.br, and the reverse proxy will work based on its conditions, which in this case would be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If a header "x-service-1" exists, it will call Service 1&lt;/li&gt;
&lt;li&gt;If the host is "service2.com.br", it will call Service 2&lt;/li&gt;
&lt;li&gt;If the path contains "/test", it will call Service 3&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A use case for using a reverse proxy is when you don't want to expose multiple domains to the internet or when these applications are on a private network. In this scenario, you can leave only your reverse proxy public while keeping the applications private.&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%2Fjurlmsht79i3qkub39ux.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%2Fjurlmsht79i3qkub39ux.png" alt="Image description" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this scenario, all Services are private, meaning you cannot access them directly. However, you use the reverse proxy to make calls using a single domain: api.domain.com&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Load balancer:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Load balancer is an approach used to handle multiple instances of a single application (or multiple applications with certain conditions, though this approach is not ideal and is typically used to reduce costs).&lt;/p&gt;

&lt;p&gt;Similar to a reverse proxy, the key difference with a Load Balancer is that it uses algorithms to decide which instance to call. Consider an example:&lt;/p&gt;

&lt;p&gt;Suppose you have an API with 4 instances. How would you distribute traffic effectively to prevent one instance from being overloaded while another remains idle?&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%2Flb53lie6gcwtfiim999d.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%2Flb53lie6gcwtfiim999d.png" alt="Image description" width="800" height="538"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using a Load Balancer solves this problem, as you can employ the most common algorithm, Round Robin, which is equitable and efficient in distributing traffic.&lt;/p&gt;

&lt;p&gt;Unlike a reverse proxy, a Load Balancer points to a single application, distributing traffic equally and avoiding instance overload.&lt;/p&gt;

&lt;p&gt;Another interesting point about Load Balancer is that we can specify a route that it can access periodically to check if the server is up. If the server is not running, the Load Balancer will not distribute traffic to the broken server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Are they the same thing?
&lt;/h2&gt;

&lt;p&gt;Definitely not. A load balancer can point to a reverse proxy, which in turn points to N load balancers, and many other existing scenarios.&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%2Fe411g5tt7hx64m3idlg7.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%2Fe411g5tt7hx64m3idlg7.png" alt="Image description" width="800" height="662"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting into Practice:
&lt;/h2&gt;

&lt;p&gt;Now that you've learned about reverse proxy and load balancer, it's time to implement a basic example using Caddy and Node.js.&lt;/p&gt;

&lt;p&gt;We'll use Caddy to create a server that will act as a reverse proxy and balance load using round-robin, and Node.js to create multiple instances of the same API.&lt;/p&gt;

&lt;p&gt;Starting with Node.js, we'll create two files: &lt;strong&gt;server.js&lt;/strong&gt; and &lt;strong&gt;start_workers.js&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  For server.js (which creates a simple server):
&lt;/h4&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;workerData&lt;/span&gt; &lt;span class="p"&gt;}&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;node:worker_threads&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;http&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;node:http&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sleep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ms&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="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&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;ms&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// We use sleep to get a real example of a request that takes 2 seconds to respond&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Hello, this is the same API in different instance &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;workerData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instanceId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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="nf"&gt;writeHead&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="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&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="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="nx"&gt;data&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Server is running on port &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;workerData&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;server&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;workerData&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will start on the port passed by the parent process&lt;br&gt;
Each call will display a message showing the instance ID&lt;/p&gt;
&lt;h4&gt;
  
  
  For start_workers.js:
&lt;/h4&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Worker&lt;/span&gt; &lt;span class="p"&gt;}&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;node:worker_threads&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;path&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;node:path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;server.js&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="na"&gt;workerData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8081&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;instanceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;i&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;It will create 5 workers&lt;/li&gt;
&lt;li&gt;Each worker will be an API running on different ports: &lt;strong&gt;:8081, :8082, :8083, :8084, :8085&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Each worker will have a corresponding ID: 1, 2, 3, 4, 5&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To use Caddy, we'll create a file called &lt;strong&gt;Caddyfile&lt;/strong&gt; with the following configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    admin 0.0.0.0:5555
}

:8080 {
    reverse_proxy :8081 :8082 :8083 :8084 :8085 {
        lb_policy round_robin
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above file means we'll receive requests on port &lt;strong&gt;:8080&lt;/strong&gt;, and Caddy should perform reverse proxy to ports &lt;strong&gt;:8081, :8082, :8083, :8084, :8085&lt;/strong&gt;. Additionally, we specify that the Load Balancer will use Round Robin to decide which instance to call.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running the Project
&lt;/h2&gt;

&lt;p&gt;Once these three files are created, open 3 terminals in the project folder:&lt;/p&gt;

&lt;p&gt;First terminal, start the Caddy server:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;caddy run&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Second terminal, start Node servers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;node start_workers.js&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Third terminal, use autocannon to create parallel requests:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;npx --yes autocannon &lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To stop Caddy server, remember to run:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;caddy stop&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This command calls the reverse proxy, which will distribute traffic equally among our 5 Node servers.&lt;/p&gt;

&lt;p&gt;You'll see something like:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/pdJSMbjYe5Q"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;As you can see, even without directly calling ports :8081, :8082, :8083, :8084, :8085, the reverse proxy distributed traffic equally without overloading any server.&lt;/p&gt;

&lt;p&gt;If you can't reproduce this, you can verify the implementation in the GitHub repository: &lt;a href="https://github.com/ekerdev/example-reverse-proxy-and-load-balancer" rel="noopener noreferrer"&gt;https://github.com/ekerdev/example-reverse-proxy-and-load-balancer&lt;/a&gt;&lt;/p&gt;

</description>
      <category>lb</category>
      <category>proxy</category>
      <category>node</category>
      <category>caddy</category>
    </item>
    <item>
      <title>Understanding Server-Side Rendering Like a Pro</title>
      <dc:creator>Erik Santana</dc:creator>
      <pubDate>Fri, 24 Jan 2025 08:47:57 +0000</pubDate>
      <link>https://dev.to/imerik/understanding-server-side-rendering-like-a-pro-2oni</link>
      <guid>https://dev.to/imerik/understanding-server-side-rendering-like-a-pro-2oni</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;If you are a developer, especially one working in Front-end development, you probably know that the most modern way of building applications today is by using Server-Side Rendering, commonly known as SSR. This approach significantly enhances your site's indexation (SEO) across key market players.&lt;/p&gt;

&lt;p&gt;As with everything in programming, SSR has its pros and cons. For you, the developer who may only be familiar with its advantages, I decided to list some of its disadvantages as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding SSR
&lt;/h2&gt;

&lt;p&gt;First, let’s understand why the need for server-side rendering emerged and why it’s now uncommon to see applications being built with Client-Side Rendering (CSR).&lt;/p&gt;

&lt;p&gt;No, Next.js was not the creator of SSR. In fact, long before frameworks like React, Vue, and Angular existed, the web relied on either static rendering or server-side rendering. Let’s look at a few examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Static Sites: HTML, CSS, JavaScript, and jQuery:&lt;/strong&gt;
These sites were entirely rendered in the user's browser. All the information appeared instantly on the user’s screen, and the browser executed the scripts embedded in the site to populate the screen. When you inspected the code, you would see something like this:&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  &lt;strong&gt;What user and you see&lt;/strong&gt;
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;List of best players of the world&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;fetchListOfBestPlayersOfTheWorld&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&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;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

   &lt;span class="c1"&gt;// loop to add content in html&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;fetchListOfBestPlayersOfTheWorld&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  &lt;strong&gt;First Content Paint (FCP)&lt;/strong&gt;
&lt;/h5&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%2F3fc5pvo9o7jfdb7vacbi.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%2F3fc5pvo9o7jfdb7vacbi.png" alt="Image description" width="800" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Server-Rendered Sites: PHP or JSP:&lt;/strong&gt;
These sites were rendered by the language interpreter and displayed the result on the user’s screen. This meant the information was already filled in when displayed. If you inspected the code, you’d see something like this:&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  &lt;strong&gt;What you see:&lt;/strong&gt;
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsp"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;%&lt;/span&gt;
&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PlayerDTO&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bestPlayersOfTheWorld&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;APIService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBestPlayersOfTheWorld&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="nt"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;List of best players of the world&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PlayerDTO&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;bestPlayersOfTheWorld&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;%&amp;gt;&lt;/span&gt;
   &lt;span class="c"&gt;&amp;lt;%-- loop to add content in html --%&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;%&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  &lt;strong&gt;What user see:&lt;/strong&gt;
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;List of best players of the world&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Cristiano Ronaldo&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  &lt;strong&gt;First Content Paint (FCP)&lt;/strong&gt;
&lt;/h5&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%2Fo192d8sh3o7ff5zpdr0r.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%2Fo192d8sh3o7ff5zpdr0r.png" alt="Image description" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s clear that both types of sites achieve the same goal, but the static site doesn’t render the list until it’s loaded in the browser, unlike JSP, which makes the API call on the server, renders the page in the interpreter, and only then delivers it to the user.&lt;/p&gt;

&lt;p&gt;From this, we can conclude that Next.js didn’t invent SSR. This approach has existed for years across many languages like PHP, Java (using JSP or other frameworks), ASP.NET, and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Chaos
&lt;/h2&gt;

&lt;p&gt;When React, Vue, and Angular became popular, there was a shift in the market. Nobody wanted to write countless lines of code anymore to create a basic site using jQuery, JSP, PHP, etc. Why not use these modern tools instead?&lt;/p&gt;

&lt;p&gt;And so, we humble developers abandoned those old tools and started using React, Vue, and Angular to build our websites. Now, Front-end development had a single responsibility: creating pages and reusable components while reducing the load time we used to experience with tools like jQuery and Bootstrap.&lt;/p&gt;

&lt;p&gt;Let’s explore the advantages these tools offered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code reuse that brought more readability and longevity to projects.&lt;/li&gt;
&lt;li&gt;Complete builds that eliminated unused code and improved page load times.&lt;/li&gt;
&lt;li&gt;CSS compilers that removed unused styles and added cross-browser compatibility.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pretty cool advantages, right? I agree. But we had three major issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;These tools were WORSE than static sites in terms of SEO:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Despite being similar to static sites, the modern tools didn’t write your code directly into the HTML. Instead, your site relied on JavaScript generated by library (called the bundle). After being downloaded, this bundle would inject your code into the site. For example:&lt;/p&gt;

&lt;p&gt;With these tools, we wouldn’t even see the "List of Best Players of the World" until the browser had finished downloading the bundle and executing the script, as shown in the example below:&lt;/p&gt;

&lt;h5&gt;
  
  
  &lt;strong&gt;Your code&lt;/strong&gt;
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ListOfBestPlayersOfTheWorld&lt;/span&gt; &lt;span class="o"&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;players&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useAPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listOfBestPlayersOfWorld&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

 &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
   &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;List of Best Players of the World&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;players&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;players&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;player&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="c1"&gt;// loop to add content in html&lt;/span&gt;
     &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&amp;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;h5&gt;
  
  
  &lt;strong&gt;What user see&lt;/strong&gt;
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/assets/bundle.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  &lt;strong&gt;First Content Paint (FCP)&lt;/strong&gt;
&lt;/h5&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%2Fzijumawpogk6i8bt2x7s.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%2Fzijumawpogk6i8bt2x7s.png" alt="Image description" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The build file size could exceed 100MB, causing both download and load-time slowdowns:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In combination with the previous issue, if your site was very large, the generated bundle could become excessively large, causing delays for users and potentially being slower than loading the full jQuery script.&lt;/p&gt;

&lt;p&gt;Furthermore, these tools relied on internal routing, meaning the bundle would load information for all pages, even if the user was only on the homepage, for instance.&lt;/p&gt;

&lt;p&gt;One of the solutions to address this problem was the use of Lazy Loading, which delayed content presentation for the user but broke the code into smaller secondary bundles. Additionally, CDNs with caching were employed to ensure that users would only load the bundle once (with the cache being revalidated when changes were made to the site).&lt;/p&gt;

&lt;p&gt;However, depending on the size of the primary bundle, these solutions still didn’t fully resolve the issue.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Excessive Use of JavaScript, neglecting native browser solutions (a topic addressed in the HTML-first approach):&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;How 'reacters' do&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ModalComponent&lt;/span&gt; &lt;span class="o"&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setOpen&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onToggle&lt;/span&gt; &lt;span class="o"&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="c1"&gt;// using useState that render after each change&lt;/span&gt;
  &lt;span class="nf"&gt;setOpen&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;

 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Modal&lt;/span&gt; &lt;span class="na"&gt;open&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onClose&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onToggle&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onOpen&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onToggle&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;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;strong&gt;How 'html-firsters do'&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ModalComponent&lt;/span&gt; &lt;span class="o"&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLDialogElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onOpen&lt;/span&gt; &lt;span class="o"&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="c1"&gt;// using native solutions, no rerender&lt;/span&gt;
  &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;showModal&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;

 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onClose&lt;/span&gt; &lt;span class="o"&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="c1"&gt;// using native solutions, no rerender&lt;/span&gt;
  &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;

 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;dialog&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The solution to the problem we created
&lt;/h2&gt;

&lt;p&gt;Don’t be too upset with these tools—they genuinely improved the lives of front-end developers. However, certain issues started to grow too large to ignore, such as oversized bundles that led to high CDN costs, usability problems when JavaScript failed due to state management issues, and non-existent SEO, which negatively impacted site indexing.&lt;/p&gt;

&lt;p&gt;That’s when we decided to take a step back and revisit the Server-Side Rendering (SSR) approach, using tools like Next.js, Nuxt, Qwik, Gatsby, and @angular/ssr.&lt;/p&gt;

&lt;p&gt;Now that you’ve learned a bit about how Client-Side Rendering (CSR), Server-Side Rendering (SSR), and Single Page Applications (SPAs) work, I’ll share my perspective as a senior software engineer on this approach, along with its advantages and disadvantages:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Advantages:&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Effective SEO:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since the site uses the server, you can configure all metadata () and load all or most of the site’s information before rendering it in the browser. This generates the First Content Paint, which is the moment when the indexing bot "takes a snapshot" of your code and extracts information from the HTML to index your page on search engines.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Performance:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There’s a trade-off between performing tasks on the server or delegating them to the client. If you choose the client-side approach, the user’s experience might be negatively affected, as it demands high computational resources and can cause issues if they have a poor internet connection or weak hardware. It also increases the size of the bundle.&lt;/p&gt;

&lt;p&gt;On the other hand, opting for server-side tasks improves user fluidity since the server handles the heavy lifting. This avoids overloading the user's browser and prevents generating a larger bundle.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Server Network Optimization:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you make API calls within your domain, particularly within your private network (VPC), you’ll get faster responses because you can bypass much of the DNS resolution process.&lt;/p&gt;

&lt;p&gt;When making a server-side call, instead of calling &lt;a href="https://api.mydomain.com" rel="noopener noreferrer"&gt;https://api.mydomain.com&lt;/a&gt;, you can directly call the internal IP or DNS of the service, reducing response time. This is because there are fewer DNS resolutions to reach the final address. Depending on the endpoint called, this can also reduce cloud costs (such as Route 53, Cloud DNS).&lt;/p&gt;

&lt;p&gt;Note: This approach only works for server-side calls where your application is in the same network and region as your service. If attempted on the client-side, you must ensure users are part of the same private network, such as via a VPN.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Client Network Optimization:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the user does not have a very fast internet connection, performing calls and processes on the server-side will save time for the page to load completely for the user.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Security:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since your code runs on the server, you ensure that sensitive code or information—such as environment variables or internal logic—is not exposed to attackers. This adds an extra layer of security to your application.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Disadvantages:&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Costs:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a server exists, someone is paying to keep it active. Server-Side Rendering can be expensive, depending on the complexity of your application, generating resource costs in the Cloud and, for more advanced cases, entire infrastructure costs to maintain it scalably, such as the use of Load Balancers.&lt;/p&gt;

&lt;p&gt;In programming, trade-offs are always present, and in this case, you need to analyze whether the advantages compensate for the cost.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Static Files&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even when using a server-side rendering approach, some frameworks can generate static files to be loaded in the browser. For example, Next.js. If this is your scenario, you must decide whether to use the front-end server itself to serve these static files or host them on a CDN.&lt;/p&gt;

&lt;p&gt;If you choose to let your server serve the static files, remember that if your application has 5 static files, each request will result in 5 additional requests to load those files. Some frameworks include features for caching these files to prevent users from downloading them every time they access your application. However, this scenario should still be carefully considered.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Infrastructure:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Complementing the previous disadvantage, using this approach requires more cloud knowledge in certain scenarios, as you'll need to maintain an infrastructure for the application to function. If you adopt this approach, you'll likely encounter the following costs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Container image storage&lt;/li&gt;
&lt;li&gt;Load balancers&lt;/li&gt;
&lt;li&gt;Container orchestration&lt;/li&gt;
&lt;li&gt;Machine instances&lt;/li&gt;
&lt;li&gt;Networking&lt;/li&gt;
&lt;li&gt;CDN&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you misconfigure the application or allocate insufficient resources without considering the expected load, you'll likely end up with an unstable application that provides a poor user experience, since the server renders the content.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Visual Bugs:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When using a framework that employs HTML hydration (e.g., Next.js), you may inadvertently introduce production bugs if you're not careful with application hydration. You must always ensure that the server is synchronized with the client and guarantee proper control and hydration synchronization between them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tip
&lt;/h2&gt;

&lt;p&gt;After providing this entire context to help make more assertive decisions, I'll share my approach to choosing languages, frameworks, and strategies for my applications:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This flowchart takes into consideration a front-end that will communicate with a REST backend, with no delivery deadlines, and will be hosted on a cloud platform such as AWS, GCP, or Azure, without delving into detailed questions.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; These are basic questions and cannot answer all scenarios.&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  English
&lt;/h4&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%2Fizmzyn7pkioqe5njmu16.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%2Fizmzyn7pkioqe5njmu16.png" alt="Image description" width="800" height="539"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Português
&lt;/h4&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%2Fikx1padjde7h5if9yhhy.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%2Fikx1padjde7h5if9yhhy.png" alt="Image description" width="800" height="539"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ssr</category>
      <category>frontend</category>
      <category>seo</category>
      <category>web</category>
    </item>
    <item>
      <title>Reading configuration like a pro on Spring</title>
      <dc:creator>Erik Santana</dc:creator>
      <pubDate>Thu, 23 Jan 2025 01:57:48 +0000</pubDate>
      <link>https://dev.to/imerik/reading-configuration-like-a-pro-on-spring-fdb</link>
      <guid>https://dev.to/imerik/reading-configuration-like-a-pro-on-spring-fdb</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As we already know, Spring provides many ways to achieve the same thing, and one of them is how to retrieve the values registered in your configuration file.&lt;/p&gt;

&lt;p&gt;If you're new to Spring, you might come across code that uses the @Value annotation to retrieve values from your application.properties or application.yml file. If you're using this approach, know that it's not wrong; however, you might be introducing unnecessary complexity into your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with @Value
&lt;/h2&gt;

&lt;p&gt;The main issue with using @Value arises when we deal with values that contain other values. Does that make sense? No? Let's look at an example:&lt;/p&gt;

&lt;p&gt;Suppose you have the following configuration 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="s"&gt;mail.user=dev@locahost&lt;/span&gt;
&lt;span class="s"&gt;mail.password=123&lt;/span&gt;
&lt;span class="s"&gt;mail.headers.x-from=Ekerdev&lt;/span&gt;
&lt;span class="s"&gt;mail.headers.x-custom=custom&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You would need to do it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
 &lt;span class="nd"&gt;@Value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mail.user"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
 &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

 &lt;span class="nd"&gt;@Value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mail.password"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
 &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

 &lt;span class="nd"&gt;@Value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mail.headers.x-from"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
 &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;xFrom&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

 &lt;span class="nd"&gt;@Value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mail.headers.x-custom"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
 &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;xCustom&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So far, no problem. But now imagine a scenario where your application needs to use these same values in multiple places in the code. Think of how much duplicated code we’d end up with, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;The best solution, then, is to use the @ConfigurationProperties annotation. This makes it easier for our application to inject variables into a class, and we can use it just like any other dependency in Spring, injecting it as shown in the example below:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alternative 1 using Spring 3.x:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Configuration&lt;/span&gt;
&lt;span class="nd"&gt;@ConfigurationProperties&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mail"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;MailProperties&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
 &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
 &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
 &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Alternative 2 using Spring 3.x:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Configuration&lt;/span&gt;
&lt;span class="nd"&gt;@ConfigurationProperties&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mail.headers"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;MailHeadersProperties&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
 &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;xFrom&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
 &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;xCustom&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="nd"&gt;@Configuration&lt;/span&gt;
&lt;span class="nd"&gt;@ConfigurationProperties&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mail"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;MailProperties&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
 &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
 &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
 &lt;span class="nc"&gt;MailHeadersProperties&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Alternative 1 using Spring 2.x:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Data&lt;/span&gt;
&lt;span class="nd"&gt;@AllArgsConstructor&lt;/span&gt;
&lt;span class="nd"&gt;@ConfigurationPropertiesScan&lt;/span&gt;
&lt;span class="nd"&gt;@ConfigurationProperties&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mail"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MailProperties&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
 &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
 &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
 &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@SpringBootApplication&lt;/span&gt;
&lt;span class="nd"&gt;@ConfigurationPropertiesScan&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"your.package.mailproperties"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleApplication&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;SpringApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ExampleApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;And your service use properties like this:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="nd"&gt;@RequiredArgsConstructor&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
 &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;MailProperties&lt;/span&gt; &lt;span class="n"&gt;mailProperties&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Advantage
&lt;/h2&gt;

&lt;p&gt;The major advantage of using @ConfigurationProperties is that we don't have to hunt for @Value annotations in our code, which makes the code much more readable.&lt;/p&gt;

</description>
      <category>spring</category>
      <category>springboot</category>
      <category>java</category>
      <category>backend</category>
    </item>
  </channel>
</rss>
