Seven Up! Neos 7.0 and Flow 7.0

Neos 7.0 and Flow 7.0 have finally been released! 

But wait! Where is Neos 6.0, you ask?

Read more about our decision, features, fixes and more below :)

– Written by

Neos 7.0 & Flow 7.0

So, why has Neos 6.0 been skipped? It's a relatively short and straightforward answer. During one of the last team Tiga weeklies, the question came up if it would make sense to sync the version numbers of Neos and Flow with the upcoming major release.

From the top of the team's heads, that seemed like a good idea. This suggestion was then discussed internally, and everyone was able to contribute arguments for or against it.

To keep a short story short - we decided to sync both version numbers, hopefully making all of our lives easier and leading to a cleaner roadmap for future releases.


Prepared for a bright future

With the new versions of Neos & Flow, we revised large parts of the code base, cleaned up deprecated parts, and modernized the overall code style. This will make further development more comfortable, faster, and safer.

So, let's get into it:

Neos/Flow 7 require PHP 7.3+

PHP 7.2 reached End Of Life.

Neos/Flow 7.0 now require PHP 7.3 or 7.4.
Support for PHP 8.0 has been prepared and will be added as soon as Doctrine is compatible.
We also adjusted our PHP Coding Guidelines slightly to reflect the new best practices.

Supported PHP versions

Supported PHP Versions

Atomic Fusion added to the core

Two years ago, Wilhelm and Martin introduced their JSX inspired packages around "Atomic Fusion" in a blog post.
It was trendy from the start, is considered best practice in the meantime and the Neos.Demo package has already been reworked to demonstrate some of the possibilities of AFX.
While Fluid still plays an important role, especially in the Neos backend, version 7 marks an essential step towards a unified, Fusion-based templating system.

A short story about Templating

Back in the days, about 12 years ago, we have made the first steps with Neos. During this time, we have been investigating templating engines to find a suitable replacement for the marker-based approach:

page.10 = TEMPLATE
page.10 {
  template = FILE
  template.file = fileadmin/template.html
  marks.HEADLINE = title
  subparts.LINK = TEXT
  subparts.LINK.current = 1
  subparts.LINK.typolink {
    parameter = 1

// ...

<!--###LINK###-->Some link<!--###LINK###-->

A snippet from "TypoScript by Example" and the corresponding HTML template

After we couldn't find a solution that would fit all our needs, we came up with our own implementation of a Templating Engine, called "Fluid":

content = Template {
	templatePath = 'resource://SomeTemplate.html'
	title = ${q(node).property('title')}

// ...

{namespace neos=Neos\Neos\ViewHelpers}
<neos:link.node>Some link</neos:link.node>

Classic Fusion and Fluid template

Release by release, Fusion, the successor of TypoScript, has grown up. With the introduction of Atomic.Fusion, it became our new best practice for templates:

content = afx`
	<Neos.Neos:NodeLink node={props.node}>Some link</Neos.Neos:NodeLink>

So, with today's release TYPO3Fluid has been removed from the Flow core & distribution package. It is now considered deprecated and has been replaced almost everywhere with Neos.Fusion. This has also been done in favor of AFX.

Now, the Neos Site Kickstarter package automatically creates AFX based templates.

Node Presets

Many developers are familiar with the Sitegeist.Silhouettes package that allows integrators to specify presets that can be used across multiple node type definitions.
This feature is now part of the core functionality, and it can be used to centralize recurring configuration:



              type: string
                inlineEditable: true

              type: 'string'
                inlineEditable: true
                    autoparagraph: true
                      em: true
                      strong: true

Presets can then be applied in NodeTypes.yaml via:

  # ...
        preset: 'rte.plaintext'
      defaultValue: 'Title'
        preset: 'rte.basicText'

PSR-15 Middleware

This is the consistent continuation of our last releases regarding PSR standards. As part of this, HTTP component chains (custom implementation) were replaced with middlewares compatible with PSR-15.

It is now possible to seamlessly use 3rd party middlewares in Neos/Flow.

For example, a single command

composer require middlewares/response-time

…and a few lines of Settings.yaml

          middleware: 'Middlewares\ResponseTime'
          position: start enough to measure the timing of requests.

Read the Middleware documentation to find out more about the new possibilities and make sure to read the Flow 7.0 Upgrade instructions to find out whether you'll have to adjust your code.

Faster and more extensible Routing

With version 7, Neos leverages the full power of the latest Routing features and moves most of the logic of the LinkingService into the infamous FrontendNodeRoutePartHandler.
This results in greatly improved performance for the frontend routing because information about the current context can be shared between routes and cached independently from the content.

Furthermore, the handler has been extended by a nodeType option that allows custom routes to be applied for the specified node type exclusively:

  name:  'Custom'
  uriPattern: '{node}/custom.html'
    '@package':    'Neos.Neos'
    '@controller': 'Frontend\Node'
    '@action':     'show'
    '@format':     'html'
    custom:         true
      handler: 'Neos\Neos\Routing\FrontendNodeRoutePartHandlerInterface'
        nodeType: 'Some.Package:SomeDocument'

Read the Routing documentation to find out more about the new possibilities and make sure to read the Flow 7.0 Upgrade instructions to find out whether you'll have to adjust your code.

More Neos 7.0 Highlights


New default insert mode

To make life easier for our editors, we have changed the default behavior of the insert mode. For content nodes, the default has been changed from insert after to insert into mode if available (e.g. for content collections) since that is usually the intended behavior.

So that will save time and makes the life of our content editors easier:

Configurable default backend module

The content module always felt like a regular backend module, but technically it was not. This fact has been changed now. So content is now an own module with its privileges. 

This brings the ability that users no longer need to have access to the content module to log into the backend.

Furthermore, it's now possible to define the default module that is shown after login via the preferredStartModules setting:

      preferredStartModules: [ 'user/usersettings', 'content' ]

StaticResource Eel Helper

A new Eel helper has been added that allows for easy rendering of static resource URIs:

<!-- create static resource uri -->
<link rel="stylesheet" href={StaticResource.uri('Neos.Demo', 'Public/Styles/Main.css')} media="all" />

And, since it sometimes makes sense to inline the contents of a static resource, this is possible as well:

<!-- get static resource content -->
<style>{StaticResource.content('Neos.Demo', 'Public/Styles/Main.css')}</style>

Support for I18n plurals

Example of language plurals in the neos user internface

In our beloved PHP framework Flow, we can use language plurals for ages. But until now, it was not possible to use the plurals in the React-UI of Neos, for instance. The I18n registry used the XLIFF endpoint of Neos, and this endpoint only delivered the singular label.

The endpoint can now deliver plurals as well. We adjusted the API of the I18n registry method to translate a bit added a new quantity parameter. The change is not breaking existing code; if you don't use the quantity parameter, you will get the singular.

The following example shows the backward compatibility of the javascript code. So if you extended the UI, for instance, you could still use that for older Neos versions and, of course, the new version seven!

// current behavior that will return the singular
const actual = registry.translate('Neos.Neos:Main:pluralLabel', undefined, undefined, 'Neos.Neos', 'Main');

// With quantity parameter will return the plural
const plural = registry.translate('Neos.Neos:Main:pluralLabel', undefined, undefined, 'Neos.Neos', 'Main', 1);

Lazy loading images

Image tags rendered with the Neos.Neos:ImageTag fusion prototype (or the ImageViewHelper from the Neos.Media package) will now be rendered with the loading attribute set to “lazy” by default leveraging modern browsers’ power to defer loading of images until they are visible.

Read more about the loading attribute on MDN

New options for sort() FlowQuery operation

Now you are able the pass a third parameter to the sort() method, supporting all flags of the array sort() PHP function. For example, to order nodes case-independently:

tags = ${q(node).find("[instanceof My.Site:Document.PressTag]").sort("title", "ASC", ["SORT_NATURAL", "SORT_FLAG_CASE"]).get()}

Further changes

  • Deprecated Fusion prototype usage has been removed from the core
  • The AssetSourceInterface has been extended by getIconUri() & getDescription() in order to provide a more descriptive UI in the Neos backend
  • Default prototype generator has been removed
  • Improved AFX parser exception message
  • Removed legacy aloha configuration handling from Neos.Ui

Of course, this is just an abstract of the many changes included in this release, thanks to all the outstanding contributors.
See Neos 7.0 and Neos UI 7.0 change logs for a list of all changes and further details.

More Flow 7.0 Highlights


Doctrine Migrations updated to 3.0

The doctrine/migrations package and all relevant dependencies have been updated from version 1.8 to 3.0.

While there are new features in Doctrine Migrations, the reason for us to do an upgrade is to move forward – the previously used version will not be maintained forever.

This post also gives some background on that.

Make sure to apply core migrations in order to adjust any existing Migration in your own packages.

DBAL connection factory

Previously, in order to get hold of the current DBAL connection, one had to inject the doctrine EntityManager increasing complexity and coupling. With version 7, a ConnectionFactory has been added, allowing for the painless injection of the current database connection:

class SomeClass {

     * @Flow\Inject
     * @var \Doctrine\DBAL\Connection
    protected $connection;

Human-readable labels and descriptions for Roles & Privileges

The user roles and privileges can quite quickly become a forest of technical labels like Neos.Flow:Everybody, and until now, there was no right way to document them in a human-readable form that can be used, e.g., in the Neos backend.

With Flow 7, metadata can be assigned to roles and privilege targets in order to add human-readable labels and descriptions:

    label: 'Neos User Manager'
    description: 'A user with this role is able to create, edit and delete users which has the same or a subset of his own roles.'
    # ...

      label: 'The privilege to see the content preview in the backend.'
      # ...

Two new commands have been added that will output this information to the CLI:

./flow security:listRoles --include-abstract
./flow security:describeRole <role>

Unidirectional OneToMany relations

In Flow specifically, we try to follow DDD best practices in modeling. This means that the aggregate root is the entry point, and the entity sent to a repository to persist it and all its sub-entities. This can not be achieved with the standard doctrine OneToMany annotation when one side is supposed to be closer to the root.

This change allows the user to annotate such a relation simply as:

 * @ORM\OneToMany
 * @var Collection<Comment>

Value Objects are embedded by default

With Flow 7.0+ all Value Objects are embedded by default.
Embedded value objects are the preferred storage method for all value objects since they better reflect true value object semantics.

Make sure to apply core migrations and/or change the embedded behavior in your own Value Object implementations:

 * @Flow\\ValueObject(embedded=false)

Removed Fluid as a dependency

More of an “honorable mention” than a Feature: With version 7, TYPO3Fluid is no longer a requirement to run Flow. This is part of an ongoing process to make the base distribution lighter and allow developers to opt into features selectively.

Note: Fluid is still being used by default when creating packages with the Kickstarter (not the Neos Site Kickstarter), and it is also still used heavily in the Neos core.

If you make use of Fluid in your packages, make sure to declare a dependency on neos/fluid-adaptor

Added virtual object configurations for framework loggers

The deprecated PsrSecurityLoggerInterface and PsrSystemLoggerInterface interfaces have been replaced in favor of the corresponding virtual objects:

  • Neos.Flow:SystemLogger
  • Neos.Flow:SecurityLogger
  • Neos.Flow:SqlLogger
  • Neos.Flow:I18nLogger

Further changes

  • Default Session cookie SameSite attribute changed to "lax"
  • Relative position to non-existing key in PositionalArraySorter throws exception
  • Removed deprecated functionalities

Of course, this is just an abstract of the many changes included in this release thanks to all the outstanding contributors.
See Flow 7.0 change log for a list of all changes and further details.

Documentation and Support


The detailed upgrading process for Neos 7.0 is explained in the upgrade instructions and Release Notes.

For Flow related upgrade instructions please refer to the Flow 7.0 Release Notes.


See the Neos 7.0, Neos UI 7.0 and Flow 7.0 change logs for all changes and further details.

Support for Neos and Flow 7.0

As shown in our release roadmap, Neos 7.0 and Flow 7.0 will get bug fixes until August 2022 and security fixes until August 2023.

Thank you!

Thanks to all core team members and the community for your valuable contributions and sponsorships. Especially during this difficult time in which a lot of people have many private topics on their mind and less time to contribute.

Take care of everyone and stay healthy ❤️