Elements vs Coolify

Markdown

Coolify is an open-source, self-hostable platform as a service (PaaS) for deploying apps, databases and services to servers you control. You install Coolify, a web dashboard with an API, on a server of your own. It connects to your other servers over SSH, installs Docker on them, and runs each app as a Docker container, built from a Git repository by an automatic build pack or your own Dockerfile, or pulled as a prebuilt image. A proxy on each server routes domains to containers and obtains HTTPS certificates (proxy). Coolify also runs databases such as Postgres and Redis, and more than 280 one-click services (what is Coolify, GitHub). It is licensed under Apache 2.0, and its makers also sell Coolify Cloud, which runs the dashboard for you while your apps stay on your servers (self-hosted vs Cloud).

Elements also deploys apps to servers you control, with the same tooling you build the app with: it is an integrated app environment for people and their agents, where the project server, the default framework, the test runner and Postgres live in the same system as the deploy command. elements deploy ships your app to any Ubuntu server you reach over SSH, and sets up Postgres, the load balancer and TLS certificates on it.

The difference is where deploy lives. Coolify is a separate system that deploys whatever you hand it as a container, so it knows your app only as a container image: each new commit becomes a new image, and your tests and migrations are commands you wire in yourself. In Elements, deploy is part of the build tooling. The project server on your machine talks directly to the one on your server, which runs your tests and migrations before the release goes live. A deploy usually finishes in under a second, with no dashboard server to keep running and no container images to build.

At a Glance

Elements Coolify
What it is An integrated app environment that includes deploy A dashboard you host that deploys apps to your servers
A separate server to run None The Coolify instance: a dashboard with its own Postgres, Redis and WebSocket server
How an app ships Only the changed source files, sent directly to your server A Docker image, built on the server or a build server
A deploy Changed files sync, then an atomic release swap; usually under a second An image build, then a container swap
Tests Run on every deploy, and a failure stops the release Not run unless you add them to the image build
Migrations Run on every deploy, in one transaction, before the release goes live Commands you add to a hook; the hook that can run a new commit's migrations runs after its code is live
Where deploy settings live config.jsoc, in your repository The Coolify instance's database
Several servers Add them to the config; each one balances requests across all of them Push images to a registry, and put your own load balancer in front

Deploy Belongs in the Build Tooling

Coolify's strength is that it deploys anything that fits in a container: a Rails app, a Next.js app, a WordPress site, a Redis server. The cost of deploying anything is that Coolify knows your app only as a container. It reports whether the image built and whether the new container started and passed its health check (build and deployment model). Type checking, tests and migrations depend on commands you write into the image build or a hook, and each is a separate place to look when a deploy goes wrong.

Elements knows your app, because it builds it. Its project server runs while you work and holds the build graph and build state in memory; on every save the build state is updated almost instantly, and it builds in milliseconds and answers agents and humans in microseconds (build). A copy of that project server runs on each deploy machine, so a deploy is one more step of the build you already have. elements deploy -json reports every compile error, failing test and failed migration, local and remote, with each remote one tagged with the machine it came from, and your agent reads it the same way it reads a build (what deploy does).

Elements deploys more than the app. Custom backend services, such as a Go worker, are declared in the same config, built locally, and synced to every machine, where each runs as a systemd service on its own port behind the same load balancer (operations).

No Dashboard Server to Run

Coolify is an app of its own. The Coolify instance runs as containers for the dashboard and API, its own Postgres database, Redis for queued work, and a WebSocket server for dashboard updates (how Coolify works), and it needs at least 2 CPU cores, 2 GB of RAM and 10 GB of disk (self-hosted setup). If you host it yourself, you update it, back it up and restore it (update, back up). Coolify's own docs call it "a privileged control plane": it stores the SSH private keys to every server it manages (security model). With Coolify Cloud, that instance runs on infrastructure managed by the Coolify team (self-hosted vs Cloud).

Elements has no control plane. Deploy is a command in the tooling you already use to build, and it runs from your machine or your agent's, with the SSH key you already have. Each deploy machine runs the Elements project server, the app, the load balancer and the job runner as systemd services, each as its own low-privilege user, next to its Postgres (what deploy does). There is no extra server to keep alive, and no third system holding keys to your machines.

No Container Images to Build

Coolify turns each deploy into a Docker image. For a Git app, the build pack builds the image on the deployment server, or on a separate build server you add to keep builds off production, and Coolify then replaces the running container (build and deployment model, build servers). To deploy one app to several servers, Coolify pushes the image to a Docker registry you provide, and each server pulls it (multi-server deployments).

Elements has no image, no registry and no build server. Instead of shipping a container, your local project server reconciles with the remote one and sends the source files that differ, often a few kilobytes. The remote side keeps its build state from the last deploy, so it redoes only what the change touches, then swaps the release atomically. A machine's initial deploy takes a few seconds; after that, a deploy usually completes in under a second (what deploy does).

Tests and Migrations Run as Part of Every Deploy

Coolify has no migration step of its own. It offers two command hooks. A pre-deployment command runs inside the currently running container, the previous version of your app, before the replacement is built. A post-deployment command runs in the new container after Coolify marks the deployment complete. The previous version does not contain the new commit's migration files, so of the two hooks, only post-deployment can run a migration that ships with new code, and it runs after the new code is already live. If the migration fails there, the failure is written to the log, and "the deployment remains marked as successful because the new container has already been deployed" (Coolify general settings).

Elements migrates before the code goes live, not after, and has no hook to configure. Each machine compiles the release and the first machine migrates a test database; the tests then run on each machine against that schema, and only if they pass does the first machine migrate production, inside one transaction, before the release goes live. A deploy that fails at any of those steps is not marked successful: it stops, and the running release carries on serving (deploy, tests, migrations).

Postgres, the Load Balancer and TLS Come With the App

On the first deploy to a new machine, Elements installs everything the app needs to run: its Postgres cluster, the systemd units, and its load balancer, which obtains and renews Let's Encrypt certificates for every configured domain (setup, load balancer). One server is a complete deployment. There is no database to create in a dashboard and connect to the app by hand.

The bundled Postgres fits a prototype or a single-server app. When one server is not enough, or you want managed backups and scaling, add servers to config.jsoc and point them at a hosted Postgres, such as DigitalOcean Managed PostgreSQL or Amazon RDS, by setting DB_HOST. Every machine runs the same load balancer and knows about every other machine, so you can point DNS at any of them and each one balances requests across the environment (load balancer). In Coolify, adding servers "does not distribute traffic by itself"; you configure a cloud load balancer or another traffic layer in front of them (multi-server deployments).

Deploy Config Lives in the Repository

Coolify keeps each app's deploy settings in its own database: domains, environment variables, the build pack and the deployment hooks are saved on the Coolify instance (how Coolify works), and you or your agent reach them through its dashboard, API, CLI or MCP server. A change to how the app deploys is made in one place, and a change to the code in another.

For an agent, that split is the expensive part. Coolify's MCP server and API teach it one more set of concepts, build packs, resources, deployment hooks and proxy labels, and each is a surface where its change can be wrong in a way the code never shows. Some machinery between a repository and a running server is necessary, and past it each new concept costs an agent more to learn than it saves. What an agent gets the most from is correction: hearing about a mistake while it is still working on that change.

An Elements deploy is described in one file, config.jsoc, in the repository next to the code: the machines, the domains, the apt packages and any custom services. It is versioned and reviewed with everything else, a branch can change it along with the code that needs the change, and deploying is one command whose -json output covers every machine (setup, deploy).

Because the deploy settings, the code and the tests sit in one coherent system, built on SSH, Ubuntu and Postgres, one build checks them together, and the agent reads a bad setting, a failing test or a broken migration from the same -json answer.

Day-to-day access needs no dashboard either: elements ssh -remote=production gets you a shell in the app and elements db -remote=production a psql prompt, both from the same CLI (operations).

Where to Run an Elements App

You need no Coolify instance, only the app servers: Ubuntu with SSH, from DigitalOcean, Hetzner, AWS or any other host. Write their IP addresses into config.jsoc and deploy (walkthrough):

elements deploy                    # production
elements deploy staging            # a named environment
elements ssh -remote=production    # shell access, no control plane

To switch hosts, swap the address in config.jsoc for the new server's and deploy. @elements/app and the other packages your app loads at runtime are under the MIT license (licenses).

Questions

What is the difference between Elements and Coolify?

Coolify is a self-hosted PaaS: a dashboard you run that deploys apps to your servers as Docker containers. Elements is an integrated app environment, and deploy is part of its build tooling: it ships only the changed files straight to an Ubuntu server, usually in under a second, and runs your tests and migrations as part of the deploy.

Is Elements a Coolify alternative?

Yes. Elements deploys your app, and any backend services you declare next to it, to any Ubuntu server you reach over SSH, and sets up Postgres, the load balancer and TLS certificates there, with no dashboard server to run and no container images to build.

Does Elements use Docker?

No. Elements installs Postgres on the server and runs the app and its load balancer as systemd services, and a deploy sends source changes from the project server on your machine to the project server on the deploy machine (what deploy does).

How does Coolify run database migrations?

Coolify has no migration step of its own. You can run a command in the running container before a deploy, or in the new container after Coolify marks the deploy complete, and a failure after the deploy leaves it marked successful (Coolify general settings). Elements runs migrations on every deploy, in one transaction, after your tests pass and before the new release goes live.

How fast is an Elements deploy?

With no image to build, usually under a second, after a few seconds for a machine's initial setup. Only changed source files are sent, and the deploy runs tests and migrations before going live.

Where do I host an Elements app?

On the same kind of servers Coolify manages: Ubuntu machines with SSH, from DigitalOcean, Hetzner, AWS or elsewhere. Without a separate dashboard server, one machine is enough for the app, Postgres and the load balancer.