Coming from a well structured creative web agency I wanted to maintain this high level of structure in my own studio and have been slowly evolving Mintyy’s global infrastructure since inception.
The pain of manual complexity, repetitive tasks, and the inherent risk of human error when managing multiple projects, environments, and technologies, was a problem we have solved by continuously evolving our infrastructure. We built our infrastructure on top of the universally available Make.
In this article I will delve into what Make is, how we use it, and 5 useful implementations I think you could use today. For security purposes I may not share the code for all the examples I provide.
What is Make?
In its simplest form, Make is a utility originally designed to manage compilation sequences in software development. However, I look at it as a universal command orchestrator and a single source of truth for all project tooling.
Instead of writing long, fragmented shell scripts, we use a concise Makefile within each project. This file defines simple, memorable targets (like make install-dependencies or make deploy-sanity). It’s available almost everywhere, it runs fast, and it forces a level of documented clarity into our infrastructure that shell scripts often miss. It’s the ultimate antidote to boilerplate and fragmented workflow knowledge.
How we use Make
We use Make to abstract away complexity. For a developer starting a project, they don’t need anything about the project other than reading the root README, which showcases a single, simple command: make create-project.
This single universal command checks what CMS the project uses, stops all other projects, creates a new docker instance (or sets up a new sanity/next project), decrypts envs, copies auth files, installs dependencies (composer, npm, yarn or any other bundler) and opens the project in your browser. This striking example shows the chief purpose of our infrastructure – cohesion.
This centralisation ensures that every project, whether it’s a bespoke Sanity build or a high-performance Craft CMS platform, follows the exact same operational standards, defined and maintained by me.
Category 1: Establishing the Foundation
The goal here is radical speed in setup and onboarding. I wanted a system that could onboard a new developer or start a new client environment in mere seconds, not hours.
- Zero-Hassle Dependency Installation: The frustration of “what packages do I run next?” is eliminated. My
make install-dependenciestarget intelligently scans the project, decides whether to run Composer, NPM, Yarn, or a combination, and executes them with the correct flags. This ensures a flawless, one-step setup.
install-dependencies:
@make copy-auth-config
@make composer-install
@make node-install
@make copy-stylelint-config
- Project Environment Management: We rely heavily on DDEV for local development on WordPress (Roots) or Craft CMS projects. We built custom targets like
make create-projectwhich runs multiple setup commands, from configuration to database import, instantly. For maximum efficiency, I even created targets to manage all DDEV projects in bulk on a local machine (e.g., stopping all containers with a single command).
create-project:
@if [ "${DDEV_PROJECT_TYPE}" = "craftcms" ] || [ "${DDEV_PROJECT_TYPE}" = "wordpress" ]; then \
make project-start || exit 1; \
elif [ "${DDEV_PROJECT_TYPE}" = "sanity" ]; then \
read -p "Are you starting from scratch (Y) or using a template (N)? [y/n]: " ans && ans=${ans:-N}; \
if [ "${ans}" = "y" ] || [ "${ans}" = "Y" ]; then \
npm create sanity@latest -- --template sanity-io/sanity-template-nextjs-clean --output-path ./ || exit 1; \
else \
echo "Creating a new sanity project"; \
if sanity debug | grep -q "Not logged in"; then \
echo "Please log in --" && \
npx sanity login; \
fi; \
npx sanity init --bare || exit 1; \
echo "Sanity project created - please update your ./frontend & ./studio .envs with the new Project ID printed above."; \
echo "---"; \
echo "Proceeding to decrypt envs and install dependencies..."; \
make sanity-decrypt-envs; \
make install-dependencies; \
fi \
else \
echo "Error - please check infra"; \
fi \
project-start:
@make ddev-stop-all
@make ddev-create
@make ddev-dependencies
@make ddev-start
@make ddev-launch
- Vercel Initialization: Modern headless projects require precise configuration. Our Vercel project initialisation and management targets ensure all environment variables and deployment settings are correctly configured from day one, guaranteeing smooth, consistent deployments across the platform.
Category 2: Security and Data Integrity
These make commands are designed to standardise and secure every sensitive interaction.
- Encrypted Secrets Management: I never want sensitive credentials (like API keys) living in plain text. My
make encrypt-envsandmake decrypt-envstargets wrap powerful encryption tools, securely managing our secret.envfiles. This includes automating our internal.authfile migration process, ensuring credentials are only exposed under strict, controlled circumstances. - Database Assurance: Manual backups are prone to error. We use
make db-backupandmake db-restoreto execute reliable, one-click data management for SQL databases. Crucially, we extended this to content platforms with specific targets for Sanity Studio database backup and restore, ensuring that all our client’s valuable content is protected with equal rigour.
Category 3: Productivity Hacks
I believe developers should spend 90% of their time solving creative problems, not fighting the terminal. These are the shortcuts that make daily life at Mintyy frictionless.
- Command Abstraction (The Dictionary): Why remember complex CLI arguments? My
maketargets act as a simple dictionary. Whether it’s WordPress command simplification (make import-signatures) or Sanity studio command simplification (make sanity-deploy), we turn lengthy tool syntax into instant, readable shortcuts. - Front-End Templating: For projects requiring email templates or specific pre-processing, our targets automate compilation. For example, our Automating mjml commands target allows our developers to instantly watch and compile email templates, speeding up the design process.
mjml-dev:
@$(MJML_WATCH_TASK)
MJML_WATCH_TASK=
echo "Please define your mjml file to watch"; \
echo "This will automatically generate your .html file with the SAME NAME."; \
echo "To get your file name right click on your mjml file > Copy Path/Reference > Path From Content Root"; \
echo "--------"; \
read -p "Enter your mjml file (e.g., path/to/template.mjml): " mjml_input; \
mjml_base=$$(echo "$$mjml_input" | sed 's/\.mjml$$//');\
mjml_src="$$mjml_base.mjml"; \
html_dest="$$mjml_base.html"; \
\
( \
count=0; \
while [ ! -f "$$html_dest" ] && [ $$count -lt 10 ];
do \
sleep 0.5; \
count=$$((count+1)); \
done; \
if [ -f "$$html_dest" ]; then \
echo "File created. Opening in browser..."; \
$(OPEN_BROWSER_CMD) "$$html_dest"; \
fi \
) & \
\
echo "Starting MJML Watcher..."; \
mjml --watch "$$mjml_src" -o "$$html_dest"
- Version Control Simplification: Consistency is key for clean Git history. Targets like
make squashormake git-push-force(used carefully!) help enforce our internal Git workflow standards, turning complex Git sequences into simple, safe commands.
Category 4: Maintenance and Deployment Control
Managing active client websites across multiple environments demands efficiency and accountability. These commands are our solution for smooth, reliable live operations.
- Universal Maintenance Rollouts: This is one of my favourites for client value. Instead of individually logging into dozens of sites, my custom scripts, wrapped by
make update-all-plugins, allow us to centrally manage updating WordPress plugins remotely across all servers/projects. This is a huge time-saver and a major security advantage. Because I built this custom I don’t need to pay for any external products for this functionality. - Server Access and Control: Our
make ssh-stagingandmake ssh-prodtargets remove the need to remember IPs or specific keys, giving instant, secure access. For controlled environment management, even critical actions like remotely rebooting servers are wrapped, ensuring they are executed cleanly and audibly. - Deployment Communication: High standards demand high transparency. Our
make deploytarget executes the deployment and, upon success, automatically triggers a Slack deployment message, ensuring the entire team and relevant stakeholders are instantly informed of the new release.
Category 5:
While the other categories focus on internal efficiency, this final one ensures our clients benefit directly from our structured approach through clearer communication and documentation.
- Project Document Generation: The complex build details needed for handover often reside in code. I created targets that automatically pull environment variables, dependency lists, and unique configuration details into a structured README or handover document, which is run via
make docs-export. - Testing and Validation Reports: Before every launch, we run mandatory checks. Commands like
make lighthouse-audittrigger external tools and generate performance reports. This standardised approach ensures every project meets our quality threshold and provides the client with clear, tangible results.
To conclude
My investment in custom internal tooling, governed by the humble make command, is not a coding vanity project. It is a fundamental part of the Mintyy service offering. These automated processes free up my team to focus on creativity, design, and delivering exceptional client results, rather than fighting infrastructure.
If the infrastructure behind your current website is slowing down your growth or posing security risks, let’s talk about building a clean, modern, and automated solution. Contact me directly to discuss how Mintyy can bring this high level of structure and reliability to your next project.
