Home/Modernize/ColdFusion to Java
Modernize

You are already on the JVM. That changes the whole risk profile.

CFML compiles to Java bytecode and runs in a servlet container. Java is the only migration target where the old system and the new one can share a process, a connection pool and a transaction, so a half-finished migration is still a working system.

Why this route is different
  1. 01
    RuntimeAlready the JVM, no change
  2. 02
    TargetSpring Boot, or plain Jakarta EE
  3. 03
    InteropIn-process, no network hop
  4. 04
    TransactionsShared across old and new
  5. 05
    Connection poolOne pool, both sides
  6. 06
    RollbackPer module, same deployment
The premise

CFML is not a foreign language to Java. It is a dialect of the same runtime.

Adobe ColdFusion and Lucee are both Java applications. Your CFML is compiled to bytecode and executed by the same JVM that would run a Spring Boot service, inside the same servlet container, against the same JDBC drivers.

That is not a trivia point. It is the reason a CFML application can call createObject("java", ...) and get a real Java object back, with no serialisation, no HTTP hop and no separate deployment.

For a migration it means the boundary between old and new can be a method call instead of an API. A module you have rewritten in Java is invoked directly from the CFML that has not been rewritten yet, inside the same transaction, sharing the same connection pool.

Every other target on the shortlist forces you to choose: run two systems and reconcile them over the network, or hold the release until everything has moved. On the JVM you do neither, and that is worth more than any language comparison.

How the two halves coexist

One process, two languages, no network between them.

The migrated modules are ordinary Spring beans. The CFML that has not moved yet calls them the way it has always called Java classes, and neither side knows or cares that the other is written in a different language.

Because there is one connection pool, a CFML transaction can span a Java service call. That single fact removes the entire class of distributed-transaction problems that make .NET and Node migrations awkward in the middle phase.

Operationally it stays one deployment, one set of JVM metrics, one log stream. Your operations team does not have to learn a second platform while the migration is in flight, which is usually when they have the least spare capacity.

The trade-off is honest: you are committing to the JVM for the long term. If your organisation is trying to leave it, this is the wrong route and .NET is probably the right one.

ColdFusion and Spring Boot services running inside the same Java virtual machine, sharing a JDBC connection pool and a transaction
The half-migrated state is a supported state, not something to survive.
In code

What the boundary looks like.

Two snippets from real transition work. Neither requires the CFML around it to be finished, which is the entire point.

01

CFML calling a migrated module directly

ColdFusion (CFML)
<cfset pricing = createObject("java",
        "com.acme.pricing.PricingService")
        .init() />

<cfset quote = pricing.quoteFor(
        orderId  = order.id,
        currency = session.currency) />

<cfoutput>#quote.getTotal()#</cfoutput>
Java / Spring Boot
@Service
public class PricingService {

  private final RateRepository rates;

  public Quote quoteFor(long orderId,
                        String currency) {
    // The rules that used to live in
    // pricing.cfm, now testable.
    return rates.priceOrder(orderId, currency);
  }
}

No REST layer, no JSON, no second deployment. The CFML above is unchanged in structure from what it replaced, only the body of the calculation moved.

02

A cfquery becomes a repository, against the same pool

ColdFusion (CFML)
<cfquery name="q" datasource="app">
  SELECT id, total
  FROM   orders
  WHERE  customer_id = <cfqueryparam
           value="#custId#"
           cfsqltype="cf_sql_integer">
</cfquery>
Java / Spring Boot
@Repository
public class OrderRepository {

  private final JdbcTemplate jdbc;  // same
                                    // DataSource
  public List<OrderRow> byCustomer(long custId) {
    return jdbc.query(
      "SELECT id, total FROM orders "
      + "WHERE customer_id = ?",
      ORDER_ROW, custId);
  }
}

The datasource configured in the ColdFusion administrator and the DataSource bean can be the same pool. That is what lets one transaction cover both sides during the transition.

What changes

The runtime stays. The discipline does not.

Migrating to Java is technically the shortest trip on the shortlist, and culturally the longest. It is worth being clear about which parts of your current working life this ends.

Today

ColdFusion working habits

  • Edit a template, refresh the browser, done
  • Types checked when the request runs, if at all
  • Dependencies reached for wherever they are needed
  • Deployment is a file copy
  • Testing is largely manual, by the person who wrote it
  • One engineer holds most of the system in their head
After

JVM working habits

  • Compile, test, deploy an artefact
  • Types checked before the code ever runs
  • Dependencies injected, which makes them replaceable in tests
  • Deployment is a build pipeline you can audit
  • Regression suites run on every change, unattended
  • The system is legible to anyone who can read Java
Choosing honestly

When Java is the right target, and when it is not.

We deliver .NET, Java and Node, so this section costs us nothing to write accurately. Java is the right answer more often than its reputation suggests, and the wrong answer in a few specific situations that are easy to identify up front.

  • Choose Java if you are on Oracle or DB2. The drivers, the tooling and the operational knowledge are already in the building, and the JDBC layer you are using today carries over unchanged.
  • Choose Java if the migration will run for more than a year. The longer the transition, the more the shared-process advantage compounds. A two-year migration in which the half-done state is fully supported is a fundamentally different risk from one where it is not.
  • Choose Java if you already run JVM services. Same build pipeline, same monitoring, same deployment story, same on-call runbook. The operational cost of the migration approaches zero.
  • Do not choose Java to escape the JVM. If the strategic goal is to leave the Java ecosystem, this route is exactly backwards. Take the .NET path and accept the higher transitional risk.
  • Do not choose Java for a small team with no JVM experience. Spring's learning curve is real. A four-person team with no Java background will usually be more productive, and happier, on .NET or Node.
  • Do not choose Java because it sounds like the safe option. It is the safe option for the transition, not for the next decade. The decision that matters is who will be maintaining this in five years and what they know.
Further reading

Written up in more depth on the blog.

Two pieces from our own engineers on the JVM side of ColdFusion.

Questions worth asking

ColdFusion and Java, specifically.

The three that come up once a team realises the JVM angle is real.

If we are already on the JVM, could we just keep ColdFusion and add Java where we need it?

Yes, and for some organisations that is the right final destination rather than a transitional state. A ColdFusion application with its heavy or business-critical logic progressively moved into tested Java services, with CFML retained for the display layer and the long tail of admin screens, is a perfectly defensible architecture. It keeps the screens you would gain nothing from rewriting, and it puts the parts that carry risk into a language you can hire for and test properly. We would rather deliver that than a full migration you did not need. The decision point is usually the front end: if the CFML templates themselves are the problem, you are heading for a full move anyway.

Does this work with Lucee as well as Adobe ColdFusion?

Yes, and in some respects better. Lucee is an open-source CFML engine on the JVM, so the same interop applies, and Lucee's Java integration is generally more predictable. Several teams take both steps in sequence: move Adobe ColdFusion to Lucee first to remove the licence cost and get onto an actively developed engine, then migrate module by module into Java from there. Each step is independently valuable and independently reversible, which is a much easier programme to get funded than a single large rewrite.

Spring Boot or something lighter?

It depends on your team, not on the code. Spring Boot brings dependency injection, transaction management, configuration and a large ecosystem, and if you have or can hire Java engineers it is the least surprising choice, everyone knows it, which matters when you are hiring. For smaller teams or simpler applications, Javalin or Quarkus produce something considerably easier to hold in your head. What we would avoid is choosing a framework because it benchmarks well; you are migrating away from a system nobody can maintain, so maintainability is the criterion that earned its place at the top.