Oracle APEX feature parity โ
This page compares pgkiln with Oracle APEX 26.1 (May 2026), area by area. It's meant to be honest: it shows what a team moving from APEX can use today and what is still missing. Pick an open item and open an issue or pull request; see CONTRIBUTING.md.
Legend: โ available ยท ๐ก partial (see notes) ยท โ not yet ยท โ not planned (a deliberate choice, or better served by the PostgreSQL ecosystem; see the notes and extensions)
Last reviewed: 2026-10-06 (pgkiln 0.31.0, in progress: static application files and the Execute JavaScript dynamic action; region, item, dynamic action and process plug-ins; conditional and dynamic theme styles; XML and Excel in meta.parse_data, zips in SQL, meta.v_boolean; file items in S3-compatible object storage; map layers by the visible area and as vector tiles; a graphical query builder; tenants for workflows and tasks; application files as YAML and region static IDs; Lucide icons and icon modifiers; PWA push notifications; 0.30.0: 136 icons and an icon picker; an axe-core accessibility audit; cropping pictures; session sharing between applications; twenty-two built-in languages; 0.29.0: workspaces; the Iris base style; drawers; built-in template components including the metric card; Theme Roller dark-mode colours, live preview and template options on items and report columns; report selection across pages; instance settings; fourteen built-in languages; 0.28.0: AI with Claude and OpenAI; 0.27.0: Data Reporter; sample data generator; create application from several sheets, pasted data or existing tables; 0.26.0: working copies with a three-way merge; theme, library and boilerplate applications with subscriptions; 0.25.0: Gantt, pyramid and polar charts; map layers, clustering and server-side spatial filters; REST data sources that write back from forms and grids and synchronise into tables, OAuth2 password and refresh-token grants; debug messages per request and an install/upgrade log; meta.web_request() and meta.parse_data(); Theme Roller style variants and template options; 0.24.0: automations with several actions, error handling per row and runs from SQL; invoke-API workflow steps; Unload Data in the Data Workshop; create page wizards for cards, calendar, chart, map, faceted search, form and master-detail; create an application from a file; 0.23.0: interactive grid aggregates, frozen/moved/resized columns, layouts and saved grid reports, master-detail, row actions and copy/paste; download processes, execution chains in the background, workflow processes, branches to a function's URL or another app, the Dialog Closed event; number format masks, automatic time zone, runtime messages in German, French and Spanish; SQL scripts, Quick SQL, a query builder, XML loading and data load definitions; custom authentication, lists, page and application locks with developer comments, supporting objects; 0.22.0: keyset paging, report PDFs and REST collections streamed from a cursor, database-account authentication; 0.21.0: HTTP-header authentication behind a reverse proxy; 0.20.0: a popup list of values with server-side search; 0.19.0: row-range pagination, maximum row counts and row limits, lazy loading and caching of regions, streamed CSV/Excel downloads; 0.18.0: calendar week/day/list views with drag and drop, bubble/gauge/funnel/radar charts and drill-down, smart filters, a region display selector and more facet types, computations, conditional branches, build options, menu buttons, REST data sources and web credentials, rich text/Markdown, rating, combobox, date range and QR code items; 0.17.0: an App Builder home, workspace dashboard and utilities like APEX's; 0.16.0: a Page Designer with drag-and-drop layout, a code editor with autocomplete, template components and plug-ins, parallel branches and versions of workflows, the pgkiln command line with one file per component; 0.15.0: drop and paste files, heat maps, filtering a report by the map area; 0.14.0: stacked, combo, scatter and pie charts, several files per upload item; 0.13.0: map and tree regions; 0.12.0: REST modules in the builder; 0.11.0: workflows and Progressive Web Apps; 0.10.0: LDAP, SAML, "Keep me signed in", document templates, JSON loading, approvals and the task list; pgkiln installs no application, HR is an example).
At a glance โ
| Area | โ | ๐ก | โ | โ | In short |
|---|---|---|---|---|---|
| App Builder and development | 16 | 0 | 0 | 0 | Page Designer with drag-and-drop and a code editor, wizards, search, where used, an Advisor, a CLI with one file per component, page locks and comments, supporting objects, working copies with a three-way merge, theme/library/boilerplate apps with subscriptions; App Builder AI (pages, SQL and table descriptions) |
| Regions | 19 | 1 | 3 | 0 | All everyday regions; sixteen chart types with drill-down; calendars with week/day/list views and drag and drop; faceted search, smart filters and a region display selector; interactive reports with breaks, aggregates, highlights, compute, group by, pivot, chart view and saved reports; maps (with vector tiles) and trees; template components; row ranges, lazy loading and region caching for large tables |
| Items | 12 | 0 | 1 | 0 | All common items, file upload (several files per item), rich text and Markdown editors, star rating, combobox, date range, QR code, password reveal |
| Logic and processing | 12 | 1 | 4 | 1 | Core APEX model complete with computations, conditional branches, build options and menu buttons, download, chain and workflow processes; JavaScript from static application files in dynamic actions; region, item, dynamic action and process plug-ins |
| Security | 20 | 0 | 1 | 0 | On par or stricter (CSP without unsafe-inline); OIDC, SAML and LDAP; header authentication behind a proxy; database accounts; custom authentication |
| User interface | 10 | 2 | 0 | 0 | Universal Theme-like and responsive; a Theme Roller with style variants and conditional, dynamic styles; about 1,700 icons with Font APEX-like modifiers |
| Globalization | 5 | 1 | 1 | 0 | One translated app like 26.1; number format masks and automatic time zone; twenty-two built-in languages |
| Data and integration | 9 | 0 | 2 | 2 | REST APIs via PostgREST, REST data sources that write back and synchronise, web credentials with OAuth2 grants, CSV/XLSX/JSON/XML loading with saved definitions and unloading, SQL scripts and Quick SQL, report PDFs and document templates |
| Workflow, automation and AI | 6 | 0 | 0 | 0 | Scheduled automations with several actions and runs from SQL, approvals, a task list and workflows with parallel branches, versions and invoke-API steps; AI with Claude or OpenAI: Generate text with AI, an assistant region with tools, natural-language report filters and blueprints |
| Administration | 4 | 1 | 3 | 0 | Workspaces that group applications and developers (not a tenant boundary); Top SQL per app; debug messages per request; an install/upgrade log |
| Total | 113 | 6 | 15 | 3 | 137 APEX features compared: 82% available, 4% partial |
(Counts are of the rows in the tables below. A review on 2026-10-06 added 18 rows for APEX features that were not compared before, so the share available dropped without anything being removed.)
App Builder and development โ
| APEX | pgkiln | Notes |
|---|---|---|
| App Builder: create, edit, delete, run apps | โ | Builder at /builder |
| Create application wizard | โ | Blank app with its own database role and schema, started from a boilerplate application if wanted; from a file: CSV/TSV/XLSX/JSON/XML, where an Excel workbook with several sheets (or JSON with several arrays) becomes several tables, with a preview to include or leave out each sheet, edit table/column names, types and primary keys, and foreign keys proposed from matching columns; from pasted data (CSV/TSV text); from existing tables (pick the tables and views of a schema). Each gives a report and form per table, navigation and an optional dashboard (a chart per table), plus an optional faceted search for a single table, all created in one transaction. Missing: blueprints (26.1) |
| Create page wizards | โ | Report and form, interactive grid, form, cards, calendar, chart, map, faceted search and master-detail (stacked grids) from any table or view, with defaults from the catalog (columns, key, dates, positions, foreign keys), an optional modal form page and a navigation entry; also from SQL (meta.generate_page). No side-by-side or drill-down master-detail, no wizard for smart filters or trees |
| Page Designer | โ | IDE-style window (dark or light): component tree, a layout canvas with drag and drop (with keyboard and button alternatives) and a gallery of regions, items and buttons, a filterable property editor; undo/redo; panes become tabs on phones. Settings forms for report, grid, chart, cards, calendar, faceted search, smart filters, display selector, map, tree and template component regions. A code editor for SQL, PL/pgSQL, JSON and HTML with highlighting and autocomplete of tables, columns and :ITEM binds (no extra libraries). Drag and drop needs a mouse; on touch screens the Arrange buttons move components |
| Shared components | โ | Navigation menu, lists (static entries with nesting, badges, conditions, authorization and build options, or a query; for list regions, the navigation menu and the navigation bar), authorization schemes, build options, lists of values, application items and processes, access control, globalization, template components and plug-ins, web credentials, REST data sources, data load definitions, supporting objects |
| Export / import | โ | meta.export_app() / meta.import_app(): portable JSON, also in the builder |
| APEXlang: human-readable, diffable app files; static IDs (26.1) | โ | pgkiln export --format dir: one JSON file per component with sorted keys, SQL and HTML in sibling files, references by static id instead of database ids; pgkiln import --replace updates an app in place, pgkiln diff compares (chapter 18). (0.31) --format text: the same files as YAML (a strict subset any YAML tool reads) with the SQL and templates inline, read back losslessly (text files); regions have a stored Static ID (exported as their key, rendered as data-static-id), other components are named by their stored names. The syntax is YAML rather than APEXlang's own, so APEXlang files don't import |
| Working copies, merge, team development | โ | Working copies of an application (chapter 3): a second app on the same schema and data, compared three ways per component (settings, each shared component, page, region, item, โฆ) with the main app as it was when copied; changes on one side merge, conflicts are chosen per component with a line diff; merge into the main app or refresh the copy, keeping users, sessions, saved reports, secrets and automation switches; locks respected. Conflicts are resolved per component, not per property |
| Application lock (26.1), page locks, comments | โ | Page and application locks, enforced on the server for every builder change; the owner or an administrator unlocks, and an administrator breaking a lock is logged. Developer comments per page and per app (chapter 3) |
| Static application files | โ | Shared Components โ Static application files (chapter 3): JavaScript, CSS, JSON, images and fonts uploaded or written in the builder, served at /a/<alias>/static/<name> with long caching per version, loaded by every page or by one page (APEX's JavaScript/CSS File URLs), exported with the application (as files in a directory export). No HTML; the CSP stays script-src 'self' |
| Supporting objects (install scripts) | โ | Install, upgrade and deinstall scripts travel with the export (JSON and directory formats), never run on import; reviewed and run from the builder as the app's role, in one transaction, with a result per statement (chapter 3) |
| Theme, library and boilerplate application types (26.1) | โ | An application type in Settings (chapter 3): a theme app offers its theme (colours, navigation, Theme Roller styles) and template components, a library app its lists of values, authorization schemes, build options, template components and lists; other apps subscribe (the component is copied), see whether they are in sync, refresh one or all, and the master publishes to its subscribers (locked apps skipped). A boilerplate app is a Start from choice in Create application. Subscriptions are not exported; no subscriptions to pages or plug-ins other than template components |
| Advisor | โ | Per app: every SQL fragment planned (EXPLAIN, as the app's role, rolled back) for syntax, unknown objects, types and grants; PL/pgSQL blocks compiled; references to missing pages, items, lists of values, schemes and layouts; PL/pgSQL functions with plpgsql_check when installed. Plus the security checklist |
| Builder search, "where used" | โ | Search over every page and component (names, SQL, settings, help); "Used in" under items, pages, lists of values, schemes and report layouts. No search and replace |
| AI assistant, pages from natural language, describe tables for LLMs (26.1) | โ | App Builder AI (administrators choose the builder's AI service): SQL Workshop โ AI writes SQL from a question (shown in an editor, never run automatically), explains a query or an error, and describes tables and columns for LLMs (notes, optionally COMMENT ON, with AI drafts from names, types and keys only); Create pages with AI turns a description into proposed pages that the developer edits and confirms (chapter 3). The model never sees table rows |
| Sample data source for development (26.1) | โ | SQL Workshop โ Sample Data (chapter 16): generators proposed per column from the catalog and column names (names, e-mail addresses, phones, companies, addresses, words and sentences, codes, number/date/time ranges, booleans, value lists from enums and CHECKs, sequences, foreign keys picking existing or newly inserted parent rows, values relative to another column, % nulls; identity/serial/generated columns skipped; unique and simple CHECK constraints respected), rows per table, a seed for repeatable data, preview (inserted and rolled back), insert in one transaction with parents first, download as SQL INSERTs or CSV, saved generator definitions |
Regions โ
| APEX | pgkiln | Notes |
|---|---|---|
| Classic report | โ | report with interactive: false |
| Interactive report | โ | Search, column filters, sort, rows per page, control break, aggregates (with subtotals), highlight, saved private and public reports, computed columns, group by, pivot, chart view, row selection into a page item, CSV, Excel (typed cells) and PDF download, print, reset, reflow on phones. a maximum row count (max_rows), natural-language control (Ask in your own words, 26.1) and row selection that stays across pages. Not possible: flashback queries (PostgreSQL has none; use an audit or temporal table) |
| Interactive grid | โ | Inline edit, add and delete rows, lists of values, required columns, per-row errors, all-or-nothing save, signed row keys, search and paging; aggregates over the whole result (developer and user defined), frozen columns, column reorder/resize/hide (Actions โ Columns, or drag and drop), per-user layouts and saved grid reports (private and public), master-detail (signed row selection, details refreshed in place), a row actions menu (edit, duplicate, delete, links) and copy/paste of cell ranges (tab-separated, spreadsheet compatible) (chapter 4) |
| Interactive grid views: single row view, chart view, group by | โ | The grid shows rows only; the interactive report has chart view and group by |
| Form (automatic row processing) | ๐ก | Fetch, insert, update, delete, in a page or a modal dialog. Detects rows deleted meanwhile. Missing: lost update detection (APEX compares a checksum of the row as fetched before it saves; pgkiln saves over a row someone else changed meanwhile) |
| Charts | โ | Bar, column, stacked, line, area, combination (columns + lines), scatter, bubble, donut, pie, gauge, funnel, radar, Gantt (start/end, progress, milestones, dependencies, a today line, a time axis from hours to years), pyramid (area-proportional segments, or two series back to back) and polar (polar area); multi-series, tooltips, data table, palette checked for colour-vision deficiency; drill-down links on chart marks (checksummed, only to pages the user may open). Drawn on the server as SVG without inline styles. Missing: other Oracle JET types (e.g. stock, box plot, range), editing a Gantt by drag and drop |
| Cards and metric cards (26.1 metric card template) | โ | Cards from SQL, with a KPI "metric" style |
| Calendar | โ | Month, week, day and list views (agenda list on phones); create on click (a checksummed link with the slot); drag and drop to move events through the developer's move SQL, run as the app's role (CSRF, a who may drag authorization, only events the user sees). Works without JavaScript; dragging adds on top (chapter 4) |
| Faceted search | โ | Checkbox, range (predefined, or a custom from/to on numbers and dates), star rating and search facets with live counts that honour the other facets; exclude on checkbox facets (26.1). Values travel as query parameters, never as SQL text. Missing: facet charts |
| Smart filters | โ | One search field with filter chips and suggestions over a report, the same facet types; URL-based, works without JavaScript (chapter 4) |
| Static content, dynamic content | โ | static (HTML with substitutions) and dynamic (a SELECT returning HTML) |
| Breadcrumb | โ | Automatic, from the page's breadcrumb parent |
| Navigation menu (side or top) | โ | Collapsible side menu or top bar; a drawer on tablets and phones |
| Region display selector, tabs | โ | Tabs or a select list; regions can share a tab, Show all, the choice remembered in the session, #R<id> links. Accessible tabs with JavaScript; without it every region shows with links to each |
| Tree | โ | tree region from id / parent id / label rows, with icons, links and the first levels open; works without JavaScript |
| Map region (26.1: vector tiles, bounding box) | โ | map region: several layers per map, each with its own query (markers, lines and areas from GeoJSON or a PostGIS geometry, heat maps), a legend that switches layers on and off and a colour per layer; marker clustering; popups with links. A report can be filtered by the visible area or by the distance from the map's centre on the server: with PostGIS (ST_Intersects/ST_DWithin, detected automatically) when installed, otherwise on latitude/longitude (bounding box, haversine). Configurable tile server. (0.31) Large data sets: a layer loads only the places in the visible area, again as the map moves (visible_area), or is served as Mapbox Vector Tiles (tiles, MVT 2.1, drawn on canvases with popups; readable by MapLibre, OpenLayers or QGIS), both filtered on the server like the report filter (chapter 4) |
| Timeline, comments, media list, avatar template components (26.1: groups, Metric Card) | โ | Built in for every application: avatar (groups), badge, comments, media list, metric card and timeline, as regions (one or all rows, the group) and report column templates; an application's own copy replaces a built-in one (chapter 4) |
| Pagination of large tables (row ranges, maximum row count) | โ | Reports and grids page in the database; "pagination": "range" shows APEX's "row ranges X to Y" without a total (it reads one row more for Next); max_rows is a maximum row count (the total is counted over at most max+1 rows: "of more than N"; downloads are capped too); page numbers and sizes are clamped on the server. Cards (500), charts (1000), dynamic content (1000) and lists of values (5000) have configurable row limits. Keyset ("seek") paging on an indexed sort ("keyset"), with signed positions |
| Lazy loading of regions | โ | "lazy": true on report, chart, cards, dynamic, tree and template component regions: a placeholder, fetched after the page shows (page, condition and authorization re-checked); without JavaScript a link shows the region (chapter 4) |
| Region caching (per user, per session, for a duration) | โ | "cache": {"scope": "user" | "session" | "all", "seconds": N} keeps rendered regions in server memory, keyed by app, region, roles, language, the query string and the item values the region uses; a page submit empties it. CSRF tokens and per-user links are never shared. Per server process |
| Search configurations and the search region (22.2) | โ | One search box over several sources (tables, lists, REST data sources) with a result template per source. Faceted search and smart filters search one source |
| URL region | โ | Another site's page in the region. Would need frame-src for chosen hosts in the CSP |
| Template components and template directives | โ | Shared Components โ Template components: #PLACEHOLDERS# (always escaped), {if}, {case} and {loop} directives, custom attributes, a wrapper; as a region type and as report column templates, with a preview. Templates are checked against an allow-list (no scripts, styles, event handlers or javascript: links) (chapter 4) |
Items โ
| APEX | pgkiln | Notes |
|---|---|---|
| Text field, textarea, number, date picker, password, hidden, display only | โ | Native inputs, with the right phone keyboard (inputmode) |
| Select list, radio group, checkbox, switch | โ | |
| Checkbox group, shuttle / multi-select | โ | Colon-separated values, as in APEX |
| Popup LOV | โ | popup_lov: a dialog with server-side search (paged, at most 100 rows a page) of the item's own shared, static or SQL list of values, extra display columns, return vs display value; the posted value is checked against the list; a select list without JavaScript (chapter 5) |
| Cascading, shared and static lists of values | โ | cascade_parents, LOV:NAME, STATIC: |
| E-mail, phone, URL, colour picker | โ | Typed inputs |
| Read-only condition, required, help text, default | โ | |
| BOOLEAN session state (26.1) | โ | Switches and checkboxes store true / false (castable with ::boolean in SQL), boolean columns map to switches, and meta.v_boolean(item) reads any item as a boolean (yes/no, Y/N, 1/0, on/off) (chapter 9) |
| File browse / image upload, paste files (26.1) | โ | Item type file: into a bytea column (with name and type) or a session temporary file (meta.temp_files), several files per item (one row per file in a child table, or a list of temporary files), drag-and-drop and paste (26.1), image preview, signed downloads through RLS (chapter 16). cropping pictures in the browser before upload (free or a fixed aspect ratio, mouse and keyboard). Object storage: an S3-compatible bucket per item (AWS Signature Version 4 with an aws_sigv4 web credential; the bucket follows the table on replace, remove, delete and failed saves; downloads through the app) (chapter 16) |
| Rich text / markdown editor | โ | richtext (HTML rebuilt from an allow-list on the server when saved and shown, pasted HTML cleaned in the browser) and markdown (rendered on the server, HTML typed in it shown as text); a toolbar with JavaScript, a plain text field without (chapter 5) |
| Star rating, QR code, combobox (tags), date range | โ | rating (radio buttons drawn as stars), qrcode (SVG drawn on the server, no dependency), combobox (free text with list-of-values suggestions, tags, colon-separated), daterange (from:to); all work without JavaScript and are checked on the server |
| Password reveal toggle (24.2) | โ | {"reveal": true} on password items; the value is never sent back to the page |
| Display image, geocoded address | โ | No item that shows an image from a column or URL (a display item with HTML, or a file item's preview, comes close); no address item checked against a geocoder |
Logic and processing โ
| APEX | pgkiln | Notes |
|---|---|---|
Session state, page items, :BIND and &SUBST. syntax | โ | Binds become escaped untyped literals, so APEX patterns like :X is null or col = :X work |
| Application items and processes | โ | after_login, before_page |
| Validations | โ | Not null, SQL expression, regex, required items; RAISE โฆ USING COLUMN in PL/pgSQL targets a field |
| Conditions and authorization on components | โ | Pages, regions, items, buttons, processes, dynamic actions, navigation entries; re-checked on submit |
| Computations | โ | Static, item, SQL query, SQL expression and PL/pgSQL function body; before header and after submit; with a condition, authorization and build option (chapter 6) |
| Page processes | โ | SQL / PL/pgSQL, form DML, grid DML, data loading (data_load), invoke API (a REST data source or URL, response values into items), download (a file from a query; several rows become one zip; on submit or on load), execution chains (child processes with their own conditions, nested, optionally run in the background with a status view), workflow (start, terminate, retry), Generate text with AI (text or structured output into items) |
| Branches | โ | Before header and after processing, to a page (with items) or a URL inside the app, When button pressed, server-side conditions (SQL, exists, item null/equals, request); the button's target page stays the fallback (chapter 6); a PL/pgSQL function returning a path in the app, and a page of another application (with signed items) |
| Dynamic actions | โ | Show, hide, enable, disable, set value (SQL), execute SQL, refresh region or item, alert, submit, set focus, add/remove class, show success/error message and clear errors (26.1); the Dialog Closed event (per dialog page, with the dialog's message). Execute JavaScript: calls a function a static application file registered with pgkiln.actions.register (no inline code: the CSP stays strict) (chapter 7); dynamic action plug-ins |
| Dynamic action events | ๐ก | Change, click, page load and Dialog Closed. Missing: After Refresh, Selection Change (grid, report, cards), Get/Lose Focus, Key Release, Before Page Submit, custom events |
| Dynamic action actions: confirm, close/cancel dialog, clear, open/close region, download, print, current position, share | โ | Buttons have a confirm question, dialog pages close through a branch, and Execute JavaScript can do the rest with an app's own code; none are built-in actions yet |
Ajax callbacks (On Demand processes, apex.server.process) | โ | Application and page processes run after sign-in, before a page, on load and on submit only. JavaScript can't call a named process and get JSON back; plug-ins and Execute SQL / Set Value actions cover some cases |
| Error handling function | โ | APEX lets an app rewrite every error message in one PL/SQL function. pgkiln shows its own message with a reference number; RAISE โฆ USING COLUMN targets a field |
User preferences, application settings (APEX_UTIL.SET_PREFERENCE, APEX_APP_SETTING) | โ | Item values kept per user across sessions, and named settings an administrator changes after deployment. Application items last one session; use a table |
| APEX PL/SQL APIs | โ | meta.app_user(), meta.has_role(), meta.v(), meta.page_url(), meta.message(), meta.html_escape(), password functions, meta.debug(); meta.web_request() / meta.web_request_source() + meta.web_response() (APEX_WEB_SERVICE: queued and made by the server, right after the page process that queued it or by the scheduler after commit, through the allow-list/SSRF checks and the app's web credentials; responses kept 24 h) and meta.parse_data() / meta.parse_data_columns() (APEX_DATA_PARSER for CSV/TSV and JSON in SQL, same names and types as the data loader) (chapter 9). (070) XML and Excel in meta.parse_data (as the data loader reads them; Excel files that pgkiln received: uploads and web responses), APEX_ZIP (meta.zip_add/zip_finish/zip_agg build zips in SQL, meta.zip_entries/zip_entry read them), BOOLEAN state (meta.v_boolean), and a mapping from APEX_JSON to PostgreSQL's JSON functions (chapter 9). A synchronous HTTP call inside one statement needs the http extension (chapter 15); meta.web_request is queued by design |
| Declarative menu buttons, button badges (26.1) | โ | Menu buttons with links and submit requests (a hidden button can't be reached through a menu), works without JavaScript; badges as text with &ITEM. or from SQL (chapter 6) |
| Plug-ins | โ | Region, item, dynamic action and process plug-ins with their own code (chapter 4): one pgkiln-plugin/2 file with custom attributes, JavaScript and CSS (static application files, registered with pgkiln.plugins.register; the CSP stays strict), a template component for regions, a PL/pgSQL function for processes and install SQL that a developer reviews and runs; Shared Components โ Plug-ins, `pgkiln plugin build |
| Build options | โ | Include / exclude (and !NAME for the reverse) on pages, regions, items, buttons, dynamic actions, validations, processes, computations, branches, navigation entries and application processes; fail closed; Used in, Advisor and export (chapter 6) |
Collections (APEX_COLLECTION) | โ | Temporary or unlogged tables, or jsonb in session state |
Security โ
| APEX | pgkiln | Notes |
|---|---|---|
| APEX accounts | โ | Instance-wide user directory, bcrypt, session rotation, idle and absolute timeouts |
| Application Access Control (roles per app, any-user switch) | โ | Access control per application |
| Social sign-in / OpenID Connect | โ | Any OIDC provider (Entra ID, Google, Okta, Keycloak, โฆ): PKCE, group โ role mapping, account linking, automatic accounts |
| Multi-factor authentication | โ | As in APEX: through the identity provider (OpenID Connect) |
| Change own password | โ | A built-in My account page (APEX offers the API CHANGE_CURRENT_USER_PW) |
| Password expiry, change on first use, admin reset, complexity | โ | Lifetime in days, expire/unexpire, admin reset, length and letters+digits rules, unlock |
| Lockout after failed sign-ins | โ | Per user and per IP, time-based (APEX: until an administrator unlocks) |
| Authorization schemes | โ | Role or SQL based, negation, fail closed |
| Session state protection (checksums) | โ | HMAC per app, page and user; meta.page_url() in SQL |
| Parsing schema | โ | Per-app database role (SET LOCAL ROLE) |
| VPD / row level security | โ | PostgreSQL RLS with meta.app_user() / meta.has_role(), shared by the UI and the REST API |
| CSRF protection | โ | Tokens on every POST, SameSite cookies |
| Activity monitoring and audit | โ | Page views, sign-ins, denials, errors per app. Database-level auditing via pgaudit |
| Error handling that hides internals | โ | Reference numbers; debug mode per app |
Content Security Policy without unsafe-inline (26.1) | โ | Scripts and styles: script-src 'self', style-src 'self' 'nonce-โฆ'. No inline scripts or style attributes; theme colours and chart geometry are in one <style> with a fresh nonce per response |
| Session sharing between applications | โ | Applications with the same session sharing group share a sign-in: the others open without signing in again, each with its own access check and roles; signing out of one signs out of all; idle and maximum times apply (chapter 8). With OpenID Connect the second sign-in is silent too |
| LDAP and SAML authentication | โ | LDAP / Active Directory (search + bind, StartTLS/LDAPS, groups โ roles) and SAML 2.0 (signed assertions, SP metadata), next to local passwords and OpenID Connect |
| Database accounts, HTTP-header authentication | โ | HTTP header variable (header): the user from a header set by a reverse proxy or SSO gateway, trusted only from proxy addresses in PGKILN_AUTH_HEADER_PROXIES, session bound to the header value, optional automatic accounts, sign-out URL; database accounts (database): a PostgreSQL login role and its password, checked by PostgreSQL through a short-lived connection, only listed roles or members of a role (chapter 8) |
| Custom authentication | โ | A PL/pgSQL function or body checks the user name and password as the app's database role, plus post-authentication code; throttling and the activity log as for other types (chapter 8) |
| Session timeout warning | โ | APEX warns before an idle session ends and offers to extend it; pgkiln sends the user to sign in after the idle time (forms sent offline by a PWA are kept) |
| Persistent authentication ("remember me") | โ | Per app, 1โ365 days; rotating one-time tokens, revoked on sign-out, new password, deactivation or removed access; "Sign out on all devices" |
User interface โ
| APEX | pgkiln | Notes |
|---|---|---|
| Universal Theme look and layout | โ | Header, side/top navigation, breadcrumbs, 12-column grid, region templates |
| Region templates (Carousel, Hero, Inline Dialog/Popup/Drawer, Wizard Container, Title Bar, Buttons Container, Login) | ๐ก | Standard, plain and collapsible; dialog and drawer pages. Missing: the other templates, among them inline dialogs and drawers (a region opened on the same page) and a wizard progress bar |
| Warn on unsaved changes | ๐ก | The interactive grid asks before leaving with unsaved rows. Missing: the page attribute that does this for every form |
| Responsive: phone, tablet, desktop | โ | Tested at 390, 768, 1024 and 1440px on every change (npm run test:e2e) |
| Modal dialog pages | โ | Full screen on phones |
| Dark mode and user-chosen theme style | โ | Automatic (follows the device), light or dark per app; users may switch, saved on the account; plus a choice of the app's style variants |
| Theme Roller (26.1: conditional and dynamic properties, CSS variables) | โ | Base styles Iris and Standard; accent and header colours for the light and the dark theme; style variants (up to 10 saved styles per app: colours for light and dark mode, font, font size, corners; a default; users may choose one, kept per app on the account; exported with the app) with a live preview on Settings โ Theme โ Theme Roller; template options on regions, buttons, items and report columns (fixed lists of CSS classes) (chapter 14). Conditional styles (a SQL condition per style, run as the app's role: the first that holds applies unless the user chose one) and dynamic colours from items (&ITEM., used only when #rrggbb) (chapter 14) |
| Icons (Font APEX 2.5) | โ | 136 line icons of pgkiln's own and (0.31) the Lucide set of about 1,600 more in the same line style, each served on its own; modifiers like Font APEX's (sizes, spin, rotate, flip, colours) and Font APEX names (fa-users fa-lg) where Lucide has the icon; a visual picker in the builder that searches all of them by name and search word (chapter 9). Font APEX's own drawings are Oracle's, so icons look different and a few Font APEX names have no match |
| Accessibility | โ | Labels, keyboard, focus rings, reduced motion, table alternatives for charts, scrolling tables reachable from the keyboard; an automated WCAG 2.1 A/AA audit (axe-core) of every example page in light, dark and Iris and of the builder's main pages runs in CI with no violations allowed. Not a manual expert audit |
| Drawers, top/bottom dialogs (26.1) | โ | Modal pages open as a centred dialog or as a drawer from the left, right, top or bottom edge, in three sizes, sliding in (without animation for reduced motion); on phones full screen (chapter 4). Not yet: a footer slot for inline drawers |
| New "Iris" default style (26.1) | โ | Base style Iris (indigo accent, larger corners, softer shadows, light and dark palettes checked for WCAG AA contrast), the default for new applications; existing ones keep Standard until switched in Settings โ Theme (chapter 14) |
| Progressive Web App (push notifications: 23.1) | โ | Per app: installable (manifest, icon, standalone), service worker, offline pages (opt-in, wiped at sign-in/out), forms sent offline queued on the device and sent later (files included, once only, under the same user), location, camera and barcode items. (0.31) Push notifications: users turn them on per device (My account, or the dynamic action push_subscribe); meta.send_push(user, title, body, page, items) and a send_push process queue them, sent after the commit, encrypted for the device (RFC 8291) and signed with the application's own VAPID key (RFC 8292, stored encrypted, never exported); links signed for the recipient; devices end at sign-out, a new password, deactivation or removed access (chapter 17). No images or action buttons in notifications |
Globalization โ
| APEX | pgkiln | Notes |
|---|---|---|
| Translated applications (26.1: text-message-based translation of one app) | โ | One app with translations, like 26.1; XLIFF 1.2 and CSV export/import, coverage per language |
Text messages (APEX_LANG.MESSAGE, &APP_TEXT$โฆ) | โ | meta.message(), &APP_TEXT$NAME., fallback to the base and primary language |
| Language from browser, preference or session | โ | Browser, user preference or primary; ?lang=; right-to-left languages |
| Date and timestamp format masks | โ | Per app or per language |
| Built-in runtime messages in ~34 languages | ๐ก | Twenty-two: English, Dutch, German, French, Spanish, Italian, Portuguese, Polish, Swedish, Danish, Norwegian, Finnish, Czech, Turkish, Greek, Russian, Ukrainian, Japanese, Chinese (simplified), Korean, Arabic and Hebrew (right to left), each with its date formats and currency; other languages via text messages with the same names |
Dynamic translations (APEX_LANG.LANG: translated data values, e.g. list of values entries) | โ | Translations cover the app's own texts and text messages, not values from tables; use a translation table in the query |
| Number format masks, automatic time zone | โ | Oracle-style number masks (999G999G990D00, FMLโฆ, 0000, %, S/MI/PR, EEEE, X, RN) on report, grid and cards columns, charts and number/display items, in the language's separators with the app's currency; Automatic Time Zone (browser, My account, app or database), timestamptz shown in it (chapter 14) |
Data and integration โ
| APEX | pgkiln | Notes |
|---|---|---|
| SQL Workshop: SQL commands, object browser | โ | The object browser shows columns, RLS policies, grants, data and function source |
| RESTful services (ORDS) | โ | PostgREST next to pgkiln: api schema, the same RLS as the UI, per-app API role, tokens in the builder, a pre-request check, and OAuth clients (client credentials, like ORDS oauth.create_client) so tokens renew themselves |
| REST handler editor, REST-enabled SQL | โ | REST modules in the builder: handlers (method, path with parameters, SQL as collection, item or statements, roles, public) served by pgkiln with bearer tokens and an OpenAPI description; plus PostgREST for schema-wide APIs. Missing: REST-enabled SQL (rarely desirable) |
| SQL scripts, query builder, Quick SQL | โ | SQL Scripts: saved, upload/download, a result per statement, stop or continue on errors, optionally one transaction, run history. Quick SQL (a subset: tables, child tables, types, the main column directives, /auditcols, settings, views). A graphical query builder: tables as boxes on a canvas (dragged, placed where left), joins along foreign keys or drawn from column to column (inner or left), column functions with automatic group by, conditions, sort, open in SQL Commands; without JavaScript the same as forms (chapter 3) |
| Data Workshop (load and unload) | โ | SQL Workshop โ Load Data: CSV/TSV/XLSX/JSON into a new table (inferred types) or an existing one (append, merge, replace) with a per-row error report; data_load process for end users; XML (a repeating element, attributes and paths; DTDs refused) and saved data load definitions (mapping, transformations, format masks, defaults; used by Load Data and the process, exported with the app). Unload Data: a table or view (chosen columns, where, order) or a query to CSV (separator, enclosure, heading), JSON, XLSX or XML (element names), streamed with a cursor in a read-only transaction with a statement timeout (chapter 16) |
| Large downloads without buffering (ORDS streams) | โ | CSV and Excel downloads stream from a database cursor (1,000 rows at a time, a streaming Excel writer) up to DOWNLOAD_MAX_ROWS (default 1,000,000), so memory stays flat. Report PDFs read their rows from a cursor in batches of 500 (PDF_MAX_ROWS, default 5,000, at most 100,000); REST collection handlers stream a chunked JSON array from a cursor |
| REST data sources, web credentials (26.1: OAuth refresh tokens, password flow) | โ | Shared Components โ REST data sources: JSON endpoints with path, query, header and body parameters, a row selector, typed columns and a response cache feed reports, cards, charts, calendars, maps, trees, template components and shared lists of values as SQL over rest. Write-back: insert, update, delete and fetch operations (path and JSON body templates after the source's URL) used by forms and interactive grids. Synchronisation into a local table (merge on key columns with optional delete, replace, append) on demand, on a cron schedule or from SQL (meta.request_rest_sync), as the app's role, with a run log. Web credentials: basic, API-key header, bearer and OAuth2 client credentials, password and refresh-token grants (refresh tokens stored encrypted and rotated), secrets encrypted and write-only. Outgoing calls only to an allow-list of hosts, with SSRF checks (chapter 19). Missing: XML/SOAP, the OAuth2 authorization code flow (consent in the browser) |
| Printing, document generator (PDF) | โ | Document templates: a query (with JSON columns for lines) fills an HTML template with Mustache-style tags, drawn as PDF with a report layout; buttons and links download them. Report PDF with report layouts and a print stylesheet on every page. No Word/Excel templates or DOCX/XLSX output |
APEX_DATA_EXPORT (a query to CSV, XLSX, PDF, HTML or JSON from PL/SQL) | โ | The download process, report downloads and Unload Data do this from the UI; there is no SQL function that returns the file |
| SQL Workshop utilities: schema comparison, generate DDL | โ | The object browser shows definitions; use pg_dump --schema-only or migra |
| Data Reporter: self-service reports for business users (26.1) | โ | A Data Reporter region (chapter 4): the developer offers tables and views with chosen columns, labels and format masks; signed-in users pick columns, filter, group with totals (count, sum, average, minimum, maximum), sort and chart, and save reports privately or shared with the app's users. Runs as the app's role (grants and RLS apply); works without JavaScript and fits phones. One source per report (offer a view to combine tables); no downloads from a reporter yet |
| JSON sources, duality views (24.2) | โ | PostgreSQL jsonb works in any SQL region, form or grid source |
| Remote servers / database links | โ | postgres_fdw or dblink |
Workflow, automation and AI โ
| APEX | pgkiln | Notes |
|---|---|---|
| Approvals and task list | โ | Task definitions (approval / action, owner roles and users, business administrators, priority, due date, details page), meta.create_task from application SQL, a task list region (claim, approve/reject/complete with comment, release, delegate, cancel, history), completion SQL in the same transaction. Missing: e-mail notifications (pgkiln sends no mail), vacation rules, expiry/escalation policies |
| Workflow (26.1: parallel flows, multi-tenancy) | โ | Workflow definitions of task, SQL, switch, wait, invoke API (a REST data source or URL through the invoke-API code, response values and the HTTP status into variables, retryable faults, no transaction open during the call) and end steps with variables, started from application SQL, run by the server (NOTIFY + polling) as the app's role; console region (terminate, retry a faulted step); diagram in the builder. Parallel branches (split, then a join that waits for all or for the first branch) and versions (development, active, inactive; running instances keep theirs) (chapter 6). (0.31) Tenants: meta.set_tenant() (APEX: APEX_SESSION.SET_TENANT_ID); workflows, their tasks, background chains, the task list, the console and every action follow the session's tenant (chapter 6). No e-mail activity, by design (pgkiln sends no mail; queue mail in a table) |
| Automations (scheduled) | โ | Shared Components โ Automations: cron schedules with time zones, once or per row of a query, several ordered actions with their own conditions, error handling (stop, skip the row and continue, or disable; row errors in the run history), roles, run history and Run now, on-demand runs from SQL with meta.run_automation() (like APEX_AUTOMATION.EXECUTE, synchronous in the caller's transaction), safe with several servers (chapter 6) |
| AI assistant, natural-language reports (NL2IR), AI agents and tools (26.1) | โ | Region type AI assistant: a conversation per session, context queries (RAG over developer queries, run as the app's role, read-only), and tools the model may call: SQL with bound arguments checked against declared parameters (read-only unless marked as writing, row limit, timeout) and REST data sources, each optionally behind an authorization scheme. Natural-language report filters: an "Ask in your own words" box turns a question into the report's normal filters, search and sort, limited to its visible columns (chapter 4). Agents are defined per region (not as shared components); answers are not streamed. pgvector covers semantic search on the data side |
| Generate Text with AI process, structured outputs (26.1) | โ | AI services (Workspace utilities, administrators): Claude through @anthropic-ai/sdk or OpenAI through openai, encrypted write-only keys (or ANTHROPIC_API_KEY / OPENAI_API_KEY), per-app access with daily request and token limits, a usage log. Page process ai_generate (text into an item, or structured output into several items with a schema built from the items or your own) and a dynamic action that runs it without a page submit; meta.ai_generate / ai_result / ai_available from SQL (chapter 6). Prompts, item values included, go to the chosen provider |
| Blueprints, spec-driven development (26.1) | โ | Create โ From a blueprint: a JSON spec of tables (types, required, unique, allowed values, references), pages, navigation and sample data; optionally drafted by AI from a description; always reviewed (problems, SQL, pages, menu) before the application is created in one transaction; saved blueprints. Missing: a blueprint from an existing application |
Administration โ
| APEX | pgkiln | Notes |
|---|---|---|
| Developer accounts | โ | |
| Instance administration, install/upgrade logs (26.1) | โ | Versioned migrations (npm run db:migrate), every run logged; Workspace utilities โ Installation (administrators): server version, install and upgrade runs with errors, applied migrations, and warnings for migrations the database misses or the server doesn't know (chapter 3). Workspace utilities โ Instance settings: session length and sign-in throttling (stored in the database, over the environment variables) and an overview of the server's configuration without secrets; a server whose database lacks migrations says so (503) or applies them (MIGRATE_ON_START). Other settings stay environment variables |
| Debug messages | โ | Debug levels 1โ9 per app; meta.debug(level, text) and meta.debug_enabled(level) from application SQL (APEX_DEBUG); timed entries per request (page steps, regions, processes, branches, errors, SQL notices); Activity โ Debug messages viewer per page view with filters and the slowest step highlighted; retention 1โ90 days; password item values are never recorded (chapter 6). Missing: switching debug on per user or session (see the developer toolbar below), debug entries for background jobs and REST requests |
| Developer toolbar, session state viewer | โ | APEX shows developers a toolbar on every page of the running app (App Builder, edit this page, session state, debug on/off, Quick Edit). pgkiln has Run links from the builder only |
| Feedback (users send feedback from a page, developers answer) | โ | Build it as a page with a table, or as an approval task |
| Automatic application backups, page groups | โ | APEX keeps the last exports of every application and lets developers group pages. Export the app (or keep its files in git with pgkiln export --format text) |
| Monitoring (top SQL) | โ | Activity per app; Top SQL per app's database role from pg_stat_statements (sortable, resettable) |
| Workspaces (multi-tenant) | ๐ก | Workspaces group applications and developers: the builder shows and opens only the applications of a developer's workspaces (administrators: all), a current workspace with a switcher, new and imported applications go into it, administrators add workspaces, choose their developers and move applications (chapter 3). Missing: isolation between tenants (the SQL Workshop and application code run with installation-wide rights; use separate installations), per-workspace user accounts, schemas and workspace administrators |
Different on purpose โ
- No e-mail. pgkiln doesn't queue or send mail, and has no "forgot password" link (APEX apps don't have one out of the box either). Mail is an operational subsystem (SMTP, retries, deliverability) that teams usually already have; connect to it from your own schema.
- PostgREST instead of ORDS, and no web listener at all: the pgkiln server talks to PostgreSQL directly.
- Row level security instead of VPD, and one set of policies for the UI and the API.
- JSON or YAML export instead of SQL or APEXlang files.
- Server-rendered HTML with progressive enhancement: pages work without JavaScript, and no inline scripts are needed.
Gaps that PostgreSQL extensions close today โ
| Gap | Extension | See |
|---|---|---|
| Automations / scheduler | built in, or pg_cron | chapter 6, chapter 15 |
Calling REST APIs synchronously from SQL (APEX_WEB_SERVICE; the built-in meta.web_request() is queued) | http, pg_net | chapter 15 |
| Map data | PostGIS | chapter 15 |
| Semantic search / RAG | pgvector | chapter 15 |
| Statement auditing | pgaudit | chapter 15 |
| Code checks (Advisor for PL/pgSQL functions) | plpgsql_check (used by the Advisor when installed) | chapter 15 |
| Pivot reports | tablefunc | chapter 15 |
| Porting PL/SQL | orafce | chapter 15 |
Where pgkiln goes further โ
Small but real differences, for teams comparing the two:
- Open source (Apache-2.0), on any PostgreSQL 15+, including every managed service.
- A strict CSP by default (no inline scripts or styles), and a security regression suite that runs in CI.
- Responsive layouts verified automatically at four screen sizes.
- The theme follows the device's light/dark setting automatically, and the choice is saved per user.
- A built-in My account page (own password, theme, language).
- One RLS policy set protects both the web UI and the REST API.
Roadmap (proposed priority) โ
Done in 0.23.0: the interactive grid, page logic, globalization, SQL and Data Workshop and builder gaps above. Done in 0.19.0: large tables (row ranges, maximum row counts, lazy loading, region caching, streamed downloads). Done in 0.18.0: calendar views, more chart types and drill-down; smart filters, display selector and facet types; computations, branches, build options and menu buttons; REST data sources and web credentials; rich text and the other new item types.
Done in 0.29.0 (sprint 37): workspaces, the Iris base style, drawers, built-in template components, Theme Roller additions, report selection across pages, instance settings and nine more languages.
Done in 0.28.0 (AI with Claude and OpenAI): Generate text with AI, the AI assistant with tools, natural-language report filters, App Builder AI and blueprints.
- The remaining ๐ก rows except more languages (sprint 39, owner: parity before languages).
PWA push notifications(done in sprint 39).- The rows a review on 2026-10-06 added (the features above that were not compared before): lost update detection, Ajax callbacks and the missing dynamic action events and actions first, as developers coming from APEX use them every day; then warn on unsaved changes, the session timeout warning, the developer toolbar and the region templates; the rest after.
Sources: APEX 26.1 new features, What's new in APEX 24.2, APEX_MAIL (APEX API reference).