<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[APEX in the Wild]]></title><description><![CDATA[APEX in the Wild]]></description><link>https://apexinthewild.hashnode.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/6aec7203cf456770bc7c07c5/31f6c9ad-d1dd-4728-b5e8-cacd2775d13a.jpg</url><title>APEX in the Wild</title><link>https://apexinthewild.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Sat, 07 Nov 2026 15:08:09 GMT</lastBuildDate><atom:link href="https://apexinthewild.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[DevOps in Oracle APEX - The Lazy Developer's Guide to Not Losing Your Code]]></title><description><![CDATA[The simplest way to add version control to your Oracle APEX projects. Push your app and DB objects to GitHub using PLSQL - straight from SQL Workshop]]></description><link>https://apexinthewild.hashnode.dev/devops-in-oracle-apex-the-lazy-developer-s-guide-to-not-losing-your-code</link><guid isPermaLink="true">https://apexinthewild.hashnode.dev/devops-in-oracle-apex-the-lazy-developer-s-guide-to-not-losing-your-code</guid><category><![CDATA[#oracle-apex]]></category><category><![CDATA[Devops]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[PL/SQL]]></category><category><![CDATA[Oracle Cloud]]></category><category><![CDATA[devops-in-apex]]></category><dc:creator><![CDATA[Sriram Jaishanker]]></dc:creator><pubDate>Thu, 05 Nov 2026 12:36:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6aec7203cf456770bc7c07c5/dd56b0ec-4e80-4bc9-9a98-d2c52a49ba74.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Let me paint a picture.</p>
<p>It's 11:47 PM. You just spent three hours perfecting a Dynamic Action on Page 14. The validation logic is <em>chef's kiss</em>. The CSS is pixel-perfect. You test it one last time, and it works.</p>
<p>You go to bed happy.</p>
<p>The next morning, your colleague messages you: <em>"Hey, I made some changes to Page 14. Hope that's okay."</em></p>
<p>It is not okay.</p>
<p>Your Dynamic Action is gone. Your CSS is overwritten. Three hours of work - vanished into the database like it never existed.</p>
<p>If this has ever happened to you (or if you just felt a chill reading it), this post is for you.</p>
<p>I'm going to show you the <strong>simplest possible way</strong> to add version control to your Oracle APEX projects. No complex CI/CD pipelines. No terminal commands. No DevOps certification required.</p>
<p>Just PL/SQL, GitHub, and about 15 minutes of your time.</p>
<h2>The APEX Developer's DevOps Problem</h2>
<p>Let's be honest. Most APEX developers hear "DevOps" and immediately think:</p>
<blockquote>
<p><em>"That's for React developers and Kubernetes people. I build apps in a browser. My code lives in the database. Git doesn't apply to me."</em></p>
</blockquote>
<p>And honestly? I get it.</p>
<p>Traditional version control assumes you're working with files on disk. But APEX stores everything - pages, regions, processes, Dynamic Actions, templates - inside Oracle Database tables. There are no <code>.js</code> files to commit. No project folder to <code>git init</code>.</p>
<p>Here's what most APEX teams do instead:</p>
<ul>
<li>Export the app as a SQL file before making big changes (sometimes)</li>
<li>Name it <code>f100_backup_oct_final_v2_FINAL.sql</code> (always)</li>
<li>Store it in a shared drive folder that nobody organizes (inevitably)</li>
<li>Pray that nothing goes wrong (religiously)</li>
</ul>
<p>This is not DevOps. This is hope-driven development.</p>
<p>And the real cost isn't just lost code. It's the <strong>fear of making changes</strong>. When you don't have a safety net, every edit to a production app feels like defusing a bomb.</p>
<p>So what's the fix?</p>
<h2>Plot Twist: Your Database Already Has Git Powers</h2>
<p>Here's something most APEX developers don't know:</p>
<p>If you're running on <strong>Oracle Autonomous Database</strong> (even the Always Free tier), you already have a PL/SQL package called <code>DBMS_CLOUD_REPO</code> sitting in your database. Right now. Doing nothing. Waiting for you.</p>
<p>This package lets you:</p>
<ul>
<li>Create GitHub repositories from PL/SQL</li>
<li>Push database objects (tables, packages, views) directly to Git</li>
<li>Export your entire APEX application to Git - split into individual files per page</li>
<li>Pull scripts from Git and run them in your database</li>
</ul>
<p>All from <strong>SQL Workshop</strong>. No terminal. No command line. No Docker. No YAML files.</p>
<p>Just write PL/SQL. Push to GitHub. Done.</p>
<p>Let me walk you through it.</p>
<h2>The Setup (One-Time, ~10 Minutes)</h2>
<h3>1. Get a GitHub Personal Access Token</h3>
<p>Go to GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic) → Generate new token.</p>
<p>Check the <strong>repo</strong> scope. Copy the token (starts with <code>ghp_</code>). You'll need it once.</p>
<h3>2. Store the Credential in Your Database</h3>
<pre><code class="language-sql">BEGIN
  DBMS_CLOUD.CREATE_CREDENTIAL(
    credential_name =&gt; 'GITHUB_CRED',
    username        =&gt; 'your-github-username',
    password        =&gt; 'ghp_your_token_here'
  );
END;
/
</code></pre>
<p>That's it. Your database now knows how to talk to GitHub.</p>
<h3>3. Create a Repository (From PL/SQL!)</h3>
<pre><code class="language-sql">DECLARE
  l_repo CLOB;
BEGIN
  l_repo := DBMS_CLOUD_REPO.INIT_GITHUB_REPO(
    credential_name =&gt; 'GITHUB_CRED',
    repo_name       =&gt; 'my-apex-project',
    owner           =&gt; 'your-github-username'
  );

  DBMS_CLOUD_REPO.CREATE_REPOSITORY(
    repo        =&gt; l_repo,
    description =&gt; 'My APEX App - Version Controlled',
    private     =&gt; TRUE
  );
END;
/
</code></pre>
<p>Go check GitHub. You now have a private repository. You created it from SQL Workshop. Let that sink in.</p>
<h2>Pushing Code to GitHub</h2>
<h3>Export a Database Object</h3>
<pre><code class="language-sql">DECLARE
  l_repo CLOB;
BEGIN
  l_repo := DBMS_CLOUD_REPO.INIT_GITHUB_REPO(
    credential_name =&gt; 'GITHUB_CRED',
    repo_name       =&gt; 'my-apex-project',
    owner           =&gt; 'your-github-username'
  );

  -- Push a table's DDL to Git
  DBMS_CLOUD_REPO.EXPORT_OBJECT(
    repo        =&gt; l_repo,
    object_type =&gt; 'TABLE',
    object_name =&gt; 'EMPLOYEES_T',
    file_path   =&gt; 'db/tables/EMPLOYEES_T.sql'
  );

  -- Push a package
  DBMS_CLOUD_REPO.EXPORT_OBJECT(
    repo        =&gt; l_repo,
    object_type =&gt; 'PACKAGE',
    object_name =&gt; 'EMPLOYEES_PKG',
    file_path   =&gt; 'db/packages/EMPLOYEES_PKG.sql'
  );
END;
/
</code></pre>
<p>Every call creates a commit in your GitHub repo. Real version history. Real diffs.</p>
<h3>Export Your Entire Schema</h3>
<pre><code class="language-sql">DECLARE
  l_repo CLOB;
BEGIN
  l_repo := DBMS_CLOUD_REPO.INIT_GITHUB_REPO(
    credential_name =&gt; 'GITHUB_CRED',
    repo_name       =&gt; 'my-apex-project',
    owner           =&gt; 'your-github-username'
  );

  DBMS_CLOUD_REPO.EXPORT_SCHEMA(
    repo        =&gt; l_repo,
    file_path   =&gt; 'db/',
    schema_name =&gt; 'YOUR_SCHEMA'
  );
END;
/
</code></pre>
<p>All your tables, views, packages, sequences - exported to GitHub in one call.</p>
<h3>The Big One: Export Your APEX Application</h3>
<p>This is where it gets really good.</p>
<pre><code class="language-sql">DECLARE
  l_repo  CLOB;
  l_files APEX_T_EXPORT_FILES;
BEGIN
  l_repo := DBMS_CLOUD_REPO.INIT_GITHUB_REPO(
    credential_name =&gt; 'GITHUB_CRED',
    repo_name       =&gt; 'my-apex-project',
    owner           =&gt; 'your-github-username'
  );

  -- Split export: one file per page, 
  -- shared component, etc.
  l_files := APEX_EXPORT.GET_APPLICATION(
    p_application_id =&gt; 100,
    p_split          =&gt; TRUE
  );

  -- Push every file to GitHub
  FOR i IN 1 .. l_files.COUNT LOOP
    DBMS_CLOUD_REPO.PUT_FILE(
      repo      =&gt; l_repo,
      file_path =&gt; 'apex/' || l_files(i).name,
      contents  =&gt; l_files(i).contents
    );
  END LOOP;
END;
/
</code></pre>
<p>The <code>p_split =&gt; TRUE</code> flag is the secret ingredient. Instead of one massive SQL file, it creates separate files for each page, each shared component, each authorization scheme. Now when you look at the Git diff, you see <em>exactly</em> which page changed and what changed on it.</p>
<h2>What You Get</h2>
<p>Once you've pushed your first export, open your GitHub repo. You'll see something like this:</p>
<pre><code>my-apex-project/
├── apex/
│   └── f100/
│       ├── install.sql
│       ├── application/
│       ├── pages/
│       │   ├── page_00001.sql
│       │   ├── page_00014.sql   ← your precious Page 14
│       │   └── ...
│       └── shared_components/
├── db/
│   ├── tables/
│   │   └── EMPLOYEES_T.sql
│   └── packages/
│       └── EMPLOYEES_PKG.sql
</code></pre>
<p>Now every time you re-export and push:</p>
<ul>
<li><strong>GitHub shows you the diff</strong> - exactly which lines changed on which page.</li>
<li><strong>You have commit history</strong> - scroll back to any previous version of your app.</li>
<li><strong>Rollback is one click away</strong> - find the last working version, copy the SQL, run it.</li>
<li><strong>Your colleague's changes are visible</strong> - no more mystery overwrites.</li>
</ul>
<p>That Dynamic Action you lost at 11:47 PM? Never again.</p>
<p>This isn't a full CI/CD pipeline with automated deployments and blue-green strategies. But honestly? For most APEX teams, it doesn't need to be. <strong>Having any version history is infinitely better than having none.</strong> And this approach gets you there in 15 minutes, using tools you already know.</p>
<h2>TL;DR</h2>
<table>
<thead>
<tr>
<th>What</th>
<th>How</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Where does the code go?</strong></td>
<td>GitHub (free private repos)</td>
</tr>
<tr>
<td><strong>What tool do you use?</strong></td>
<td><code>DBMS_CLOUD_REPO</code> — built into Autonomous Database</td>
</tr>
<tr>
<td><strong>Do I need a terminal?</strong></td>
<td>No. SQL Workshop is enough.</td>
</tr>
<tr>
<td><strong>Does it work on Always Free?</strong></td>
<td>Yes.</td>
</tr>
<tr>
<td><strong>How long to set up?</strong></td>
<td>~15 minutes</td>
</tr>
<tr>
<td><strong>What gets version-controlled?</strong></td>
<td>APEX app + DB objects (tables, packages, views, etc.)</td>
</tr>
</tbody></table>
<h2>What's Next? (Part 2 Teaser)</h2>
<p>This post covered the "lazy" approach - and for solo developers or small teams, it might be all you ever need.</p>
<p>But what if you want:</p>
<ul>
<li>Automated exports on a schedule?</li>
<li>A CI/CD pipeline that deploys to TEST on every push?</li>
<li>Pull requests and code reviews for APEX changes?</li>
<li>OCI DevOps integration with build and deployment pipelines?</li>
</ul>
<p>That's <strong>Part 2</strong> - where we graduate from "lazy" to "serious" DevOps. Coming soon (if this post gets enough love 😄).</p>
<hr />
<p>If you found this useful, share it with an APEX developer who's still naming their backups <code>_final_v3_REAL.sql</code>. They'll thank you.</p>
<p><strong>Have you tried version-controlling your APEX apps? What approach do you use? Let me know in the comments.</strong></p>
]]></content:encoded></item></channel></rss>