stokoe / statamic-postgres-engine
Package info
github.com/Stokoe-dev/statamic-postgres-engine
pkg:composer/stokoe/statamic-postgres-engine
Requires
- statamic/cms: ^6.0
Requires (Dev)
- orchestra/testbench: ^10.8
This package is auto-updated.
Last update: 2026-05-07 07:54:33 UTC
README
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=pgsql DB_HOST=127.0.0.1 DB_PORT=5432 DB_DATABASE=your_database DB_USERNAME=your_user DB_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 identically Entry::query()->where('collection', 'blog')->orderBy('date', 'desc')->get(); // Facades — work identically Collection::findByHandle('blog'); Taxonomy::findByHandle('tags'); GlobalSet::findByHandle('site_settings'); // Repository contracts — resolve to PostgreSQL implementations app(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 import php 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=collections php artisan pg-engine:import content --type=entries --collection=blog php artisan pg-engine:import content --type=taxonomies php artisan pg-engine:import content --type=terms --taxonomy=tags php artisan pg-engine:import content --type=globals php artisan pg-engine:import content --type=navigations php artisan pg-engine:import content --type=assets php artisan pg-engine:import content --type=forms php artisan pg-engine:import content --type=submissions php artisan pg-engine:import content --type=revisions
Export specific content types
php artisan pg-engine:export path/to/export --type=collections --overwrite php artisan pg-engine:export path/to/export --type=globals --overwrite php 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 caches php artisan cache:clear php artisan statamic:stache:clear php 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!