<?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: mohamed amine</title>
    <description>The latest articles on DEV Community by mohamed amine (@mohamed_amine_78123694764).</description>
    <link>https://dev.to/mohamed_amine_78123694764</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%2F2147711%2F3eb86e20-676f-4263-9e10-87f0f7c560e3.png</url>
      <title>DEV Community: mohamed amine</title>
      <link>https://dev.to/mohamed_amine_78123694764</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mohamed_amine_78123694764"/>
    <language>en</language>
    <item>
      <title>Best Practices for Mapping in Spring Boot</title>
      <dc:creator>mohamed amine</dc:creator>
      <pubDate>Wed, 09 Oct 2024 14:31:26 +0000</pubDate>
      <link>https://dev.to/mohamed_amine_78123694764/best-practices-for-mapping-in-spring-boot-47l4</link>
      <guid>https://dev.to/mohamed_amine_78123694764/best-practices-for-mapping-in-spring-boot-47l4</guid>
      <description>&lt;p&gt;When deciding on the best practice for mapping DTOs to entities and vice versa in a Spring Boot application, there are several key factors to consider: simplicity, maintainability, performance, and testability. Each method has its strengths, so the best practice depends on your project's requirements. Here’s a breakdown of different approaches and when to use them:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Use Libraries like &amp;lt;&amp;lt; MapStruct &amp;gt;&amp;gt; (Preferred for Large Projects)
&lt;/h3&gt;

&lt;p&gt;MapStruct is a compile-time code generator that automates the mapping process between DTOs and entities.&lt;br&gt;
&lt;strong&gt;Best for:&lt;/strong&gt; Large projects where you have many DTOs and entities, and you want to avoid repetitive, manual mapping code.&lt;br&gt;
&lt;strong&gt;Why MapStruct is a good choice:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance:&lt;/strong&gt; Because it generates mapping code at compile-time, it is very efficient compared to runtime solutions.
Type safety: Compile-time errors if the mapping is incorrect or missing, reducing the chances of runtime failures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintainability:&lt;/strong&gt; It generates all the boilerplate code for you, reducing duplication.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Mapping Support:&lt;/strong&gt; You can easily define custom mappings for complex fields (e.g., different field names, nested objects).&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;When to use MapStruct:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;When you have many DTOs and entities to map.&lt;/li&gt;
&lt;li&gt;When performance is a concern (since it's compile-time generated).&lt;/li&gt;
&lt;li&gt;When you want to reduce boilerplate code but maintain control over mappings.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;BaseMapper&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;D&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="no"&gt;D&lt;/span&gt; &lt;span class="nf"&gt;toDto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="nf"&gt;toEntity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;D&lt;/span&gt; &lt;span class="n"&gt;dto&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;@Mapper&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;componentModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"spring"&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;interface&lt;/span&gt; &lt;span class="nc"&gt;ClientMapper&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BaseMapper&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ClientDTO&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// MapStruct will automatically inherit the methods from BaseMapper&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;@Mapper&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;componentModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"spring"&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;interface&lt;/span&gt; &lt;span class="nc"&gt;SentimentMapper&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BaseMapper&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SentimentDTO&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Inherits from BaseMapper&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;You should organize the files as follows:&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;src
 └── main
     └── java
         └── com
             └── yourapp
                 ├── mapper                &lt;span class="c"&gt;# Package for mappers&lt;/span&gt;
                 │    ├── BaseMapper.java  &lt;span class="c"&gt;# Abstract base mapper&lt;/span&gt;
                 │    ├── ClientMapper.java &lt;span class="c"&gt;# Client-specific mapper&lt;/span&gt;
                 │    └── SentimentMapper.java &lt;span class="c"&gt;# Sentiment-specific mapper&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Example: How to Use Mappers in a Service&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="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.yourapp.service&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.yourapp.dto.UserDTO&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.yourapp.entity.User&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.yourapp.mapper.UserMapper&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.stereotype.Service&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&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;ClientService&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;ClientMapper&lt;/span&gt; &lt;span class="n"&gt;clientMapper&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Constructor injection (preferred method)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;UserService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ClientMapper&lt;/span&gt; &lt;span class="n"&gt;clientMapper&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clientMapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clientMapper&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Method to convert Client entity to ClientDTO&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ClientDTO&lt;/span&gt; &lt;span class="nf"&gt;getClientDto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;clientMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toDto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Method to convert ClientDTO to Client entity&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="nf"&gt;createClientFromDto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ClientDTO&lt;/span&gt; &lt;span class="n"&gt;clientDTO&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;clientMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toEntity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clientDTO&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;h3&gt;
  
  
  2. Use Libraries like &amp;lt;&amp;lt; ModelMapper &amp;gt;&amp;gt; (For Quick, Dynamic Mapping)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;ModelMapper&lt;/strong&gt; dynamically maps fields between DTOs and entities at runtime.&lt;br&gt;
&lt;strong&gt;Best for:&lt;/strong&gt; Quick setup, especially in prototyping or when you don’t want to manually write mapping logic for many fields.&lt;br&gt;
&lt;strong&gt;Why ModelMapper:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ease of setup:&lt;/strong&gt; Requires very little setup and works well for simple use cases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic mappings:&lt;/strong&gt; Great for cases where entities and DTOs have a similar structure, and you don’t want to write individual mapping methods.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Example:&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="nc"&gt;ModelMapper&lt;/span&gt; &lt;span class="n"&gt;modelMapper&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;ModelMapper&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;ClientDTO&lt;/span&gt; &lt;span class="n"&gt;clientDTO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;modelMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ClientDTO&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="nc"&gt;Client&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;modelMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clientDTO&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Client&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When to use ModelMapper:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;When the project is small or medium, and you don’t want to write individual mappers.&lt;/li&gt;
&lt;li&gt;When the structure of your DTOs and entities are very similar and don’t require much customization.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3. Manual Mapping (Best for Small Projects or Specific Cases)
&lt;/h3&gt;

&lt;p&gt;Manual mapping involves writing the conversion code yourself, typically with simple getter/setter calls.&lt;br&gt;
&lt;strong&gt;Best for:&lt;/strong&gt; Small projects, simple mappings, or when you need full control over every aspect of the mapping process.&lt;br&gt;
&lt;strong&gt;Why Manual Mapping can be a good choice:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simple mappings:&lt;/strong&gt; If you only have a few DTOs and entities, manual mapping can be straightforward and easy to implement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full control:&lt;/strong&gt; You have complete control over how the mapping is done, which is useful when you have complex logic or data transformations during mapping.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Example:&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="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ClientMapper&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ClientDTO&lt;/span&gt; &lt;span class="nf"&gt;toDto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;ClientDTO&lt;/span&gt; &lt;span class="n"&gt;clientDTO&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;ClientDTO&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;clientDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEmail&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;clientDTO&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="nf"&gt;toEntity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ClientDTO&lt;/span&gt; &lt;span class="n"&gt;clientDTO&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Client&lt;/span&gt; &lt;span class="n"&gt;client&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;User&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clientDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEmail&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;client&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;When to use Manual Mapping:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;In small or simple projects where only a few DTOs and entities exist.&lt;/li&gt;
&lt;li&gt;When you need maximum control over mapping logic.&lt;/li&gt;
&lt;li&gt;For edge cases where mapping libraries might be too much overhead.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Key Considerations for Choosing a Mapping Approach
&lt;/h2&gt;

&lt;h5&gt;
  
  
  Maintainability
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MapStruct&lt;/strong&gt; is easier to maintain as your project grows because it automatically generates the mapping code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manual mapping&lt;/strong&gt; can become harder to maintain in large projects, as each DTO-entity pair requires separate methods.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ModelMapper&lt;/strong&gt; can quickly become difficult to maintain if you need a lot of custom logic since it’s dynamic and doesn’t enforce compile-time checking.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Performance
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MapStruct&lt;/strong&gt; is highly performant since mappings are generated at compile-time. This makes it ideal for performance-critical applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manual mapping&lt;/strong&gt; is also efficient, but it can introduce human error and is more verbose.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ModelMapper&lt;/strong&gt; can be slower, as it uses reflection to map fields at runtime.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Complexity of Mappings
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;For simple mappings: &lt;strong&gt;Manual mapping&lt;/strong&gt; or &lt;strong&gt;ModelMapper&lt;/strong&gt; might be sufficient.&lt;/li&gt;
&lt;li&gt;For complex mappings (nested objects, custom field names, or transformations), &lt;strong&gt;MapStruct&lt;/strong&gt; or &lt;strong&gt;manual mapping&lt;/strong&gt; is preferred, as it provides more control.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Project Size
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;In small projects, &lt;strong&gt;manual mapping&lt;/strong&gt; is usually sufficient and easy to maintain.&lt;/li&gt;
&lt;li&gt;For large projects with multiple entities and DTOs, it’s better to use &lt;strong&gt;MapStruct&lt;/strong&gt; to reduce boilerplate and improve readability.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  General Best Practice:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;MapStruct&lt;/strong&gt; for larger projects where maintainability, performance, and compile-time safety are critical.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;manual mapping&lt;/strong&gt; in small projects or when you need to write very specific conversion logic.&lt;/li&gt;
&lt;li&gt;Avoid using &lt;strong&gt;ModelMapper&lt;/strong&gt; in large or complex projects, as runtime mapping with reflection can be slow and error-prone.&lt;/li&gt;
&lt;li&gt;Always strive to keep DTOs simple, containing only the necessary data, and avoid including domain logic in them.&lt;/li&gt;
&lt;li&gt;Handle null safety and edge cases (e.g., optional fields, collections) properly when mapping.&lt;/li&gt;
&lt;li&gt;If your DTOs frequently change, tools like &lt;strong&gt;MapStruct&lt;/strong&gt; will help you adapt faster by automatically generating the code and providing compile-time feedback.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;For large-scale applications where many DTOs and entities exist and mapping is repetitive, &lt;strong&gt;MapStruct&lt;/strong&gt; is generally the best practice.&lt;/li&gt;
&lt;li&gt;For small-scale projects with minimal mapping, &lt;strong&gt;manual mapping&lt;/strong&gt; is sufficient and keeps things simple.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ModelMapper&lt;/strong&gt; can be used for quick prototypes or simple use cases, but it is not the best choice for production environments due to performance and maintainability concerns.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Authors
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gitlab.com/mohamedamine.mhenni" rel="noopener noreferrer"&gt;@mohamedamine.mhenni&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Support
&lt;/h2&gt;

&lt;p&gt;For support, email &lt;a href="mailto:mhenni.medamine@gmail.com"&gt;mhenni.medamine@gmail.com&lt;/a&gt; .&lt;/p&gt;

&lt;h2&gt;
  
  
  License
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://choosealicense.com/licenses/mit/" rel="noopener noreferrer"&gt;MIT&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>mapper</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Best Practices of Docker &amp; Docker-Compose for NextJS application.</title>
      <dc:creator>mohamed amine</dc:creator>
      <pubDate>Mon, 07 Oct 2024 08:23:04 +0000</pubDate>
      <link>https://dev.to/mohamed_amine_78123694764/best-practices-of-docker-docker-compose-for-nextjs-application-2kdm</link>
      <guid>https://dev.to/mohamed_amine_78123694764/best-practices-of-docker-docker-compose-for-nextjs-application-2kdm</guid>
      <description>&lt;h1&gt;
  
  
  Best Practices of Docker &amp;amp; Docker-Compose for NextJS application.
&lt;/h1&gt;

&lt;p&gt;To create an optimized Dockerfile for a Next.js 14 application that supports both development and production environments, you can follow a multi-stage build approach. This method ensures that the development environment has hot-reloading and source maps, while the production environment builds the app for production with optimizations like smaller image sizes and improved runtime performance.&lt;/p&gt;

&lt;p&gt;Here's a Dockerfile for both development and production environments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Stage 1: Base build environment
FROM node:18-alpine AS base
WORKDIR /app
COPY package.json package-lock.json ./

# Install dependencies
RUN npm ci --legacy-peer-deps
COPY . .
# Install necessary dependencies for sharp (for image optimization)
RUN apk add --no-cache libc6-compat
# Stage 2: Development environment
FROM base AS development
ARG ENVIRONMENT=development
ENV NODE_ENV=$ENVIRONMENT
EXPOSE 3000
CMD ["npm", "run", "dev"]

# Stage 3: Production build
FROM base AS build
ARG ENVIRONMENT=production
ENV NODE_ENV=$ENVIRONMENT
RUN npm run build

# Stage 4: Production runtime environment
FROM node:18-alpine AS production
WORKDIR /app
COPY --from=build /app/.next ./.next
COPY --from=build /app/package.json ./package.json
COPY --from=build /app/package-lock.json ./package-lock.json
COPY --from=build /app/public ./public
COPY --from=build /app/node_modules ./node_modules
EXPOSE 3000
CMD ["npm", "run", "start"]

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Key Points in the Dockerfile:
&lt;/h2&gt;

&lt;p&gt;Base Image (node:18-alpine): This is a lightweight version of Node.js based on Alpine Linux. It is both fast and optimized for smaller container sizes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multi-stage Build:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Base Stage&lt;/strong&gt;: This sets up the basic environment, installs dependencies, and prepares the application. It’s used as the foundation for both the development and production stages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Development Stage:&lt;/strong&gt; Installs all necessary development dependencies.Runs the Next.js development server (npm run dev) with hot-reloading.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build Stage:&lt;/strong&gt; Runs the Next.js production build (npm run build), preparing the .next folder for production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Production Runtime Stage:&lt;/strong&gt; Only copies the built .next folder, public assets, and production dependencies (node_modules). Starts the app using npm run start, which serves the production-optimized app.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Optimizations:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Alpine Image:&lt;/strong&gt; Using node:18-alpine ensures a minimal image size.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependency Caching:&lt;/strong&gt; Dependencies are cached properly by separating the package.json and package-lock.json copying step before copying the app's source files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Image Layers:&lt;/strong&gt; Using multi-stage builds minimizes the size of the final production image by keeping the build-related dependencies and files out of the final runtime image.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;apk add for sharp:&lt;/strong&gt; Installs necessary dependencies for sharp, a popular library for image optimization that Next.js uses internally.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to Use the Dockerfile
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;To build for development, run:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build --target development --build-arg ENVIRONMENT=development -t next-app-dev .

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;To build for production, run:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build --target production --build-arg ENVIRONMENT=production -t next-app-prod .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Breakdown of the Command:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;--target development:&lt;/strong&gt; This flag tells Docker to build the specific target stage named development in the Dockerfile.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;In the multi-stage Dockerfile, each stage has a name (for example, development, build, production). Docker will stop the build process once it reaches the development stage and output an image for that stage.&lt;/p&gt;

&lt;p&gt;By specifying &lt;strong&gt;--target development&lt;/strong&gt;, Docker will use this stage as the final image.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;--build-arg ENVIRONMENT=development:&lt;/strong&gt; This is a build argument that you are passing to the Docker build process. In your Dockerfile, you've set an argument for the ENVIRONMENT and are using it to set NODE_ENV.&lt;br&gt;
In the Dockerfile, this is where you use it:&lt;br&gt;
So, by passing ENVIRONMENT=development, it sets NODE_ENV=development for the development stage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;-t next-app-dev:&lt;/strong&gt; This flag is used to give the resulting Docker image a tag (name). Here, you're tagging the built image as next-app-dev. This makes it easier to refer to the image later when you want to run or push it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;. (dot):&lt;/strong&gt; The dot refers to the current directory as the build context. Docker will look for the Dockerfile in the current directory and include any files and directories in the build process based on the instructions in the Dockerfile.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Once the Docker image has been built and your container is running, you can access your Next.js application in the following steps:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Run the Container&lt;/strong&gt;
To start a container from your built Docker image, use the docker run command. For example, assuming your image is tagged next-app-prod and your app is listening on port 3000, you can run the following command:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -p 3000:3000 next-app-prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explanation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;-p 3000:3000:&lt;/strong&gt; This flag maps the container's internal port (3000) to your local machine's port (3000). The first 3000 is the port on your machine, and the second 3000 is the port inside the container where the Next.js app is running.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;next-app-prod:&lt;/strong&gt; This is the name of the Docker image you built. You are telling Docker to start a container based on this image.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Access the App&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once the container is running, you can access your Next.js app by opening your web browser and navigating to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is because the -p 3000:3000 flag exposes the app running inside the Docker container on port 3000 of your local machine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits of a Single Multi-Stage Dockerfile&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Code Reuse:&lt;/strong&gt; You avoid duplicating configurations across multiple files by defining different stages (development, build, and production) in a single Dockerfile. You can share common layers between stages, such as base images, dependencies, and configurations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Consistency:&lt;/strong&gt; Having everything in one file ensures that your environments are consistent. The same base setup (like Node.js version, dependencies, and build tools) is used for both development and production.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Image Size Optimization:&lt;/strong&gt; Multi-stage builds allow you to define a build process in one stage and then use only the necessary output in the production stage, resulting in smaller and more optimized production images.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Maintainability:&lt;/strong&gt; Maintaining one Dockerfile is easier than managing separate files. You can easily update the common parts (like dependencies or configurations) without worrying about syncing changes across multiple files.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simplicity:&lt;/strong&gt; By using a multi-stage Dockerfile, you simplify your project structure by not needing extra files for different environments.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Case for Separate Dockerfiles&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In some cases, however, you might want to define separate Dockerfiles for development and production. Here are a few reasons why you might choose this approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Specialized Development Setup:&lt;/strong&gt; If the development environment needs significantly different tooling or services (e.g., testing frameworks, live reload tools), and you don't want to clutter the production Dockerfile with them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Faster Iteration in Development:&lt;/strong&gt; If the development Dockerfile needs to be streamlined for faster iteration (e.g., skipping certain optimizations or using different tooling).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Complex Setup:&lt;/strong&gt; In some complex cases, the production setup might be very different from the development one, and combining them in a single file can be cumbersome.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When to Use Separate Dockerfiles&lt;br&gt;
If you have very different setups, you might do something like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dockerfile.dev&lt;/strong&gt; for development&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dockerfile.prod&lt;/strong&gt; for production&lt;/p&gt;

&lt;p&gt;You would then specify which file to use when building the image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Build for development
docker build -f Dockerfile.dev -t next-app-dev .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Build for production
docker build -f Dockerfile.prod -t next-app-prod .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Recommendation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For most cases, especially in typical Next.js apps, the single multi-stage Dockerfile is the best practice. It promotes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reusability of layers&lt;/li&gt;
&lt;li&gt;Consistency&lt;/li&gt;
&lt;li&gt;A smaller image size for production&lt;/li&gt;
&lt;li&gt;Easier maintenance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, if your development and production environments are drastically different, separate Dockerfiles might be a better choice, though this is less common.&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker-Compose
&lt;/h2&gt;

&lt;p&gt;Here is a Docker Compose file to run a Next.js 14 application along with MongoDB. This setup follows best practices, including using environment variables from a .env file and setting up multi-service configuration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a .env file to store your environment variables.&lt;/li&gt;
&lt;li&gt;Create a docker-compose.yml file for defining your services.
.env File:
Make sure this file is in the root of your project. This will contain your environment variables for both Next.js and MongoDB.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# .env
# Next.js Environment Variables
NEXT_PUBLIC_API_URL=https://your-api-url.com
MONGO_URI=mongodb://mongo:27017/yourDatabaseName
DB_USERNAME=yourUsername
DB_PASSWORD=yourPassword
DB_NAME=yourDatabaseName
NODE_ENV=production

# MongoDB Variables
MONGO_INITDB_ROOT_USERNAME=admin
MONGO_INITDB_ROOT_PASSWORD=adminpassword
MONGO_INITDB_DATABASE=yourDatabaseName

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;docker-compose.yml File:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This file defines both your Next.js app and the MongoDB service. The Next.js service depends on MongoDB, and they are both configured to communicate within the same Docker network.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: "3.8"

services:
  mongo:
    image: mongo:6.0
    container_name: mongodb
    restart: unless-stopped
    ports:
      - "27017:27017" # Exposing MongoDB port
    environment:
      MONGO_INITDB_ROOT_USERNAME: ${DB_USERNAME}
      MONGO_INITDB_ROOT_PASSWORD: ${DB_PASSWORD}
      MONGO_INITDB_DATABASE: ${DB_NAME}
    networks:
      - app-network
    volumes:
      - mongo-data:/data/db # Persist MongoDB data in a Docker volume

  nextjs-app:
    image: digipros-prod
    container_name: digipros-app
    build:
      context: .
      dockerfile: Dockerfile
    restart: unless-stopped
    ports:
      - "4000:3000" # Exposing Next.js app on port 5000
    depends_on:
      - mongo # Ensures MongoDB starts before Next.js
    env_file:
      - .env
    environment:
      MONGO_URI: ${MONGO_URI}
      DB_USERNAME: ${DB_USERNAME}
      DB_PASSWORD: ${DB_PASSWORD}
      DB_NAME: ${DB_NAME}
    volumes:
      - ./public/uploads:/app/public/uploads # Only persist the uploads folder
    command: "npm run start" # Running the Next.js app in production mode
    networks:
      - app-network
volumes:
  mongo-data: # Named volume to persist MongoDB data
networks:
  app-network:
    driver: bridge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explanation of docker-compose.yml:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;version: '3.8':&lt;/strong&gt; The Compose file version, supporting more features.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;services:&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;mongo:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;image: mongo:6.0:&lt;/strong&gt;&lt;br&gt;
  Specifies the MongoDB image and version.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;container_name: mongodb:&lt;/strong&gt; Names the MongoDB container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;restart: unless-stopped:&lt;/strong&gt; Restarts the container unless you explicitly stop it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ports: "27017:27017":&lt;/strong&gt; Exposes MongoDB on port 27017 so it can be accessed locally.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;environment:&lt;/strong&gt; Reads environment variables from the .env file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;volumes:&lt;/strong&gt; Mounts a Docker volume for persistent data storage, even if the container is removed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;nextjs-app:&lt;/strong&gt; image: next-app-prod: The name of the image to be used (assumes the image is built already).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;build:&lt;/strong&gt; Specifies the build context and the Dockerfile to use for building the Next.js app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;depends_on:&lt;/strong&gt; mongo: Ensures that MongoDB is started before the Next.js app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;env_file: .env:&lt;/strong&gt; Loads environment variables from the .env file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;volumes:&lt;/strong&gt; - ./public/uploads:/app/public/uploads # Only persist the uploads folder&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;command: "npm run start":&lt;/strong&gt; Runs the Next.js app in production mode.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;mongo-data:&lt;/strong&gt; Named volume to persist MongoDB data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to Run:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Build the Docker Image for your Next.js application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build -t next-app-prod .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start the Docker Compose services:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Access the Next.js application at &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MongoDB&lt;/strong&gt; will be available locally on port 27017, or within the Docker network as mongo (for your Next.js app).&lt;/p&gt;

&lt;h3&gt;
  
  
  Best Practices Followed:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Environment variables are managed via a .env file.&lt;/li&gt;
&lt;li&gt;MongoDB data persistence using Docker volumes.&lt;/li&gt;
&lt;li&gt;Multi-stage Dockerfile (assumed) for optimized builds.&lt;/li&gt;
&lt;li&gt;depends_on ensures services are started in the correct order.&lt;/li&gt;
&lt;li&gt;Restart policy to ensure services remain running.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This setup allows for easy management of the Next.js and MongoDB containers while keeping everything modular and maintainable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authors
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gitlab.com/mohamedamine.mhenni/" rel="noopener noreferrer"&gt;@medAmine&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Support
&lt;/h2&gt;

&lt;p&gt;For support, email &lt;a href="mailto:mhenni.medamine@gmail.com"&gt;mhenni.medamine@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  License
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://choosealicense.com/licenses/mit/" rel="noopener noreferrer"&gt;MIT&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>nextjs</category>
      <category>docker</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
