Templates
Deploy an open-source app or a starter in one click, with the database, Redis, MySQL, ClickHouse® database and disk it needs.
What a template is
A template is an app Deplane knows how to deploy: a self-hosted open-source app (such as analytics, monitoring or a wiki), or a starter for a common stack, a static site or a small app with Postgres. The gallery shows the templates available today. Deploying one creates an ordinary app in your team. After that it is yours like any other app: scale it, add a domain, read its logs. Deplane does not update it to newer versions of the template.
The starters cover the common stacks: a static site, Next.js, Express, Flask, FastAPI, Django, Rails and Go, plus Notes, an Express app with Postgres. The Django and Rails starters come with a Postgres database and show a visit counter stored in it, so you can see the whole path from your code to the database at once. Both are production-safe from the start (debug off, a generated secret key, the app's own address as the only allowed host) and run their database migrations each time the app starts. Edit the code and deploy again with deplane deploy; to serve a Django starter from your own domain, add the domain to its DJANGO_ALLOWED_HOSTS setting.
Browse them on the New app page of the dashboard, at deplane.io/templates, or with deplane templates list.
What it checks first
Each template says what it needs: memory (its size, plus its database, its Redis, its MySQL and its ClickHouse database if it has them; a Redis counts 256 MB, a MySQL and a ClickHouse database their size), one app, a Postgres database, a Redis, a MySQL, a ClickHouse database or a 5 GB disk. A database, a MySQL and a ClickHouse database each count as one instance of their size, like an app instance. A ClickHouse database is large, so it needs 2 GB of your plan's memory on its own. Deplane compares that with your plan and with what your team already uses:
- If your plan could never hold it, for example "Needs 2.5 GB memory; Hobby has 1.5 GB" or "Needs ClickHouse; Pro does not include it", the template asks you to upgrade (template_needs_upgrade). Templates that do their work in the background, such as Listmonk sending campaigns and Miniflux polling feeds, need an app that never sleeps, so on Free they say "Needs an app that never sleeps; Free apps sleep when idle".
- If your plan could hold it but your free room cannot, for example "Needs 1 GB; you have 512 MB free", free some room first (template_no_room).
What a deploy does
You choose only the app's name. Deplane then:
- creates the app with the template's size, port and health check;
- creates a Postgres database named after the app, waits until it is ready and attaches it (as
DATABASE_URL); - creates a Redis named after the app (
APP-redis), waits until it is ready and attaches it (asREDIS_URL); - creates a MySQL named after the app (
APP-mysql), waits until it is ready (about 30 seconds) and attaches it (asMYSQL_URL); - creates a ClickHouse database named after the app (
APP-clickhouse), waits until it is ready and attaches it (asCLICKHOUSE_URL); - adds the disk;
- sets the app's settings: random secrets are generated once for your app and are never shown (except the admin sign-in, shown once; see below), and values such as the app's address, the database's host or the MySQL's password are filled in;
- builds the app from Deplane's own copy of the template and rolls it out.
Each step happens only if the template needs it: the gallery shows Postgres, Redis, MySQL, ClickHouse and Disk badges for what a template makes.
You see each step as it happens. At the end you get the address and what to do first.
The admin sign-in
An app that is live but not set up yet belongs to whoever opens it first, and its address is public within seconds: every certificate Deplane gets is published in Certificate Transparency logs, which bots watch for fresh installers. So no template in the gallery waits for its first visitor:
- Grafana, Listmonk, Gitea, Forgejo, Keycloak, Directus, Open WebUI, WordPress, Ghost, Vaultwarden, Plausible Community Edition and Langfuse get their administrator at deploy time. Deplane generates a random password (for Vaultwarden, the admin token of its
/adminpage) and shows it once, to you, when the deploy is done: press Show the admin sign-in on the deploy in the dashboard, or read it fromdeplane launch --template(ordeplane templates credentials DEPLOY-IDfor a deploy you started with--no-waitor from an AI tool). Copy it then: Deplane does not show it again (you can ask once more within 10 minutes, in case the first answer was lost), and it is never logged. For a deploy started by a CI token, a team owner can see it. Gitea and Forgejo start with registration off, Open WebUI and Vaultwarden with sign-ups off (invite yourself from/admin). Keycloak's is a temporary admin: create your own admin in the master realm, then delete it. Directus and Open WebUI sign in asadmin@example.com, Plausible Community Edition asowner@example.com: change it to your email. Langfuse signs in asowner@example.comtoo; see Langfuse for moving to your own address. - Templates whose app cannot be set up this way are not offered: Umami (it starts with the password
umami), Docmost, Ghostfolio, Metabase, Wiki.js, Actual Budget, Uptime Kuma, Memos, Vikunja and Activepieces (their first visitor creates the owner account). They come back once Deplane can hold the app for you until you have set it up. If your team runs an app deployed from one of them, it gets a one-time notice saying what to check.
A template whose sign-in needs care carries a warning, shown on the gallery card, on the template's page, before you press Deploy in the dashboard, in deplane templates show and by deplane launch --template before the deploy starts.
Template app names get a random 10-character ending (for example grafana-k3x9q2m7wd), so the address cannot be guessed.
Your team runs one template deploy at a time. Build minutes and your plan's limits count as if you had done each step yourself.
When a step fails
Everything made so far is kept and listed. Retry (deplane templates retry DEPLOY-ID) continues from the step that failed, with the same generated secrets. Delete all of it (deplane templates delete DEPLOY-ID) deletes the app (with its disk), the database, the Redis, the MySQL and the ClickHouse database this deploy made, and nothing else; it asks for your passkey, like other deletions. A database, Redis, MySQL or ClickHouse database that another app uses by then is kept, and the result says so.
If your team already has a database, a Redis, a MySQL or a ClickHouse database with the name the deploy would give it, the deploy is refused before it starts (database_exists, redis_exists, mysql_exists, clickhouse_exists); pick another app name. If the Redis, the MySQL or the ClickHouse database cannot be created, the deploy fails at that step (redis_failed, mysql_failed, clickhouse_failed); Retry makes a fresh one.
How a template asks for a database, a Redis, a MySQL or a ClickHouse database
In a template's template.json, "postgres": {"size": "small"} asks for a database, "redis": {} for a Redis (one size, 256 MB), "mysql": {} for a medium MySQL ("mysql": {"size": "large"} for a large one; there is no small MySQL) and "clickhouse": {"size": "large"} for a ClickHouse database (large is the only size, and the default). The app's settings can then use references that are filled in at the "Set secrets" step and stored as secrets, never shown:
${app.url},${app.host}: the app's address;${secret:N}: a random secret of N characters (16 to 128), generated once;${postgres.url},${postgres.host},${postgres.port},${postgres.user},${postgres.password},${postgres.database};${redis.url},${redis.host},${redis.port},${redis.password};${mysql.url},${mysql.host},${mysql.port},${mysql.user},${mysql.password},${mysql.database};${clickhouse.url},${clickhouse.host},${clickhouse.http_port}(8123),${clickhouse.native_port}(9000),${clickhouse.user},${clickhouse.password},${clickhouse.database}.
A template may not set DATABASE_URL, REDIS_URL, MYSQL_URL or CLICKHOUSE_URL itself; attaching does. An app that wants the Redis under another name uses, for example, "CACHE_URL": "${redis.url}"; an app that wants the MySQL's parts as separate settings uses, for example, "WORDPRESS_DB_HOST": "${mysql.host}:${mysql.port}" and "WORDPRESS_DB_PASSWORD": "${mysql.password}". Variables built this way are copies: if you detach or destroy the Redis, the MySQL or the ClickHouse database, REDIS_URL, MYSQL_URL or CLICKHOUSE_URL is removed but they keep the old value, so change or remove them yourself (deplane secrets set or deplane secrets unset). The same goes for a ClickHouse database restored from another one's backup: it takes that one's password, so CLICKHOUSE_URL changes and the copies do not.
Plausible Community Edition
Plausible Community Edition, the privacy-friendly web analytics, keeps its accounts in a Postgres database and its stats in a ClickHouse database. It needs at least 3.5 GB of plan memory: a medium app (1 GB), a small database (512 MB) and a large ClickHouse database (2 GB), three instances in all. Deplane creates its owner at deploy time, like the templates above, and starts it with registration off. Each time the app starts, it takes its ClickHouse address from CLICKHOUSE_URL, so a restore from another ClickHouse database's backup needs nothing more. Plausible Community Edition is licensed AGPL-3.0: if you change it and let others use it, you must publish your changes.
Langfuse
Langfuse, the open-source LLM observability platform (traces, evaluations, prompt management and metrics), is in the gallery since 2026-10-31, after a live deploy on Deplane: first start, sign-in, a trace sent and read back, and a restart. It keeps its accounts and settings in a Postgres database, its queues in a Redis and its traces in a ClickHouse database, so it needs at least 4.75 GB of plan memory and ClickHouse, that is the Team or Enterprise plan: a large app (2 GB), a small database (512 MB), a Redis (256 MB) and a large ClickHouse database (2 GB), three instances and a 5 GB disk in all.
Langfuse is published as two programs, web and worker, and needs S3-compatible file storage. Its app runs both, unchanged from the official images, together with SeaweedFS (Apache-2.0) as that storage, reachable only from inside the app and keeping its files on the app's disk. If any of the three stops, the app restarts. When the app stops, each gets a few seconds to finish (web is not given the 110 seconds it would wait for its open connections), so a stop takes about 20 seconds at most. Within the app's 2 GB, web and worker are capped at 576 MB and 512 MB of heap and SeaweedFS at about 192 MB; LANGFUSE_WEB_HEAP_MB, LANGFUSE_WORKER_HEAP_MB and SEAWEEDFS_MEMORY_LIMIT change that. This suits a team's traces; Langfuse's own guidance for heavy ingestion is more memory than one large app has.
Deplane creates its owner, owner@example.com, with the organization and a project, at deploy time, and shows the password once like the templates above. Sign-up is off: to add people, set AUTH_DISABLE_SIGNUP to false while they sign up, add them to your organization, then set it back to true. Langfuse changes passwords only by email, so to sign in as yourself, set SMTP_CONNECTION_URL and EMAIL_FROM_ADDRESS, sign up with your own address that way, make yourself an owner and remove owner@example.com. Then remove LANGFUSE_INIT_USER_PASSWORD from the app's settings: while it is set, a deleted owner is created again, with that password, the next time the app starts.
Langfuse 4 takes traces only over OpenTelemetry: use Langfuse's current SDKs (Python 3 and later, JS/TS 4 and later) or any OpenTelemetry exporter pointed at /api/public/otel/v1/traces, with a project's API keys, which you create in the project's settings. The older /api/public/ingestion endpoint accepts only scores. In our test, a trace sent this way was stored, processed by the worker and read back through /api/public/v2/observations within seconds, and the app used about 1.1 GB of its 2 GB at rest.
Langfuse keeps a copy of every event it receives on the disk, so watch the disk as your traffic grows. SDK media uploads (images, audio and files attached to traces) are off, because the storage has no public address. SeaweedFS writes its S3 access key ID (not the secret key) to the app's logs when it starts; the storage cannot be reached from outside the app.
Langfuse's migrations
On the first start, and after an update to a newer Langfuse, the app migrates its databases before it serves anyone; the first time this takes a few minutes. Meanwhile it answers "Langfuse is starting" (and its health check passes, so the deploy shows as done). If a migration fails, the app stops and restarts to try again, so the app shows restarts rather than running: read its logs. The migrations are never stopped half-way by the app itself, even when you change a setting or deploy again meanwhile: the new release starts once they are done, or once the 30 seconds Deplane gives a stopping app are up. A migration cut short that way is taken up at the next start: an unfinished Postgres migration is run again, and so is an unfinished migration of the ClickHouse database that can safely run twice. If the logs say that one of the ClickHouse migrations "cannot safely run twice", the cut came during the very first start, before Langfuse held any of your data: delete the deploy with Delete all of it and deploy the template again. For anything else, email support@deplane.io.
While the databases are migrated, Langfuse's ClickHouse migration tool has the ClickHouse password on its command line inside the app; the Postgres password is read from the app's settings. Langfuse's core is MIT-licensed; its enterprise features stay off, because no licence key is set.
Images and licences
Open-source apps are deployed from their official images, copied into Deplane's own registry and pinned to an exact version, so a deploy never depends on Docker Hub or GitHub and the image cannot change underneath it. Deplane does not change the apps' code; it adjusts file ownership and settings so they run safely as an unprivileged user, and a few templates add a start command or a small start wrapper that sets variables and then runs the app's own entrypoint. Each template's page says how its image was made. Each template's page shows its licence, its source and the exact version. Each app is a trademark of its owner; Deplane is not affiliated with or endorsed by them. The gallery shows each project's own logo, unmodified, as published in its official repository; logos are their owners' trademarks too. Projects whose trademark policy does not allow this use or asks for permission first, and starters with no upstream logo of their own, are shown with two letters instead. Deplane's own Static site starter shows a small neutral page glyph that Deplane drew. Django's trademark license asks that its logo link to the Django website, which a gallery card does not, so the Django starter shows two letters.
ClickHouse® is a registered trademark of ClickHouse, Inc. https://clickhouse.com. Deplane is not affiliated with, sponsored or approved by ClickHouse, Inc.
Deploy from your own repository
Any public GitHub repository can be deployed in one click, like a template, if it has a deplane.template.json at its root. Deplane reads the file, pins the repository to a commit, shows what it will make and deploys that commit as an ordinary app in your team, with the Postgres database, Redis, MySQL, ClickHouse database and disk the file asks for. Deplane has not reviewed these repositories: the code is the author's, it runs with your plan's resources, and you are its owner from then on, exactly as if you had deployed the folder yourself with deplane launch.
- Dashboard: New app, then "Deploy from a GitHub repository": type
owner/repo(or the repository's URL), optionally a branch, tag or commit, press Check, then Deploy.https://app.deplane.io/new?repo=OWNER/REPO(with&ref=BRANCHif you like) opens that card filled in and checked, after sign-in: that is what the button below links to. - CLI:
deplane launch --repo OWNER/REPO[@REF] [--name APP]shows the same check, then deploys and follows the steps. - API:
POST /v1/repo-templates/checkandPOST /v1/repo-templates/deploy; the deploy is a template deploy (template: "repo"), followed, retried and deleted like any other. Both are for a person at their own login: CI tokens and AI tools are refused (repo_deploy_interactive_only), and a team may check or deploy 30 repositories in 10 minutes.
The deploy carries the commit it checked, so Retry builds the same commit, never a newer one. To take a newer version, deploy the repository again (or connect the app to GitHub and push).
The file
{
"title": "Notes",
"description": "A notes app with Postgres.",
"app": {
"port": 3000,
"size": "small",
"health": "/healthz",
"env": {
"SECRET_KEY": "${secret:32}",
"DB_URL": "${postgres.url}",
"PUBLIC_URL": "${app.url}",
"NODE_ENV": "production"
}
},
"postgres": {"size": "small"},
"note": "Open the URL and create the first account.",
"warning": "The first visitor becomes the admin: open the app right after deploying."
}
| Field | Required | Meaning |
|---|---|---|
title | yes | One line, up to 60 characters. |
description | no | One line, up to 120 characters. |
image | no | A public image to run instead of building the repository, with its registry and tag (docker.io/owner/app:1.2.3), as the Docker image card takes it. Without it, the repository is built like deplane deploy: its Dockerfile, or the stack Deplane detects. |
app.port | yes | The port the app listens on, 1024 to 65535. |
app.size | no | small (default), medium or large. |
app.health | no | The health check path, default /. |
app.disk | no | A mount path; adds a 5 GB disk. |
app.stack | no | A label of up to 40 characters; default the repository's name. |
app.env | no | Variables, with the references above: ${secret:N}, ${app.url}, ${app.host}, ${postgres.*}, ${redis.*}, ${mysql.*}, ${clickhouse.*}. |
postgres | no | {"size": "small"} (default small). |
redis | no | {}. |
mysql | no | {} (medium) or {"size": "large"}. |
clickhouse | no | {}. |
always_on | no | true for an app that must never sleep (needs a plan whose apps never sleep). |
note | no | Shown when the deploy is done, up to 500 characters. |
warning | no | One line of up to 240 characters, shown before the deploy. |
The file is at most 64 KB, and unknown fields are refused, so a typo is caught before anything is created. The gallery's variable rules apply: a variable whose name says it holds a credential (SECRET, PASSWORD, TOKEN, KEY, SALT, ...) must be generated with ${secret:N} or referenced, never written in the file, since the file is public; a long literal that looks like a pasted key is refused too; PORT, the variables Deplane sets inside every app, DATABASE_URL, REDIS_URL, MYSQL_URL and CLICKHOUSE_URL cannot be set (attaching sets the last four). The fields of Deplane's own gallery (name, category, listed, licence, logo, credentials and the others) are not accepted. The rules the file breaks are listed in the check's answer (repo_template_invalid).
Only public repositories on github.com work (repo_not_found for anything else), fetched by Deplane without any token, so nothing of yours is used to read them. The repository's source is downloaded at the build step, within the same 100 MB limit as an upload.
Link a Deploy button
Put this in your README, with your repository's name:
[](https://app.deplane.io/new?repo=OWNER/REPO)
Or as HTML: <a href="https://app.deplane.io/new?repo=OWNER/REPO"><img src="https://deplane.io/static/site/deploy-button.svg" alt="Deploy to Deplane" height="36"></a>. Add &ref=BRANCH to the link to deploy a branch or tag other than the default branch.
For a gallery template, https://deplane.io/new?template=NAME opens the New app page with that template selected, after sign-in.
This page is also available as Markdown. AI agents can start at /llms.txt.