A handler that raises on some inputs leaks one database connection per failing request. After thirty of those, the pool is empty and healthy requests start dying with timeouts. Why cleanup belongs in finally, and where to put it so nobody has to remember.
A new series with a different format: short posts, one database practice each, all pulled from things that actually break under load. Connection leaks, invisible N+1s, migrations that lock tables, tasks that run against data that does not exist yet.
Part 12's scanners tell you which dependencies are vulnerable; someone still has to upgrade them. Self-hosted Renovate as a scheduled CI job, the two tokens that keep it alive, and the pre-flight check that turned a recurring debugging session into a one-line log read.
The managed security scan takes 21 minutes, floods every merge request with findings about code nobody touched, and the team learns to scroll past it. Diff-aware SAST with Semgrep, a severity gate for OSV-Scanner, and the report format that puts findings back in the MR widget.
The E2E suite is too slow and too flaky to gate merges, but you still need the signal, and a place to see its history. Scheduled pipelines, service tokens for a gated environment, Playwright sharding, and a report hub that outlives its pipelines.
A release job that pushes a version-bump commit triggers a new pipeline, and two merges landing close together race each other to npm. Serializing releases with resource_group, authenticating the push, and the difference between [skip ci] and -o ci.skip.
Fifty packages and eight apps in one repo means rebuilding the world on every commit is not an option. Change detection with rules:changes and compare_to, one YAML anchor per app, a task runner that already knows the dependency graph, and the week the runners ran out of disk.
Ten sibling repos copy-pasted the same 300 lines of pipeline YAML and every copy drifted in its own direction. include:, hidden jobs as a public API, a !reference rules vocabulary, and how to ship changes when every consumer tracks main.
Merging a frontend change should run E2E tests that live in a different repo, owned by a different team. Trigger jobs, multi-project vs parent-child pipelines, mirroring the downstream status, and a variables allowlist that doubles as a secret boundary.
Push a branch that has an open merge request and you get two pipelines for the same commit: double the cost, two statuses to read. Pipeline types, workflow rules as the gatekeeper, and what running branch-only pipelines actually costs.
Every job runs on every push: deploy jobs tag along on feature branches, and expensive suites run when nothing relevant changed. Job-level rules (if, changes, exists), manual gates, and a regex that silently matched almost every commit message.
Your jobs are efficient but your pipeline is slow, because stages make every job wait for jobs it does not depend on. Replacing stage barriers with a needs graph, and splitting the slowest job across runners with parallel.
Your deploy job rebuilds the app that another job just built. Caching dist/ seems to fix it, until it silently deploys stale code. Artifacts, expiry, failure reports, and passing computed values between jobs with dotenv.
A working cache still wastes time in three ways: every job re-uploads it, a lockfile bump starts from zero, and merge requests never see what main warmed up. Cache policies, fallback keys, and the protected-branch split.
A ground-up walkthrough of .gitlab-ci.yml: jobs, stages, runners, variables, and a dependency cache keyed on your lockfile. Plus the self-hosted cache trap that cost us 90 seconds per job for nothing.
Building a custom ESLint rule that bans a component, with a walk through traversing the AST, picking the right node type, and bundling the rule into a local plugin.
Using @aws-sdk/client-s3 from Node.js to upload single files and entire folders to AWS S3, plus the gotchas you only learn the hard way (content type, leading slashes, Windows paths).
A handful of GORM snippets I keep around when I start a project in Go: installing, modeling, validations, many-to-many relations, hooks, and the queries I run most often.
What I learned in my first three years as a Frontend Developer at Crehana: failing fast, believing in what you build, and why people matter more than anything else.
How to wire webpack-dev-server into a Django project to get hot module replacement, including a template tag that switches between development and production.
Why controller specs often re-test what Rails already guarantees, and how feature tests with RSpec and Capybara let you test what the user actually sees.