All references

Database Composer

A single container stack with scripts to provision isolated MySQL, PostgreSQL, and MongoDB databases per project.

  • Docker
  • Docker Compose
  • Bash
  • MySQL
  • PostgreSQL
  • MongoDB
  • Redis

Introduction

I built Main Database Composer as a solo side project to solve a problem I kept running into: every new or old project needed a different mix of databases, and I was either installing them on the host or baking them into each project’s own Docker setup. That worked until I started mixing dockerized apps with locally run ones. Managing credentials, ports, and fresh machine setup became a recurring headache. I designed and built the whole thing myself: one shared stack, simple scripts, and a workflow I could reuse everywhere.

Purpose and goal

The goal was quality of life, plain and simple. I was spending the same time over and over on:

  • Setting up databases on new laptops
  • Reviving old projects
  • Spinning up presentation servers
  • Keeping work environments in sync

I wanted one place where MySQL, PostgreSQL, MongoDB, and Redis always lived, and where creating a new project database took one command instead of a half remembered install guide. The expected outcome was boring in the best way: start a machine, run the stack, provision what the project needs, and move on to actual development.

Today it backs:

ContextScale
Live projectsA handful
Hidden staging setupsA few
Local reposAround a dozen
Engines per projectTypically 1 to 3

I use it on my own deployments, servers, and the different machines I work from. It was never meant to be a product for others, but it became the default way I handle databases across both personal and work projects.

Spotlight

The core idea is one long lived stack instead of a database container per project. A single docker compose up brings up pinned versions of four engines with healthchecks and persistent volumes. When a project needs storage, create_db.sh provisions the database and a dedicated user with the right grants on whichever engines you pass in. MySQL, PostgreSQL, and MongoDB each handle authentication differently. The script layer is where that complexity lives.

The other decision that mattered as usage grew was treating configuration and safety seriously:

  • Pinned image versions so a random major upgrade does not break an old project
  • Localhost binding by default, configurable for LAN or server use
  • Scripts that resolve paths from their own location and fail with readable errors when a container is down

Redis stays as a shared instance because it does not split the same way relational and document stores do. That was a conscious tradeoff: simpler ops, less isolation.

Lessons learned

The biggest surprise was how deep database setup goes once you leave tutorial territory. Each engine has its own opinions on users, grants, auth sources, and what “create a database” even means. MongoDB in particular forced me to think about users per database rather than one global credential. Pinning versions early saved me from silent breakage when images moved to new major releases. I also learned that a tool like this is never really finished. Every new machine, server, or project surface exposed something to tighten: permission defaults, script ergonomics, binding behavior.

What I would do next: add more lifecycle tooling, things like teardown or migration helpers, rather than keep extending the create path. But the pattern stuck: invest once in a shared foundation, then let project work stay focused on the application. That mindset carried into how I approach other repetitive infrastructure around my projects.