APEXlang en Oracle APEX: del export SQL al diff útil en Git

I am a technology professional with about a decade of experience in software development, specialising in Oracle APEX. My career began in telecommunications engineering, but my passion for technology and software development led me to transition into this field. Since then, I have been deeply involved in leading teams and driving digital transformation across various projects. As a part of my daily tasks, I focus on fostering collaboration, efficiency, and technical excellence, ensuring that the projects where I'm involved embrace digital advancements effectively. I take great pride in sharing my knowledge and experience, whether through mentorship, conferences, or engaging with the tech community.
Versionar aplicaciones Oracle APEX nunca ha sido solo cuestión de hacer un export y subirlo a Git.
Eso ya se podía hacer. La dificultad estaba en la calidad del artefacto que llevábamos al repositorio y en lo útil que resultaba después para revisar cambios, entender un diff o comentar una pull request sin tener que volver constantemente al Builder para comprobar qué había pasado.
APEXlang aparece en Oracle APEX 26.1 para cubrir parte de esa necesidad. No convierte APEX en un framework code-first, ni resuelve de golpe CI/CD, merge, branching o despliegues complejos. Pero sí introduce una representación más legible, estructurada y basada en archivos de los metadatos de una aplicación APEX.
Esa representación también abre una conversación interesante con la IA generativa, porque una aplicación descrita en archivos es más fácil de leer, analizar o proponer que una aplicación encerrada únicamente en el Builder. Aun así, en este artículo conviene empezar por la base: qué cambia para Git, diff y control de versiones. La parte de IA da para un análisis propio.
Para equipos que trabajan con Git, revisión de cambios y automatización, esto puede cambiar bastante la experiencia diaria de desarrollo.
El problema no era exportar APEX, era revisar bien los cambios
APEX siempre ha tenido una naturaleza particular. Buena parte de una aplicación vive como metadatos gestionados desde el Builder: páginas, regiones, items, botones, procesos, listas, autorizaciones, navegación, componentes compartidos y atributos declarativos.
Cuando esos metadatos se exportan en un formato poco cómodo para revisión humana, Git puede guardar el histórico, pero no necesariamente ayuda a entenderlo bien.
Podemos tener commits, ramas y pull requests, y aun así encontrarnos con revisiones incómodas: demasiado ruido, poca intención visible, cambios difíciles de interpretar y una dependencia fuerte del Builder para reconstruir qué se ha modificado realmente.
No conviene exagerar el problema. Muchos equipos llevan años versionando aplicaciones APEX con exports SQL, SQLcl, scripts y distintas convenciones de repositorio. La cuestión no es si se podía versionar APEX. La cuestión es si el artefacto versionado era adecuado para trabajar como solemos trabajar hoy: revisar, comparar, automatizar, documentar y validar cambios con algo más de precisión.
APEXlang resulta interesante precisamente por eso: porque mejora la forma en la que la aplicación puede salir del Builder y entrar en un repositorio.
Qué es APEXlang, sin venderlo como algo que no es
APEXlang es una sintaxis declarativa para representar aplicaciones Oracle APEX como archivos fuente. Su valor está en hacer más explícita la estructura de la aplicación.
En lugar de tratar la app solo como una exportación SQL poco amable para revisión, podemos verla como un conjunto de archivos que describen páginas, componentes compartidos, supporting objects, deployments y metadatos organizados.
Esto no significa que el Builder deje de importar. Sigue siendo una pieza central del desarrollo APEX. Lo que cambia es que el repositorio puede contener un artefacto más útil para entender la aplicación fuera de la interfaz web.
Diría que aquí conviene ser bastante preciso: APEXlang no es “el código fuente de APEX” en el mismo sentido que lo sería un proyecto Java, Node o Python. Es una representación declarativa y soportada de los metadatos de una aplicación APEX, pensada para ser legible, validable y gestionable como archivos.
Si lo tratamos como si APEX hubiera pasado a un modelo puramente file-first, estaríamos forzando el discurso. Si lo reducimos a “otro formato de exportación”, tampoco estaríamos recogiendo bien el cambio.
Una nueva forma de visualizar los metadatos de nuestras aplicaciones.
Git no necesitaba más archivos, necesitaba mejores diffs
El valor de APEXlang para Git no está en tener más ficheros. Está en que esos ficheros pueden hacer más visible la intención del cambio.
Si modificamos una página, una región, una lista de valores o un componente compartido, interesa que el diff nos ayude a localizar qué ha cambiado. No queremos revisar un bloque enorme de metadatos sin contexto suficiente.
Con APEXlang, los cambios tienen más opciones de quedar cerca del componente afectado. La revisión en VS Code o en una pull request puede ser más razonable. La búsqueda de referencias resulta más natural. Algunas tareas de documentación, análisis o validación también pueden apoyarse mejor en una representación textual más clara.
Esto no significa que el diff vaya a ser perfecto siempre. Tampoco significa que el merge esté resuelto. Lo que sí mejora es la posibilidad de entender un cambio sin depender tanto de reconstruirlo todo desde un export monolítico o desde el propio Builder.
¿Cómo de sencillo resultaba cambiar el título de una app en un export
.sql?
Export SQL y export APEXlang no cumplen exactamente el mismo papel
Una duda bastante natural al empezar con APEXlang es dónde queda el export SQL tradicional.
No lo plantearía como una sustitución inmediata.
En APEX 26.1 podemos seguir teniendo ambos artefactos: el export SQL como fichero .sql y el export APEXlang como estructura de archivos .apx. Representan la misma aplicación, pero no tienen por qué ocupar el mismo papel en el repositorio.
El export SQL puede seguir siendo útil como artefacto tradicional de instalación, fallback, compatibilidad o integración con flujos existentes.
APEXlang, en cambio, tiene más sentido como representación revisable de la aplicación: algo que podemos leer, comparar, validar y discutir con más criterio.
Por eso conviene separarlos bien.
Una estructura razonable podría ser:
apex/
core/
app-100/
README.md
apexlang/
application.apx
page-groups.apx
pages/
shared-components/
supporting-objects/
deployments/
sql/
f100.sql
Aquí hay una decisión deliberada: no dejamos f100.sql mezclado al mismo nivel que los archivos .apx.
Los dos artefactos pueden proceder de la misma aplicación, pero no cumplen exactamente la misma función. El SQL export puede actuar como snapshot o artefacto tradicional. La carpeta apexlang/ es la que nos interesa para revisión, diff y validación como archivos fuente.
Git ya no es un lujo adicional para gestionar proyectos APEX, y APEXlang lo pone mucho, mucho más fácil.
El application ID no es un detalle menor
Al organizar una aplicación APEX en Git aparece otra duda práctica: ¿usamos el alias de aplicación, el ID, una mezcla de ambos o algo como f100?
El alias es más legible para humanos. demo-app dice más que app-100.
Pero el application_id tiene peso operativo en APEX. Si importamos una aplicación con otro ID, APEX puede tratarla como una aplicación distinta, no como una actualización de la aplicación existente.
Esto puede tener consecuencias.
En una aplicación real puede haber información asociada al runtime de esa app: informes guardados, variantes públicas o privadas de Interactive Reports, preferencias, suscripciones, personalizaciones o configuraciones vinculadas a la aplicación instalada.
Si la app original es la 100 y desplegamos “la misma” app como 101, no estamos necesariamente actualizando la misma identidad APEX. Podemos estar creando otra aplicación.
Por eso, aunque el alias sea mucho más cómodo para leer el repositorio, en un flujo serio de despliegue no conviene esconder el ID.
Una carpeta como app-100 puede parecer menos elegante que el alias, pero deja claro el contrato operativo:
apex/
core/
app-100/
README.md
apexlang/
sql/
f100.sql
El alias, el parsing schema y otros datos de contexto pueden quedar documentados dentro del README.md de la propia app:
# DEMO-APP
- Application ID: 100
- Application alias: demo-app
- Parsing schema: DEMO_APP
- Source format: APEXlang
- SQL export: sql/f100.sql
Una regla práctica que me parece razonable es esta: el alias identifica la aplicación para humanos; el application_id identifica la aplicación para APEX. En versionado podemos usar ambos, pero en despliegue no deberíamos ignorar el ID.
La estructura de carpetas forma parte del contrato operativo del equipo, por lo que es importante definir correctamente nuestro repositorio.
SQLcl y VS Code: cuando APEXlang pasa a un flujo operativo
APEXlang se vuelve más interesante cuando no se queda como una idea de formato y entra en un flujo concreto de trabajo.
Un ciclo mínimo podría ser:
exportar la aplicación en formato APEXlang;
revisar o editar los archivos localmente;
ejecutar validación con SQLcl;
revisar errores, warnings y alcance del cambio;
importar en un entorno controlado;
probar la aplicación en navegador.
Por ejemplo, para exportar:
apex export -applicationid 100 -exptype APEXLANG
Para validar:
apex validate -input ./apex/core/app-100/apexlang
Y para importar:
apex import -input ./apex/core/app-100/apexlang
La extensión de SQL Developer para VS Code también encaja bien en este flujo, porque permite trabajar con archivos APEXlang desde el mismo entorno donde ya revisamos código, Git y terminal.
Ahora bien, apex validate no convierte el cambio en seguro por sí solo.
La validación puede decirnos si el artefacto es aceptable para el compilador de APEXlang. No nos dice que la aplicación sea funcionalmente correcta, que la seguridad esté bien resuelta o que el usuario pueda completar el flujo en navegador.
Es un filtro técnico, no una prueba funcional completa.
De estos tres comandos, me encanta poder validar antes de dar los siguientes pasos…
Qué cambia para equipos que versionan APEX
El primer cambio está en la revisión.
Si el equipo puede ver mejor qué página, componente o atributo ha cambiado, el code review deja de ser una revisión casi ciega del export y se acerca más a una conversación técnica sobre la aplicación.
El segundo cambio está en la trazabilidad.
Cuando los metadatos se expresan de forma más legible, resulta más fácil conectar un issue, una rama, una pull request y una modificación concreta de la app.
El tercer cambio está en la automatización.
No hace falta pensar todavía en un pipeline perfecto. Basta con algo más sencillo: validar artefactos, detectar inconsistencias, buscar patrones, revisar nomenclaturas o preparar análisis estático sobre la estructura de una aplicación APEX.
El cuarto cambio está en la experiencia de desarrollo.
APEX sigue siendo APEX. Pero el trabajo fuera del Builder gana algo de peso: VS Code, SQLcl, Git, pull requests, documentación del workspace y reglas de equipo empiezan a encajar de forma más natural en el ciclo.
Hay además una derivada que no conviene ignorar: una representación textual y estructurada también da mejor contexto a herramientas de IA. No porque debamos pedirle a un modelo que genere aplicaciones sin control, sino porque resulta más sencillo revisar metadatos, detectar inconsistencias, preparar documentación o contrastar una intención funcional contra una estructura de aplicación.
No estamos ante una revolución completa del desarrollo APEX, pero sí ante una mejora concreta en una zona donde había margen para trabajar mejor.
Este podría ser un flujo mínimo, todavía lejos de ser un pipeline CI/CD completo.
El merge sigue siendo el punto delicado
Un diff más legible no equivale a un merge seguro.
Git puede resolver conflictos textuales. Pero una aplicación APEX no es solo texto. Son metadatos relacionados: páginas que usan componentes compartidos, procesos que dependen de items, autorizaciones reutilizadas, listas de valores, plugins, menús, condiciones y lógica PL/SQL.
Dos ramas pueden tocar archivos distintos y generar una incompatibilidad funcional.
También puede pasar lo contrario: Git puede detectar un conflicto textual, resolverlo a mano y dejar una aplicación inválida o incoherente desde el punto de vista de APEX.
Por eso, si usamos APEXlang en equipo, el flujo mínimo debería incluir algo parecido a esto:
1. Exportar desde una base conocida.
2. Trabajar en una rama o entorno aislado.
3. Ejecutar apex validate antes de fusionar.
4. Ejecutar apex validate después de fusionar.
5. Resolver conflictos con criterio APEX, no solo textual.
6. Importar en un entorno controlado.
7. Probar los flujos principales en navegador.
Este punto pesa especialmente en Shared Components: LOVs, Authorization Schemes, listas, plugins, navigation menus o procesos reutilizados pueden afectar a varias páginas a la vez.
APEXlang ayuda a ver mejor el problema, pero no elimina la necesidad de entender la aplicación.
[Imagen sugerida: zoom conceptual de un merge conflict en un archivo .apx, junto a una anotación discreta: “Git resuelve texto; APEX necesita consistencia de metadatos”. Otra opción es un diagrama pequeño de dependencias entre Page, LOV, Authorization Scheme y Process.]
Working Copies no desaparecen automáticamente
Otra conclusión rápida sería pensar que, si tenemos APEXlang y Git, las Working Copies dejan de tener sentido.
No lo veo tan claro.
En entornos APEX compartidos, las Working Copies pueden seguir aportando aislamiento dentro del propio Builder, protección de la app principal y una forma APEX-first de trabajar sobre cambios antes de promoverlos.
APEXlang cambia más el escenario cuando el equipo adopta un flujo Git-first, con entornos aislados, reglas claras de export/import y disciplina suficiente para evitar que un import completo sobrescriba trabajo ajeno.
Dicho de otra forma: APEXlang no vuelve obsoleto todo lo anterior. Añade una pieza nueva y potente, pero hay que decidir dónde encaja.
En algunos equipos, APEXlang podrá convertirse en la base principal para revisión y versionado. En otros, convivirá con Working Copies durante bastante tiempo. Y en apps maduras, quizá empiece como herramienta de inspección y limpieza antes de entrar en el flujo de despliegue.
Apps existentes: aquí conviene ir con más cuidado
En aplicaciones nuevas, APEXlang puede entrar en el flujo de trabajo con menos fricción.
En aplicaciones existentes, sobre todo si vienen de varias versiones anteriores, la situación puede ser distinta.
Antes de tratar una app madura como buen material APEXlang conviene revisar varias cosas: compatibility mode, theme refresh, plugins, JavaScript antiguo, Static IDs, componentes heredados, shared components poco consistentes y metadatos que el Builder puede tolerar, pero que un flujo más explícito puede sacar a la luz.
Esto no es necesariamente malo. De hecho, puede ser una ventaja.
APEXlang puede ayudarnos a ver deuda de metadatos que antes quedaba más escondida. Pero eso también significa que la adopción en apps reales puede requerir una fase previa de limpieza, diagnóstico y pruebas.
No basta con importar una app antigua en APEX 26.1, exportarla en APEXlang y asumir que ya tenemos un flujo moderno de desarrollo.
| Punto a revisar | Por qué importa antes de usar APEXlang |
|---|---|
| Compatibility Mode | Puede condicionar cómo se interpreta o mantiene la aplicación tras actualizarla. |
| Theme Refresh | Las apps antiguas pueden arrastrar estructura visual o plantillas que conviene limpiar antes. |
| Plugins | Pueden introducir dependencias externas difíciles de revisar solo desde el export. |
| JavaScript antiguo | Puede funcionar en runtime, pero ser deuda técnica poco visible en el Builder. |
| Static IDs | Ayudan a estabilizar referencias, pruebas, automatización y revisión de componentes. |
| Shared Components | Un cambio pequeño puede afectar a varias páginas si hay LOVs, autorizaciones o menús reutilizados. |
apex validate |
Detecta problemas del artefacto APEXlang, pero no sustituye pruebas funcionales. |
Una forma prudente de empezar
La forma más sensata de evaluar APEXlang no es rediseñar todo el ciclo de desarrollo en la primera semana.
Tiene más sentido empezar con una aplicación pequeña, exportarla, hacer cambios controlados y mirar qué ocurre.
Un primer laboratorio razonable sería:
1. Exportar la app como APEXlang.
2. Hacer commit inicial.
3. Cambiar el título de una región.
4. Exportar de nuevo.
5. Revisar el diff.
6. Cambiar un item o proceso.
7. Revisar el diff.
8. Cambiar un Shared Component.
9. Ejecutar apex validate.
10. Importar en un entorno controlado.
11. Probar la app en navegador.
Lo interesante no es solo que el comando funcione. Lo interesante es comprobar si el resultado ayuda a trabajar mejor:
si el diff es entendible;
si el export es estable entre ejecuciones;
si los cambios aparecen donde esperamos;
qué detecta
apex validate;qué no detecta;
qué ocurre si tocamos algo directamente en Builder;
cómo organizamos el SQL export y el APEXlang export;
qué reglas necesita el equipo antes de usarlo en serio.
A partir de ahí podemos decidir si APEXlang se queda como herramienta de revisión, como formato principal de versionado, como apoyo a documentación o como pieza dentro de un flujo más amplio con SQLcl Projects y CI/CD.
Ahora, resulta muy sencillo auditar cambios usando recursos estándar en el resto de la industria.
Lo que no deberíamos dar por resuelto todavía
APEXlang es una mejora importante, pero conviene evitar algunas conclusiones rápidas.
No sustituye APEX Builder.
No convierte automáticamente una app APEX en un proyecto Git-first seguro para edición concurrente.
No hace que Working Copies dejen de tener sentido en todos los escenarios.
No convierte un import completo en un parche incremental.
No resuelve por sí solo CI/CD.
No garantiza que un merge de Git deje una aplicación válida.
No sustituye pruebas funcionales, revisión de seguridad ni pruebas en navegador.
Y, sobre todo, no elimina la necesidad de reglas claras en el equipo.
Cuando varias personas trabajan sobre la misma aplicación, el problema no es solo técnico. También es de coordinación: desde qué base se exporta, quién puede importar, qué entorno se usa para validar, qué ocurre si alguien cambia algo directamente en Builder y cómo se gestionan los conflictos entre archivos y metadatos reales.
APEXlang puede reducir fricción. No sustituye la disciplina de ingeniería.
Vayamos acabando…
APEXlang no resuelve todos los problemas históricos de versionado en Oracle APEX. Pero sí mejora una pieza que llevaba tiempo pidiendo evolución: la representación legible de la aplicación fuera del Builder.
Ese cambio puede parecer pequeño si lo miramos solo como formato de exportación. Pero, si lo miramos desde Git, code review, diff, validación y trabajo en equipo, la conversación cambia bastante. La clave está en no confundir potencial con madurez absoluta.
La derivada con IA generativa es evidente, pero conviene no mezclar las capas. Antes de pedir a un asistente que genere o modifique una app APEX, necesitamos entender bien qué representa APEXlang, cómo se valida, qué riesgos introduce y qué parte del flujo sigue dependiendo de revisión humana.
Antes de prometer CI/CD completo, merge limpio o desarrollo colaborativo sin fricciones, quizá el primer objetivo sea más modesto y más útil: conseguir que una aplicación APEX sea más fácil de leer, revisar y validar desde el repositorio.
Una vez más, me quedó un post largo. Sin más, ¡gracias por llegar hasta aquí!
Happy coding,
Juan L.





