Managing Releases & Execution
A release is a versioned list of scripts that runs as one fail-fast unit. This page covers composing and signing off a release, running it, per-script target binding, execution modes, catalog-driven target discovery, the execution record, deterministic rollback generation, and running the same release in another environment.
Execution Modes
The Run dialog exposes an Execution Mode governing multi-statement failure behavior. All modes run on a single connection, so session state (temp tables, SET) carries across statements, and the record captures per-statement outcome. The dialog explains the chosen mode under it.
- Transactional (all or nothing), one enclosing transaction; first failure rolls back the whole script, leaving the target untouched. Default. Non-transactional statements (
CREATE INDEX CONCURRENTLY,VACUUM) must use "Stop on first error". On MongoDB, Redis, Cassandra and Elasticsearch, which have no multi-statement transaction, and on Neo4j scripts that mix schema and data statements, DB Studio captures each statement's rollback before the run; if a statement fails, the statements already applied are reversed from their captured prior state, newest first, and the run says it was rolled back. Other sessions can see the applied changes until they are reversed. A statement that cannot be reversed (for example a MongoDBbulkWrite, a RedisFLUSHDBor a CypherMERGE) is allowed only as the last statement, since nothing after it can fail; anywhere else the script is refused in this mode before anything runs, with the reason, and runs with "Stop on first error". If a reversal itself fails, the run names the statement and the error. - Stop on first error, sequential, halt on first failure; already-applied statements persist (no rollback).
- Continue on error, attempt every statement, report exactly which failed. For idempotent batch remediation.
A run has no time limit on any engine: a statement runs for as long as the database takes, whether seconds or hours. The connection's Statement timeout applies to IDE queries only, and pre-flight checks that run as part of a script have no time limit either. A run keeps TCP keep-alive on for its connection, so a statement that runs for hours is not dropped by a firewall or load balancer that closes idle connections. A time limit set in the database itself, such as a PostgreSQL role's statement_timeout, still applies.
Composing a Release
Release Managers and admins create a release with Create Release: a name, a target environment and a target (a grouping or a connection), and if you like a version (generated as vYYYYMMDD-HHMMSS when left empty), a description and a planned date in your local time. The target environment and target label the release; they do not limit where it runs. The planned date records when you intend to run the release; nothing runs automatically. A new release starts Pending. The release card and detail name the version and target environment and show the script count; the detail also names the target. Every change is saved on the server before the screen updates; a refused change names the release and gives the server's reason, and leaves the release as it was.
Add Scripts in the release detail lists the scripts already in the release, then the scripts in the release's environment, then the others. Each row shows the script's status, environment, target and database system. A script that cannot join says so on its row (Other database system or Other environment); click it to read why. You can also choose a release while uploading or editing a Release-type script; those lists offer only the releases the script can join and say how many they leave out. Rules:
- Any script can be added, approved or not; every script must be approved before the release can be signed off.
- A release holds one database system: scripts whose target connections are different database types cannot be combined.
- A release runs in one environment: each script runs on its own target, so scripts whose targets are in different environments cannot be combined. The targeted scripts already in a release decide its environment.
- Scripts without a target fit any release; they run on the fallback connection chosen in Execute.
- A script appears in a release at most once. The scripts run in dependency order (each after the scripts it depends on), otherwise in the order they are listed; sign-off stores that order.
- Sign-off is refused when the scripts depend on each other in a loop, or when a script depends on a script that is neither in the release nor has completed a run.
- Changing the scripts of a signed-off release returns it to Pending.
Release Statuses
| Status | Meaning | What can happen next |
|---|---|---|
| Pending | Being assembled, or changed since its sign-off. | Add or remove scripts, edit, sign off |
| Signed Off | Reviewed by an approver; who signed off, when, and the SQL of every script are recorded. | Run; changing the scripts or their SQL returns it to Pending |
| Running | A run is in progress. | Nothing until it finishes: a second run, sign-off and changes to the release are refused |
| Executed | The last run completed every script; the completion time is shown on the release. | Run again, for example against another environment's connection |
| Failed | The last run stopped at a failed script. | Fix the cause and run again |
Signing Off a Release
Approvers, Release Managers and admins see Sign Off on a pending release. The server refuses, with the reason, a release that has no scripts, a release with scripts that are not approved (it names them), and a release that is already signed off. A sign-off records who signed off and when, and the SHA-256 of each script's SQL at that moment, adds an entry to the audit log, and notifies Release Managers and the release's creator.
Running a Release
Release Managers and admins see Execute on a signed-off, executed or failed release. The dialog lists the scripts to run, asks for a fallback connection for scripts without a target (with an optional database override) and an execution mode, and runs. The server refuses to run a release that is not signed off. When a script's SQL no longer matches what was signed off, the server returns the release to Pending and names the scripts that changed; the dialog shows the server's reason. Otherwise the scripts run in dependency order, each against its bound target (or the fallback), each recorded RUNNING → COMPLETED | FAILED, and the run stops at the first failure; later scripts are not attempted. A live progress panel tracks each script (pending, running, completed, failed or skipped, with rows affected and timing). When the run ends, the release becomes Executed or Failed.
While a run is in progress the release is Running: a second run of it is refused with who started the first, and so are sign-off and changes to the release. The scripts run with the SQL that was signed off, so editing a script during a run does not change that run (it does return the release to Pending afterwards). Every run is recorded with who started it, when, its connection's environment and its outcome, and the release detail lists the latest runs. A run that stops without finishing, for example because the server restarted, is marked failed after three minutes without progress.
Per-Script Target Binding
Each script persists its own target_connection_id and target_database, so one release can run its scripts against several instances of one database system in one environment. Binding is resolved at execution time; a script without a target runs on the fallback connection.
Deleting a Release
Only admins can delete a release, and the card is removed only after the server confirms. A release that has run (it has execution records) or that has approval requests is kept with its history: Delete is disabled and says why on hover, and the server refuses such a delete with the reason. A release without history is deleted together with its script list; the scripts themselves stay in Migration Scripts.
Standalone Execution
Execute a single script directly: the Execute dialog names the script and its target, starts from the script's own instance and database, and offers only instances of the script's engine in its environment. Use the connection's database runs against the database set on the connection. Running calls POST /api/db-devops/executions/run and shows the result inline (Running, then Completed or Failed, with rows affected and duration). The server refuses the run, records nothing and shows why when a release script is not approved, or when an ad-hoc script that is not approved targets an environment that requires approval; changing an approved script's SQL returns it to Pending, so new SQL never runs unreviewed. Press Esc to close the dialog unless a run is in progress.
Target Discovery
Target pickers read each instance's databases through its engine with GET /api/db-devops/connections/:id/databases:
| Engine | Source | Filtering / detail |
|---|---|---|
| PostgreSQL, CockroachDB, TimescaleDB | pg_database | Excludes templates; includes size. |
| MySQL / MariaDB | information_schema.schemata | information_schema, mysql, performance_schema and sys are listed as system databases. |
| SQL Server | sys.databases | Online only; master, model, msdb and tempdb are system databases. |
| MongoDB | listDatabases | admin, config and local are system databases. |
| Oracle | v$pdbs | Open pluggable databases; the connected service when v$pdbs cannot be read. |
| Redis | CONFIG GET databases, INFO keyspace | Numbered databases 0 to N-1 with their key counts. |
| Cassandra | system_schema.keyspaces | Keyspaces; the system keyspaces are system databases. |
| Neo4j | SHOW DATABASES | Databases with their status; system is a system database. |
| Elasticsearch, ClickHouse | None | Answered as having no list; scripts use the connection's database. |
Run Progress
A run continues on the server from the moment you confirm it, whether or not anyone watches. While it runs, the Run dialog shows what the run is doing and how far it has got, read from the server every second:
- The step before the first statement: evaluating the pre-flight checks, or capturing the rollback.
- Running statement 3 of 10, a bar of the statements done out of the total, and how many failed. The bar moves only when a statement finishes, so it never claims more than has run.
- The statement running now, its first 80 characters, and how long it has been running. How long the whole run has taken is shown beside it.
- For a release, the same for the script that is running, with the scripts before it completed and the scripts after it waiting.
- When an all-or-nothing run on MongoDB, Redis, Cassandra, Elasticsearch or Neo4j fails, the reversal of the statements already applied, counted the same way.
- Inside a long statement, what the database itself reports about it, read every 3 seconds once the statement has run for 2 and dated with when it was read. Where the database gives a share done, a second bar shows it:
- PostgreSQL and compatible engines: index builds, CLUSTER and VACUUM FULL, VACUUM, ANALYZE and COPY, from their
pg_stat_progressviews, and a statement waiting for a lock that another session holds. - MySQL: the stage and its work done when performance_schema records stages (the
events_stages_currentconsumer and thestage/innodb/alter%instruments). Otherwise the statement's state, and that stage recording is off. - MariaDB: the stage it reports for ALTER TABLE, LOAD DATA and similar statements (stage 2 of 4), and the percent of that stage when it gives one.
- SQL Server: percent complete and the time left for the commands that report them (backup, restore, DBCC, index reorganize, rollback); otherwise the command and what it waits on. The connection's login needs VIEW SERVER STATE, and the run says so when it lacks it.
- Oracle: long operations from
V$SESSION_LONGOPS, for users who can readV$SESSIONandV$SESSION_LONGOPS(for example with SELECT_CATALOG_ROLE); the run says so when the user cannot. - CockroachDB, Redshift, TiDB, PlanetScale, SQLite, MongoDB, Redis, Cassandra, Neo4j, Elasticsearch and the other engines report nothing inside a statement, and the run says so.
sdbs-run-followed by the execution id (the PostgreSQLapplication_name, the SQL Server program name, the Oracle module), so a DBA can find them, and the progress reader's own session is namedsdbs-progress. - PostgreSQL and compatible engines: index builds, CLUSTER and VACUUM FULL, VACUUM, ANALYZE and COPY, from their
Escape and a click outside leave the dialog open while the run is in progress. Close and keep running closes it and the run carries on; Executions and Active Deployments show its progress, and its record holds the outcome when it ends. A statement is counted the way the engine runs the script: a SQL statement, a SQL Server batch (the script is split at GO lines, so a script without them is one batch), a MongoDB call, a Redis command, an Elasticsearch operation, or for PostgreSQL without an execution mode the whole script as one statement.
The server records a run's progress about once a second and confirms every 15 seconds that it is still running. If the server running a run stops (a restart, a crash, a lost database connection), another server marks the run Failed after 90 seconds without that confirmation, saying that the server stopped before the run finished and that what it applied is unknown. A rollback that stops this way leaves the original run completed, so it can be rolled back again. SQLite scripts run on a separate thread, so a long SQLite statement does not hold up the server.
Execution History
Executions lists every run: single script runs, each script of a release run, and rollbacks. It loads the history from the server each time it opens, and says so with a Retry button when the history cannot be loaded. Search by script, who ran it, release or connection, and filter by status, environment and kind of run. Each card shows the environment, the release or that it is a rollback, who ran it and when it started, and for a run in progress how far it has got. While any run is in progress the list refreshes every 2 seconds. Opening a run in progress shows the same progress as the Run dialog. Opening it says who ran it and when, the connection and database, the release, the rows affected and duration or the error. Full Details shows the status and result, the script with its revision and execution mode, where it ran (environment, connection, database and release, each named), when it finished or that it is still running, the SQL that ran, the output and the rollback; Copy copies the SQL that ran and says so. A recent run on the Overview opens its details directly.
Execution Record
Each run, a single script or each script of a release run, leaves a record that the API cannot create or rewrite:
| Field | Content |
|---|---|
| Script | The script that ran. |
| SQL | The exact SQL that ran, its SHA-256 and the script revision it came from. If the script changes later, the run's details say so and name the current revision. |
| Target Connection | The connection it ran against: the script's own target, or the run's connection for a script without one. |
| Database | The database it ran in: the script's own target database, the database chosen for the run, or the connection's default. |
| Mode | Transactional, stop on first error, or continue on error, when the run chose one. |
| Executed By | Who started the run. |
| Start / End / Duration | Timing. |
| Status | RUNNING, COMPLETED, FAILED, ROLLED_BACK (ROLLING_BACK while its rollback runs). |
| Rows Affected / Output | The engine's summary of the run. |
| Error Message | Full driver error on failure. |
| Rollback | The rollback captured for this run: the deterministic rollback generated before it ran, otherwise the script's own rollback SQL at the time it ran. |
Rolling Back a Run
A Release Manager or admin can roll back a completed run from its card in Executions. The card shows the SQL that Roll Back will run, the run's own captured rollback, and Roll Back asks for a reason, naming the script and when it ran; an empty reason changes nothing. Roll Back is offered only when the rollback has a statement to run: some changes, such as dropping a schema, cannot be undone automatically, and their rollback holds only notes that say why, so the card shows those notes and says the run cannot be rolled back. The rollback runs on the server against the same connection and database, in one transaction where the engine supports it, and is recorded as its own run marked as the rollback of the original. While it runs, the card shows its progress and can be closed; a message says when it has finished. Only when it succeeds does the original become Rolled back, with who rolled it back, when and why; a rollback that fails is recorded as failed and the original stays completed.
- A run can be rolled back once. A failed run, a run that is itself a rollback, a run with no rollback SQL, and a run whose connection was deleted cannot be rolled back; the reason is shown.
- A rolled-back run no longer counts as a completed run of its script, so scripts that depend on it wait until it runs again. A rollback run never counts as a run of the script.
Deterministic Rollback Generation
On every engine, before the forward script runs DB Studio reads the pre-change state of what the script changes and derives an exact inverse in the engine's own language, not a guess, but a rollback computed from the actual prior state, kept with that run (shown in its details and in the result), and saved as the script's rollback only when the script has none of its own. The inverse statements run in reverse order of the script.
- PostgreSQL, TimescaleDB, CockroachDB, MySQL, MariaDB, SQL Server, Oracle and SQLite: an UPDATE becomes per-row restores of the prior values, matched by primary key (by
ROWIDon Oracle androwidon SQLite when the table has none); a DELETE becomes INSERTs re-creating the removed rows (insideSET IDENTITY_INSERTon SQL Server tables with an identity column); an INSERT whose primary key values are written in the statement becomes DELETEs of those rows, and an upsert (ON DUPLICATE KEY,INSERT OR REPLACE,REPLACE INTO,ON CONFLICT) also puts back the rows it replaced; CREATE of a table, index, view, sequence, function or procedure becomes its DROP; a replaced view gets its prior definition back (and on PostgreSQL a replaced function or procedure too); ADD COLUMN becomes DROP COLUMN, a named constraint is dropped again, and a RENAME (including SQL Server'ssp_rename) is renamed back. - MongoDB: a created collection or view is dropped; inserted documents with an
_idare deleted; updated and replaced documents are put back whole by_id; deleted documents are inserted again; a created index is dropped and a dropped index created again with its options; a renamed collection is renamed back. Values keep their types (ObjectId,ISODate,NumberLong,NumberDecimal). - Redis: every key the commands write is put back as it was, its string, hash, list, set or sorted set and its expiry, and a key that did not exist is deleted.
- Cassandra: a created table, index, materialized view, type or keyspace is dropped; ADD becomes DROP; rows an INSERT, UPDATE or DELETE touches (by the primary key in the statement) are put back as they were, or deleted when they did not exist.
- Neo4j: created nodes are deleted, leaving nodes that already matched the same pattern; SET and REMOVE are undone by restoring each node's or relationship's properties and labels by element id; a DETACH DELETE re-creates the nodes with their relationships; a created index or constraint is dropped and a dropped one created again from its definition.
- Elasticsearch: a created index is deleted; indexed, updated and deleted documents are put back from their prior source or deleted when new, including those an
updateByQueryordeleteByQuerytouches; an added alias is removed and a removed alias added again.
Genuinely irreversible operations, TRUNCATE, DROP, DROP COLUMN, lossy type changes, a mapping field added in Elasticsearch, a server-wide Redis command, values an engine cannot write back such as binary Redis values, are enumerated as irreversible rather than fabricated, and a change that matches more than 10,000 rows, documents or members is not captured, so the rollback's coverage is explicit. Statements a rollback cannot be derived from, such as a MongoDB bulkWrite or a Cypher MERGE, are listed as notes.
Failure Handling
When a script fails, the driver error is recorded in full on its execution record, later scripts are not attempted, and the release becomes Failed. Fix the cause and run it again. A problem outside the scripts (a connection, a lock, missing data) needs no new sign-off; a change to a script's SQL returns the release to Pending, and it must be signed off again before it runs.
Running in Another Environment
A signed-off release can run again in another environment: choose a connection there as the fallback. A run happens in the environment of the connections it touches (the fallback and each script's own target), and they must all be in one environment; otherwise the run is refused and names the environments it would touch. The sign-off still covers the run as long as the release's scripts and their SQL are unchanged.
Two environment settings gate a run, and a refused run names what is missing:
- Runs Only After: the release needs a completed run in that earlier environment since it was signed off.
- Requires Approval: the release needs an approved approval request for that environment, made after it was signed off. Request it from the release detail (Environment approvals, then Request Approval), and have an Approver sign it in the Approvals view. The fresh install's Staging and Production require approval.
Every run records its environment, so the release detail shows where the release has already run.