The state of configuration

In another thread, I have been putting forward the idea of using a serialization library to transition the global TYPO3_CONF_VARS structure into injectable objects. The benefits of that are many, but mainly boil down to “PHP syntax does 90% of the work for us, eliminating a huge host of potential bugs and ugly code that tries to account for those potential bugs.” It also allows for configuration objects to be injected, rather than read via globals, which makes anything configurable more unit testable.

One of the points raised in that thread is that while such an improvement is all well and good, the overall configuration story of TYPO3 is a bit of a mess anyway and such a change should take place in the context of a broader redesign of the concept of configuration. Fair enough, and I can’t disagree with that position.

To that end, I want to take a survey of the current configuration story in TYPO3, as of v11.5. That will help us get our collective heads around the status quo. This survey may have missed some bits, but I have tried to be as complete as possible. Thanks to Benni Mack and Helmut Hummel for their input and review.

I warn you, this is a bit long, because there’s that many different configuration systems to worry about today…

TYPO3 has, by my count, six distinct and only partially overlapping configuration systems.

$GLOBALS[‘TYPO3_CONF_VARS’]

The global conf-vars array is TYPO3’s main configuration mechanism. It consists of one gigantic global, mutable array, and goes through several stages to get built up. It contains all sorts of different kinds of configuration, some of which should be environment-dependent and some not. The following is a simplified, high-level picture of how it works.

First, sysext/core/Configuration/DefaultConfiguration.php is loaded, which provides a default definition for most configuration.

  • It returns an array, which becomes $GLOBALS['TYPO3_CONF_VARS'].
  • Users SHOULD NOT edit this file, ever.
  • This happens on every request.

Second, an install-specific file, typo3conf/LocalConfiguration.php, is loaded. It is populated on a new install by copying the sysext/core/Configuration/FactoryConfiguration.php file.

  • This file also returns a deeply nested array of the same structure as in DefaultConfiguration.php. Some sites implement custom utilities that get used in this file.
  • The system does a deep merge of this file with $GLOBALS['TYPO3_CONF_VARS'], resulting in a single combined array.
  • Users SHOULD edit this file to suit their needs.
  • This file SHOULD be stored in Git.
  • This happens on every request.

Third, an install-specific file, typo3conf/AdditionalConfiguration.php is loaded. It is populated by the installer, and by default contains environment-specific overrides.

  • This file does not return anything, but modifies $GLOBALS['TYPO3_CONF_VARS'] directly. Some sites implement custom utilities that get used in this file.
  • Users SHOULD edit this file to suit their needs.
  • This file SHOULD NOT be stored in Git.
  • This happens on every request.

Fourth, extensions MAY declare an ext_localconf.php file.

  • These files get concatenated together by the system once at build time (give or take some tweaking to make that concatenation possible).
  • These files do not return anything, but modify $GLOBALS['TYPO3_CONF_VARS'] directly. Some sites implement custom utilities that get used in these files.
  • The combined file is loaded on every request.
  • Users SHOULD NOT edit these files to suit their needs.
  • These SHOULD be stored in Git, or downloaded along with the extension from TER or Packagist.

The TYPO3_CONF_VARS array is not self-describing. Arrays are inherently not type safe, and keys are frequently non-obvious in intent. Documentation is provided out-of-band via the sysext/core/Configuration/DefaultConfigurationDescription.yaml file, which is kept in sync with the code (or not) manually.

One tricky part of the TYPO3_CONF_VARS array is that, because it contains a variety of different types of information, some parts of it are required for loading future parts. Therefore, there are portions of the bootstrap process that rely on it being already available and still mutable. This is for example the error handling configuration and the logging configuration.

Extension code reads from this array directly, and is responsible for its own default and type safety handling at each call site.

There is no built-in environment specific “switch” for dev/test/prod or similar for configuration that does need to vary in that regard. Different extensions roll their own in various ways.

Some of the configuration specified here is callbacks or other executables that get used at random places in the code. This includes the old “hooks” system, but not exclusively that, technically.

Configuration here is mostly not editable from the UI, except for some basic settings in the Install Tool section. Those require the install tool writing back to the LocalConfiguration.php file.

Benefits

  • Both extensions and site admins get “free reign” to adjust the system configuration as they see fit.
  • There’s a single, relatively simple mechanism to consider. (Simple in the naive sense, not in the resulting usage sense.)

Drawbacks

  • It’s extremely hard to document.
  • It’s extremely hard to learn; the developer has no built-in way to “learn as they do” through, eg, IDE autocomplete or inline documentation.
  • It’s not self-documenting or self-enforcing, meaning data in it is never guaranteed to be even remotely close to the structure or type that is expected.
  • The previous point means error handling must be implemented at every single read-point. (The majority of PHP 8.0 compatibility issues were caused by this point.)
  • Because it mostly happens at runtime, the cost of building the array is born on every request.
  • Because it mostly happens at runtime, the memory overhead of a giant global array is born on every request.
  • Environment-specific information (DB credentials, API keys, error reporting, etc.) is comingled with environment-agnostic information (backend configuration, site name, password hashing, form engine configuration, etc.)
  • Information that most sites will want to customize (site name, log configuration, etc.) is comingled with information extremely few sites will want to customize (form engine configuration, HTTP clickjacking protection, etc.)
  • Global variables hinder testing.
  • Global variables reduce flexibility by making it impossible to have two instances of a service with the same code but different configuration.
  • Because the global array is mutable, nothing prevents an extension from altering the global array at any time, making all data in it unreliable. The system is built to enable “Spooky action at a distance” (SAAAD).

ext_conf_template.txt

This file is an alternative way for extensions to provide their own extension-specific configuration. Each extension MAY define this file, which is in a proprietary schema format (see the docs). It allows an extension to define a single logical configuration object, consisting of one or more properties grouped into one or more categories.

This schema is used to auto-generate an admin form for editing the configuration object in the UI.

The resulting configuration object is actually an array, which gets written into $GLOBALS['TYPO3_CONF_VARS']. When that happens, the LocalConfiguration.php file regenerated.

Extensions can read their own configuration through $GLOBALS['TYPO3_CONF_VARS'].

Benefits

  • Extensions get a simple way to define their needed configuration
  • Extensions get an admin UI for free.

Drawbacks

  • Everything described above for $GLOBALS['TYPO3_CONF_VARS'] itself.
  • Proprietary, one-off schema format syntax.
  • Writing back to LocalConfiguration.php means that file has to be mutable at runtime, which is incompatible with many cloud-based hosts or good deployment practices.

Table Configuration Array (TCA)

The TCA serves several parallel purposes. Primarily, its purpose is to define the entire formal data model of the system. It does so at multiple different levels of abstraction, all in a single global array blob.

The TCA definition is used for:

  • Extracting an SQL table definition to auto-create SQL tables.
  • Defining what fields in those tables have special meaning for the system (eg, they’re used for human-readable labels, they’re the primary key, etc.)
  • Defining what fields in those tables carry data.
  • Defining what fields in those tables should have additional validation restrictions beyond what SQL provides (eg, ranges, restricted values, etc.)
  • Defining processing rules on those fields (trimming strings, etc.)
  • Define how a given field should be displayed in the admin UI.
  • Defining complex UI structures (i.e., palettes).
  • Opt-in to advanced functionality like workspaces.
  • And probably other things I am forgetting.

TCA definition is handled by a series of files, and the specifics have varied over time, with some older APIs still remaining. The current version works as follows:

First, a TCA table is defined in Configuration/TCA/<tablename>.php within an extension, and is a giant nested array that gets returned. This file is loaded on every request. Sometimes utility functions are used that will pull from the TYPO3_CONF_VARS configuration to define portions of the array dynamically. (This creates some interesting dependency challenges.)

Second, extensions MAY define a Configuration/TCA/Overrides/<tablename>.php file. This file is loaded if and only if the corresponding table is defined elsewhere. It does not return anything, but is expected to modify the TCA array directly. Usually it does not access the global itself but relies on a series of static methods on the ExtensionManagementUtility class, which in turn will modify the global array. This happens on every request.

There is also an ext_tables.php file for direct modification of the TCA that should be considered deprecated and vestigial.

The TCA data is used for most automation to dynamically build database tables, admin forms, and so forth.

Benefits

  • An abstracted way to define the data model has a number of advantages, in particular the ability to auto-generate storage and forms.
  • Allowing extensions to enhance each other’s tables offers a horizontal extension mechanism, which traditional ORMs (such as Doctrine) cannot easily support.

Drawbacks

  • Most of the drawbacks of TYPO3_CONF_VARS apply here as well: Untyped, hard to document, not self-documenting or self-teaching, no meaningful error handling, etc.
  • Direct mapping of TCA to database tables and fields is both too flexible and too limiting. It makes any kind of table refactoring an automatic API break. At the same time, because the meaning of all fields is dynamic, writing raw SQL becomes inherently unreliable in many to most cases.
  • While horizontal extensibility of data objects at a logical level is a useful feature, doing so at the raw storage level is very brittle. Upgrading data types may sometimes break the data in exciting ways.
  • Uninstalling extensions may leave data flotsam around the database in other extensions’ tables.
  • Information on the data model, the admin form, and the front-end display is all mixed in together with little organization or regard to how it would logically group. That makes the self-documenting problem even worse.
  • Because rendering and admin form information is stored in a single array, there is no way to provide multiple alternate formats for different contexts.

Site configuration

In TYPO3 v11, site configuration is handled by a one-off YAML file. That YAML file is editable through the UI via a custom editing page, but also hand-editable on disk. As it does not use the TYPO3_CONF_VARS array, it is insulated against arbitrary extensions altering it. However, the fact that it is editable both from UI and code creates potential synchronization problems, especially with cloud-based hosts. (More on that later.)

One-off custom stuff

Extensions are free to setup their own tables and write to them themselves if they wish, and some do. Details here vary so it’s difficult to say anything more detailed.

In particular, extensions MAY ship an ext_tables.sql file. This file contains MySQL-specific syntax for table creation (and only table creation). It is not executed directly, however, but custom-parsed and converted into Doctrine table definitions, which are then used to populate the database. The Doctrine table representation is used for automatic migrations and schema updates where possible.

If a table is mentioned in the TCA array and also in ext_tables.sql, a series of additional control columns will be added to the table definition by TCA. (See the docs for the full list.)

Extensions may also include an ext_tables_static+adt.sql file, which is a raw SQL dump that will be imported directly without processing.

Benefits

  • Extensions are free to do whatever works for them.
  • Doctrine table updates make some (but not all) extension updates straightforward and often no-effort in simple cases.

Drawbacks

  • This can be a lot of work for extension authors setting up custom tables, forms, and workflows that they shouldn’t need to spend.
  • Extension authors need to create a lot of files to create or extend database tables (either managed via TCA or not), which need to be kept in sync (ext_tables.sql and TCA).
  • Configuration stored in the database is not deployable from dev/staging to production.
  • This information is entirely opaque from any common automation mechanisms.

Container configuration

Both TYPO3 core and any extension may include a Services.yaml file, which is used by the Symfony Dependency Injection Container to configure the container. This is a different form of configuration than the others listed here, but is still technically a form of configuration. In some systems (such as Symfony framework itself), the main configuration system feeds into the Container configuration as additional constructor arguments to various services.

Benefits

  • As the container is compiled, that has the advantage of practically no runtime overhead to configuration.
  • A cleanly injected system is, by definition, highly reconfigurable. It also encourages highly-testable code.

Drawbacks

  • The “inject into container” approach has scaling limitations when done with primitive values.
  • Reconfiguring the container, outside of specific injection points as noted above, can be a very cumbersome and error-prone process, especially if multiple extensions try to manipulate the same definition.

Types of configuration

The above status quo is highly suboptimal. From people I’ve spoken to about it there doesn’t seem to be much disagreement about that. How to turn it into something more optimal is a more interesting question. It starts, of course, with determining what would be more optimal.

In abstract terms, I want to lay out the different categories of configuration, as they apply to any system. As one would expect, there is some overlap between different categories because software development is hard. (This list is heavily based on my earlier talk on “Building a Cloud-Friendly Application,” (slides, video) and the experience of watching Drupal build a configuration system ground up from a very similarly disjointed status quo.)

Global Per-install application configuration

Application configuration is configuration that applies to a given install, and to all copies of that install. Examples include the site name, the template engine in use, the form engine configuration, etc.

Depending on the system, sometimes this information is configured by a site administrator via code, and other times via a UI of some kind. Both have their pros and cons, but the major difference is that code-based configuration is very easy to deploy via Git, and UI-based configuration is extremely hard to deploy via Git. “Deploy via Git” in this case includes cloud-based web hosts, which are an increasingly significant part of the market and so compatibility with them is a must-have for any modern system.

While there are ways to “have your cake and eat it too” in this regard, they tend to be highly complex. Drupal, for instance, has an elaborate system of importing and exporting configuration between a database key/value blob and YAML files. The YAML files are Git-deployable, and then synchronized with the database blobs. At runtime, the code reads from the database blobs only. The code to manage that is highly non-trivial.

Instantiated per-install application configuration

This class of configuration has most of the same properties as global configuration, but may appear an arbitrary number of times. For example, the site name is a global configuration value, as it appears only once. Configuration of a particular language is an instantiated configuration, as there may be any number of languages defined on a particular install, each with its own unique identifier and settings.

All deployment questions that apply to global application configuration also apply to instantiated configuration just the same.

I would argue that content type definitions should be in this category, although currently TCA is effectively in the previous category.

Environment-specific configuration

Environment-specific configuration is what it says on the tin: configuration that is specific to a given environment, and thus MUST change from production to staging to local-laptop environments. Examples here include database credentials, API keys, search server or cache server credentials, etc.

Environment configuration that lives in Git is an error. Always. Doing so hinders compatibility with cloud-based hosts, as in those situations the number and configuration of different environments is dynamic. The industry standard way to manage such configuration is via .env files, for which there are ample existing libraries. The .env file is not committed to Git but used on development environments only. In test, stage, and production environments the Unix environment variables are read directly instead.

(There are a few systems that work by storing the .env file in Git, and providing an additional .env.local or similar file to override it, because the .env file contains some non-env-specific configuration as well. Symfony is one such system. Such systems are wrong.)

A popular alternative way to provide environment-specific information is a dedicated executable file (PHP in our case), which is not committed to Git and can either contain hard coded values or bridge to env vars, as appropriate. That is effectively what AdditionalConfiguration.php is today, although somewhat clunkily implemented.

I would argue that such an executable override file is mandatory for dealing with cloud-based hosts. Cloud hosts often have their own environment variable format, so some degree of glue code to shuffle that into the format the application expects is necessary.

An interesting intersection here is environment-specific instantiated configuration. For example, sites configuration includes a domain name or path root for each site. However, that information necessarily varies from one environment to another.

The information currently exposed by the Environment class falls into this category, but is only a subset of this category.

Environment-type specific configuration

This isn’t really a type unto itself per se. There are many cases where application-level configuration should also vary by environment, but not because of details external to the environment (eg, connected services). Examples here include

  • Disabling caching in dev but enabling it in staging/prod.
  • Appending “DEVELOPMENT” to the site name in non-prod environments to remind you of which site you’re on (so you don’t do something on prod you don’t intend to).
  • Adding debugging symbols to generated output, such as templates.
  • Changing error reporting from very verbose (dev) to log-only (prod).
  • Enabling deprecation warnings (dev) or not (prod).
  • Etc.

The most common approach here is to have configuration defined in “chunks”, and allow each chunk to be overridden per-environment with extra config files. The chunk size can vary from an individual property to a large portion of the configuration depending on the system. Symfony is the most commonly recognized example here, with a common configuration directory of YAML files and then separate dev, test, prod directories that can per-property override some value. The env-directory values override those in the base configuration.

Instance-specific state

This is not really configuration, but is sometimes conflated with it so I mention it for completeness. It is common to have non-content state data that is distinct from configuration, and is specific to a given copy of an application. The most natural example here is flood control, where event data has to be tracked in a given instance at reasonably high speed, but that information should absolutely not be replicated to other instances (dev, staging, etc.), and deployment is irrelevant.

Summary

Putting all of that together, then, we end up with a series of permutations of configuration.

  • GUI editable, Admin editable
  • Git deployable, not Git deployable
  • Environment-specific, Environment-type-specific, Environment-global
  • Instantiated, global

That is 2x2x3x2 or 24 possible categories of configuration. Supporting all of them is, I would argue, both unwise and unnecessary. Some combinations are just impractical to implement, and others are possible, but unnecessary in certain types of systems.

Attributes of an ideal configuration system

In a perfect world, we would be able to have all of the following attributes in a configuration system:

Type safe with defaults

As a general rule, the more validation you can push to the language syntax the less code you need and the fewer opportunities there are for bugs to appear. The difference between an integer and an array is quite significant, and random nulls popping up in unexpected places is the source of a huge number of bugs.

Ideally, by the time you are reading a piece of configuration your code should be able to rely on it existing, of the right type, and have a valid value, even if that value is a default.

By necessity, this requires explicitly pre-defining the structure of configuration.

Self-documenting

In addition to type safety, ideally configuration structures are self-documenting. That applies both for those setting configuration and those reading configuration (i.e., code).

On the read side, explicit typing covers this fairly well. Combined with any reasonable IDE, explicit types with a few well-placed code comments make this a solved problem.

On the authoring side, if configuration is done through the GUI, the GUI is responsible for providing good documentation. If configuration is done through files, it becomes a more difficult question as most config file formats are not particularly self-documenting. XML is least-bad here because it can have a schema. YAML is the worst as it has no official schema, although JSON Schema can sometimes be used in a pinch. Not many IDEs read that, however. (There is https://www.schemastore.org/, which is used by VS Code and PHPStorm, but it’s still less than ideal.)

HIgh speed reads

Configuration, by design, changes rarely. Therefore it’s write speed is not particularly important. Read speed, however, is critical, as whatever the read cost is will be born on every request. (This is more of an issue in PHP than other languages thanks to its shared-nothing design.)

That means while configuration may be editable in some human-friendly format like YAML, at runtime it needs to be read from something faster. Hard-coded PHP itself is the fastest option, if that can be pulled off.

Low memory consumption

Configuration data is data that takes up memory in the process. The more of it you have, the more memory it consumes. Memory usage should be kept as low as possible, but not to the point that it hinders other factors.

Of note here, objects are substantially more memory efficient than PHP arrays (about twice as efficient, in fact). Arrays stored completely statically in code are even more memory efficient, as their cost is born only once rather than per-process, if and only if their data is never duplicated into process memory, even accidentally. (That’s easy to do accidentally.)

Scope-local

While configuration state is to an extent naturally global, that is undesirable from a code perspective. A given code component (class or otherwise) should never be reading from global values directly. Instead, it should have meaningful values passed to it, dependency-injection style. That has two benefits:

  • It’s trivial to create two or more copies of a class with different configuration, even if only one of them comes from the global configuration definition.
  • It’s trivial to test a given component under a variety of configuration settings.

This point holds regardless of whether the data is clustered into objects or passed as primitives.

Read-time immutable

Spooky action at a distance is something to avoid, generally speaking. That means it’s best to avoid allowing a particular piece of code at runtime to modify the configuration for its request only. That breaks all sense of encapsulation, memoization, caching, and basic predictability. While this is rarely done, it’s something that should not be allowed as it can create all kinds of exciting race conditions.

Easily editable

The easiest way to change settings is through a GUI, with nice user-friendly messages, documentation, and validation.

Easily versionable/deployable

If configuration is edited via files on disk, this becomes trivial. There may be a compile step to turn an editable file into a fast-read format (eg, container configuration, perhaps even code generation), but as long as that can be reproduced from the sources on demand that’s a minor issue.

As noted above, this attribute is, usually, mutually exclusive with “Easily editable.”

Intermission

If you’ve actually read this far, you have my thanks and appreciation. It’s been a ride. :slight_smile: My intent is to ensure that everyone is on the same page and speaking about the same problem space the same way.

As this is already rather, um, long, I am going to pause here. In a day or two I’ll post another follow up with possible directions we can take and my recommendations around them. Stay tuned.

(In the meantime, if there’s nuance or detail you can add to the above, or wacky things you do in extensions that you’d like a better solution for, this is the place to mention it!)

First comment after reading the first few lines about LocalConfiguration and AdditionalConfigration.
I’m pretty sure you mixed those two up.

LocalConfiguration is generated and written by the Install Tool.
AdditionalConfiguration is not generated by default (ddev does so to override DB settings in some cases) and is never written to by any code in TYPO3.

Whether either of those should or shoud not be in GIT depends on the use-case. I do not dare to give a general recommendation on this. Never. I can’t even make up a general rule for our projects, it’s always different.

That’s what I said, isn’t it? I skipped over AdditionalConfiguration.php being optional, I think, but LocalConfiguration.php is created by the Install Tool by copying over FactoryConfiguration.php as a template.

Side note: there’s also an API to read / write this configuration, the \TYPO3\CMS\Core\Configuration\ExtensionConfiguration::class.

Thank you for that essay! I welcome your cloud-perspective with focus on (im)mutability and hope you can advocate it.

There are some parts that seem solved in TYPO3 that you might have missed so I would like to have commented at that line. Maybe we could put it up as a Google Doc with allowed commenting?

One example is the TYPO3_CONTEXT context/subcontexts which are worth mentioning at “Environment-type specific configuration” in my opinion.

That’s incorrect. It simply loads every file in this folder. The naming schema is only a convention.
$finder = Finder::create()->files()->sortByName()->depth(0)->name('*.php')->in($package->getPackagePath() . 'Configuration/TCA/Overrides');

Moreover, the whole TCA is cached, see \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::loadBaseTca. So your statement about the various TCA files being loaded on every request is not quite true.

Thanks for the overview, but I think in terms of configuration I would add three more candidates:

  • Templates
  • Page TSconfig
  • User TSconfig

In terms of what I would like to see improved is this:
(I use different phrases from what you used above, those are more taken from the practical sphere.)
I see the current TYPO3 configuration options in these levels:

  • TYPO3_CONV_VARS: installation-wide settings
  • TCA: installation-wide data-settings
  • Site configuration: settings per individual website inside the installation, valid for FE and BE
  • Page TSconfig: settings per page(!) valid for BE only
  • User TSconfig: settings per user/group, valid for BE only (overriding page TSconfig)
  • Template: settings per page(!) valid for FE only

All of this configuration can already be stored in files, so cloud-readiness is there.

What should be improved is the scope of TCA (specifically in conjunction with Extbase). “TCA does too much” and “TCA does not enough” is true in the same moment.
For some use cases TCA should be site-specific. (currently a workaround with page TSconfig exists, to partially mangle TCA in the scope of a page)

Specifically in complex multi-site installations, the TYPO3_CONV_VAR should actually be site-specific as well. (Different sites could use different MAIL configuration, could use different image processing, etc.)

Of course all your points about storage format, syntax, compilability, etc. still apply.

Hm, I hadn’t even gotten into TypoScript, honestly. I still don’t really grok that thing. :slight_smile:

Per-site configuration is an interesting problem space. Per-page gets even fuglier. The part 2 writeup (which I’ve already written) doesn’t account for those, which creates an interesting problem space. I suspect none of what I recommend there will account for them, but the basic tradeoffs will be the same even if we figure out a first-class way to do that.

If we have to have config objects that can vary on an env-type axis, and a site axis, and the site axis is a configuration setting… that gets back into the circular dependency space we very much want to avoid.

“Stored in files” is only part of cloud-readiness. “Those files are read only” is the other side of it, which runs smack into any GUI-based config editing.

I’m confused, though: Why would different sites hosted on the same install need different mail or image backend processing? Wouldn’t it make more sense to make it separate sites at that point? I mean… that would come down to different container configurations per-site, which is where I would draw the line and say “disk is cheap, just make a second install, please.”

I don’t know if we can get away with that, but a major part of design is figuring out what to say No to. :slight_smile:

TCA and Extbase are a complicated beast; I actually want to avoid dealing with those for the moment, because I have other thoughts there that are better handled as part of a content modeling story, not a configuration story. It may leverage the configuration system under the hood, but it would be a separate layer. Let’s deal with that later. (Though I would absolutely agree about “too much” and “not enough” at the same time, in its current state.)

I have a google doc where I wrote this thing in initially, but I am skeptical about splitting the discussion. For now, I think just call things out in the thread.

(Unless people really want me to post a link to a doc instead where people can comment. I’m open to that, but google doc comments are a very ephemeral type of data, so we should expect it to get lost.)

Simple example:
The corporation has its TYPO3 instance, where there are a few special sites (for various purposes) next to the main big website.
The contact forms in the special sites need to send via a specific SMTP server, due to legal reasons.
Splitting those out would cause even more troubles… users need to login on different systems, content sharing is a lot more complicated, etc.

I’m not sure I get the problem: I can modify those files with any GUI locally, once deployed to the cloud, they are readonly.

That’s probably one of the USPs of TYPO3 I would credit the the most. Seriously. This capability has proven “life saver” so many times.

I’m not sure I get the problem: I can modify those files with any GUI locally, once deployed to the cloud, they are readonly.

Correct, but then you need to allow the GUI to change accordingly, so that you cannot make changes in prod-mode. Or if the disk is readonly. Or whatever. That means all the work you put into making those GUIs, which are not all just blindly auto-generated, goes to waste.

If you have a site where a Professional Admin™ is managing it, that person is almost certainly capable of editing a few files and pushing.

On the flipside: On my personal Drupal site (which I barely manage, frankly), I don’t bother with config deployment. I just let it all sit in the DB, because it’s just a blog and doesn’t need fancy pants config staging. If I want to flip a setting, I just flip a setting in the GUI and move on with life. That use case does exist. Are we OK saying we just don’t support it (or don’t support it on cloud hosts)? (Maybe we are; I’m not sure of the answer, just stating the question.)

[Per-page configuration]’s probably one of the USPs of TYPO3 I would credit the the most. Seriously. This capability has proven “life saver” so many times.

I’d argue that means the configuration is in the wrong place to begin with if that’s the case, or you’re doing something that shouldn’t be done. :slight_smile: Please expand on this, though, because that’s the sort of use case I don’t know about, but we do need to surface so we know we can support it, even if differently from how it is supported today. (Per-URL override of any configuration value is… a nightmare I don’t want to think about. Especially if we can find a cleaner alternative.)

Sure, we allow and should allow this. But the only config that TYPO3 has in the database is Template and TSconfig. Both use TypoScript syntax, so it can include files, which is what we always do.

Practical example:

We have a pretty big conference management system for TYPO3. It has a lot of features. One of them is that you can have multiple conferences within the same site. Each conference basically uses a sysfolder to store its records.
Within the Template you define on which conference the site currently should work on, i.e. you define the UID of the so called “conference record”.

For the purpose of showing the conference schedule, there is a handy plugin, which you can place on any page.
Another use case here is that event hosts want to show the schedule of a previous conference on a dedicated page (usually called “Archive”).
All we need to do to enable this is to put an “extension template” on the archive page and configure a different “conference record” UID to use. => the schedule of the previous conference is rendered.

(Keep in mind that this is a very simple example. We could in this case of course extend the plugin to have a selection of available conferences and let the user select this per plugin, but there is “little more” than that, what is possible. :wink: )

So in our eyes: extension templates, hence configuration per page, is damn helpful in many cases.

As mentioned by Markus, you can set storageUids either via TypoScript constants/setup on a page level but additionally also on a per content element level.

Oh and by the way, @crell you also forgot Content Plugin specific configuration (storageFolder, template…), also known as Flexforms :stuck_out_tongue:

I don’t think we have to go down that deep :wink: The infamous intermingled FlexForm structure/data is just an option and can be replaced by other means already. IMHO we should just start recommending the other ways in tutorials and documentation. That level is just in the hands of the integrator.

PageTS/UserTS (officially called “TSConfig”) and TypoScript (officially called “TypoScript template”) are worth noting, though. They are our way to provide configuration that is inherited to subpages. So that’s a powerful, yet difficult beast.

About configuration GUIs (in TYPO3 BE): I think they will always be thwarting the main idea we are tossing around here. Phasing them out (that will be a BIG discussion about onboarding to TYPO3 etc.) or putting big “Rather not use” stickers on them will help IMHO. We had problems with the Site Configuration GUI for example which made for a rough ride for those using it. I think it proves that GUIs are an overhead even for just keeping them in sync with data structure changes.

A note about Site Configuration @crell: They include at least one built-in conditional already: baseVariants and languages->baseVariants for “Environment-type specific configuration”. Just adding that because you wrote “includes a domain name or path root for each site”. These kind of conditionals are present in several places, for example also in TCA types. Not sure if a configuration framework needs to directly cater for it (it does not now).