The Tech Stack We Use at Zenpixl and Why
We've tried a lot of stacks. Here's what we actually use on production projects at Zenpixl — and the reasoning behind each choice.
Every agency has opinions about tech stacks. Most of those opinions are shaped more by familiarity than evidence. Here's an honest breakdown of what we use at Zenpixl, why we use it, and where we'd use something different.
Backend: Laravel (Primary) + Node.js (Secondary)
Laravel is our primary backend framework for product-heavy work — SaaS platforms, ERPs, multi-tenant systems. After 8+ years of production use across dozens of projects, we know its strengths and its edge cases deeply.
What we appreciate about Laravel:
- Eloquent ORM is genuinely good and maps well to complex relational data
- Queue system (Horizon + Redis) is mature and battle-tested
- Sanctum and Passport for API authentication without wheel-reinvention
- Artisan commands make recurring tasks scriptable
- The ecosystem (Spatie packages, especially) solves 80% of common SaaS needs without custom code
Node.js with Express or Fastify is our choice for real-time features (WebSockets, live notifications), AI-heavy backends where we want to run in the same environment as LLM SDKs, and lightweight API services that need to handle high concurrency.
We don't religiously choose one over the other. The decision is driven by the project's dominant requirements.
Frontend: Next.js (App Router)
We moved fully to Next.js App Router in 2024. The combination of server components, streaming, and the file-based routing system solves problems we used to solve with complex tooling.
Specifically:
- Server components reduce client-side bundle size significantly on content-heavy pages
- The
loading.tsx/error.tsxconventions make loading states and error boundaries straightforward - ISR (Incremental Static Regeneration) for marketing pages, dynamic rendering for product pages — without separate apps
- Built-in image optimisation, font optimisation, and metadata API
For simpler projects where a full Next.js setup is overkill, we use React with Vite.
Database: MySQL (Default) + PostgreSQL (When Warranted)
MySQL is our default. It's what most hosting environments support, the Laravel integration is excellent, and for the vast majority of SaaS data models it does everything needed.
We reach for PostgreSQL when:
- The project needs JSONB columns with indexed queries
- We're building schema-per-tenant multi-tenancy
- Full-text search requirements are complex (PostgreSQL's tsvector is superior)
- The team is already PostgreSQL-fluent
We don't use MongoDB for most projects. The promise of "schemaless flexibility" usually produces unmaintainable data over time, and most product data is inherently relational.
Caching: Redis
Redis for caching, session storage, and queues on every production project. Nothing controversial here. We use Redis Cluster for high-availability setups and standalone Redis for smaller projects.
One pattern we enforce: all cache keys are namespaced per tenant in multi-tenant systems. tenant:{id}:dashboard:stats rather than dashboard:stats. Simple rule, avoids entire class of data leakage bugs.
Infrastructure: DigitalOcean + Docker
Most of our client projects run on DigitalOcean — a mix of Droplets for application servers and Managed Databases for PostgreSQL/MySQL. For clients with AWS preferences, we work in AWS.
Docker is mandatory for us. Every project ships with a docker-compose.yml for local development that exactly mirrors production. This eliminates environment parity issues — the number one source of "works on my machine" bugs.
For container orchestration at scale, we use Docker Swarm (simpler operational model than Kubernetes for most client projects) or hand off to a managed platform like Render or Railway.
Process Management: PM2
For Node.js and Next.js production deployments, PM2. It handles process resurrection, zero-downtime reloads, log management, and cluster mode for using multiple CPU cores. Simple, reliable, well-understood.
For Laravel, we use PHP-FPM with Nginx and Laravel Horizon for queue workers.
Monitoring: Sentry + UptimeRobot
Sentry for error tracking on both frontend and backend. It surfaces exceptions with full stack traces, request context, and user breadcrumbs — exactly what you need to debug a production issue at 2am.
UptimeRobot for basic uptime checks on critical endpoints. Simple, cheap, effective.
What We Don't Use (and Why)
GraphQL: Adds complexity that REST doesn't. We use REST for most projects and add it only when the client specifically needs a public API with flexible querying.
Microservices: Not for early-stage products. See our separate post on SaaS architecture for the full reasoning.
ORMs that fight you: We avoid ORMs that add abstraction without clarity. Eloquent is good because it's transparent — you can always see the SQL it generates and override it.
Serverless for primary product logic: Cold starts, limited execution time, complex debugging — the operational simplicity comes with trade-offs that don't suit the kind of stateful product work we do.
The Honest Truth About Tech Stacks
The framework is rarely the bottleneck. We've seen elegant systems built in "boring" frameworks and disaster systems built in the latest trendy stack.
What matters more: consistent patterns, clear module boundaries, good test coverage on critical paths, and a deployment pipeline that makes releases boring. The language and framework are largely secondary.
Use what your team knows deeply. Use what has a mature ecosystem for your problem domain. And resist the urge to rewrite in a new framework until you have clear evidence that the framework — and not the architecture — is the actual constraint.
Curious how we'd approach your project? Let's have a conversation.