Skip to content

From Atlas to Ptah: Keep the History, Control the Deployment

Continue an Atlas migration history with Ptah, catch a changed payment-queue view, and test both CLIs without external network access.

Ptah helps you plan, review, and apply database migrations. Try in your browser

A payment queue already has an Atlas migration history. Its next release adds a reference column and a view of unpaid invoices. The deployment team wants to keep the existing SQL and revision records while operating the migration runner and schema checks inside its own network.

We tested that handover with Ptah 0.12.0, PostgreSQL 18.6, and Atlas Community Edition compiled from v1.3.0 source. The supporting files contain the build command, complete fixtures, and recorded results. All invoices are synthetic.

This comparison follows a source-only rule for Atlas. We compiled CE ourselves; we did not download or run its commercial distribution. Statements about Atlas Pro below are theoretical comparisons based on official documentation read on September 21, 2026, not results from a Pro trial.

The starting directory has two Atlas SQL files and an atlas.sum. CE applies both files, creating app.invoices and then its paid column. We insert an unpaid invoice for Heron and a paid invoice for Badger.

The next migration adds the payment queue:

examples/migrations/20260921000300_payment_queue.sql
ALTER TABLE app.invoices ADD COLUMN reference text;
CREATE VIEW app.unpaid_invoices AS
SELECT id, customer, total_cents
FROM app.invoices
WHERE NOT paid;

Ptah can read an Atlas directory and its revision-table format directly. These are separate choices: the file convention does not determine which database table Ptah reads. Our existing history lives in atlas_schema_revisions.atlas_schema_revisions.

With PTAH_DB_URL set to the lab database, we prepare the directory and preview the handover:

Terminal window
ptah migrations hash --dir migrations --dir-format atlas
ptah migrations up --migrations-dir migrations \
--dir-format atlas --revision-format atlas \
--migrations-schema atlas_schema_revisions --verify-sum --dry-run

Hashing records the reviewed files in atlas.sum. It does not authenticate their author or establish that the SQL is correct. The dry run reports:

Current version: 20260921000200
Total migrations: 3
Pending migrations: 1

Both existing versions remain applied. The dry run leaves the recorded revision values unchanged. Omitting the revision-format setting would select Ptah’s native history layout instead; that is not the history this database holds. Check the actual table location before changing a deployment command.

Apply the pending file with the same settings:

Terminal window
ptah migrations up --migrations-dir migrations \
--dir-format atlas --revision-format atlas \
--migrations-schema atlas_schema_revisions --verify-sum
ptah schema compare --schema-file schema.sql --schemas app --exit-code

The database advances to 20260921000300. The final comparison finds no schema differences. The two original invoices retain their values; the new nullable reference is empty on those rows. A SQL client inserts invoice 3 for Otter and reads the view. The queue contains invoices 1 and 3, with totals 12500 and 4200 cents.

A second Ptah run finds zero pending migrations. Atlas CE subsequently reads the same revision table and reports three executed files with none pending. We also replayed the complete directory on separate empty databases with each CLI. Both reached the expected schema and produced the same queue after the same inserts. This establishes compatibility for these files and completed revisions; it does not cover every Atlas directive or an interrupted migration.

Executing SQL and understanding its schema objects are different capabilities. Both CLIs executed the file containing CREATE VIEW. In the resulting database, CE’s SQL inspection included the invoice table but omitted the view. Ptah’s inspection included both.

We then changed the view’s filter from WHERE NOT paid to WHERE paid. The query now returned Badger’s paid invoice, 2, instead of invoices 1 and 3. The table and migration history still looked correct.

Comparing that database against schema.sql produced different results:

Check on the altered view Observed result
Source-built Atlas CE schema diff Reported synchronized schemas; exit 0
Ptah schema compare --exit-code Reported views_modified for app.unpaid_invoices; exit 1
SQL query through the view Returned invoice 2, confirming the application-facing error

Ptah printed SQL to restore the view definition. The comparison did not execute it. We restored the definition explicitly, then checked that the queue again returned invoices 1 and 3 and the schema comparison passed.

This is a reason to evaluate the objects an application actually uses. It is not a result about Atlas Pro: the standard distribution’s documented object coverage includes views and other objects omitted from CE. A source-built CE comparison cannot establish parity with that distribution.

Give both tools credit for the checks they passed

Section titled “Give both tools credit for the checks they passed”

We changed a migration after hashing it. Both tools refused the altered directory: CE returned 1, and Ptah returned 2. Neither needed a vendor service to detect that mismatch.

A separate migration drops the customer column. Both linters found the risk:

Tested linter Finding Exit
Atlas CE migrate lint --latest 1 DS103, destructive column removal 1
Ptah migrations lint --latest 1 DS102, data loss; BC104, deployed-code compatibility 1

Ptah also warned that DS110P lacked its baseline schema. That run was thinner than a complete database-backed analysis, even though it detected the drop. The linter article examines the boundary between static findings and tests of database or application behavior.

The current Atlas feature page lists migration linting outside CE, but the pinned source build above demonstrably ran its linter. Use the recorded build and command result when evaluating this case. CE’s migrate down command did explicitly refuse execution as unsupported. We did not execute a rollback in this comparison.

Separate offline execution from telemetry and licensing

Section titled “Separate offline execution from telemetry and licensing”

The runtime lab used a container with Docker’s none network. PostgreSQL and both binaries ran inside it, communicating over loopback. It had no external network interface or default route. Source and dependency downloads happened before the isolated run.

CE received ATLAS_NO_UPDATE_NOTIFIER=1, ATLAS_NO_ANON_TELEMETRY=1, and ATLAS_NO_UPGRADE_SUGGESTIONS=1. Its pinned entry point checks the update-notifier variable before contacting the version-check service. Neither CLI received an Atlas Cloud account token. Migration execution, inspection, and the checks above completed inside this boundary.

That proves the tested local workflows do not require an internet response. It does not measure every attempted connection or cover features configured to use external registries, secret stores, or model providers. CE itself is therefore a viable offline option for the capabilities this run demonstrated.

The commercial distribution needs a separate evaluation. Atlas’s privacy documentation distinguishes anonymous telemetry from identified-user telemetry. The documented anonymous opt-out disables anonymous collection. For logged-in Pro users, the page lists command and runtime information, local hostname, database type, CLI version, and licensing identifiers. It says database contents and passwords are not collected, and describes commands or flags that upload schemas and migrations. An anonymous opt-out is not a documented switch for every category of cloud communication.

The Atlas Trust Center treats license verification separately. It documents offline user licenses, custom Enterprise offline licenses for CI/CD, and cached grants for standard pipelines. Those options matter when assessing disconnected operation. We did not test their behavior, expiry, or commercial terms.

Ptah’s tested release has no account or license-grant step in this workflow. Its default build has a no-op OpenTelemetry implementation. A build with the observability tag can enable OTLP tracing through an explicit endpoint. User-configured observability is still data leaving a process; its destination belongs in the deployment’s network policy.

For a deployment with sovereignty requirements, the useful questions are concrete: where do artifacts live, who can approve a change, what credentials can the runner use, and which outbound services are required?

Ptah’s MIT-licensed source lets this deployment retain its runner implementation and build process. Atlas CE’s source license is Apache 2.0. The distinction for this payment queue is the tested schema coverage and the deployment features the team needs around it, not whether CE can run locally.

The CI example exercises scoped database roles and checks before starting an application. The Harbor example stores schema artifacts in a private registry and passes a pinned digest to the Ptah operator. Those are separately verified ways to operate the surrounding workflow under your own control.

A locally running CLI does not establish that an entire cloud control plane can be self-hosted. This example makes no such claim about Atlas Cloud, and it does not qualify either product for a regulatory regime. It shows a narrower operational result: the payment queue moved to Ptah without replaying its existing history, and its view became part of the schema check.

Put Ptah to work

Example files