Moderne frontend-engineering ziet er totaal anders uit dan een decennium geleden. Je schrijft niet alleen HTML en CSS. Een typisch project wordt tegenwoordig geleverd met een specifieke Node.js-runtime, een vaste versie van de package manager, een wirwar aan build-tools en deployment-pipelines die verwachten dat alles perfect op elkaar aansluit. Er sluipen kleine verschillen in tussen de eerste npm install en de uiteindelijke productiebuild. Een teamgenoot gebruikt Node 20. Jij gebruikt Node 18. Een globale CLI-tool op jouw machine verbergt een ontbrekende dependency op die van hen. Dan komt de zin die niemand wil horen: "Het werkt op mijn machine."

Docker verdient zijn plek in je frontend-toolkit omdat het die onzekerheid wegneemt. Het bundelt je applicatie met de exacte runtime, systeemlibraries en dependencies die nodig zijn. Of je nu codeert op Windows, vanuit macOS publiceert of naar een Linux-cloudinstantie deployt, het gedrag blijft identiek.

Waarom frontend developers dit belangrijk moeten vinden

De pijnpunten die Docker oplost zijn niet abstract. Ze komen elke sprint weer naar voren.

Versieconflicten kosten tijd. Een legacy-klantproject heeft Node 18 nodig, je zijproject heeft Node 20 nodig en het werk voor een nieuwe startup vereist Node 22. Zonder containers beheer je dit via version managers. Dat werkt, totdat het niet meer werkt. Een klein verschil in de npm-versie kan de manier waarop peer dependencies worden opgelost veranderen, waardoor je eindigt met een kapotte build die bij iemand anders wel gewoon werkt. Wanneer een framework een nieuwe release aankondigt, zou de feedbackloop niet twee uur aan herinstallaties moeten duren. Het zou een enkele wijziging in een bestand en een herstart van de container moeten zijn.

Globale packages zijn een andere bron van stille wrijving. Je hebt misschien de Angular CLI, Expo of Prisma zes maanden geleden globaal geïnstalleerd. Een nieuwe developer installeert dezelfde tool opnieuw en krijgt een andere versie. Plotseling geven je build-scripts waarschuwingen die elders niet voorkomen. Docker lost dit op door alles projectlokaal te houden. Je definieert de Node-versie in je Dockerfile. Dependencies worden binnen de container geïnstalleerd, geïsoleerd van je host-besturingssysteem. Je laptop kan macOS, Windows of Ubuntu zijn; de applicatie ziet elke keer exact dezelfde omgeving.

De voordelen voor onboarding zijn moeilijk te negeren. Nieuwe medewerkers hebben geen readme van drie pagina's nodig over Homebrew-installaties, nvm-aliases en het oplossen van globale permissieproblemen. Ze installeren Docker, clonen de repository en voeren één commando uit. Een setup die vroeger een middag in beslag nam, wordt teruggebracht tot minuten. En wanneer ze van project wisselen, blijft er niets achter. Geen achtergelaten globale tools. Geen version managers die strijden om PATH-prioriteit. Hun lokale machine blijft schoon.

Images en containers: de basis

Als Docker nieuw voor je is, is de terminologie eenvoudiger dan het klinkt. Een Docker-image is een blauwdruk. Het bevat je broncode, de Node.js-runtime, je lockfile en elke dependency die nodig is om de app te draaien. Een container is een actieve instantie die is gemaakt van die image. Zie de image als een recept en de container als de maaltijd zelf. Je kunt honderd keer dezelfde taart bakken met één recept. Je kunt identieke containers opstarten vanuit één image zonder je zorgen te maken over wat er op de hostcomputer is geïnstalleerd.

Een praktische Dockerfile

Laten we naar een concreet startpunt kijken. Als je