Skip to main content

APEXlang - I Tried It, and Here's What Actually Changed for Me

APEXlang: My Honest Take After Playing With It

Oracle APEX 26.1

APEXlang I Tried It, and Here's What Actually Changed for Me

When Oracle announced APEXlang in APEX 26.1, I wasn't sure what to make of it. Another export format? I've been building APEX apps for years and felt comfortable with the old ways. But after spending a few weeks actually using it on a real project, I have to say this one is different.

I'll be honest: I came in with low expectations. I've seen "improved export formats" before and they rarely changed my day-to-day much. So I ran APEXlang through its paces on an internal HR portal our team had been maintaining for about two years 14 pages, approval workflows, email triggers, a couple of interactive grids. Enough moving parts to surface real issues. Here's what I actually found.

A bit of context: The app I tested on was a leave management portal built for an internal HR team. Nothing glamorous, but it had enough shared components and a CI/CD pipeline I'd describe charitably as "quirky." That's where most of this post comes from.

Okay, so what even is APEXlang?

The short version: APEXlang is an open, declarative specification language for Oracle APEX apps. Instead of your application living inside one massive SQL dump, it's broken out into clean, readable files you can actually open in VS Code and understand at a glance.

I like to think of it as giving your APEX application a proper source code home the kind developers working in React or Java have always had. Each page, each shared component, each SQL script lives in its own structured file. Together they form an APEXlang package, which is a ZIP archive that looks like this when you unzip it:

  • .apxApplication and page definition files. Each page gets its own file. On our HR portal this meant 14 separate files one per page which made it immediately obvious who had last touched what.
  • .sqlNative SQL scripts. Supporting objects, install and deinstall scripts all sit right here alongside the application definition.
  • .css / .jsCustom styling and JavaScript bundled with the project. No more hunting through the app builder for that one bit of custom CSS you added six months ago.
  • staticImages, icons, logos static resources stored alongside everything else.
  • sharedAuthentication schemes, authorization rules, LOVs, lists, breadcrumbs each type in its own file. Really useful when more than one person is touching shared components.

Once this package lives in Git, it becomes the governed, diffable source of truth for the entire application. That's something I'd wanted for years.

Heads up: If you were using the YAML export format before, it's been fully retired in APEX 26.1. APEXlang takes over completely. I migrated our HR portal and it was mostly straightforward though I did hit one snag with a legacy authorization scheme that needed manual review. The upgrade path handles most things, but budget a bit of time if your app is older.

The headaches it actually fixes

There were real problems with the old approach that I'd quietly accepted as "just how APEX works." APEXlang addresses most of them. Here's what actually changed:

🔍

Pull requests that meant nothing

Reviewing a 12,000-line SQL export in a PR was theatre, not review. A colleague once approved a change that accidentally dropped a validation neither of us caught it in the diff. With APEXlang, changes to Page 5 show up in one file, not buried in a monolithic export.

🤖

AI tools were flying blind

I'd tried pasting bits of our SQL export into AI assistants before and the suggestions rarely made sense too much noise, not enough structure. With APEXlang, I pasted a single page file and got back an actually relevant suggestion about a redundant validation. First time that's happened.

🔐

Security audits were painful

Our security team had previously asked us to document every authorization check in the app manually. With APEXlang, those rules live in a readable shared file. The last audit went noticeably faster they could scan it themselves.

⚙️

CI/CD was held together with tape

Our pipeline had a brittle import step that occasionally failed with a cryptic ORA error and no useful message. The SQLcl integration gives it something real to validate before anything touches the workspace. That step hasn't broken since we switched.

The AI point is the one I keep coming back to. I'd genuinely given up on AI assistants being useful for APEX work the structure just wasn't there for them to reason about. APEXlang changed that enough that I now keep a page file open alongside my AI tab when I'm debugging something tricky.

The actual step-by-step workflow

This is the bit I wish I'd had when I started a clear picture of the full loop from Builder to local editor and back. I'll walk through exactly how I set it up and where I stumbled, so you don't have to.

  • 1

    Export your app in APEXlang format from Builder

    In APEX Builder, go to Export / Import → Export and select APEXlang as the format. You'll get a ZIP with all the structured files. The export type you pick here matters, so it's worth thinking about upfront:

    Export Type When to use it What's included
    Standard Source control, day-to-day dev Developer comments and audit trail. No runtime data.
    Runtime Deploying to test or production Strips comments, locks build status to run-only.
    Full Moving an app across environments with data Runtime data + full audit info. Don't commit this to Git.
    Custom When you need exact control Flashback option, granular toggles for every export setting.
    First time I did this, I accidentally picked Full and committed a 47 MB ZIP to our repo. My team was not thrilled. Standard is almost always the right choice for Git.
  • 2

    Open the project locally in VS Code

    Unzip the export and open the folder in VS Code. You'll see your pages directory, shared components, SQL scripts, and static files all laid out cleanly. Even before installing any extension, you can read the .apx files and make basic edits the syntax is readable enough that it doesn't feel foreign.

    Tip: On first open, VS Code may prompt you to install recommended extensions for the workspace. Click Install All it'll save you a step in the next stage.
  • 3

    Install the Oracle SQL Developer Extension for VS Code

    Search for "Oracle SQL Developer" in the Extensions panel (Ctrl+Shift+X) and install it. This is what unlocks syntax highlighting, Ctrl+Space code completion on APEXlang properties, and live error indicators that flag problems before you try to import.

    The Problems panel (Ctrl+Shift+M) becomes your early-warning system it tells you which file and line has an issue. I caught two property-name typos on our first export before the database was even involved.

    The extension requires VS Code 1.85 or later. I was on an older version and got a confusing activation error worth checking before you start.
  • 4

    Create a database connection in VS Code

    Open the Oracle SQL Developer panel from the sidebar, click Add Connection, and fill in your host, port, service name, and credentials. Once connected, you can browse schema objects, run queries, and import your APEXlang package directly from VS Code no switching back to Builder needed.

    You can set up multiple connections (dev, test, prod) and switch between them as needed. I keep our dev connection as the default and only switch to test when I'm actually ready to deploy something.

    Using Oracle Autonomous Database? You'll need a wallet-based connection the standard username/password flow won't work with ADB without the wallet file configured first.
  • 5

    Modify your app using the structured .apx files

    Open the page file you want to change say pages/p00005-leave-requests.apx and edit it directly. The structure is readable enough that you get up to speed on a file quickly. Here's roughly what a form page looks like:

    pages/p00005-leave-requests.apx
    // Page 5 – Leave Request Submission
    page(
      name: Leave Request
      alias: leave-request
    
      region(
        name: request-form
        type: Form
    
        source {
          sql: ```
            SELECT request_id, emp_id, leave_type,
                   start_date, end_date, status
            FROM   hr_leave_requests
            WHERE  emp_id = :APP_USER_ID
          ```
        }
    
        layout {
          position: BODY
          startNewRow: true
        }
      )
    )

    Before committing, run a validate to catch anything the editor missed:

    $ apex validate -input ./leave-portal

    It checks the whole package without touching the workspace. I run this before every commit it's caught a few mistakes that would have caused a failed import.

    One thing that tripped me up: component names get auto-assigned system Static IDs on first export from an older app. APEX derives them from component names, so a region called "Leave Requests" becomes leave-requests but some of mine came out less readable than that. Worth reviewing them before your first edit session.
  • 6

    Import the updated app back into your workspace

    Either right-click the project folder in VS Code and choose Import to APEX, or run it from the terminal:

    $ apex import -input ./leave-portal

    APEX compiles the APEXlang source and deploys it. If anything goes wrong, the Problems panel tells you exactly which file and which line no guessing, no vague ORA errors to Google. Once I had the flow down, the full round-trip (export → edit → validate → import) took about four minutes.

    For CI/CD: This same apex import command works in a pipeline. We wired it into our GitHub Actions workflow. Much more reliable than our old import step, which had a habit of failing silently.

A look at the APEXlang syntax it's simpler than it looks

When I first opened a .apx file I wasn't sure what I was looking at. But after about twenty minutes I had the pattern down. There are really only a handful of constructs to learn:

ConstructWhat it means
( )Wraps a component a page, a region, or an item
{ }A property group like source, layout, or appearance
camelCase:Property name followed by its value after the colon
```...```Multi-line SQL, PL/SQL, or JavaScript just like markdown code fences
@nameA reference to another component for example, pointing to a parent region
[ ]A list of multiple values

The format reads almost like structured prose once you're in it. You can glance at a page file and know immediately what that page does compare that to hunting through a 10,000-line SQL export for the same information.

One thing I'd do differently: When you upgrade an existing app to APEX 26.1, review the auto-generated Static IDs before your first APEXlang export. APEX derives them from component names "Store Products" becomes store-products but some of mine came out cryptic enough that I spent time figuring out what they referred to. A cleanup session upfront saves confusion later.

Three ways to work with it

One thing I appreciate is that Oracle hasn't locked APEXlang into a single workflow. Depending on what I'm doing, I reach for one of three tools:

🏗️

APEX Builder

The familiar starting point. Export from the dialog, import by dragging the ZIP in. There's also a new read-only APEXlang view inside Page Designer useful for a quick sanity check before editing locally.

🖥️

VS Code + SQL Developer

My daily driver now. Code completion, syntax highlighting, live validation, DB connection, and import all in one place. The Problems panel alone has saved me from several broken imports.

SQLcl CLI

For anything automated CI/CD, scripting, nightly deployments. Four clean commands cover everything I need. Wired into our pipeline and solid so far.

The four SQLcl commands worth knowing

$ apex export -applicationid 100 -dir ./my-app -exptype APEXLANG
$ apex validate -input ./my-app
$ apex import -input ./my-app
$ apex generate -workspaceid 1234 -alias myapp -name "My App" -dir ./my-app

The generate command is new in 26.1. I used it to scaffold a quick proof-of-concept last week you run the command, get a starter project on disk, and import it straight into your workspace without opening Builder. It works, though the scaffolded app is fairly bare-bones. Treat it as a skeleton rather than anything with structure built in.

Worth knowing: when you generate a new app this way, the deployments/default.json file won't have an application ID yet APEX assigns one on first import. If you need a specific ID, add it to that file before importing. I found this out the hard way when our test environment got a different ID than dev and a few hardcoded links broke.

My honest verdict

I went into APEXlang with low expectations and came out genuinely convinced it's the right direction. It's not just a new file format it's a proper rethink of how an Oracle APEX application can live outside of the Builder.

The transition wasn't completely frictionless. The initial export of our HR portal threw a warning about an old authorization scheme, and I spent an afternoon getting our SQLcl version updated to support the new commands. Those were one-time setup costs, not ongoing pain but they were real.

What I like most is that it meets you where you are. You can keep building in APEX Builder just like before, export to APEXlang when you need it in source control, and import back when you're done. Nothing forces you to change everything at once. The rewards real code review, proper CI/CD, AI tooling that actually works stack up quickly once you're in the loop.

If you've ever felt friction around code reviews, source control, or just wanting to understand your own app's structure more clearly give APEXlang a proper try. The setup is a couple of hours. The payoff starts immediately.

Comments

Popular posts from this blog

Generate Custom PDFs in Oracle APEX with jsPDF

Generate Custom PDFs in Oracle APEX with jsPDF A complete step-by-step guide to building a client-side PDF generator with profile image embedding and PL/SQL database persistence. 📄 Step-by-step guide Oracle APEX jsPDF Dynamic Actions PL/SQL JavaScript "Picture this: your Oracle APEX application is polished, your users love it — but when they ask for a downloadable report with a profile picture and custom styling, you realize vanilla APEX isn't built for that out of the box. What if a single JavaScript library and one Dynamic Action could change everything?" Welcome to the world of jsPDF inside Oracle APEX . In this tutorial, we wire up a PDF generator that captures a user's name, email, phone number, and profile picture — renders them into a beautiful PDF layout — and saves everything to Oracle, all in one button click. ⓘ What you'll build: A dynamic PDF generat...

APEX Custom Auth Settings, Decoded!

Oracle APEX Security PL/SQL APEX Custom Auth Settings, Decoded Why I Build this I was building an internal APEX app — strictly for people on our corporate network. The default authentication worked, but it had a few things that kept bothering me. Anyone with valid credentials could log in from anywhere. Sessions expired with a useless error page. There was no audit trail — no way to know who logged in, when, or from where. And passwords were stored in plain text, which I just couldn't leave alone. So I did what any developer does — I built it myself. Custom authentication, from scratch, in PL/SQL. Turned out to be one of the best learning experiences I've had with APEX. Here's exactly how I did it. Img 1 : Head to Shared Components → Authentication Schemes → Create, choose Custom as the Scheme Type, and plug in your function and procedure names. Quick note before we get into the code — the s...

APEX 26.1 is here - and there's a lot to talk about

Oracle APEX APEX 26.1 is here - and there's a lot to talk about 🚀 A quick look at everything that came in this release - big and small. May 2026  ·  90+ community ideas shipped When APEX 26.1 dropped, I honestly wasn't expecting this much. I opened the release notes thinking I'd be done in 10 minutes. An hour later, I was still reading - going "wait, they added this too?" This post is not a deep dive into any single feature. It's just me walking you through what's new in 26.1, so you know what to look forward to. We'll cover each feature properly in separate posts. But first, let's get the full picture. I also personally tried some of the community-submitted features in this release, and I'll share my honest experience with each one. Some of them are small things - but small things are what make daily dev life better. You'll see what I mean. 😄 New 1. APEXlang - Your App Des...