Quick start
1
Enable migrations on the connection
Add
migrations.enabled: true to your OpenSearch connection. This works both for connections declared directly in application.yml and for connections defined in a module config file such as opensearch-config.yml.opensearch-config.yml
2
Create the migration directory
opensearch reads files from /migrations/opensearch/.3
Add JSON files
Create
/migrations/opensearch/sf-entities-template.json:4
Run migrations
-m (or pass -m sql) to run SQL migrations instead. The --sqlPath argument is the shared migrations root for both types.Migration file types
An explicit envelope ({method, path, body?, name?}) is always sent as a raw request. Otherwise the filename decides first:
For
*-template.json, a full composable template body (with index_patterns) is sent as-is. A raw settings / mappings / aliases definition is wrapped into a valid template, defaulting index_patterns to ["{name}*"] (which covers the bare index plus dated variants like sf-events-2026.09.04). Put an explicit index_patterns list in the file to override that default.
For other filenames the content decides:
The resource
{name} defaults to the file name without .json and without a trailing -template, -policy, or -index suffix, so sf-entities-template.json manages the sf-entities index (or template, or policy, depending on content). Index names are lowercased because OpenSearch requires lowercase index names.
Files are executed in alphabetical order (including sub-folders such as release-1.0/), and the relative path is the migration identity.
Idempotency
Executed migrations are recorded as documents in thewinter_migrations index (one document per connection plus relative path, the OpenSearch equivalent of the winter_migrations SQL table), together with a SHA-256 hash of the file content. Re-runs skip files whose hash is unchanged and re-apply files whose content changed, so editing a template or policy file and re-running updates it in place.
Every operation is also safe to replay:
- Index template and ISM policy PUTs are natural upserts.
- Index creation first checks whether the index already exists, so re-running against a cluster whose
winter_migrationsindex was lost succeeds instead of failing withresource_already_exists_exception.
Connection configuration keys
hosts(required)username/password(basic auth)ssl_verification(defaulttrue)timeoutandconnect_timeoutin secondsproxy(explicit proxy URL, orfalseto disable proxying)
Notes
- The HTTP client is self-contained (no
opensearch-phpdependency). It uses the Swoole coroutine HTTP client inside a Swoole coroutine (the same approach as the winter-opensearchSwooleHttpHandler), cURL when available, and the PHP stream wrapper as a fallback. Hosts are tried in order on transport failure. - First failure stops all migrations. There is no automatic rollback, matching the SQL migration behaviour.