1. A merge request
All code lives in our own GitLab server. Every change, big or small, starts as a merge request. Nothing is pushed straight to production.
2. Review by a person
Another developer reviews the change before it is merged. We use AI to help write and test code, but a person who knows the product decides whether a change is good enough.
3. The pipeline
Every push starts a GitLab CI/CD pipeline. It builds the application into a container image and runs the checks:
- Automated tests, for example end-to-end tests that click through the application like a user would.
- Static code analysis (SAST) that looks for security problems in the code.
- Container scanning (Trivy) that checks the image for known vulnerabilities in the operating system and libraries.
If something fails, the pipeline stops, and the change goes nowhere.
4. Acceptance
Most applications have a development, test, acceptance and production environment. A change first goes to acceptance, which only contains test data. That's where you can try it before it goes live.
5. Production, without downtime
The same image that passed acceptance goes to production on our Kubernetes platform. The deploy is a rolling update: new containers start next to the old ones, and traffic only moves over once they're healthy. If they don't come up, the old version keeps running.
6. After the deploy
We keep checking. New Relic and Sentry alert us when error rates or response times change. For this website, a scheduled pipeline also re-runs the end-to-end tests against the live site.
Why we work this way
Because it lets us move fast without breaking things. Small changes, checked automatically and by a person, instead of one big, scary release. It's also what makes it possible for us to fix security issues right away, without waiting for a release window.
Curious about the platform underneath? Read Our own Kubernetes platform, in two countries.



