My First Docker Experience
A deep dive into Docker Compose, DNS fixes, and Environment Variable security for full-stack apps

I recently finished a full-stack project using React, Express, and MongoDB Atlas. It worked perfectly on my machine, so I decided it was time to level up and Dockerize it.
I didn't realize I was about to walk into a 3-hour debugging session. Here is how I did it, the mistakes I made, and the "Aha!" moments that changed everything.
The Setup
My app is a standard MERN-ish stack:
Backend: Express.js
Database: MongoDB Atlas (Cloud)
Frontend: React (Vite)
The "Long Way" (My First Mistake)
When I started, I was doing everything manually. I created a Dockerfile for the backend, ran docker build, then docker run. Then I went to the frontend and did the same thing.
This is way too lengthy. I realized that Docker Compose is the real MVP. Instead of running 10 commands, I could just define everything in a .yml file and run docker-compose up --build once.
The Wall: The DNS Error
Everything seemed fine until I tried to connect my backend to MongoDB Atlas. I kept getting a nasty ESERVFAIL error.
The Fix: I learned that sometimes Docker's internal network gets "lost" trying to find the internet. By adding Google's DNS to my docker-compose.yml, I gave my containers a map to the outside world:
YAML dns: - 8.8.8.8 - 8.8.4.4 As soon as I added those lines, I saw the expected log in my terminal: MongoDB connected!!
How I Configured It
here is the exact structure I used to get my React and Express apps talking to each other.
- The Backend (Express/Dockerfile): I used a lightweight Alpine image to keep things fast. The key here was ensuring the WORKDIR matched my folder structure.
2. The Frontend (React/Dockerfile): For Vite, I learned that you have to expose the host so the browser can see it.
3. docker-compose.yml This is where the orchestration happens. This single file replaced all the manual docker build and run commands I was doing earlier.
Note on Security: Notice I didn't hardcode my MongoDB Atlas URI. I used ${MONGODB_URI}, which pulls from my local .env file. This way, when I pushed to GitHub, my database password stayed safe!
Dockerize in 3 Steps:
If you want to skip the manual headache and dockerize full-stack app at once, here is the shortcut:
Add Dockerfiles: Create a
Dockerfileand.dockerignoreinside your individual app folders .The Orchestrator: Create a
docker-compose.ymlin your root folder that points to those subfolders.
then Open your terminal in the root folder and run:
docker-compose up --build
That’s it. Docker will build your images, create the network, inject your secrets, and start your entire stack in one go. To run it again later without rebuilding, just use docker-compose up.
What I Learned for Next Time
If you are a student like me starting with Docker, here are my top 3 takeaways:
Don't Build Individually: Just set up your Dockerfiles and let Docker Compose handle the building and networking at once.
Use Volumes for Dev: I learned that without Volumes, I had to rebuild the image for every small code change. Mapping
./folder_name:/appsaved me so much time.Check your DNS: If your container can't see the cloud, try the
8.8.8.8fix immediately.
Check out the code!
You can see my full folder structure and how I organized the express and react folders on : Github
It was a nice experience for me. Moving from a local setup to a fully containerized environment taught me that Docker isn't just about "running an app in a box", it's about reproducibility, security, and orchestration. It wasn't easy, but solving these network and environment hurdles made the final MongoDB connected!! log so much more satisfying.
don't let the complex terminal commands scare you. Start with a simple docker-compose.yml, fix the DNS, and just keep building.
