Kirby is a file-based CMS built on PHP — there is no database in a standard setup. Content lives as plain text files inside a `content/` directory, media thumbnails are generated on demand, and the admin panel (Kirby Panel) stores user accounts as YAML files. This makes deployment different from database-driven CMS platforms: you need to think carefully about which directories belong in Git and which should persist between releases.

[DeployHQ](https://www.deployhq.com/) handles this cleanly — automate Composer installs, keep persistent directories intact across releases with [zero-downtime deployments](https://www.deployhq.com/features/zero-downtime-deployments), and clear Kirby's cache automatically after every deploy.

This guide assumes you have a server running Apache or Nginx with PHP 8.1+ and Composer installed.

## Kirby's File-Based Architecture

Unlike WordPress or Craft CMS, Kirby stores everything in the filesystem:

- **`content/`** — Pages, articles, and structured data as text files (Markdown + YAML frontmatter)
- **`media/`** — Auto-generated thumbnails and processed images
- **`site/accounts/`** — Panel user accounts (hashed passwords, roles)
- **`site/cache/`** — Template cache, pages cache, plugin caches
- **`site/sessions/`** — Active user sessions
- **`site/config/`** — Environment-specific configuration files

Every page in Kirby is a folder inside `content/`, and every field is a line in a text file. When editors make changes through the Panel, those changes write directly to `content/` — meaning this directory is modified at runtime, not just at deploy time.

## Handling the Content Directory

The biggest decision in a Kirby deployment is whether `content/` belongs in your Git repository.

**Content in Git** (recommended for developer-managed sites):

- Full version history for all content changes
- Content is part of the deployment pipeline
- Works well when developers write content locally and push
- Downside: Panel edits on the server create drift between Git and production

**Content outside Git** (recommended when editors use the Panel):

- Add `content/` to `.gitignore`
- The directory persists on the server across deployments
- Panel edits are never overwritten by a deploy
- Downside: no version control on content unless you set up a separate backup

For most teams using Kirby's Panel in production, keeping `content/` out of Git and treating it as a shared persistent directory in DeployHQ is the right approach.

## Setting Up DeployHQ

### Create a Project

After [signing up](https://www.deployhq.com/signup) and logging in, create a project via **Projects** > **New Project**. Follow the wizard to connect your Git repository. If you run into connection issues, check [DeployHQ's support page](https://www.deployhq.com/support).

### Create a Deployment User

For security, create a dedicated user on your server:

```bash
sudo adduser deployhq
sudo usermod -a -G www-data deployhq
```

### Configure the Server

Go to **Servers** > **New Server** and configure an SSH connection:

- Enter a name for the server and select **SSH** as the protocol
- Set the **Hostname** to your server's IP address
- Set **Username** to `deployhq`
- Check **Use SSH key rather than password for authentication?**

Then on your server, set up the SSH key:

```bash
su - deployhq
mkdir ~/.ssh
chmod 700 ~/.ssh
nano ~/.ssh/authorized_keys
```

Paste DeployHQ's public key, save with `Ctrl + X`, `y`, `Enter`, then set permissions:

```bash
chmod 600 ~/.ssh/authorized_keys
```

Set the **Deployment Path** to your project root, e.g. `/var/www/kirby-site`.

Enable **Perform zero-downtime deployments on this server**. This creates a `current/` symlink that points to the latest release, so your web server root should be set to `/var/www/kirby-site/current`.

Set **Environment** to `production` and enable automatic deployment.

### Zero-Downtime Shared Paths

With [zero-downtime deployments](https://www.deployhq.com/features/zero-downtime-deployments) enabled, each deploy creates a new release directory. Directories that need to persist between releases must be configured as **shared paths**.

Add these as shared directories:

- `content` — Preserves all page content and Panel edits
- `media` — Keeps generated thumbnails so they do not need to be regenerated
- `site/accounts` — Preserves Panel user accounts across releases
- `site/sessions` — Prevents users from being logged out after a deploy

DeployHQ will symlink these directories from a shared location into each new release automatically.

### Config Files

Kirby supports environment-specific configuration. If you use a `.env` file or a `site/config/config.production.php`, upload it via **Config Files** > **New Config File** so it is injected into every release without being stored in Git.

A typical `site/config/config.production.php` might look like:

```php
<?php
return [
    'debug' => false,
    'cache' => [
        'pages' => [
            'active' => true
        ]
    ],
    'thumbs' => [
        'quality' => 80
    ]
];
```

## Build Pipeline

If your Kirby project uses Composer for plugins or a frontend build step (e.g. Vite, Webpack, or Laravel Mix for CSS/JS), configure these in the [build pipeline](https://www.deployhq.com/support/build-pipelines/deploybuild-dot-yaml).

Add a `deploy.build.yaml` to your repository root:

```yaml
build:
  - composer install --no-dev --optimize-autoloader --no-interaction
  - npm ci && npm run build
```

The `--no-dev` flag skips development dependencies, and `--optimize-autoloader` generates an optimized class map for production. The npm step is only needed if you have a frontend build — remove it if your project does not use one.

## Kirby Cache Management

Kirby uses several cache layers that need to be cleared after deployment to ensure visitors see the latest content and templates.

**Template cache** — Compiled PHP templates are cached automatically. After deploying template changes, stale cache files will serve the old version until cleared.

**Pages cache** — When enabled in `config.php`, Kirby caches full page HTML output. This dramatically speeds up response times but means content changes (including those pushed via deploy) will not be visible until the cache is cleared.

**Plugin caches** — Some plugins maintain their own cache buckets.

### Post-Deploy Cache Clearing

Configure a post-deployment SSH command via **SSH Commands** > **New SSH Command**:

```bash
cd %path% && rm -rf site/cache/*
```

This removes all cache directories in one step. Kirby regenerates caches automatically on the next request.

If you are using Kirby's CLI (available via Composer), you can use the built-in command instead:

```bash
cd %path% && php vendor/bin/kirby clear:cache
```

**Recommended command order:**

1. Composer install (if not handled in build pipeline)
2. Clear cache

## Media and Thumbnails

Kirby generates image thumbnails on first request and stores them in `media/`. Without shared paths, every deployment would regenerate all thumbnails — causing slow first-load times for image-heavy pages.

By configuring `media/` as a shared directory (covered above), thumbnails persist across releases. New images will have thumbnails generated automatically when first requested.

## Kirby License

Kirby requires a license for production use. Register at [getkirby.com](https://getkirby.com/buy) and add the license key to `site/config/config.php` or your `.env` file. Kirby runs without a license locally but displays a warning banner in the Panel on production domains without a valid key.

## Multi-Environment Setup

Kirby's configuration system supports multiple environments natively through domain-specific config files:

- `site/config/config.php` — Base configuration (all environments)
- `site/config/config.staging.example.com.php` — Staging overrides
- `site/config/config.production.example.com.php` — Production overrides

Kirby loads the base config first, then merges in the file matching the current domain. In DeployHQ, set different servers for staging and production branches, each with their own config files.

## Deploying

Once everything is configured, click **Deploy Project** in the header. Select your server and the revision range, then click **Deploy**. DeployHQ will:

1. Pull the latest code from your repository
2. Run the build pipeline (Composer, npm)
3. Create a new release directory
4. Symlink shared paths (content, media, accounts, sessions)
5. Inject config files
6. Run post-deploy SSH commands (cache clearing)
7. Switch the `current` symlink to the new release

Your Kirby site is now live with zero downtime.

For guides on deploying other frameworks, visit the [DeployHQ guides page](https://www.deployhq.com/guides).

---

Need help? Reach out to us at [support@deployhq.com](mailto:support@deployhq.com) or on [Twitter/X](https://x.com/deployhq).