I'm new to Docker and want to containerize a small Node.js project for learning, with the possibility of deploying it to a VPS later. The project may use Nginx, PostgreSQL, RabbitMQ, and Redis, all running in containers.
I'm unsure whether development and production should share the same Docker Compose file. For local development, I'd like to mount my source code and use hot reload so I don't have to rebuild everything after every change. In production, I assume the application should be packaged into an image without development bind mounts, debug settings, or other local-only configuration.
Is it better to maintain separate Compose files, such as a common base file plus development and production overrides? Or should I use environment variables, profiles, or a separate development-container setup? I'd like to keep the workflow simple while learning and still follow a sensible approach for eventually deploying to a VPS.
3 Answers
Docker Compose can work perfectly well on a small VPS, especially for a simple project. You don’t need Kubernetes just because you’re deploying containers. Keep the setup manageable: run Compose on the VPS, use environment variables or an environment file for secrets and host-specific values, and avoid development bind mounts in production.
A typical arrangement would be a base compose.yaml containing services such as the application, database, Redis, and RabbitMQ. A development override can add source-code mounts and hot reload, while a production file can publish only the necessary ports, use persistent volumes for data, and run the built application image.
For local development, a dev container or a Compose development configuration is useful if you don’t want to install Node, Redis, PostgreSQL, or RabbitMQ directly on your machine. Hot reload is still achievable: mount the source directory or use Compose’s file-watch feature to synchronize changes into the container. Changes to the Dockerfile or package files can trigger a rebuild, while ordinary source edits can be handled without rebuilding the whole image.
For production, use a separate build target or production Dockerfile stage that installs only production dependencies and starts the compiled or packaged application. NODE_ENV=development and NODE_ENV=production can control application behavior, but they don’t replace the need for different mounts, commands, ports, and build settings.
There isn’t one universal answer, but development and production usually need different settings. In development, it’s common to bind-mount your working directory into the container and run a watcher so code changes appear immediately. You generally don’t want that in production, where the image should contain the application and its dependencies.
A practical setup is a common Compose file for shared services, with a development override for bind mounts, hot reload, and debug settings, and a production file for the deployed configuration. You can also keep completely separate files if the differences become confusing. The important part is to build and test the same application image, or as close to the same image as possible, in every environment.
That makes sense. I’ll start with the shared configuration and separate development and production settings, while focusing on understanding the basic Docker concepts first.

So NODE_ENV is mainly an application setting, and the Compose or Docker configuration still decides how the container is built and run. That distinction was confusing me.