coolify
Coolify
Coolify is an open-source, self-hostable platform-as-a-service for deploying applications, databases, and services via Docker on your own servers.
Documentation
Best Practices
-
Health checks are required for zero-downtime deploys — Traefik will route traffic to new containers as soon as the port is open, not when the app is ready. Without an explicit health check (Dockerfile
HEALTHCHECKor UI config), requests hit containers mid-startup or before migrations finish. Always configure a health check endpoint before relying on rolling updates. -
Destinations are isolated Docker networks — Services on different destinations cannot reach each other by container name. A database on
destination-aand an app ondestination-brequire explicit DNS or IP configuration. Default assumption from Heroku/Railway (all services on the same network) does not apply here. -
Persistent volume paths must match the container's write path exactly — Mounting
/datain the UI does nothing if the app writes to/app/data. Bind mounts require exact path matching inside the container; symbolic links and relative paths do not survive container restarts. Always verify the container's actual write path before configuring volumes. -
Nixpacks silently fails with private registries or
.npmrc— Auto-detection works for standard public projects but skips.npmrc, private package registries, and non-standard monorepo layouts without a clear error. If a build works locally but fails in Coolify with Nixpacks, switch to a Dockerfile and pass registry credentials as build-time environment variables. -
DNS must resolve before Let's Encrypt challenges are attempted — Coolify will attempt ACME challenges as soon as a domain is configured. If DNS has not propagated, the challenge fails and retries for hours without a prominent alert. Verify DNS resolution externally before adding the domain in Coolify, especially for wildcard certificates requiring DNS-01 via Cloudflare or Hetzner.
-
Entrypoint shell scripts must forward SIGTERM explicitly — Rolling updates send SIGTERM to the old container for graceful shutdown. Shell script entrypoints (e.g.,
entrypoint.sh) do not forward signals by default, causing the container to be killed after the timeout rather than gracefully shut down. Useexecas the last command in entrypoint scripts (e.g.,exec "$@") or handle signals explicitly.
More from mikkelkrogsholm/dev-skills
tanstack-query
TanStack Query — powerful async state manager for TypeScript/JavaScript with caching, background refetching, and server state synchronization. Use when building with TanStack Query (React Query) or asking about its caching, query keys, mutations, invalidation, optimistic updates, or integration with React, Vue, Solid, or Svelte. Fetch live documentation for up-to-date details.
6bullmq
BullMQ — Redis-based distributed job and message queue for Node.js with workers, schedulers, flows, and rate limiting. Use when building with BullMQ or asking about its queues, workers, job configuration, repeatable jobs, flow producers, or Redis connection setup. Fetch live documentation for up-to-date details.
3drizzle
Drizzle ORM — lightweight, TypeScript-first SQL ORM with schema-as-code and zero-dependency query builder. Use when building with Drizzle ORM or asking about its schema definition, migrations, query builder, relations, or integration with databases like PostgreSQL, MySQL, or SQLite. Fetch live documentation for up-to-date details.
3stripe
Stripe — payment processing platform with APIs for accepting payments, managing subscriptions, handling payouts, and preventing fraud. Use when building with Stripe or asking about its APIs, configuration, patterns, webhooks, or integration. Fetch live documentation for up-to-date details.
2trpc
tRPC — end-to-end typesafe APIs for TypeScript without schemas or code generation. Use when building with tRPC or asking about its router setup, procedures, middleware, context, subscriptions, or integration with React, Next.js, or other frameworks. Fetch live documentation for up-to-date details.
1