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/sharedfor 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:
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:
strategyreads from an environment variable, which we set tofullfor maximum caching (see below)driverset tofilefor the full strategy, which works well on serverlesswarm_concurrencyat6, 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:
STATAMIC_STATIC_CACHING_STRATEGY=fullSTATAMIC_STACHE_WATCHER=falseThese 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:
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:
'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:
'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:
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:
mkdir -p /mnt/data/website/shared/public/glide-cachemkdir -p public/shared
# replace anything already at the path, so the script can run on every deployrm -rf public/shared/glide-cacheln -s /mnt/data/website/shared/public/glide-cache public/shared/glide-cacheWith 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:
'disks' => [
'assets' => [ 'driver' => 'local', 'root' => public_path('shared/assets'), 'url' => '/shared/assets', ],
],mkdir -p /mnt/data/website/shared/public/assetsmkdir -p public/shared
rm -rf public/shared/assetsln -s /mnt/data/website/shared/public/assets public/shared/assetsIf 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:
#!/bin/bashset -ex
echo "Starting cache warming..."
# Clear any existing cache to ensure fresh generationphp artisan cache:clearphp artisan statamic:stache:clearphp artisan statamic:static:clear
# Warm the static cachephp artisan statamic:static:warm
echo "✓ Release complete"Make it executable:
chmod +x .webslice/release.shThen 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:
-
Configure static caching in
config/statamic/static_caching.phpand setSTATAMIC_STATIC_CACHING_STRATEGY=fullin your env vars -
Disable the Stache watcher with
STATAMIC_STACHE_WATCHER=false -
Point persistent data at
/mnt/data/website/sharedfor form submissions, logs and the Glide cache, or let the Webslice Provider handle it -
Decide how uploads are stored - committed to git, or on persistent storage with a symlink
-
Create a release script at
.webslice/release.shto warm your static cache, and make it executable -
Deploy and watch the first deploy to confirm cache warming completes