<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: dband drm</title>
    <description>The latest articles on DEV Community by dband drm (@dband-drm).</description>
    <link>https://dev.to/dband-drm</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3760580%2F35b4f7a9-e591-44f5-991e-0c7769690201.jpeg</url>
      <title>DEV Community: dband drm</title>
      <link>https://dev.to/dband-drm</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dband-drm"/>
    <language>en</language>
    <item>
      <title>Deploy to Oracle with drm-cli + Flyway: A Step-by-Step Guide</title>
      <dc:creator>dband drm</dc:creator>
      <pubDate>Wed, 22 Apr 2026 12:06:13 +0000</pubDate>
      <link>https://dev.to/dband-drm/deploy-to-oracle-with-drm-cli-flyway-a-step-by-step-guide-27go</link>
      <guid>https://dev.to/dband-drm/deploy-to-oracle-with-drm-cli-flyway-a-step-by-step-guide-27go</guid>
      <description>&lt;p&gt;Oracle deployments have a reputation. They're slow to set up, painful to automate, and the tooling ecosystem tends to assume you have deep pockets. If you've tried to build a reliable Oracle deployment pipeline, you've probably hit at least one of these walls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No consistent audit trail of what was deployed, when, and whether it succeeded&lt;/li&gt;
&lt;li&gt;Pre/post deployment steps scattered across runbooks and tribal knowledge&lt;/li&gt;
&lt;li&gt;Connection strings with credentials in environment files and CI/CD config&lt;/li&gt;
&lt;li&gt;Multi-schema releases stitched together with shell scripts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;drm-cli layers on top of Flyway or Liquibase — adding release tracking, encrypted credentials, retry logic, and pre/post deployment scripting. It's free and open-source, which means Oracle-grade deployment management without an extra licensing cost on the tooling layer.&lt;/p&gt;

&lt;p&gt;This tutorial walks through a complete Oracle deployment using drm-cli + Flyway.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before you start, you'll need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Python 3.7+&lt;/strong&gt; installed on the host running drm-cli&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;git&lt;/strong&gt; to clone the repo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flyway&lt;/strong&gt; installed and on your PATH — &lt;a href="https://flywaydb.org/download" rel="noopener noreferrer"&gt;download here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Oracle JDBC driver&lt;/strong&gt; (&lt;code&gt;ojdbc11.jar&lt;/code&gt;) — available from Oracle's &lt;a href="https://www.oracle.com/database/technologies/appdev/jdbc-downloads.html" rel="noopener noreferrer"&gt;driver download page&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;An Oracle database you can connect to (Oracle XE works fine for testing)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 1 — Install drm-cli
&lt;/h2&gt;

&lt;p&gt;Clone the repository and run the installer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/dband-drm/drm-cli.git
&lt;span class="nb"&gt;cd &lt;/span&gt;drm-cli
python3 ./install.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The installer is interactive — it will prompt you for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Installation path&lt;/strong&gt; — where drm-cli will be installed (defaults to your home directory)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encryption key&lt;/strong&gt; — to encrypt sensitive data like connection strings at rest (optional but recommended)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage type&lt;/strong&gt; — &lt;code&gt;json&lt;/code&gt; (file-based, no extra dependencies) or &lt;code&gt;sqlite&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a non-interactive install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 ./install.py &lt;span class="nt"&gt;-d&lt;/span&gt; json &lt;span class="nt"&gt;-p&lt;/span&gt; none
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(&lt;code&gt;-p none&lt;/code&gt; means no encryption — use only for local test environments)&lt;/p&gt;

&lt;p&gt;Once complete:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INFO - DRM installation finished successfully!!!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 2 — Prepare Your Flyway Migrations
&lt;/h2&gt;

&lt;p&gt;drm-cli works with your existing Flyway migration scripts. Standard Flyway naming conventions apply — nothing needs to change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-oracle-migrations/
├── V1__create_accounts_table.sql
├── V2__add_account_status.sql
└── V3__create_transactions_table.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example migrations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- V1__create_accounts_table.sql&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;accounts&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;account_id&lt;/span&gt;   &lt;span class="n"&gt;NUMBER&lt;/span&gt; &lt;span class="k"&gt;GENERATED&lt;/span&gt; &lt;span class="n"&gt;ALWAYS&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="k"&gt;IDENTITY&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;account_name&lt;/span&gt; &lt;span class="n"&gt;VARCHAR2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt;   &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;SYSTIMESTAMP&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- V2__add_account_status.sql&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;accounts&lt;/span&gt;
&lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="n"&gt;VARCHAR2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="s1"&gt;'ACTIVE'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the path to this directory — you'll need it in the next step.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3 — Configure Your Release
&lt;/h2&gt;

&lt;p&gt;drm-cli stores all release configuration in a central database. Depending on the storage type you chose at install, this is either &lt;code&gt;drm_db.json&lt;/code&gt; or &lt;code&gt;drm_db.sqlite&lt;/code&gt; inside the &lt;code&gt;db/&lt;/code&gt; folder in your drm-cli installation directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  JSON style
&lt;/h3&gt;

&lt;p&gt;Open &lt;code&gt;&amp;lt;install-path&amp;gt;/db/drm_db.json&lt;/code&gt; in any editor. Find the &lt;code&gt;releases&lt;/code&gt; array and add your release with a solution and connection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"oracle-release-v1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"solutions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"core-schema-flyway"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"solution_type_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/path/to/my-oracle-migrations"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"connections"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"oracle-prod"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"connection_type_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"connection_string"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"url=jdbc:oracle:thin:@//127.0.0.1:1521/XEPDB1;username=deploy_user;password=your-password;"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;solution_type_id: 3&lt;/code&gt; — Flyway (use &lt;code&gt;2&lt;/code&gt; for Liquibase)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;path&lt;/code&gt; — the directory containing your Flyway migration scripts&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;connection_type_id: 2&lt;/code&gt; — Oracle&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;connection_string&lt;/code&gt; — the JDBC connection string Flyway uses&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  SQLite style
&lt;/h3&gt;

&lt;p&gt;Insert via SQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Add the release&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;releases&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'oracle-release-v1'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Add the Flyway solution&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;solutions&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;release_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ordinal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;solution_type_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'core-schema-flyway'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/path/to/my-oracle-migrations'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Add the Oracle connection&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;connections&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;solution_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;connection_type_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;connection_string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1001&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'oracle-prod'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'url=jdbc:oracle:thin:@//127.0.0.1:1521/XEPDB1;username=deploy_user;password=your-password;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 4 — Run Your First Deployment
&lt;/h2&gt;

&lt;p&gt;Navigate to your drm-cli installation directory and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 ./drm_deploy.py &lt;span class="nt"&gt;-c&lt;/span&gt; oracle-prod &lt;span class="nt"&gt;-r&lt;/span&gt; 10 &lt;span class="nt"&gt;--deploy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-c oracle-prod&lt;/code&gt; — the connection name you defined in the config&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-r 10&lt;/code&gt; — the release ID&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--deploy&lt;/code&gt; — execute the deployment (use &lt;code&gt;--dryrun&lt;/code&gt; to generate scripts without running them)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You'll see output as drm-cli invokes Flyway, captures the result, and records it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INFO - DRM Deploy started
INFO - Running solution: core-schema-flyway
INFO - Executing Flyway migrate...
INFO - Flyway: Successfully applied 3 migrations to schema "DEPLOY_USER"
INFO - Deployment recorded successfully
INFO - DRM Deploy finished successfully!!!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last line is what makes drm-cli different from running Flyway directly. Every deployment is written to the release history — timestamp, connection, release ID, outcome.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5 — View Deployment History
&lt;/h2&gt;

&lt;p&gt;After a deployment runs, drm-cli records the full event.&lt;/p&gt;

&lt;h3&gt;
  
  
  JSON style
&lt;/h3&gt;

&lt;p&gt;Browse to &lt;code&gt;&amp;lt;install-path&amp;gt;/deployments/&lt;/code&gt;. Each deployment creates a log file named:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deploy_{GUID}_C{connection-name}_R{release-id}.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open it to see the full deployment record: every step, its start/end time, status, and any error messages. This audit trail lives entirely in your own infrastructure — no cloud service, no external dependency.&lt;/p&gt;

&lt;h3&gt;
  
  
  SQLite style
&lt;/h3&gt;

&lt;p&gt;Query the deployments table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;deployments&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;
&lt;span class="k"&gt;INNER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;deployment_statuses&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;ds&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;ds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deployment_status_id&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_time&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 6 — What Happens When a Migration Fails
&lt;/h2&gt;

&lt;p&gt;If your network connection to Oracle drops mid-deployment, drm-cli retries automatically. Retry behavior is configured in &lt;code&gt;drm_deploy.config&lt;/code&gt; inside your drm-cli installation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"retry_attempts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"retry_delay_seconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this config, a failed step will retry up to 3 times with a 10-second delay. If all retries are exhausted, the deployment is marked failed and the full error is recorded in the deployment log — so you know exactly what ran, what didn't, and when.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 7 — Encrypting Your Oracle Credentials
&lt;/h2&gt;

&lt;p&gt;Storing plaintext connection strings is a habit worth breaking. If you installed drm-cli with an encryption key, use &lt;code&gt;drm_crypto.py&lt;/code&gt; to encrypt your connection string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 ./drm_crypto.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The utility prompts you for your encryption key and the value to encrypt, then returns the encrypted string. Replace the plaintext value in your connection config with the result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"connection_string"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"url=jdbc:oracle:thin:@//127.0.0.1:1521/XEPDB1;username=deploy_user;password=ENCRYPTED_VALUE_HERE;"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;drm-cli decrypts credentials at deploy time — they never appear in logs or trace output.&lt;/p&gt;




&lt;h2&gt;
  
  
  Using Liquibase Instead of Flyway
&lt;/h2&gt;

&lt;p&gt;Swap &lt;code&gt;solution_type_id: 3&lt;/code&gt; for &lt;code&gt;solution_type_id: 2&lt;/code&gt; and set &lt;code&gt;path&lt;/code&gt; to your Liquibase changelog directory. The connection config is identical:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"core-schema-liquibase"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"solution_type_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/path/to/liquibase/changelogs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"connections"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"oracle-prod"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"connection_type_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"connection_string"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"url=jdbc:oracle:thin:@//127.0.0.1:1521/XEPDB1;username=deploy_user;password=your-password;"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The deployment command is identical:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 ./drm_deploy.py &lt;span class="nt"&gt;-c&lt;/span&gt; oracle-prod &lt;span class="nt"&gt;-r&lt;/span&gt; 10 &lt;span class="nt"&gt;--deploy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Week 6&lt;/strong&gt; — Pre/post deployment scripts: automating steps that always run before and after every deployment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Week 7&lt;/strong&gt; — Multi-database releases: SQL Server, PostgreSQL, and Oracle in a single coordinated release&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The full source and documentation is at &lt;a href="https://github.com/dband-drm/drm-cli" rel="noopener noreferrer"&gt;github.com/dband-drm/drm-cli&lt;/a&gt;. Open issues there if you hit anything unexpected.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;drm-cli is free and open-source. No license tiers, no paid features.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>devops</category>
      <category>oracle</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Deploy to Oracle with drm-cli + Flyway: No Enterprise License Required</title>
      <dc:creator>dband drm</dc:creator>
      <pubDate>Wed, 22 Apr 2026 04:23:07 +0000</pubDate>
      <link>https://dev.to/dband-drm/deploy-to-oracle-with-drm-cli-flyway-no-enterprise-license-required-3ain</link>
      <guid>https://dev.to/dband-drm/deploy-to-oracle-with-drm-cli-flyway-no-enterprise-license-required-3ain</guid>
      <description>&lt;p&gt;Oracle deployments have a reputation. They're slow to set up, painful to automate, and the tooling ecosystem tends to assume you have deep pockets. If you've tried to build a reliable Oracle deployment pipeline, you've probably hit at least one of these walls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flyway's Oracle support is locked behind Flyway Teams&lt;/li&gt;
&lt;li&gt;Liquibase's Oracle features are split across free and commercial tiers&lt;/li&gt;
&lt;li&gt;Rolling your own with SQLPlus scripts works — until it doesn't, and there's no audit trail when something goes wrong&lt;/li&gt;
&lt;li&gt;Connection strings with credentials scattered across environment files and CI/CD config&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;drm-cli doesn't replace Flyway. It layers on top of it — adding release tracking, encrypted credentials, retry logic, and pre/post deployment scripting. And it's free and open-source, which means Oracle-grade deployment management without an Oracle-grade price tag.&lt;/p&gt;

&lt;p&gt;This tutorial walks through a complete Oracle deployment using drm-cli + Flyway.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before you start, you'll need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;drm-cli&lt;/strong&gt; installed — &lt;a href="https://github.com/dband-drm/drm-cli" rel="noopener noreferrer"&gt;installation guide here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flyway CLI&lt;/strong&gt; installed and on your PATH — &lt;a href="https://flywaydb.org/download" rel="noopener noreferrer"&gt;download here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Oracle JDBC driver&lt;/strong&gt; (&lt;code&gt;ojdbc11.jar&lt;/code&gt;) — available from Oracle's &lt;a href="https://www.oracle.com/database/technologies/appdev/jdbc-downloads.html" rel="noopener noreferrer"&gt;driver download page&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;An Oracle database you can connect to (Oracle XE works fine for testing)&lt;/li&gt;
&lt;li&gt;Python 3.10+&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Project Structure
&lt;/h2&gt;

&lt;p&gt;drm-cli works with a straightforward directory structure. Here's what a minimal Oracle project looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-oracle-project/
├── drm.yml
├── migrations/
│   ├── V1__create_accounts_table.sql
│   ├── V2__add_account_status.sql
│   └── V3__create_transactions_table.sql
└── drivers/
    └── ojdbc11.jar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your migrations follow standard Flyway naming conventions — drm-cli doesn't change that. It just takes responsibility for the release lifecycle around them.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1 — Configure drm.yml
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;drm.yml&lt;/code&gt; is the project configuration file drm-cli reads at runtime. Here's a working example for an Oracle deployment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-oracle-project&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.0.0"&lt;/span&gt;

&lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;history_db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;release_history.db&lt;/span&gt;    &lt;span class="c1"&gt;# SQLite file — stores your full release audit trail&lt;/span&gt;
  &lt;span class="na"&gt;retry_attempts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;retry_delay_seconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;

&lt;span class="na"&gt;targets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;oracle-prod&lt;/span&gt;
    &lt;span class="na"&gt;tool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flyway&lt;/span&gt;
    &lt;span class="na"&gt;database_type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;oracle&lt;/span&gt;
    &lt;span class="na"&gt;migrations_path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./migrations&lt;/span&gt;
    &lt;span class="na"&gt;drivers_path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./drivers&lt;/span&gt;
    &lt;span class="na"&gt;connection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;encrypted&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;jdbc:oracle:thin:@//localhost:1521/XEPDB1"&lt;/span&gt;
      &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deploy_user"&lt;/span&gt;
      &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your-password-here"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A note on the connection block: &lt;code&gt;encrypted: false&lt;/code&gt; here for clarity, but drm-cli supports encrypting credentials at rest using a key you manage. We'll cover that in a follow-up article — for now, plain credentials are fine for a local test environment.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2 — Write Your Migrations
&lt;/h2&gt;

&lt;p&gt;Standard Flyway SQL migrations. Nothing unusual here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- V1__create_accounts_table.sql&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;accounts&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;account_id&lt;/span&gt;   &lt;span class="n"&gt;NUMBER&lt;/span&gt; &lt;span class="k"&gt;GENERATED&lt;/span&gt; &lt;span class="n"&gt;ALWAYS&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="k"&gt;IDENTITY&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;account_name&lt;/span&gt; &lt;span class="n"&gt;VARCHAR2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt;   &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;SYSTIMESTAMP&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- V2__add_account_status.sql&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;accounts&lt;/span&gt;
&lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="n"&gt;VARCHAR2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="s1"&gt;'ACTIVE'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- V3__create_transactions_table.sql&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;transactions&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;transaction_id&lt;/span&gt; &lt;span class="n"&gt;NUMBER&lt;/span&gt; &lt;span class="k"&gt;GENERATED&lt;/span&gt; &lt;span class="n"&gt;ALWAYS&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="k"&gt;IDENTITY&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;account_id&lt;/span&gt;     &lt;span class="n"&gt;NUMBER&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;amount&lt;/span&gt;         &lt;span class="n"&gt;NUMBER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;posted_at&lt;/span&gt;      &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;SYSTIMESTAMP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;CONSTRAINT&lt;/span&gt; &lt;span class="n"&gt;fk_account&lt;/span&gt; &lt;span class="k"&gt;FOREIGN&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 3 — Run Your First Deployment
&lt;/h2&gt;

&lt;p&gt;With your config in place, deploy with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;drm deploy &lt;span class="nt"&gt;--target&lt;/span&gt; oracle-prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll see output like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[drm-cli] Starting deployment → oracle-prod
[drm-cli] Tool: flyway | Database: oracle
[drm-cli] Running Flyway migrate...
[drm-cli] Flyway: Successfully applied 3 migrations to schema "DEPLOY_USER"
[drm-cli] Recording release to history...
[drm-cli] Deployment complete — Release ID: 001 | Status: SUCCESS
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last line is what makes drm-cli different from running Flyway directly. Every deployment is written to the local release history database — timestamp, target, release ID, outcome.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4 — Check Release History
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;drm &lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;--target&lt;/span&gt; oracle-prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Release History — oracle-prod
─────────────────────────────────────────────────────────────────
ID   Version   Status    Started              Completed
001  1.0.0     SUCCESS   2026-04-20 09:14:32  2026-04-20 09:14:38
─────────────────────────────────────────────────────────────────
1 release found.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This audit trail lives in the local SQLite file (&lt;code&gt;release_history.db&lt;/code&gt;). It's yours — no cloud service, no external dependency.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5 — What Happens When a Migration Fails
&lt;/h2&gt;

&lt;p&gt;This is where retry logic matters. Let's say your network connection to Oracle drops mid-deployment — a perfectly ordinary thing to happen in production.&lt;/p&gt;

&lt;p&gt;Configure &lt;code&gt;retry_attempts&lt;/code&gt; and &lt;code&gt;retry_delay_seconds&lt;/code&gt; in &lt;code&gt;drm.yml&lt;/code&gt; (already set above), and drm-cli will automatically retry the deployment up to 3 times before marking it as failed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[drm-cli] Starting deployment → oracle-prod
[drm-cli] Tool: flyway | Database: oracle
[drm-cli] Running Flyway migrate...
[drm-cli] Connection error — retrying in 10 seconds (attempt 1/3)
[drm-cli] Connection error — retrying in 10 seconds (attempt 2/3)
[drm-cli] Flyway: Successfully applied 1 migration to schema "DEPLOY_USER"
[drm-cli] Recording release to history...
[drm-cli] Deployment complete — Release ID: 002 | Status: SUCCESS
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If all retries are exhausted, the failed attempt is still recorded in release history — so you know exactly what ran, what didn't, and when.&lt;/p&gt;




&lt;h2&gt;
  
  
  Encrypting Your Oracle Credentials
&lt;/h2&gt;

&lt;p&gt;Storing plaintext database credentials is a habit worth breaking. drm-cli supports encrypting the connection block in &lt;code&gt;drm.yml&lt;/code&gt; using a key you control.&lt;/p&gt;

&lt;p&gt;Switch to encrypted mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;connection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;encrypted&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gAAAAABk..."&lt;/span&gt;       &lt;span class="c1"&gt;# encrypted value&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gAAAAABk..."&lt;/span&gt;      &lt;span class="c1"&gt;# encrypted value&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gAAAAABk..."&lt;/span&gt;  &lt;span class="c1"&gt;# encrypted value&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Encrypt your values with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;drm encrypt &lt;span class="nt"&gt;--value&lt;/span&gt; &lt;span class="s2"&gt;"jdbc:oracle:thin:@//localhost:1521/XEPDB1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;drm-cli prompts for your encryption key and returns the encrypted string. The key never touches &lt;code&gt;drm.yml&lt;/code&gt; — you pass it at runtime or load it from an environment variable.&lt;/p&gt;

&lt;p&gt;Full encryption setup is covered in the drm-cli docs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Using Liquibase Instead of Flyway
&lt;/h2&gt;

&lt;p&gt;If your team uses Liquibase rather than Flyway, swap &lt;code&gt;tool: flyway&lt;/code&gt; for &lt;code&gt;tool: liquibase&lt;/code&gt; in &lt;code&gt;drm.yml&lt;/code&gt; and point &lt;code&gt;migrations_path&lt;/code&gt; at your changelog directory. The rest of the workflow is identical.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
yaml
targets:
  - name: oracle-prod
    tool: liquibase
    database_type: oracle
    changelog_file: ./changelogs/db.changelog-root.xml
    drivers_path: ./drivers
    connection:
      encrypted: false
      url: "jdbc:oracle:thin:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>database</category>
      <category>devops</category>
      <category>oracle</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Deploy to PostgreSQL with drm-cli + Liquibase: A Step-by-Step Guide</title>
      <dc:creator>dband drm</dc:creator>
      <pubDate>Wed, 22 Apr 2026 04:19:08 +0000</pubDate>
      <link>https://dev.to/dband-drm/deploy-to-postgresql-with-drm-cli-liquibase-a-step-by-step-guide-2ni8</link>
      <guid>https://dev.to/dband-drm/deploy-to-postgresql-with-drm-cli-liquibase-a-step-by-step-guide-2ni8</guid>
      <description>&lt;p&gt;If you're running PostgreSQL with Liquibase or Flyway and you've ever been asked "what exactly was deployed to staging last Tuesday?" — and couldn't answer quickly — this post is for you.&lt;/p&gt;

&lt;p&gt;drm-cli is a free, open-source database release manager that layers on top of Liquibase and Flyway. It doesn't replace your migration toolchain. It adds the layer those tools were never designed to provide: release history tracking, encrypted credentials, automated retries, and pre/post deployment scripts.&lt;/p&gt;

&lt;p&gt;This walkthrough covers a complete PostgreSQL deployment with Liquibase. The setup for Flyway is identical — just swap the solution type in the config.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before you start:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Python 3.7+&lt;/strong&gt; installed on the host running drm-cli&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;git&lt;/strong&gt; to clone the repo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Liquibase 4.25.0+&lt;/strong&gt; installed and on your PATH — &lt;a href="https://www.liquibase.com/download" rel="noopener noreferrer"&gt;download here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PostgreSQL JDBC driver&lt;/strong&gt; (&lt;code&gt;postgresql-*.jar&lt;/code&gt;) — &lt;a href="https://jdbc.postgresql.org/download/" rel="noopener noreferrer"&gt;download here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A PostgreSQL database you can connect to&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 1 — Install drm-cli
&lt;/h2&gt;

&lt;p&gt;Clone the repository and run the installer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/dband-drm/drm-cli.git
&lt;span class="nb"&gt;cd &lt;/span&gt;drm-cli
python3 ./install.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The installer is interactive — it will prompt you for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Installation path&lt;/strong&gt; — where drm-cli will be installed (defaults to your home directory)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encryption key&lt;/strong&gt; — to encrypt sensitive data like connection strings at rest (optional but recommended)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage type&lt;/strong&gt; — &lt;code&gt;json&lt;/code&gt; (file-based, no extra dependencies) or &lt;code&gt;sqlite&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a non-interactive install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 ./install.py &lt;span class="nt"&gt;-d&lt;/span&gt; json &lt;span class="nt"&gt;-p&lt;/span&gt; none
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(&lt;code&gt;-d json&lt;/code&gt; selects JSON storage, &lt;code&gt;-p none&lt;/code&gt; means no encryption — use only for local test environments)&lt;/p&gt;

&lt;p&gt;Once complete:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INFO - DRM installation finished successfully!!!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 2 — Prepare Your Liquibase Changelogs
&lt;/h2&gt;

&lt;p&gt;drm-cli works with your existing Liquibase changelogs. No changes to your migration scripts are needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-changelogs/
├── db.changelog-root.xml
├── changes/
│   ├── 001-create-users-table.xml
│   ├── 002-add-email-index.xml
│   └── 003-create-orders-table.xml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the path to this directory — you'll need it in the next step.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3 — Configure Your Release
&lt;/h2&gt;

&lt;p&gt;drm-cli stores all release configuration in a central database. Depending on the storage type you chose at install, this is either &lt;code&gt;drm_db.json&lt;/code&gt; or &lt;code&gt;drm_db.sqlite&lt;/code&gt; inside the &lt;code&gt;db/&lt;/code&gt; folder in your drm-cli installation directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  JSON style
&lt;/h3&gt;

&lt;p&gt;Open &lt;code&gt;&amp;lt;install-path&amp;gt;/db/drm_db.json&lt;/code&gt; in any editor. Find the &lt;code&gt;releases&lt;/code&gt; array and add your release with a solution and connection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"postgresql-release-v1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"solutions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"app-db-liquibase"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"solution_type_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/path/to/my-changelogs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"connections"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"postgres-staging"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"connection_type_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"connection_string"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"url=jdbc:postgresql://127.0.0.1:5432/appdb;username=deploy_user;password=your-password;"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;solution_type_id: 2&lt;/code&gt; — Liquibase (use &lt;code&gt;3&lt;/code&gt; for Flyway)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;path&lt;/code&gt; — the directory containing your Liquibase changelogs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;connection_type_id: 3&lt;/code&gt; — PostgreSQL&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;connection_string&lt;/code&gt; — the JDBC connection string Liquibase uses&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  SQLite style
&lt;/h3&gt;

&lt;p&gt;Insert via SQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Add the release&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;releases&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'postgresql-release-v1'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Add the Liquibase solution&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;solutions&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;release_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ordinal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;solution_type_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'app-db-liquibase'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/path/to/my-changelogs'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Add the PostgreSQL connection&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;connections&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;solution_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;connection_type_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;connection_string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'postgres-staging'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'url=jdbc:postgresql://127.0.0.1:5432/appdb;username=deploy_user;password=your-password;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 4 — Run Your First Deployment
&lt;/h2&gt;

&lt;p&gt;Navigate to your drm-cli installation directory and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 ./drm_deploy.py &lt;span class="nt"&gt;-c&lt;/span&gt; postgres-staging &lt;span class="nt"&gt;-r&lt;/span&gt; 10 &lt;span class="nt"&gt;--deploy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-c postgres-staging&lt;/code&gt; — the connection name you defined in the config&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-r 10&lt;/code&gt; — the release ID&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--deploy&lt;/code&gt; — execute the deployment (use &lt;code&gt;--dryrun&lt;/code&gt; to generate scripts without running them)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You'll see output as drm-cli invokes Liquibase, captures the result, and records it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INFO - DRM Deploy started
INFO - Running solution: app-db-liquibase
INFO - Executing Liquibase migrate...
INFO - Liquibase: Successfully applied 3 changesets
INFO - Deployment recorded successfully
INFO - DRM Deploy finished successfully!!!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 5 — View Deployment History
&lt;/h2&gt;

&lt;p&gt;After a deployment runs, drm-cli records the full event — timestamp, connection, release ID, and outcome.&lt;/p&gt;

&lt;h3&gt;
  
  
  JSON style
&lt;/h3&gt;

&lt;p&gt;Browse to &lt;code&gt;&amp;lt;install-path&amp;gt;/deployments/&lt;/code&gt;. Each deployment creates a log file named:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deploy_{GUID}_C{connection-name}_R{release-id}.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open it to see the full deployment record: every step, its start/end time, status, and any error messages.&lt;/p&gt;

&lt;h3&gt;
  
  
  SQLite style
&lt;/h3&gt;

&lt;p&gt;Query the deployments table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;deployments&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;
&lt;span class="k"&gt;INNER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;deployment_statuses&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;ds&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;ds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deployment_status_id&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_time&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 6 — What Happens When a Migration Fails
&lt;/h2&gt;

&lt;p&gt;If a deployment step fails — network hiccup, lock timeout, transient error — drm-cli retries automatically. Retry behavior is configured in &lt;code&gt;drm_deploy.config&lt;/code&gt; inside your drm-cli installation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"retry_attempts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"retry_delay_seconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A failed step will retry up to 3 times with a 10-second delay. If all retries are exhausted, the deployment is marked failed and the full error is recorded in the deployment log.&lt;/p&gt;

&lt;p&gt;Even when a deployment fails, the record is there. You know exactly what ran, what didn't, and when.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 7 — Encrypting Your PostgreSQL Credentials
&lt;/h2&gt;

&lt;p&gt;If you installed drm-cli with an encryption key, use &lt;code&gt;drm_crypto.py&lt;/code&gt; to encrypt your connection string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 ./drm_crypto.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The utility prompts you for your encryption key and the value to encrypt, then returns the encrypted string. Replace the plaintext value in your connection config with the result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"connection_string"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"url=jdbc:postgresql://127.0.0.1:5432/appdb;username=deploy_user;password=ENCRYPTED_VALUE_HERE;"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;drm-cli decrypts credentials at deploy time — they never appear in logs or trace output.&lt;/p&gt;




&lt;h2&gt;
  
  
  Using Flyway Instead of Liquibase
&lt;/h2&gt;

&lt;p&gt;Swap &lt;code&gt;solution_type_id: 2&lt;/code&gt; for &lt;code&gt;solution_type_id: 3&lt;/code&gt; and set &lt;code&gt;path&lt;/code&gt; to your Flyway migrations directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"app-db-flyway"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"solution_type_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/path/to/flyway/migrations"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"connections"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"postgres-staging"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"connection_type_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"connection_string"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"url=jdbc:postgresql://127.0.0.1:5432/appdb;username=deploy_user;password=your-password;"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The deployment command is identical:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 ./drm_deploy.py &lt;span class="nt"&gt;-c&lt;/span&gt; postgres-staging &lt;span class="nt"&gt;-r&lt;/span&gt; 10 &lt;span class="nt"&gt;--deploy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Week 5&lt;/strong&gt; — Oracle deployments with drm-cli + Flyway or Liquibase&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Week 6&lt;/strong&gt; — Pre/post deployment scripts: the pattern for automating steps that run before and after every deployment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Week 7&lt;/strong&gt; — Multi-database releases: SQL Server, PostgreSQL, and Oracle in a single coordinated release&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The full source and documentation is at &lt;a href="https://github.com/dband-drm/drm-cli" rel="noopener noreferrer"&gt;github.com/dband-drm/drm-cli&lt;/a&gt;. Open issues there if you hit anything unexpected.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;drm-cli is free and open-source. No license tiers, no paid features.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>devops</category>
      <category>oracle</category>
      <category>postgressql</category>
    </item>
    <item>
      <title>drm-cli v1.1 is out — PostgreSQL, Oracle, Liquibase &amp; Flyway now supported</title>
      <dc:creator>dband drm</dc:creator>
      <pubDate>Fri, 10 Apr 2026 05:15:31 +0000</pubDate>
      <link>https://dev.to/dband-drm/drm-cli-v11-is-out-postgresql-oracle-liquibase-flyway-now-supported-228m</link>
      <guid>https://dev.to/dband-drm/drm-cli-v11-is-out-postgresql-oracle-liquibase-flyway-now-supported-228m</guid>
      <description>&lt;p&gt;We shipped drm-cli v1.1 this week.&lt;/p&gt;

&lt;p&gt;If you haven't heard of drm-cli before: it's a free, open-source database release manager that layers on top of your existing tools — Liquibase, Flyway, SSDT — and adds release history, encrypted credentials, automated retries, and multi-solution deployments. It doesn't replace your migration toolchain. It wraps it and fills the gaps that migration tools were never designed to fill.&lt;/p&gt;

&lt;p&gt;v1.0 supported SQL Server via SSDT and &lt;code&gt;sqlpackage&lt;/code&gt;. That covered a lot of ground for us, but it wasn't enough.&lt;/p&gt;

&lt;p&gt;Here's what changed in v1.1.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's new in v1.1
&lt;/h2&gt;

&lt;h3&gt;
  
  
  PostgreSQL support
&lt;/h3&gt;

&lt;p&gt;drm-cli now supports PostgreSQL deployments via Liquibase or Flyway. You configure your solution in the drm-cli database (&lt;code&gt;drm_db.json&lt;/code&gt; or SQLite) with &lt;code&gt;solution_type_id: 2&lt;/code&gt; (Liquibase) or &lt;code&gt;3&lt;/code&gt; (Flyway), point it at your changelog or migration directory, and drm-cli handles the rest — connection string encryption, release history tracking, retry logic, pre/post scripts.&lt;/p&gt;

&lt;p&gt;Same release model you'd use for SQL Server, now for Postgres.&lt;/p&gt;

&lt;h3&gt;
  
  
  Oracle support
&lt;/h3&gt;

&lt;p&gt;Oracle deployments via Liquibase or Flyway are now supported. If you've ever tried to wrangle Oracle connection strings, schema differences, and deployment sequencing across environments, you know why this matters. drm-cli treats Oracle the same as any other database in the release — same config structure, same audit trail, same retry behavior.&lt;/p&gt;

&lt;p&gt;No separate toolchain for Oracle. No separate release process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Liquibase and Flyway integration
&lt;/h3&gt;

&lt;p&gt;v1.0 relied on &lt;code&gt;sqlpackage&lt;/code&gt; for SQL Server. In v1.1, Liquibase and Flyway are first-class execution engines.&lt;/p&gt;

&lt;p&gt;You configure which engine to use per solution. drm-cli invokes it, captures the output, evaluates success or failure, and records the result. If something fails, the retry logic kicks in. The audit trail captures what ran, when, and what the outcome was — regardless of which engine executed it.&lt;/p&gt;

&lt;p&gt;If your team already uses Liquibase or Flyway, drm-cli doesn't ask you to change that. It sits on top of what you already have.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pre/post deployment scripts
&lt;/h3&gt;

&lt;p&gt;This one came directly from operational pain.&lt;/p&gt;

&lt;p&gt;Before deploying, you might need to run a notification script, disable a job, or snapshot something. After deploying, you might need to re-enable that job, run a smoke test, or hit an API. These steps are easy to forget, easy to skip under pressure, and expensive when missed.&lt;/p&gt;

&lt;p&gt;v1.1 introduces pre and post deployment scripts at the project level. You define the scripts once in the release config. drm-cli runs them every time, in order, before and after the main deployment — regardless of which database or execution engine is involved.&lt;/p&gt;

&lt;h3&gt;
  
  
  Encrypted connection strings (extended)
&lt;/h3&gt;

&lt;p&gt;Credential encryption was in v1.0, but v1.1 extends it to cover PostgreSQL and Oracle connection strings. The mechanism is the same — use the &lt;code&gt;drm_crypto.py&lt;/code&gt; utility to encrypt your connection strings, store the encrypted values in the release config, and drm-cli decrypts them at deploy time. No plaintext credentials sitting in your release config.&lt;/p&gt;




&lt;h2&gt;
  
  
  What stayed the same
&lt;/h2&gt;

&lt;p&gt;The core model hasn't changed. drm-cli reads the release database, executes solutions in order, tracks the result of each one, and writes the history to deployment logs. If a solution fails, it retries. If it fails past the retry threshold, it stops and reports.&lt;/p&gt;

&lt;p&gt;v1.0 users can upgrade without changing their existing config. Existing SQL Server solutions default to their previous behavior.&lt;/p&gt;

&lt;p&gt;We'll write the full upgrade guide in Week 8. The short version: run the installer against your existing installation and it handles the rest.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick look at the v1.1 config
&lt;/h2&gt;

&lt;p&gt;Here's what a v1.1 multi-database release looks like in &lt;code&gt;drm_db.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Q2-2026-release-01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"solutions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"core-schema"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"solution_type_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/ssdt/CoreSchema"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"analytics-db"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"solution_type_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/liquibase/analytics"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"connections"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"analytics-postgres"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"connection_type_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"connection_string"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"url=jdbc:postgresql://db-host:5432/analytics;username=deploy;password=encrypted-value;"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"reporting-oracle"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"solution_type_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/flyway/reporting"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"connections"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"reporting-oracle"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"connection_type_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"connection_string"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"url=jdbc:oracle:thin:@//ora-host:1521/ORCL;username=deploy;password=encrypted-value;"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SQL Server, PostgreSQL, and Oracle. Three different execution engines. One release. One audit trail.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to install or upgrade
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;New install:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/dband-drm/drm-cli.git
&lt;span class="nb"&gt;cd &lt;/span&gt;drm-cli
python3 ./install.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Upgrade from v1.0:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run the installer against your existing drm-cli installation path. It detects the existing version and walks you through the upgrade steps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 ./install.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow the prompts and point it at your current installation directory when asked.&lt;/p&gt;

&lt;p&gt;The full release notes are on the &lt;a href="https://github.com/dband-drm/drm-cli/releases/tag/v1.1.0" rel="noopener noreferrer"&gt;drm-cli GitHub repo&lt;/a&gt;. Open issues and feature requests there.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's coming in the next few weeks
&lt;/h2&gt;

&lt;p&gt;Over the next several posts we'll go deep on each of the new capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Week 4&lt;/strong&gt; — Step-by-step: deploying to PostgreSQL with Liquibase or Flyway&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Week 5&lt;/strong&gt; — Oracle deployments with Flyway or Liquibase&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Week 6&lt;/strong&gt; — The pre/post script pattern in detail&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're already using drm-cli and upgrade to v1.1, let us know how it goes. If you hit anything unexpected, open an issue. We read them all.&lt;/p&gt;

&lt;p&gt;And if this is the first time you're hearing about drm-cli — the &lt;a href="https://dev.to/dband"&gt;Week 2 post&lt;/a&gt; covers the problem we built it to solve. Start there if you want the full context before diving into v1.1.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;drm-cli is free and open-source. No license tiers, no paid features, no freemium model. Everything described here is available to everyone.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>devops</category>
      <category>opensource</category>
      <category>postgres</category>
    </item>
    <item>
      <title>The Gap Between Database Version Control and Release Management</title>
      <dc:creator>dband drm</dc:creator>
      <pubDate>Thu, 02 Apr 2026 16:15:00 +0000</pubDate>
      <link>https://dev.to/dband-drm/the-gap-between-database-version-control-and-release-management-2d1f</link>
      <guid>https://dev.to/dband-drm/the-gap-between-database-version-control-and-release-management-2d1f</guid>
      <description>&lt;p&gt;If you've been using Liquibase or Flyway for a while, you already know they solve a real problem. Migrations are tracked. Schema changes are repeatable. Your database evolves in lock-step with your application code.&lt;/p&gt;

&lt;p&gt;So why does deploying a database change still feel fragile?&lt;/p&gt;

&lt;p&gt;We asked ourselves the same question. We were running Liquibase in production across multiple environments, with a reasonably mature pipeline. Migrations were clean. The versioning worked. But the &lt;em&gt;release&lt;/em&gt; — the actual act of getting a change from dev to test to production, with confidence — still had gaps we were plugging with shell scripts, spreadsheets, and hope.&lt;/p&gt;

&lt;p&gt;This is the problem drm-cli was built to solve.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Liquibase and Flyway Actually Do
&lt;/h2&gt;

&lt;p&gt;Let's be precise here, because nothing in this post is a criticism of either tool. Liquibase and Flyway are excellent. We still use them.&lt;/p&gt;

&lt;p&gt;What they do: &lt;strong&gt;track and apply schema changes&lt;/strong&gt;. Given a target database and a set of migrations, they work out which changes haven't been applied and apply them in the right order. That's the core job, and they do it well.&lt;/p&gt;

&lt;p&gt;What they're not designed to be: &lt;strong&gt;a release management layer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The distinction matters. Version control is about tracking &lt;em&gt;what&lt;/em&gt; changed. Release management is about controlling &lt;em&gt;how&lt;/em&gt; and &lt;em&gt;when&lt;/em&gt; that change reaches each environment — with history, error handling, credential management, and coordination across multiple systems.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Gaps We Kept Running Into
&lt;/h2&gt;

&lt;p&gt;Here's what we found missing when we tried to treat Liquibase alone as a full release management solution:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. No release history&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Liquibase maintains a &lt;code&gt;DATABASECHANGELOG&lt;/code&gt; table per database. That's a migration history. It tells you what migrations have been applied to that database. It doesn't tell you &lt;em&gt;who&lt;/em&gt; ran the release, &lt;em&gt;when&lt;/em&gt;, from &lt;em&gt;which&lt;/em&gt; version of the release package, or whether the release across all your environments succeeded. There's no audit trail at the release level.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. No encrypted credential management&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your connection strings contain passwords. If you're running migrations from a CI pipeline or a deployment server, those credentials need to live somewhere. Liquibase and Flyway accept them as arguments or environment variables — but they don't provide a mechanism for encrypting them at rest. The moment your pipeline config ends up in a screenshot or a log, you have a problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. No automated retry or failure recovery&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A migration fails at step 4 of 12. Now what? Liquibase will tell you what happened. It won't automatically retry the failed step, skip to a recovery path, or log the failure in a structured way that your team can act on without hunting through console output.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. No multi-solution coordination&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your release touches a SQL Server SSDT project &lt;em&gt;and&lt;/em&gt; a Liquibase changelog &lt;em&gt;and&lt;/em&gt; a set of Oracle scripts. These are separate tools with separate invocations. Running them in the right order, capturing failures across all of them, and producing a single release record — there's nothing in any one tool that handles this. You write glue code. We all write glue code. Most of it is fragile.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. No cross-platform release definition&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;How do you define a release that runs the same way on a Windows deployment server and a Linux CI agent? With Liquibase or Flyway alone, your answer is usually "a shell script on Linux and a batch file on Windows." drm-cli is written in Python and runs identically on both.&lt;/p&gt;




&lt;h2&gt;
  
  
  Versioning vs. Releasing: A Concrete Example
&lt;/h2&gt;

&lt;p&gt;Imagine you're deploying a change that does all of the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Updates three tables in your SQL Server application database (via SSDT)&lt;/li&gt;
&lt;li&gt;Applies a new Liquibase changelog to a PostgreSQL reporting database&lt;/li&gt;
&lt;li&gt;Runs a post-deployment script that refreshes a materialized view&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With Liquibase and Flyway, you have the migration layer covered for the databases they manage. But you're still answering these questions manually:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What order do these run in?&lt;/li&gt;
&lt;li&gt;What happens if the PostgreSQL migration succeeds but the post-deployment script fails?&lt;/li&gt;
&lt;li&gt;Where is the record of this release — what ran, when, and with what outcome?&lt;/li&gt;
&lt;li&gt;How do I re-run just the failed step without re-running the whole thing?&lt;/li&gt;
&lt;li&gt;How do I pass credentials to each tool without hardcoding them in the pipeline?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are release management questions. Liquibase isn't trying to answer them. It shouldn't have to. That's a different layer.&lt;/p&gt;




&lt;h2&gt;
  
  
  What drm-cli Adds on Top
&lt;/h2&gt;

&lt;p&gt;drm-cli doesn't replace Liquibase or Flyway. It wraps and extends them.&lt;/p&gt;

&lt;p&gt;You define a release in a YAML file. That file tells drm-cli:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which tools to invoke (Liquibase, Flyway, SSDT's &lt;code&gt;sqlpackage&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;In what order&lt;/li&gt;
&lt;li&gt;Against which databases (SQL Server, PostgreSQL, Oracle — or all three)&lt;/li&gt;
&lt;li&gt;With which credentials (stored encrypted, decrypted at runtime)&lt;/li&gt;
&lt;li&gt;With which pre/post scripts to run around each step&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;drm-cli then executes the release, handles failures with configurable retries, and writes a structured release history entry — regardless of how many tools were involved or how many databases were touched.&lt;/p&gt;

&lt;p&gt;Here's a minimal example. A &lt;code&gt;release.yml&lt;/code&gt; for a single PostgreSQL deployment using Liquibase:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;v2.4.1"&lt;/span&gt;
  &lt;span class="na"&gt;solutions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;reporting-db&lt;/span&gt;
      &lt;span class="na"&gt;engine&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;liquibase&lt;/span&gt;
      &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgresql&lt;/span&gt;
      &lt;span class="na"&gt;changelog&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;changelogs/reporting/changelog.xml&lt;/span&gt;
      &lt;span class="na"&gt;connection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;connections/reporting.enc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it for the definition. drm-cli handles the invocation, the logging, and the history.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Note on What drm-cli Is Not
&lt;/h2&gt;

&lt;p&gt;We want to be honest about scope:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It doesn't write your migrations for you&lt;/li&gt;
&lt;li&gt;It doesn't manage your Liquibase or Flyway configuration beyond invocation&lt;/li&gt;
&lt;li&gt;It doesn't replace your CI/CD pipeline — it runs &lt;em&gt;inside&lt;/em&gt; it&lt;/li&gt;
&lt;li&gt;It's not trying to be an all-in-one database platform&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's a release management layer. Narrow scope, done well.&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;drm-cli is free and open-source. Installation takes about two minutes.&lt;/p&gt;

&lt;p&gt;The interactive installer (the fastest way to get started on any platform) is shown in this walkthrough:&lt;/p&gt;

&lt;p&gt;▶️ [drm-cli interactive installation — video]&lt;/p&gt;

&lt;p&gt;Or install directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;drm-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The documentation is at [docs link] and the source is on GitHub at [repo link].&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;Next week we'll announce drm-cli v1.1 — which adds full PostgreSQL and Oracle support, Flyway integration alongside Liquibase, and pre/post deployment script support.&lt;/p&gt;

&lt;p&gt;If the problem we described here is familiar, the v1.1 announcement is worth watching for.&lt;/p&gt;

&lt;p&gt;In the meantime, if you've hit any of these gaps in your own Liquibase or Flyway setup, we'd genuinely like to hear how you've been handling them. Drop a comment below.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;drm-cli is built and maintained by &lt;a href="https://d-band.io" rel="noopener noreferrer"&gt;d-band&lt;/a&gt;. Free. Open-source. No license cost.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>devops</category>
      <category>opensource</category>
      <category>python</category>
    </item>
    <item>
      <title>We're d-band — Here's Why We Build Open-Source Tools</title>
      <dc:creator>dband drm</dc:creator>
      <pubDate>Mon, 23 Mar 2026 16:12:01 +0000</pubDate>
      <link>https://dev.to/dband-drm/were-d-band-heres-why-we-build-open-source-tools-1i36</link>
      <guid>https://dev.to/dband-drm/were-d-band-heres-why-we-build-open-source-tools-1i36</guid>
      <description>&lt;p&gt;&lt;em&gt;This is the first post from d-band. We're not launching a product today. We're introducing ourselves.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  We Built What We Needed
&lt;/h2&gt;

&lt;p&gt;A few years ago, we were running database deployments across multiple environments, multiple databases, and multiple tools. Liquibase for one system, SSDT for another, custom shell scripts to glue it all together, a shared spreadsheet to track what actually deployed where.&lt;/p&gt;

&lt;p&gt;It worked. Until it didn't.&lt;/p&gt;

&lt;p&gt;The spreadsheet went stale. Scripts diverged between environments. A rollback that should have taken ten minutes took three hours because nobody could say with confidence what state the target database was actually in.&lt;/p&gt;

&lt;p&gt;We looked for a tool that could tie all of this together — something that sat on top of the tools we already had, tracked deployment history properly, handled credentials securely, and let us run a full release across multiple databases without stitching together a dozen scripts.&lt;/p&gt;

&lt;p&gt;We didn't find one that hit all of those marks without a significant license cost or a full platform migration.&lt;/p&gt;

&lt;p&gt;So we built one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Who We Are
&lt;/h2&gt;

&lt;p&gt;d-band is a small team of data engineers and DevOps practitioners. We do consulting work — helping organizations build and maintain data infrastructure — and alongside that, we build tooling.&lt;/p&gt;

&lt;p&gt;We're not a VC-backed startup optimizing for growth metrics. We're practitioners who got frustrated with a gap in the ecosystem and decided to fill it.&lt;/p&gt;

&lt;p&gt;That gap is database release management. Not version control — that problem is largely solved. Release management: the process of taking your versioned schema changes and actually getting them deployed, reliably, with a full audit trail, across all the databases you care about.&lt;/p&gt;




&lt;h2&gt;
  
  
  What We Believe
&lt;/h2&gt;

&lt;p&gt;A few things we think are true about tooling in this space:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open-source is the right model.&lt;/strong&gt; Database tooling has a long history of "free tier, enterprise price." We think that creates the wrong incentives. When a tool is fully free and open-source, the authors have to earn trust through quality, not through feature gating.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't replace what works.&lt;/strong&gt; Liquibase and Flyway are good tools. SSDT is genuinely useful for SQL Server shops. We're not interested in building a competitor to those tools — we're interested in building the layer above them that handles the parts they don't.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;History matters.&lt;/strong&gt; Every deployment should be recorded. Not in a log file that someone might or might not check — in a queryable release history that's part of your workflow. When something goes wrong at 2am, you should be able to answer "what changed, when, and where" in under a minute.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security shouldn't be an afterthought.&lt;/strong&gt; Connection strings containing credentials shouldn't live in plaintext config files. This is obvious in principle and routinely ignored in practice. We built credential encryption into drm-cli from the start.&lt;/p&gt;




&lt;h2&gt;
  
  
  What We're Releasing
&lt;/h2&gt;

&lt;p&gt;Our first public tool is &lt;strong&gt;drm-cli&lt;/strong&gt; — a free, open-source database release manager that layers on top of Liquibase, Flyway, and SSDT.&lt;/p&gt;

&lt;p&gt;It handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Release history tracking&lt;/strong&gt; — every deployment recorded, queryable, auditable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encrypted credentials&lt;/strong&gt; — connection strings encrypted at rest&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated retries and failure recovery&lt;/strong&gt; — deployments that recover gracefully when something transient goes wrong&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-database releases&lt;/strong&gt; — SQL Server, PostgreSQL, and Oracle in a single coordinated release&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pre/post deployment scripts&lt;/strong&gt; — steps that always run before or after every deployment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-platform&lt;/strong&gt; — Windows, Linux, macOS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We're not going to go deep on any of those today. Each of them deserves its own post, with real config examples and real commands. That's what's coming over the next several weeks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Post Here
&lt;/h2&gt;

&lt;p&gt;We're building in public because we think that's how open-source tooling should work.&lt;/p&gt;

&lt;p&gt;Over the next few weeks, we'll be posting technical tutorials, honest write-ups of what we got wrong and had to rethink, and a full walkthrough of what drm-cli v1.1 can do. Not press releases — actual technical content that's useful whether or not you ever touch our tool.&lt;/p&gt;

&lt;p&gt;If any of this is relevant to problems you're dealing with, follow along. We'd rather earn readers through useful content than through a product announcement.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where to Find Us
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/d-band/drm-cli" rel="noopener noreferrer"&gt;github.com/d-band/drm-cli&lt;/a&gt; — the repo, the docs, and the issue tracker&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;drm-cli docs:&lt;/strong&gt; full documentation is in the repo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;This blog&lt;/strong&gt; — we'll be posting here regularly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next week: what drm-cli actually is, what problem it solves, and why Liquibase and Flyway alone aren't enough for release management.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;We're d-band. We build things we need. If you need them too, that's a bonus.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>devops</category>
      <category>opensource</category>
      <category>python</category>
    </item>
    <item>
      <title>What's your biggest database deployment pain point?</title>
      <dc:creator>dband drm</dc:creator>
      <pubDate>Sat, 14 Feb 2026 15:17:48 +0000</pubDate>
      <link>https://dev.to/dband-drm/whats-your-biggest-database-deployment-pain-point-514k</link>
      <guid>https://dev.to/dband-drm/whats-your-biggest-database-deployment-pain-point-514k</guid>
      <description>&lt;p&gt;After spending countless hours debugging database deployment drift across multiple databases on different environments, we decided to build something better.&lt;/p&gt;

&lt;p&gt;The problem was simple but painful:&lt;br&gt;
→ Juggling multiple deployment tools for Oracle, PostgreSQL, SQL Server&lt;br&gt;
→ No unified interface for database releases&lt;br&gt;
→ Manual tracking of what's deployed where&lt;br&gt;
→ Deployments failed with no retry mechanism&lt;br&gt;
→ Team wasted hours tracking down issues&lt;/p&gt;

&lt;p&gt;So we built DRM-CLI - a unified Python CLI that:&lt;br&gt;
✓ Single interface for Oracle, PostgreSQL, SQL Server&lt;br&gt;
✓ Built-in retry mechanism for resilient deployments&lt;br&gt;
✓ Parallel execution for multiple targets&lt;br&gt;
✓ Complete deployment tracking (SQLite or JSON)&lt;br&gt;
✓ Secure encryption for sensitive configs&lt;br&gt;
✓ Integrates with Flyway, Liquibase, sqlpackage&lt;/p&gt;

&lt;p&gt;Built with Python for cross-platform support (Windows &amp;amp; Linux)&lt;br&gt;
Open source under MIT license&lt;/p&gt;

&lt;p&gt;The response from our DBA team has been incredible - we're deploying faster and catching issues before they hit production.&lt;/p&gt;

&lt;p&gt;If you're managing database deployments across multiple environments, check it out:&lt;br&gt;
🔗 &lt;a href="https://github.com/dband-drm/drm-cli" rel="noopener noreferrer"&gt;https://github.com/dband-drm/drm-cli&lt;/a&gt;&lt;br&gt;
🔗 &lt;a href="https://www.linkedin.com/company/d-band" rel="noopener noreferrer"&gt;https://www.linkedin.com/company/d-band&lt;/a&gt;&lt;br&gt;
🔗 &lt;a href="https://www.d-band.com/" rel="noopener noreferrer"&gt;https://www.d-band.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What's your biggest database deployment pain point?&lt;/p&gt;

&lt;h1&gt;
  
  
  Database #DevOps #DBA #Oracle #PostgreSQL #SQLServer #OpenSource #DataOps
&lt;/h1&gt;

</description>
      <category>database</category>
      <category>devops</category>
      <category>dataops</category>
      <category>dba</category>
    </item>
  </channel>
</rss>
