Important notice: This addon is in an alpha state. Expect bugs. Do not use in production without rigorous testing. Please raise issues.
A PostgreSQL-native content engine for Statamic 6. Replaces flat-file Stache storage with PostgreSQL while preserving full compatibility with Statamic's Query Builder, GraphQL API, Antlers tags, and Control Panel.
No Eloquent models. No statamic/eloquent-driver. Direct PostgreSQL storage through Statamic's repository contracts.
What it does
- Stores all Statamic content types in PostgreSQL: collections, entries, taxonomies, terms, globals, navigations, asset containers, forms, submissions, and revisions
- Uses PostgreSQL-native features: JSONB for flexible data, UUID primary keys, citext for case-insensitive handles, tsvector for full-text search, pg_trgm for fuzzy search
- Provides bidirectional import/export between flat files and PostgreSQL
- Includes observability tooling: slow query logging, query profiling, health checks
What it doesn't do
- Does not use Eloquent models for content persistence
- Does not require
statamic/eloquent-driver - Does not introduce a custom query API — everything works through standard Statamic methods
- Does not store blueprints, fieldsets, or users — those stay in their default locations
Requirements
- PHP 8.5+
- PostgreSQL 15+
- Statamic 6
- Laravel 13
Installation
1. Install the package
composer require stokoe/postgres-engine
2. Configure your database
Your .env should have a PostgreSQL connection:
DB_CONNECTION=pgsqlDB_HOST=127.0.0.1DB_PORT=5432DB_DATABASE=your_databaseDB_USERNAME=your_userDB_PASSWORD=your_password
3. Activate the addon
Add this to your .env:
POSTGRES_ENGINE_CONNECTION=pgsql
Without this line, the addon stays dormant and Statamic uses Stache as normal.
4. Run migrations
php artisan migrate
5. Verify
php artisan pg-engine:doctor
All checks should pass.
6. Publish config (optional)
php artisan vendor:publish --tag=postgres-engine-config
See INSTALL.md for the full installation guide including troubleshooting.
Usage
Once activated, the addon is transparent. All standard Statamic code works without modification:
// Query Builder — works identicallyEntry::query()->where('collection', 'blog')->orderBy('date', 'desc')->get(); // Facades — work identicallyCollection::findByHandle('blog');Taxonomy::findByHandle('tags');GlobalSet::findByHandle('site_settings'); // Repository contracts — resolve to PostgreSQL implementationsapp(EntryRepository::class)->find($id);app(CollectionRepository::class)->all();
Antlers templates, GraphQL queries, and the Control Panel all work without changes.
Import & Export
Import flat files into PostgreSQL
# Dry-run first (validates without writing)php artisan pg-engine:import content --dry-run # Full importphp artisan pg-engine:import content
Export PostgreSQL back to flat files
php artisan pg-engine:export storage/app/export --overwrite
Import specific content types
php artisan pg-engine:import content --type=collectionsphp artisan pg-engine:import content --type=entries --collection=blogphp artisan pg-engine:import content --type=taxonomiesphp artisan pg-engine:import content --type=terms --taxonomy=tagsphp artisan pg-engine:import content --type=globalsphp artisan pg-engine:import content --type=navigationsphp artisan pg-engine:import content --type=assetsphp artisan pg-engine:import content --type=formsphp artisan pg-engine:import content --type=submissionsphp artisan pg-engine:import content --type=revisions
Export specific content types
php artisan pg-engine:export path/to/export --type=collections --overwritephp artisan pg-engine:export path/to/export --type=globals --overwritephp artisan pg-engine:export path/to/export --type=navigations --overwrite
Import is idempotent — running it twice updates existing records without creating duplicates. Export supports --dry-run and --overwrite flags. Sensitive metadata (IP hashes, user agent hashes) is excluded from exports.
See docs/IMPORT_EXPORT.md for the full import/export architecture.
Switching Between PostgreSQL and Flat Files
| Mode | .env setting |
Content source |
|---|---|---|
| PostgreSQL | POSTGRES_ENGINE_CONNECTION=pgsql |
pg_* tables |
| Flat files | Line removed or commented | content/ YAML/MD files |
To switch back to flat files:
# Comment out the activation line in .env# POSTGRES_ENGINE_CONNECTION=pgsql # Clear cachesphp artisan cache:clearphp artisan statamic:stache:clearphp artisan statamic:stache:warm
To switch back to PostgreSQL, uncomment the line. No reimport needed.
Commands
| Command | Description |
|---|---|
pg-engine:doctor |
Health check: connection, extensions, tables, indexes, bindings |
pg-engine:import {path} |
Import flat files into PostgreSQL |
pg-engine:export {path} |
Export PostgreSQL content to flat files |
pg-engine:reindex |
Rebuild full-text search indexes |
pg-engine:search:test {query} |
Test search queries interactively |
pg-engine:stats |
Query statistics and slow query report |
All commands support --help for full option details.
Search
The addon provides PostgreSQL-native search with four modes:
- Full-text search — tsvector-based, language-aware, ranked by relevance
- Fuzzy search — pg_trgm trigram matching for typo tolerance
- Hybrid search — combines full-text and fuzzy results
- Accent-insensitive search — uses the unaccent extension
Search weights are configurable per field (A/B/C/D ranking). Rebuild indexes after import:
php artisan pg-engine:reindex
Architecture
See docs/ARCHITECTURE.md for the full technical architecture.
The addon is structured in layers:
ServiceProvider — Registers all bindings, validates config ├── Repositories — Implement Statamic contracts (Entry, Collection, etc.) │ ├── Hydrators — Convert DB rows ↔ Statamic objects │ └── Storage — Raw PostgreSQL operations (no Eloquent) ├── Query — EntryQueryBuilder, TermQueryBuilder, SQL compilation ├── Search — Full-text, fuzzy, hybrid search engine ├── Import/Export — Bidirectional flat-file ↔ PostgreSQL ├── Observability — Query profiling, slow query logging ├── Support — Identity map, cycle detector, bulk loader └── Commands — Artisan commands (doctor, import, export, reindex, stats)
Testing
composer test
The test suite enforces strict guards — any incomplete, skipped, or noticed test fails the run:
- 976 tests, 5114 assertions
- 0 incomplete, 0 skipped, 0 PHPUnit notices
failOnIncomplete,failOnSkipped,failOnNotice,failOnRiskyall enabled
Compatibility
This addon maintains full compatibility with:
- Statamic Query Builder —
Entry::query(),where(),orderBy(),paginate(), JSONB dot-notation - Statamic GraphQL API — collections, entries, globals, filtering, sorting, pagination
- Antlers tags —
{{ collection }},{{ nav }},{{ global }}, all standard tags - Control Panel — listings, filtering, sorting, pagination, publish/unpublish
- Native Statamic objects —
Entry,Collection,Term,GlobalSet,Nav, etc.
Existing Statamic code works without modification.
Postgres Engine is a Commercial Addon.
You can use it for free while in development, but requires a license to use on a live site. Learn more or buy a license on The Statamic Marketplace!