Build Options in APEX: Five Patterns to Keep In Mind
Build Options have been around in APEX since forever. They are not new. They are not undocumented. Oracle's own blog post explains the basics, What I want to share instead are the five patterns I keep coming back to in my own work.
What a Build Option actually does
A Build Option is a named switch. Two values: Include or Exclude. You assign it to a component (a page, region, item, validation, process, dynamic action, list entry, branch, whatever) and the APEX engine either treats that component as present or treats it as if it does not exist. The Oracle docs put it this way: "the Oracle APEX engine treats the component as if it did not exist." That distinction matters.
Four attributes appear when you create one:
Status. Include or Exclude. The current state in this application.
Default on Export. The state the Build Option will have when the application is exported and imported elsewhere.
On Upgrade Keep Status. When set to Yes, importing an updated application keeps whatever Status the target already has, instead of overwriting it from the import file.
Build Option Comment. A free-text field. Use it. Six months from now you will not remember what FEATURE_NEW_FLOW_V2 does.
The Default on Export attribute is what makes Build Options safe to use for in-progress work. Development can happen with Status = Include in the dev environment, with Default on Export = Exclude, and the feature will be deployed to other environments switched off until someone changes it.
Pattern 1: feature flags for in-progress work
In-progress work needs somewhere to live. Leaving the work in the dev application with no protection means another developer might click through and file a bug, or worse, deploy it.
The way I handle this is with a Build Option called something like FEATURE_BULK_INVOICE_EDIT, Status = Include, Default on Export = Exclude, attached to every component that belongs to the feature. Dev sees it. Test and Prod does not.
Pattern 2: Environment-specific behaviour
A "Run as Demo User" button visible only in dev and test, never in production. A debug panel that that dumps session state on screen.
Create a Build Option called DEV_ONLY:
Status = Include
Default on Export = Exclude
On Upgrade Keep Status = Yes
Assign it to the dev-only stuff. The Default on Export means the Build Option arrives switched off in the other environments.
The On Upgrade Keep Status means that if you ever re-export from dev (where it is on) and re-import to prod, the prod Status sticks at off.
Both attributes need to be right. From experience, getting one right and forgetting the other is the most common cause of dev-only features quietly appearing in production after a release. This is the closest thing APEX has to a real environment-based feature flag, and it works reliably when configured properly.
Pattern 3: soft delete before hard delete
Sometimes a region or item looks unused but you cannot be sure. Page Designer will not always reveal who depends on what. Deleting and seeing what breaks is a bad strategy in production.
The safer approach: create a Build Option called something like DEPRECATED_2026Q2 (date-stamping helps later cleanup), set Status = Exclude, attach it to the suspect component, deploy. Wait. If there are no issues reported over the next sprint or two, delete the component.
Every new application gets a built-in Build Option called Commented Out. Right-clicking a component in Page Designer reveals a "Comment Out" toggle in the tree context menu, which assigns the component to that Build Option behind the scenes.
Pattern 4: A/B between two implementations
A report has been rewritten. The old version is a classic report. The new version is an interactive grid. The new version should ship but the old one should stay reachable in case something goes wrong.
Two Build Options: REPORT_V1 and REPORT_V2. Old region attached to one, new region to the other. Flip whichever you want to expose. Both versions live in the application at once, so rolling back is instant.
Pattern 5: Querying Build Option status from PL/SQL
Build Options can drive code paths as well as components. The runtime API for this lives in apex_application_admin (since 23.1). The older apex_util versions of the same procedures still work but the current docs flag them deprecated, with a direct instruction to use the new package.
The GET function has two signatures: one that takes the Build Option ID, one that takes the name. The name version is the readable choice for application code:
declare
l_status varchar2(30);
begin
l_status := apex_application_admin.get_build_option_status(
p_application_id => :app_id,
p_build_option_name => 'FEATURE_BULK_INVOICE_EDIT'
);
if l_status = 'INCLUDE' then
run_bulk_edit;
else
run_single_edit;
end if;
end;
None of this is complicated once you have used it a few times. Build Options are just switches, and the five patterns above are really just five good habits built around them: flag your in-progress work, keep dev-only tools out of production, soft-delete before you hard-delete, keep a rollback option alive, and let PL/SQL read the switch when it needs to. The one mistake I would steer you away from is treating Build Options purely as a development convenience and forgetting they have a deployment side. Set Default on Export deliberately, check the Utilisation tab before you ship, and they will quietly do their job for years.