If you ask an Oracle Forms migration team what their first technical step is, the experienced ones will say the same thing: convert every FMB in the estate to XML, programmatically, before anything else gets decided.
Not because the XML is the deliverable — it isn’t — but because almost every meaningful technical decision downstream depends on having a machine-readable representation of the estate. Effort estimation, complexity scoring, dependency mapping, automated conversion, static analysis, secure assessment sharing, even basic questions like “how many distinct database schemas are touched by this Forms portfolio” — all of them require XML, not FMB.
This article is for the engineers and architects who actually have to do the work. It covers what FMB is and why its binary nature is a structural problem, what frmf2xml does and how to use it correctly, how to script a reliable batch conversion across an estate of several hundred or several thousand FMBs, what’s in the resulting XML and how to extract useful information from it, the version-compatibility and encoding pitfalls that catch people, how to sanitize the output so it can leave your security perimeter for an external assessment, and how the whole conversion step fits into the broader migration workflow.
The argument running through it is that FMB-to-XML conversion is usually treated as a perfunctory mechanical step and then done badly — incomplete inventories, no validation, no analysis, no sanitization, and FMBs from the wrong Forms version that fail conversion silently. Done properly, it’s the single most leveraged 1–3 days of work in a Forms migration programme.
FMB stands for Forms Module Binary. It’s the source format of Oracle Forms applications — what Forms Builder (the IDE) saves to disk. At runtime, FMBs are compiled into FMX files (the executable form) and deployed to the Forms server. The development workflow has been the same since at least Forms 4.5 in the mid-1990s: edit in Forms Builder, save as FMB, compile to FMX, deploy. The same workflow ships in Forms 14c today.
The problem is that FMB is a proprietary binary format. It is not text. It is not human-readable. It is not meaningfully diffable by Git, SVN, or any other source-control system — you can store it in a repo, but you can’t see what changed between commits beyond “the bytes are different.” You can’t grep it. You can’t run a regex over it.
You can’t write a Python script that walks the FMBs in a directory tree and counts triggers, lists item types, identifies database tables referenced, or measures complexity per form.
Forms Builder is the only tool that can natively open an FMB and tell you what’s in it — and Forms Builder is a GUI tool designed to inspect one form at a time, not to produce inventories or run static analysis across hundreds of forms.
For a single small application, this is annoying but tolerable. For a migration programme operating on an estate of 200, 500, or 2,000 forms, it’s disqualifying. Every analysis question — “Which forms reference table CUSTOMERS?”, “What’s the average number of triggers per form?”, “Which forms haven’t been changed in five years?”, “Which forms have hardcoded passwords in trigger code?” — requires opening every FMB by hand and inspecting it, unless you first convert the estate to a machine-readable representation. That representation, by design and by Oracle’s own tooling support, is XML.
The XML produced by frmf2xml is a complete, lossless representation of the FMB. Every property of every object in the form — modules, blocks, items, triggers, program units, canvases, windows, LOVs, record groups, visual attributes, alerts, property classes — is present in the XML as a structured element with attributes.
The PL/SQL inside triggers and program units is included verbatim as text content inside the relevant XML elements. The XML can, in principle, be converted back to FMB via the inverse utility (xml2frmf) and produce a functionally identical form.
That losslessness matters. It means the XML is not a degraded summary of the FMB — it’s an equivalent representation in a different syntactic envelope. Tooling that operates on XML can produce results that are exactly as accurate as tooling that operates on FMB, with the substantial advantage that XML is universal, well-supported, and trivially processed by every general-purpose programming language and many specialised tools.
Practically, conversion to XML enables six categories of work that are otherwise impossible or prohibitively expensive:
frmf2xml is the Oracle-shipped command-line utility that converts FMB to XML. It is included in every Oracle Forms Developer and Forms Server installation since Forms 9i, located in $ORACLE_HOME/bin/frmf2xml on Unix/Linux or %ORACLE_HOME%\bin\frmf2xml.bat on Windows. The corresponding xml2frmf performs the reverse conversion. Neither is a separate licensed product; both ship with the same Forms installation you’re already running.
The basic syntax is:
frmf2xml [options] <input.fmb>
The utility produces, by default, an XML file with the same base name in the current working directory — so frmf2xml CUSTOMER_FORM.fmb produces CUSTOMER_FORM.xml. There is no flag for output path; the file lands wherever frmf2xml was invoked, which has implications for batch scripts.
The most useful options:
The utility also accepts .mmb (menu module) files for conversion in the same way, producing XML representations of menus. PL/SQL libraries (.pll) and object libraries (.olb) are handled by separate utilities — frmpll2xml and frmolb2xml — which behave analogously.
The version-compatibility trap is the single most common cause of conversion failure in real estate. frmf2xml reads FMBs using the Forms version it ships with. If you’re running frmf2xml from a Forms 12c installation against FMBs that were last saved by Forms 6i, the conversion will either fail outright or, worse, produce subtly incorrect XML. Forms 6i FMBs need to be opened and re-saved by an intermediate Forms version (typically 10g) before they can be reliably processed by 12c or 14c tools. Plan for this — Forms estates with applications that span 6i, 9i, 10g, 11g, and 12c are common, and the conversion environment needs to be staged accordingly.
The encoding trap is the second most common. FMBs that contain non-ASCII characters — Polish, German, French, Spanish accents in labels, prompts or comments; Chinese, Japanese, or Korean text in internationalised applications — produce XML whose encoding depends on the locale settings of the conversion environment. The default NLS_LANG on the conversion host needs to match the FMB’s character set, and the produced XML needs an explicit encoding declaration. Skipping this produces XML that parses fine in some tools and silently corrupts non-ASCII characters in others. The diagnostic is straightforward — open the XML in a hex editor and look for the encoding declaration in the first line, then confirm the character bytes match — but the failure is silent enough that it routinely reaches production migration tooling before being noticed.
For an estate of more than a handful of forms, manual invocation of frmf2xml is impractical. The conversion needs to be scripted, idempotent, parallelisable, and logged. The following pattern works on Linux/Unix and adapts directly to Windows PowerShell.
Step 1 — inventory. Before any conversion, produce a complete list of FMBs in the estate. Many estates have FMBs scattered across multiple servers, network shares, developer workstations, and source-control branches; the inventory step is non-trivial and frequently surfaces forms nobody knew were still in use.
#!/bin/bash # inventory.sh — produce a manifest of all FMBs found in a tree FORMS_ROOT="/path/to/forms/tree" MANIFEST="/tmp/forms-manifest.csv" echo "path,size_bytes,mtime,sha256" > "$MANIFEST" find "$FORMS_ROOT" -name "*.fmb" -type f -print0 | \ while IFS= read -r -d '' fmb; do size=$(stat -c%s "$fmb") mtime=$(stat -c%Y "$fmb") sha=$(sha256sum "$fmb" | cut -d' ' -f1) echo "\"$fmb\",$size,$mtime,$sha" >> "$MANIFEST" done echo "Manifest written to $MANIFEST" wc -l "$MANIFEST"
The SHA-256 column is more useful than it looks. Forms estates routinely contain multiple copies of the same FMB under slightly different names, in different directories, sometimes from different development streams. Hash-based deduplication during inventory typically reduces a nominal 500-FMB estate to 350–400 unique forms, which is a meaningful saving on conversion time and a much more honest baseline for sizing the migration.
Step 2 — batch conversion. Once the manifest is produced, conversion is a straightforward loop with parallelisation, logging, and error capture.
#!/bin/bash # convert.sh — batch-convert FMB to XML with logging MANIFEST="/tmp/forms-manifest.csv" OUTPUT_ROOT="/tmp/forms-xml" LOG="/tmp/conversion.log" PARALLEL_JOBS=4 mkdir -p "$OUTPUT_ROOT" : > "$LOG" convert_one() { local fmb="$1" local basename=$(basename "$fmb" .fmb) local outdir="$OUTPUT_ROOT/$(dirname "$fmb" | sed 's|^/||')" mkdir -p "$outdir" cd "$outdir" || return 1 if frmf2xml OVERWRITE=YES "$fmb" > /tmp/frmf2xml.$$.log 2>&1; then echo "OK: $fmb" >> "$LOG" else echo "FAIL: $fmb" >> "$LOG" cat /tmp/frmf2xml.$$.log >> "$LOG" fi rm -f /tmp/frmf2xml.$$.log } export -f convert_one export OUTPUT_ROOT LOG tail -n +2 "$MANIFEST" | cut -d, -f1 | tr -d '"' | \ xargs -P "$PARALLEL_JOBS" -I {} bash -c 'convert_one "$@"' _ {} echo "Conversion complete. Summary:" grep -c "^OK:" "$LOG" echo "Failures:" grep -c "^FAIL:" "$LOG"
The parallelisation factor matters. frmf2xml is single-threaded internally, but multiple instances run independently against separate FMBs without contention. On a modern multi-core conversion host, running four to eight parallel jobs typically saturates IO and CPU and produces 4–8× speedup over serial conversion. For a 500-FMB estate of average complexity, the difference is roughly six hours serial vs forty-five minutes parallel.
Step 3 — validation. Not every conversion will succeed, and silent partial failures are common. Validate the output systematically.
#!/bin/bash # validate.sh — confirm every FMB in the manifest has a corresponding XML MANIFEST="/tmp/forms-manifest.csv" OUTPUT_ROOT="/tmp/forms-xml" MISSING="/tmp/missing-xml.log" : > "$MISSING" tail -n +2 "$MANIFEST" | cut -d, -f1 | tr -d '"' | \ while IFS= read -r fmb; do basename=$(basename "$fmb" .fmb) relpath=$(dirname "$fmb" | sed 's|^/||') expected="$OUTPUT_ROOT/$relpath/$basename.xml" if [[ ! -f "$expected" ]]; then echo "$fmb" >> "$MISSING" elif ! xmllint --noout "$expected" 2>/dev/null; then echo "MALFORMED: $fmb" >> "$MISSING" fi done if [[ -s "$MISSING" ]]; then echo "Validation failed. See $MISSING" wc -l "$MISSING" else echo "All FMBs converted to well-formed XML." fi
The xmllint step catches the encoding-related silent failures discussed earlier — XML that exists but isn’t well-formed because of character-set issues. Roughly 1–3% of FMBs in internationalised estates fail this check on first conversion, and most of them are fixable by adjusting NLS_LANG on the conversion host and re-running.
Step 4 — version-aware re-conversion. Failures from the validation step often fall into version-mismatch categories. The remediation is to identify the originating Forms version of the failed FMBs (typically visible in the FMB header bytes, or known from the source application), open them in an intermediate Forms version, save them as the current version, and re-run conversion.
This step is typically the longest tail in a large-estate conversion programme. For 500-FMB estates, expect 5–15 FMBs to require manual remediation; for 2,000-FMB estates, expect 50–100. None of this is technically difficult — it’s just slow and detail-heavy.
The XML produced by frmf2xml follows a consistent structure. The root element is <Module>, containing module-level properties as attributes and child elements for each top-level form object. The basic skeleton looks like this (compressed for readability):
<?xml version="1.0" encoding="UTF-8"?> <Module Name="CUSTOMER_FORM" FormsVersion="12.2.1.4.0" DateFormatMask="DD-MON-YYYY" ...> <FormModule Name="CUSTOMER_FORM"> <ProgramUnit Name="VALIDATE_CUSTOMER" ProgramUnitType="73"> <ProgramUnitText> <![CDATA[ PROCEDURE validate_customer IS BEGIN IF :customer.status NOT IN ('A','I','P') THEN RAISE form_trigger_failure; END IF; END; ]]> </ProgramUnitText> </ProgramUnit> <Block Name="CUSTOMER" DatabaseDataBlock="true" QueryDataSourceName="CUSTOMERS" ...> <Trigger Name="WHEN-VALIDATE-RECORD" TriggerStyle="1"> <TriggerText> <![CDATA[ validate_customer; ]]> </TriggerText> </Trigger> <Item Name="CUSTOMER_ID" DataType="2" Required="true" DatabaseItem="true" ColumnName="CUSTOMER_ID" ...> <Trigger Name="WHEN-VALIDATE-ITEM" TriggerStyle="1"> <TriggerText><![CDATA[ ... ]]></TriggerText> </Trigger> </Item> <Item Name="CUSTOMER_NAME" DataType="1" MaxLength="100" ...> ... </Item> </Block> <Canvas Name="MAIN_CANVAS" CanvasType="0" ...> ... </Canvas> <Window Name="MAIN_WINDOW" Width="800" Height="600" ...> ... </Window> </FormModule> </Module>
The patterns to internalise:
Once the estate is in XML, the analytical leverage is large. Three categories of analysis pay back disproportionately during migration planning.
Estate-wide inventory and complexity scoring. A simple Python script using lxml can produce per-form metrics across hundreds of XML files in seconds.
#!/usr/bin/env python3 # analyse.py — produce per-form complexity metrics from XML import os import csv from lxml import etree OUTPUT_ROOT = "/tmp/forms-xml" REPORT = "/tmp/complexity-report.csv" def analyse_form(xml_path): tree = etree.parse(xml_path) root = tree.getroot() blocks = root.findall(".//Block") items = root.findall(".//Item") triggers = root.findall(".//Trigger") program_units = root.findall(".//ProgramUnit") # Count lines of embedded PL/SQL plsql_lines = 0 for elem in root.findall(".//TriggerText") + root.findall(".//ProgramUnitText"): if elem.text: plsql_lines += len(elem.text.splitlines()) # Database items vs control items db_items = sum(1 for it in items if it.get("DatabaseItem", "false") == "true") return { "form": os.path.basename(xml_path).replace(".xml", ""), "blocks": len(blocks), "items": len(items), "db_items": db_items, "triggers": len(triggers), "program_units": len(program_units), "plsql_lines": plsql_lines, } with open(REPORT, "w", newline="") as f: writer = None for dirpath, _, files in os.walk(OUTPUT_ROOT): for fname in files: if not fname.endswith(".xml"): continue try: row = analyse_form(os.path.join(dirpath, fname)) if writer is None: writer = csv.DictWriter(f, fieldnames=row.keys()) writer.writeheader() writer.writerow(row) except etree.XMLSyntaxError as e: print(f"Parse error in {fname}: {e}") print(f"Report written to {REPORT}")
This script — under fifty lines — produces the foundational data for every subsequent analysis. From the resulting CSV, you can rank forms by complexity, group them into migration waves of comparable effort, identify the long-tail of trivial forms that may not justify migration at all, and produce honest effort estimates per form. The same data is what an external migration assessment partner asks for first, and what they often spend the first week of the engagement producing if it isn’t provided.
Dependency and reference extraction. Database objects referenced by forms are findable by grepping the embedded PL/SQL inside the XML, with appropriate care for PL/SQL syntax.
# Within a Trigger or ProgramUnit text, find table references import re TABLE_REF_PATTERN = re.compile( r"\b(FROM|INTO|UPDATE|JOIN)\s+([A-Z_][A-Z0-9_]*)", re.IGNORECASE ) def extract_table_refs(plsql_text): return set(m.group(2).upper() for m in TABLE_REF_PATTERN.finditer(plsql_text))
This is approximate — proper PL/SQL parsing requires a real parser, not regex — but the regex pass produces 80–90% accuracy on most estates, which is enough for migration-planning purposes. Combined with the schema list extracted from the database itself, it produces a reference graph from forms to tables that lets you reason about migration sequencing, schema dependencies, and which forms can be migrated independently.
Code-quality and security pattern detection. Static analysis for the patterns that matter to migration risk:
Each of these is a short XPath-plus-text-match script, and the outputs feed directly into both migration effort estimation and pre-migration security remediation.
Almost every external Forms migration assessment runs into the same blocker. The assessment requires visibility into the FMBs (or, equivalently, the XML). The client cannot release the FMBs because they contain confidential business logic, hardcoded references to customer data, schema names that aren’t supposed to leave the perimeter, embedded comments referencing specific clients or products, and — occasionally — credentials that nobody has gotten around to removing in twenty years of development.
The sanitization step transforms the XML into a form that preserves the structural information necessary for assessment (number of blocks, items, triggers, complexity metrics, control patterns) while removing the substantive information that’s sensitive (specific identifier names, embedded data, business logic).
A reasonable sanitization pipeline performs five transformations:
Doing this by hand across an estate is infeasible. A serious migration partner will operate an automated sanitization pipeline — Pretius runs the workflow as part of its discovery practice for regulated clients — that produces sanitized XML preserving migration-relevant structural information at near-100% fidelity while removing substantive content.
The output is the format that can leave the security perimeter for assessment work — and crucially, the structural metrics derived from the sanitized XML are the same as the metrics derived from the original (complexity counts, trigger counts, item counts, dependency-graph topology all survive sanitization). The assessment producible from the sanitized XML is therefore quantitatively equivalent to one produced from the originals.
For institutions where the alternative is “we can’t share the FMBs, so we can’t get an external assessment, so we have to do the assessment internally,” — which is a common position in regulated industries — the sanitization step is the difference between getting a credible external view of the estate and not.
The conversion step is foundational but not, by itself, a migration. Understanding where it sits in the larger workflow prevents the common error of treating XML as a deliverable when it’s actually an intermediate format.
A complete Forms migration workflow runs roughly:
Steps 2 through 4 are what this article has covered. They are typically completed in the first 3–6 weeks of a serious migration programme. Skipping them — going from inventory directly to step 6 with a vendor tool that “handles FMB directly” — is possible but usually a mistake, because you lose the ability to do steps 3 and 5 rigorously, which means you lose the ability to size, sequence, and prioritise the migration based on actual estate characteristics rather than rough guesses.
A complete estate conversion handles four file types, not one. The pattern is the same for each, with separate utilities:
Batch scripts for these follow the same pattern as the FMB batch script above, with the appropriate utility substituted. The validation and analysis steps are similar; the static-analysis output schemas differ in structure but not in spirit.
Estates that convert FMBs but skip PLLs and OLBs produce static analysis with significant gaps — every PL/SQL call into a library function becomes an unresolved reference, and every form that inherits properties from an object library appears to have fewer properties than it actually does. The completeness of the conversion step determines the accuracy of everything downstream.
The technical workflow described above assumes a team with deep Oracle Forms expertise, available Python and bash development capacity, and three to six weeks of focused bandwidth to dedicate to estate conversion and analysis. For many organisations still running Forms in production in 2026, that assumption doesn’t hold.
The original Forms developers have retired, moved on, or been redeployed to other systems. The internal team that exists is fully occupied keeping the current Forms estate running and cannot absorb a parallel analytical workstream without measurable production risk.
Building one-off internal expertise for a phase that lasts six weeks and then doesn’t recur is economically irrational. And the specific sub-skills the workflow requires — frmf2xml version troubleshooting across legacy Forms releases, encoding diagnostics across multi-decade FMB libraries, sanitization pipelines that survive Internal Audit and DPO review, dependency-graph construction at estate scale — aren’t taught anywhere. They’re acquired through repetition across many estates, which means they live in the heads of people who do this work professionally and almost nowhere else.
This is the common situation rather than the exception, and it’s the gap Pretius’s flexible Oracle Forms migration practice exists to fill. The relevant capabilities for the conversion-and-discovery phase specifically are these.
Pretius’s discovery practice uses the same foundational open-source tooling described above — frmf2xml, scripted batch conversion, XML-native static analysis — alongside an AI-driven discovery process that materially changes the economics for clients without in-house Forms specialists.
The discovery process ingests multiple sources of information about the system in parallel, rather than relying on FMB conversion alone. The published input set is:
| Input | What it tells the analysis |
|---|---|
| FMB files (Oracle Forms XML source) | Complete map of screens, triggers, and program logic |
| Oracle database schema | Table relationships, stored procedures, dependencies |
| Existing documentation | Business context, intended behaviour, known edge cases |
| Historical support tickets | What actually breaks, what users actually use |
| Test cases and process descriptions | Behavioural coverage and exception scenarios |
| AI agent running against the live system | Real usage paths discovered autonomously |
The output is the structured specification, dependency graph, risk register, and effort estimate, which this article describes as the goal of conversion-and-analysis, but produced from a wider information base than FMB conversion alone can support, and produced in days rather than the months internal teams typically take to assemble the same data manually. The AI-assisted scope analysis hits approximately 90% accuracy on effort estimation, against a baseline of internal estimates that routinely diverge from actual delivery by 50% or more.
Two further characteristics of the practice matter for what the discovery deliverable enables downstream. The Pretius AI Forms to APEX Assistant is the tooling that operates on the converted XML and the discovery output to drive semi-automated translation when APEX is the chosen destination. And the practice supports three distinct destination paths — staying on Oracle Database with an APEX frontend, modernising the frontend in Java or React while preserving the Oracle Database, or full exit from Oracle to PostgreSQL — which means the discovery output is structured to support a destination decision rather than presupposing one. The discovery and the destination decision are sequenced correctly: analyse first, recommend second, build third.
The leverage is most significant where the FMB inventory is large (100+ forms), where the original developers are no longer reachable, where Forms versions span multiple Oracle generations, or where the discovery deliverable must be defensible to Internal Audit, Risk, and Compliance functions — i.e., exactly the conditions under which doing the work internally is hardest and where amateur execution is most consequential.
Pretius’s flexible Forms migration practice exposes four delivery models specifically for the discovery-and-conversion phase, in addition to subsequent migration delivery. The right model depends on what your team can already do and what you want them to be able to do afterwards.
Full project delivery. Pretius runs the full conversion and analysis end-to-end against a defined scope and timeline. Fixed scope, fixed timeline, fixed budget. Suitable for organisations that need the deliverable and don’t have the internal capacity to participate meaningfully in producing it. Typically, the right choice for institutions where the Forms migration is one of multiple parallel programmes competing for finite internal attention, the discovery phase becomes a fixed-price input to the broader programme rather than a resourcing problem.
Co-creation. Pretius engineers and your in-house team operate as a single working unit through the conversion-and-discovery phase, with continuous knowledge transfer throughout. The output is the conversion and analysis described in this article — but produced jointly, so that by the end, your team has acquired the skills to extend, modify, and maintain the analytical pipeline. Suitable for organisations that intend to remain Oracle-aware long-term and want to build internal capability rather than depend on an external partner permanently. This is the model Pretius used for a large international bank migration referenced on the Flexible Forms Migration page.
Team augmentation. One or two specialists from Pretius — typically an Oracle Forms architect plus a PL/SQL engineer — embed in your existing team to fill specific skills gaps. The conversion-and-analysis work is led by your team; Pretius provides the missing expertise on a defined-duration basis. Suitable for organisations with a strong internal team that lacks one or two specific competencies (Forms tooling specifically, or static-analysis design, or sanitization-pipeline construction) and where the gap is bounded rather than systemic.
Dedicated development team. A complete Pretius cross-functional team — analyst, Forms architect, developers, DevOps, QA — operates as an extension of your organisation, owning the conversion-and-analysis phase as a self-contained workstream while you maintain strategic and architectural control. Suitable for large estates (300+ forms) where the workstream is too large for staff augmentation but co-creation is impractical because your internal team lacks the depth to pair credibly with the Pretius engineers.
The four models are not mutually exclusive across the full programme lifecycle. A common pattern in regulated industries is full project delivery or dedicated team during conversion-and-discovery (because the analytical deliverable has to be produced quickly and to a regulator-defensible standard), transitioning to co-creation during migration delivery (because the production system is moving and the client team needs to build operational ownership), and team augmentation post-go-live (because steady-state runs on the client side with occasional specialist support).
A useful version of this section also names the cases where bringing in Pretius — or any external partner — is overkill rather than essential. Three honestly don’t justify it:
For estates in the 50–500+ range, with degraded internal Forms expertise, multiple Forms versions in production, regulatory or audit pressure on the discovery deliverable, or a requirement that the analytical output leave the security perimeter for assessment — which describes most serious Forms estates still in production in 2026 — the case for external delivery of the conversion-and-discovery phase is clear. Economics, security, and timeline pressure all point in the same direction.
FMB-to-XML conversion is the single most leveraged early technical step in an Oracle Forms migration. Done thoroughly, in 3–6 weeks of effort for most estates, it produces the machine-readable foundation for every subsequent analytical, planning, and tooling activity — complexity scoring, dependency mapping, automated translation, secure assessment sharing, static security analysis, and source-controlled change tracking that none of these are otherwise possible without.
Done casually — converting only the FMBs you happen to think of, skipping validation, ignoring version-compatibility failures, not sanitizing for external sharing, treating the XML as a final artefact rather than an intermediate — it leaves the migration programme operating on guesses for the remainder of its duration. Effort estimates become guesses. Sequencing becomes guessing. Risk identification becomes a guess. The 18-month programme overruns by six months, and nobody knows why until they look back at the conversion step and realise that’s where the data they needed was supposed to come from.
The engineering investment is small. The leverage is large. The article above describes how to make it land.
Pretius runs Oracle Forms estate conversions, AI-driven discovery and complexity assessments at scale, with the Pretius AI Forms to APEX Assistant supporting downstream migration to APEX, Java, React, or PostgreSQL destinations depending on what the analysis recommends.