Skip to content

Optimizing Statamic

Statamic runs well on Webslice out of the box, but with some minor configuration you can achieve excellent performance and keep costs low. This guide covers the changes we recommend, based on running Statamic for our own website.

It assumes you already have a site deployed. If you don’t, start with Getting Started with Statamic.

Key Concepts

  • The best performance on any hosting platform comes from static caching. Using Statamic’s static caching is strongly recommended for an excellent combination of performance and price. If you can use the full Static Site Generator, you’ll get even better results.
  • Use /mnt/data/website/shared for files you want to persist between deploys, such as uploads, image caches, logs and form submissions. This is especially important with versioned deploys, where anything not tracked in git is dropped each time.
  • Webslice Serverless uses NFS (Network File System) storage with our caching layer over the top. This makes it fast, but some tasks, such as locking files or writing to SQLite, can impact performance.

Static Caching

Statamic’s static caching is your best friend on a serverless platform. It pre-generates HTML files for your pages, which means:

  • Lightning fast page loads
  • Minimal PHP execution
  • Lower costs from fewer invocations
  • Better performance under traffic spikes

Enable it in config/statamic/static_caching.php:

config/statamic/static_caching.php
return [
'strategy' => env('STATAMIC_STATIC_CACHING_STRATEGY', 'half'),
'strategies' => [
'half' => [
'driver' => 'application',
'expiry' => null,
],
'full' => [
'driver' => 'file',
'path' => public_path('static'),
'lock_hold_length' => 0,
'warm_concurrency' => 6,
],
],
];

The key settings here are:

  • strategy reads from an environment variable, which we set to full for maximum caching (see below)
  • driver set to file for the full strategy, which works well on serverless
  • warm_concurrency at 6, the number of pages warmed in parallel

Environment Variables

In the Webslice Console, add the following to the Env Vars section alongside the production variables you set during setup:

Terminal window
STATAMIC_STATIC_CACHING_STRATEGY=full
STATAMIC_STACHE_WATCHER=false

These enable full static caching and turn off the Stache watcher, which rechecks content files for changes on every request. In production your content only changes on deploy, so that work isn’t needed.

Persistent Storage

Anything written at runtime (uploads, image caches, logs, form submissions) lives inside your deploy directory and won’t survive the next versioned deploy unless you store it in persistent storage. The shared directory /mnt/data/website/shared exists outside your deploys and persists across all of them:

  • Directory/mnt/data/website/shared/
    • Directoryform-submissions/ Form submissions
    • Directorylogs/ Application logs
    • Directorypublic/
      • Directoryglide-cache/ Image manipulation cache, symlinked into public/

The Webslice Provider creates these three directories and points Statamic’s config at them for you. The sections below cover doing it by hand.

Form submissions and logs are private, so a config path pointing at the shared directory is all they need. The Glide cache is different: those files are served to the browser, so it also needs a symlink into public/. The persistent storage section of the Deployments overview covers the general pattern.

Asset uploads are the one case the provider leaves alone, because whether uploads belong in git is a decision about your editing workflow rather than a platform default. Asset Uploads below covers both options.

Forms

If you use Statamic’s built-in forms, point your form storage at the shared directory so submissions are preserved across deploys.

Which config key you need depends on your Statamic version. Statamic 4 reads the path from config/statamic/forms.php:

config/statamic/forms.php
return [
'forms' => resource_path('forms'),
'submissions' => '/mnt/data/website/shared/form-submissions',
];

Statamic 5 and 6 resolve it from the form-submissions Stache store instead, so set that too:

config/statamic/stache.php
'stores' => [
// ... your other stores
'form-submissions' => [
'class' => Stores\SubmissionsStore::class,
'directory' => '/mnt/data/website/shared/form-submissions',
],
],

Setting both is safe, and it keeps the path correct if you upgrade later.

Logs

Laravel writes logs to storage/logs by default, which sits inside the deploy directory. Point the channels you use at the shared directory instead:

config/logging.php
'channels' => [
'single' => [
'driver' => 'single',
'path' => '/mnt/data/website/shared/logs/laravel.log',
'level' => 'debug',
],
'daily' => [
'driver' => 'daily',
'path' => '/mnt/data/website/shared/logs/laravel.log',
'level' => 'debug',
'days' => 14,
],
'emergency' => [
'path' => '/mnt/data/website/shared/logs/laravel.log',
],
],

Image Manipulation (Glide)

Statamic uses Glide for on-the-fly image manipulation. Caching the transformed images in persistent storage avoids regenerating them on every deploy. Because these files are served to the browser, the cache needs to live somewhere under public/, which we then symlink to the shared directory.

Point the Glide route and cache at the same public path in config/statamic/assets.php:

config/statamic/assets.php
return [
'image_manipulation' => [
// Served from public/shared/glide-cache, symlinked to persistent storage below
'route' => 'shared/glide-cache',
'driver' => 'gd', // or 'imagick' if available
'cache' => true,
'cache_path' => public_path('shared/glide-cache'),
'presets' => [
// Your image presets
],
],
];

Then create the symlink so that path resolves to persistent storage. Add these lines to the build script you created during setup, after the composer install step:

.webslice/build.sh
mkdir -p /mnt/data/website/shared/public/glide-cache
mkdir -p public/shared
# replace anything already at the path, so the script can run on every deploy
rm -rf public/shared/glide-cache
ln -s /mnt/data/website/shared/public/glide-cache public/shared/glide-cache

With the symlink in place the webserver serves cached images straight from disk, rather than routing every image request through PHP. On a serverless platform that’s the difference between a static file read and a billed invocation.

Asset Uploads

Statamic asset containers write uploads to a disk defined in config/filesystems.php, which points at public/assets inside your deploy directory by default. There are two ways to handle this, and the right one depends on how your content gets edited.

Commit uploads to git. This is what we do for our own site. Assets are part of the repository, so they deploy like any other file and versioned deploys need no extra configuration. The trade-off is that anything uploaded through the Control Panel on the live site has to be committed and pushed, the same as any other Control Panel edit.

Point the disk at persistent storage. If editors upload through the Control Panel and you’d rather keep uploads out of git, move the disk root into the shared directory. Uploads are served to the browser, so this needs a symlink as well:

config/filesystems.php
'disks' => [
'assets' => [
'driver' => 'local',
'root' => public_path('shared/assets'),
'url' => '/shared/assets',
],
],
.webslice/build.sh
mkdir -p /mnt/data/website/shared/public/assets
mkdir -p public/shared
rm -rf public/shared/assets
ln -s /mnt/data/website/shared/public/assets public/shared/assets

If your asset container uses a different disk, check its handle in content/assets/ and edit that disk instead.

Cache Warming

Cache warming pre-generates your static cache files so that as many pages as possible are cached before a visitor hits them. A release script runs after each deploy goes live, which is the right place to warm the cache.

Create a .webslice/release.sh file:

.webslice/release.sh
#!/bin/bash
set -ex
echo "Starting cache warming..."
# Clear any existing cache to ensure fresh generation
php artisan cache:clear
php artisan statamic:stache:clear
php artisan statamic:static:clear
# Warm the static cache
php artisan statamic:static:warm
echo "✓ Release complete"

Make it executable:

Terminal window
chmod +x .webslice/release.sh

Then set the release script path under Settings » Build & Deploy in the Webslice Console (or in your .webslice/settings.toml), the same way you configured the build script.

Deployment Checklist

When optimizing your Statamic site for Webslice, work through these steps:

  1. Configure static caching in config/statamic/static_caching.php and set STATAMIC_STATIC_CACHING_STRATEGY=full in your env vars

  2. Disable the Stache watcher with STATAMIC_STACHE_WATCHER=false

  3. Point persistent data at /mnt/data/website/shared for form submissions, logs and the Glide cache, or let the Webslice Provider handle it

  4. Decide how uploads are stored - committed to git, or on persistent storage with a symlink

  5. Create a release script at .webslice/release.sh to warm your static cache, and make it executable

  6. Deploy and watch the first deploy to confirm cache warming completes