## My DevOps stack in 2026
Context
I’m a DevOps engineer at movecloser - a Polish software house where I build and maintain infrastructure for client projects. At the same time I run my own open-source projects (donata, starlight-auth, this website) and the Flightcore Studios infrastructure. My stack needs to work at two levels: enterprise (movecloser) and personal (own servers, home labs).
This article is a review of tools I actually use in 2026 - not a list of “cool tech from Hacker News” but a set that has survived the natural selection of daily use.
Containerization - Docker everywhere
Docker is the foundation. Every project I create or maintain starts with a Dockerfile. Not because it’s trendy - because it eliminates an entire class of problems that used to eat hours: “works on my machine,” version discrepancies, dirty dev environments.
Multi-stage builds
Multi-stage is the standard - a separate build stage with the full toolchain, a separate runtime with a minimal image. For Node.js applications that’s the difference between a 1.2 GB image and 180 MB.
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --production=false
COPY . .
RUN npm run build
# Production stage
FROM node:20-alpine AS runtime
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
USER node
CMD ["node", "dist/index.js"]
Docker Compose for development
For local development - a docker-compose.yml with the full stack: database, cache, app, reverse proxy. One docker compose up and the environment is identical to production. At movecloser every project has its own compose file with predefined seeds and migrations.
Orchestration - Kubernetes where it makes sense
Kubernetes isn’t the answer to every question. For my personal projects - a VPS with Docker Compose is enough. But at movecloser, where we manage a dozen-plus services with different deployment cycles, scaling requirements, and SLAs - Kubernetes solves real problems.
What K8s does well
- Rolling updates - zero-downtime deploys with automatic rollback. One bad build doesn’t take down production.
- Resource limits - resource isolation between services. One memory leak doesn’t kill the rest.
- Secrets management - integration with external secrets operator, rotation without restarts.
What I avoid
- Overengineering - Helm charts with hundreds of parameters for a simple CRUD app. A plain set of YAML manifests is more readable and easier to debug.
- K8s by force - personal projects (donata, szymongwozdz.pl) run on plain Docker Compose behind a Cloudflare Tunnel. They don’t need auto-scaling or a service mesh.
Infrastructure as Code - Terraform
Terraform manages cloud infrastructure - AWS/GCP resources, DNS records in Cloudflare, K8s clusters. The key principle: if I can click it in a console, I can describe it in HCL.
State management
Remote state in S3 with a DynamoDB lock. Each team at movecloser has a separate workspace. For personal projects - Terraform Cloud on the free plan, because maintaining your own state backend for three projects is overkill.
# Typical workflow
terraform plan -out=tfplan
# review the plan
terraform apply tfplan
Modularization
Custom modules for repeatable patterns - a VPC with a predefined topology, an EKS cluster with sensible defaults, an S3 bucket with retention policies. Modules versioned in a separate repo, referenced by git tags.
CI/CD - GitHub Actions
After experimenting with GitLab CI, Jenkins, and CircleCI - GitHub Actions won through integration with the ecosystem I already live in. Repos on GitHub, code review in PRs, workflows alongside the code.
Patterns that work
- Reusable workflows - shared pipelines (build → test → deploy) as separate workflows, called from project repositories. A change in one place propagates everywhere.
- Environment protection rules - production deploys require approval. Automatic deploy to staging on every merge to main.
- Cache aggressively - Docker layer cache, dependency cache, build artifacts. The difference between 12 minutes and 3 minutes per pipeline.
# Workflow fragment with caching
- uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: ${{ runner.os }}-npm-
Edge and CDN - Cloudflare
Cloudflare is my default edge solution - DNS, CDN, WAF, Tunnel, Workers. This site (szymongwozdz.pl) is served statically from Cloudflare Pages - zero servers to maintain, automatic deploys from GitHub, SSL with no configuration.
Cloudflare Tunnel
For services that need public access but run on a private server - Tunnel instead of opening ports. Donata, my self-hosted donation system for streamers, works exactly like this: Docker Compose on a VPS, Cloudflare Tunnel as the only entry point. No public IPs, no open ports, no stress-testing the firewall.
Workers and KV
Lightweight edge functions - redirects, A/B testing, token validation. For the Flightcore Studios website I use Workers to handle contact forms without a backend server.
What has changed in recent years
- Dropped Ansible in favor of containerization. Server configuration is now a Dockerfile + compose, not a playbook with a hundred tasks.
- Less AWS, more Cloudflare - for personal projects. AWS is a powerful tool, but the pricing model requires a dedicated accountant.
- Simplified monitoring - from Prometheus + Grafana + AlertManager to uptime-kuma + logs to stdout. For small projects a full observability stack is overhead that doesn’t pay off.
- PostgreSQL as the default database - after years of experimenting with MongoDB, Redis as a primary store, SQLite - PostgreSQL solves 95% of problems and doesn’t surprise you.
Summary
My stack in 2026 is: Docker for packaging, Kubernetes for orchestration (where it makes sense), Terraform for infrastructure management, GitHub Actions for CI/CD, Cloudflare at the edge. It’s not perfect, but it’s battle-tested - I’ve used each of these tools daily for at least two years.
The most important lesson? A good stack is one you know well enough to debug at 3 AM. Not the one with the most stars on GitHub.