Guides and Tutorials

Understand Expression and Scripting Languages Used in Nuxeo

Updated: July 17, 2023

The Nuxeo platform uses different expression languages and scripting languages (MVEL, EL, Freemarker). The following documentation will help you in understanding which of these languages are available and which variables may be used based on the Nuxeo context you are using.


The Nuxeo Platform is divided into several layers communicating with each other. In terms of expression and scripting languages, we may simplify the communications between layers:

Numbers circled in orange specify available contexts. Have a look at the available variables depending on context section for further information.

What Expression/Scripting Language do I Need to Use?

  • Operation chains use the MVEL scripting language.
  • Widget fields, the Enablement tabs and the workflow's Availability tab (aka filters) use the EL expression language.
  • Email templates use the Freemarker templating language.
  • Document templates can either use the Freemarker or MVEL scripting languages depending on the rendering engine chosen.

What Variables Can I Use?

Before giving you a list of examples to work with, it is important to understand that the variables you can use depend on two major conditions: the scripting language and the context you are in. We already mentioned which language to use in which Nuxeo Platform layer (refer to the previous section), so let's talk about the context within each layer.

The user interface can send information to the core layer in order to execute operations, however, the opposite is not possible.  Any operation done automatically by the platform without a user interaction first (eg : scheduled jobs) cannot take advantage of what you currently see on screen. Let's say that you launch an operation manually, for example by clicking on a button. The information can be sent to the core layer.  The information sent  depends on the screen you are using. Even though the information from the UI is available to the core layer do not expect any information originating in the core to be available to the UI layer. For example: A workflow variable cannot be used outside of a workflow.

In order to determine more easily which of these variables will be usable in your context, you may ask yourself the following questions :

  • Does a user need to be logged in to execute this operation?

    • No → Only system variables, like today's date, will be available.
    • Yes → Which screen will the user be on when executing this operation?

      • Depending on the answer, context variables may vary.
  • Is a workflow launched on the document?

    • No → Workflow variables can't be used.
    • Yes → Workflow variables can be used.

Please check the availables variables depending on context section for more detailed information.

What are the Main Differences Between Expression/Scripting Languages?

ConceptAdvanced scripting language.Advanced scripting and templating language.Templating language. Used for email or document templates.
Expression syntax#{}@{}${}
Variables availableHas access to the SEAM (user interface) components, providing many variables.Can use the variables provided by the UI layer.Depends on context: send mail operation, doc rendering operation or workflow email notification.
Current document variable#{**currentDocument**.property}@{**Document**.property} Send mail / doc rendering:${**Document**.property} Workflow email notification:${**workflowDocuments[0]**.property}

Variable name and context
The same object may be given a different variable name depending on language or context, as shown in bold in the previous table.

Be careful if you intend to copy / paste an expression taken from a different context.

How Can I Use SEAM Components in EL Expression Language?

  1. First of all, you need to find the right SEAM component. To do so, go to the Nuxeo Platform explorer, choose your distribution and browse the SEAM components available. They are given explicit names so you can find what you are looking for more easily (eg : clipboardActions, navigationContext).
  2. Dive into the component documentation and search for the method you wish to use.
  3. You may now call it by typing the following syntax in the appropriate field : #{seamComponentName.method()}.

    Note that you may also create your own SEAM components and call them.

How Can I Make Sure that the SEAM Component or Other Variable Will be Available in my Context and Also Check What Value Will be Returned by an EL or MVEL Expression?

EL Language

If your EL expression is meant to be evaluated into a UI screen a simple way to check is to create a XHTML file containing it.

  1. Upload your file in Nuxeo Studio into the widget templates, using the Resources menu.

  2. Add a « template » widget (available in More widgets > Advanced widgets) to a layout form where your EL expression is supposed to be used, and select the file.

  3. Go to the corresponding page and check the result.

MVEL Language (Automation Chains Context)

The easiest way to check your expression is to log it using a Notification > log operation.

If you kept Nuxeo's default logging configuration, you should mark this message as being on error level. The variable's content will be logged into the server.log file (available in your Nuxeo directory, then log directory).

Available Variables Depending on Context

Workflow Automatic Transition

Please have a look at this page: Available variables in the automation context

Email Templates

Please have a look at this page: Available Variables in Email Templates

Document Templates

Please have a look at this page: Document Templates and Automation Rendering Service

Automation Chains

Please have a look at this page: Use of MVEL in Automation Chains

Event Handlers

Event handlers call automation chains, therefore you should refer to the Use of MVEL in Automation Chains documentation. Event handlers also give access to the Event object, which contains interesting properties:

  • Event.context.getProperty('**property**') - contextual properties. You can replace "property" with:

    • transition - the name of the transition followed by the document when a lifecyle change happens. For example, Event.context.getProperty('transition') == 'undelete' will allow you to execute actions in case a document is restored from trash.
    • category - the event's category
    • sessionId - the session id
    • repositoryName - the repository name
    • comment - the comment sent by the event
    • documentLifeCycle - the document's current lifecycle state
    • parentPath - The path of the parent (Empty Document Created.
    • destinationRef - the path of the parent
    • destinationName - the name of the parent

      Availability of These Properties

      Some of these properties are available only for some events.

      For instance: parentPath is available only for "Empty Document Created" ("emptyDocumentModelCreated"). transition only for "Lifecycle transition event", destinationName and destinationRef are available for "About to Create" and "Document Created", ...

      To get a list of properties available for an event, you can call Event.context.getProperties().toString() (and log the result for instance).

      A list of common events can be found on the Common Events page.

  • Event.getName() - returns the event name

For example, if you have a document which can be undeleted, you could update a field in the In the MVEL expression of an Automation Chain called for the "Lifecycle transition event" event:

Document > Update property

value: @{Event.context.getProperty("transition") == "undelete" ? true : false}

xpath: mydoc:was_undeleted

Please note that:

  • In Nuxeo Studio, the event handlers "custom EL expression" field uses MVEL as well. However, you should not format your variables using brackets but directly state them in the field.

    • Document['[dc:title](http://dctitle)'] == "myTitle" will work.
    • @{Document['[dc:title](http://dctitle)'] == "myTitle"} will not work and generate an error.


Filters use the EL expression language. You have access to all Seam components and should refer to to get an exhaustive list depending on your platform version. See also information in the category 7: it is actually the same context.

Widgets, XHTML and Content Views

In widgets, layout, content views and in XHTML templates, you can use the EL expression language. You have access to all Seam components (see upper how to access them) and should refer to to get an exhaustive list depending on your platform version. Here are a few interesting possibilities you could use to get started:

  • Taken from the NavigationContextBeanSeam component:
    • **#{changeableDocument}** - the document on screen when showing the creation form.
    • **#{currentContentRoot}** - the current content root, for instance could be the WorkspaceRoot or the SectionsRoot.
    • **#{currentDocument}** - the current document.
    • **#{currentDomain}** - the document's parent domain.
    • **#{currentSuperSpace}** - the document's closest parent having the "SuperSpace" facet.
    • **#{currentWorkspace}** - the document's parent workspace.
    • **#{documentManager}** - the CoreSession object (see example below)
  • Some from the native SEAM context:
    • #{currentUser}
    • #{currentDate}
  • When you are on a document, you can access various information:
    • the metadata using the following pattern : _myDocument.schema_prefix.property_name_ Ex: #{currentDocument.dc.source}
    • the system properties : path, type (of the document), currentLifeCycleState, ... currentDocument is a "DocumentModel" class, see the javadoc to check all you can access. One rule is simple: if it is a "getter" you can just type the name. For example: getType() --> currentDocument.type (first letter is lowercase)
  • You can do some comparisons, when you need to return a boolean values. Ex: #{currentUser.isMemberOf('quality_managers') && (layoutValue.dc.nature=='procedure'||layoutValue.dc.nature=='decree')?'value1':'value2'}
  • You may need to use ".toString()" sometimes, depending on what object is returned. Ex: on the documentModel javadoc, you can see that "getPath()" method returns a Path object. So if you need the string of the path (for an NXQL query for instance) you need to use the .toString() method.
  • You also have access to some "functions" that were added by Nuxeo, you can see the list on the Tag Library Documentation . ex: #{[nxd:hasPermission](http://nxdhasPermission)( currentDomain, 'Write')} will return true only if the connected user has the edit permission on the current domain.
  • The JSTL functions are available, for string manipulation for instance, see the doc.

  • Taken from the ClipboardActionsBeanSeam component:

    • {#isCurrentWorkListEmpty()} - checks if the current worklist is empty.
  • Using the documentManager object can be useful in some case. For example, in a content view of a folder when you want to display a list of documents that are in its parent:
    • The NXQL filter in this example uses the STARTSWITH operator, with the path property: . . . AND [ecm:path](http://ecmpath) STARTSWITH ?
    • The parameter will the be: #{documentManager.getParentDocument(currentDocument.parentRef).path}

Tips and Tricks

Document typeLanguageContextTip
Email templateFreeMarkerWorkflow email notification Schema prefixes cannot be used when using the ${workflowDocuments[0].property} variable. ${workflowDocuments[0].dublincore.title} works. ${workflowDocuments[0].dc.title} will throw an error.
Email templateFreeMarker Workflow email notification Send mail operation To use a date field taken from a schema in your template, you need to cast it as date using the following syntax: ${workflowDocuments[0]} (workflow email notification context) ${} (send mail operation)
N/AELN/A EL expressions can be used to evaluate conditions. A few examples: - Checking that the current document type is something specific (usually used in filters): #{currentDocument.type == 'MySpecificDoctype'} - Showing a different pattern based on a boolean condition (true or false): #{currentDocument.type == 'MySpecificDoctype' ? "Yes it is" : "No it isn't"} - Checking that the worklist is not empty: #{documentsListsManager.isWorkingListEmpty("CURRENT_SELECTION") == false}

You may find more information in these related pages :