Modern TypoScript conditions help you write cleaner, safer, and more maintainable TYPO3 configuration. This guide is built as a practical cheatsheet, focused on real-world examples using Symfony Expression Language for fast copy-paste and immediate use.
Modern TypoScript conditions help you write cleaner, safer, and more maintainable TYPO3 configuration. This guide is built as a practical cheatsheet, focused on real-world examples using Symfony Expression Language for fast copy-paste and immediate use.
Since TYPO3 v9.4 LTS, Symfony Expression Language powers modern TypoScript conditions and replaces legacy syntax. If you work with TYPO3 daily, you already know how critical conditions are for controlling rendering, environments, and behavior across projects.
Instead of theory, this guide focuses on how modern TypoScript conditions actually work, including variables, functions, custom conditions, and common pitfalls.
In this guide, we will walk through everything you need to use TypoScript conditions correctly, confidently, and upgrade-safe.
TypoScript Conditions Cheatsheet (Quick Reference)
| Use Case | TypoScript Condition | Context |
| Check site language ID | [siteLanguage("languageId") == 1] | FE |
| Check site language title | [siteLanguage("title") == "English"] | FE |
| Check page UID | [page["uid"] == 17] | FE |
| Check multiple pages | [page["uid"] in [17,24]] | FE |
| Check page backend layout | [page["backend_layout"] == 1] | FE |
| Check root page | [tree.level == 0] | FE |
| Check if page is in rootline | [2 in tree.rootLineIds] | FE |
| Check frontend user logged in | [frontend.user.isLoggedIn] | FE |
| Check backend user logged in | [backend.user.isLoggedIn] | BE |
| Check backend admin user | [backend.user.isAdmin] | BE |
| Check application context | [applicationContext == "Development"] | FE / BE |
| Check production environment | [applicationContext matches "#^Production#"] | FE / BE |
| Check TYPO3 version | [compatVersion("11.5")] | FE / BE |
| Check domain / host | [like(request.getNormalizedParams().getHttpHost(), "*.example.com")] | FE |
| Check HTTPS | [request.getNormalizedParams().isHttps()] | FE |
| Check query parameter | [request.getQueryParams()['foo'] == 1] | FE |
| Check current weekday | [date("w") == 5] | FE |
| Check site identifier | [site("identifier") == "mysite"] | FE |
| Check workspace | [workspace.isLive] | FE / BE |
| Check frontend user group | [usergroup("12")] | FE |
TYPO3 Version Compatibility for Symfony TypoScript Conditions
Symfony Expression Language–based TypoScript conditions are the modern, supported way to write conditions in TYPO3. They replace legacy condition syntax and are stable across current LTS versions.
TYPO3 Versions That Support Symfony TypoScript Conditions
| TYPO3 Version | Support | Notes |
| TYPO3 8 LTS | No | Legacy TypoScript conditions only |
| TYPO3 9.0–9.3 | No | Symfony Expression Language not available |
| TYPO3 9.4 LTS | Yes | First release with modern conditions |
| TYPO3 10 LTS | Yes | Fully stable |
| TYPO3 11 LTS | Yes | Recommended for production |
| TYPO3 12 LTS | Yes | Current best practice |
Deprecated vs Recommended Condition Syntax
- Legacy conditions ([globalVar], [userFunc]) are deprecated
- Symfony-based conditions are:
- Forward-compatible
- Upgrade-safe
- Actively maintained
Use only Symfony Expression Language for new and updated projects.
Migration & Upgrade Guidance
- TYPO3 ≤ 8
Upgrade required before using modern conditions - TYPO3 9.0–9.3
Refactor conditions before upgrading - TYPO3 ≥ 9.4
Use Symfony-based conditions exclusively
Enterprise Best Practices
- Assume TYPO3 ≥ 9.4 as the baseline.
- Validate conditions during upgrades to:
- TYPO3 11 LTS
- TYPO3 12 LTS
- Never mix legacy and modern condition syntaxes
Symfony Expression Language in TYPO3 TypoScript Conditions
TYPO3 integrates selected Symfony components to strengthen its core architecture without adding unnecessary complexity.
- The components, such as Console, Routing, YAML, PropertyAccess, and ExpressionLanguage, are deeply embedded in the TYPO3 Core and designed for long-term stability.
- Symfony Expression Language provides a compact, readable way to evaluate logical expressions that return a value, most commonly booleans.
- TYPO3 uses this component to power modern TypoScript conditions, replacing fragmented legacy syntax with a unified expression model.
- Since TYPO3 v9.4 LTS, Symfony Expression Language is the foundation for TypoScript conditions in both Frontend and Backend contexts.
Condition logic is exposed through variables and functions, enabling cleaner configuration, easier extension, and fully upgrade-safe custom conditions aligned with TYPO3’s long-term roadmap.
Old vs New TypoScript Conditions (Before & After Comparison)
TYPO3 replaced legacy TypoScript conditions with Symfony Expression Language to introduce a unified, extensible, and future-proof syntax.
Below is a direct before - after comparison, showing how common conditions translate from legacy syntax to modern TYPO3 (≥ 9.4).
Condition Syntax Structure
TYPO3 ≤ 9.3 (Legacy)
Conditions were evaluated individually and chained together.
[condition1] && [condition2]
TYPO3 ≥ 9.4 (Symfony-based)
Conditions are evaluated as a single expression.
[condition1 && condition2]
Language Detection
Legacy
[globalVar = GP:L = 1]
Modern
[siteLanguage("languageId") == 1][siteLanguage("title") == "English"][siteLanguage("locale") == "en_US.UTF-8"]
TypoScript Constants
Legacy
[globalVar = LIT:1 = {$myConstant}]
Modern
[{$myConstant} == 1]
Page UID Checks
Legacy
[globalVar = TSFE:id = 17][globalVar = TSFE:id = 17, TSFE:id = 24]
Modern
[page["uid"] == 17][page["uid"] in [17,24]][getTSFE().id == 17][getTSFE().id in [17,24]]
Page Properties
Legacy
[page|backend_layout = 1]
Modern
[page["backend_layout"] == 1]
Domain / Hostname Checks
Legacy
[globalString = IENV:HTTP_HOST = *.example.com]
Modern
[like(request.getNormalizedParams().getHttpHost(),"*.example.com")]
Date-Based Conditions
Legacy
[dayofweek = 5]
Modern
[date("w") == 5]
Extension / Request Parameters
Legacy
[globalVar = GP:tx_extkey|param > 0]
Modern
[(request.getQueryParams()['tx_extkey'])['param'] > 0]
Why the New Syntax Is Better
- One unified expression language
- Cleaner, more readable conditions
- Supports complex logic (&&, ||, in, regex)
- Enables custom TypoScript conditions
- Consistent behavior across Frontend and Backend
Understanding Variables and Functions in TypoScript Conditions
Modern TypoScript conditions expose variables and functions through Symfony Expression Language. Both are used inside condition expressions, but they serve different purposes.
Variables
Variables represent available runtime data and are used for direct comparisons.
Characteristics
- Read-only
- No arguments
- Context-dependent (FE / BE)
Typical use cases
- Page properties
- Language information
- User state
- Application context
- Site configuration
Example:
[page["uid"] == 1]
Functions
Functions encapsulate logic or processing and may accept parameters.
Characteristics
- Callable expressions
- Accept arguments
- Can return dynamic values
Typical use cases
- Request inspection
- Date evaluation
- Pattern matching
- Version checks
- Environment logic
Example:
[date("w") == 5]
Use variables for simple checks and functions for dynamic or computed conditions. The sections below are grouped accordingly.
Why This Distinction Matters
- Prevents misuse of conditions
- Improves readability in complex setups
- Helps structure custom condition providers
- Makes debugging faster
Available TypoScript Condition Variables
TYPO3 provides a set of built-in variables that can be used directly in modern TypoScript conditions. These variables expose runtime information and are evaluated using Symfony Expression Language.
Each variable below represents a data source, not executable logic.
applicationContext - Application Environment
Returns the current TYPO3 application context as a string.
Common use cases
- Environment-based configuration
- Feature toggles per stage (Dev / Staging / Live)
[applicationContext == "Development"][applicationContext matches "#^Development#"][applicationContext matches "#^Production/Dev#"][applicationContext matches "#^Production/(Dev|Staging)#"][applicationContext matches "#^Production/Live#"][applicationContext == "Production/Live/ClusterServer1"][applicationContext matches "#^Production/Live#" && getTSFE().isBackendUserLoggedIn()][not (applicationContext matches "#Production#")]
page - Page Properties
Provides access to the current page record as an array.
Common use cases
- Page-based rendering logic
- Template or layout switching
[page["pid"] == 2][page["uid"] == 17][page["backend_layout"] == 1]
TypoScript Constants - {$foo.bar}
All TypoScript constants are available inside conditions. Be mindful of data types when comparing values.
[{$foo.bar} == 4711]["{$foo.bar}" == "4711"]
tree - Page Tree Information
Provides access to page tree and rootline data.
Common use cases
- Root page detection
- Section-based configuration
[tree.level == 0][tree.rootLine[0]["uid"] == 1][2 in tree.rootLineIds]
backend - Backend User Context (BE Only)
Exposes backend user information. Available only in Backend context.
[backend.user.isAdmin][backend.user.isLoggedIn][backend.user.userId == 5][like("," ~ backend.user.userGroupList ~ ",", ",1,")]
frontend - Frontend User Context (FE Only)
Exposes frontend user authentication data. Available only in Frontend context.
[frontend.user.isLoggedIn][frontend.user.userId == 5][like("," ~ frontend.user.userGroupList ~ ",", ",1,")]
typo3 - TYPO3 Environment Information
Provides TYPO3 system-level metadata.
[typo3.version == "10.4.2"][typo3.branch == "10.4"][typo3.devIpMask == "192.168.0.100"]
workspace - TYPO3 Workspace Context
Exposes workspace-related information. Primarily used in Backend context.
[workspace.workspaceId == 1][workspace.isLive][workspace.isOffline]
Important Notes
- Variables are read-only
- Availability depends on execution context (FE / BE)
- Prefer variables for simple, deterministic checks
Frontend-Only TypoScript Conditions
Frontend-only conditions are evaluated during Frontend rendering and depend on an active HTTP request and an initialized TSFE (TypoScript Frontend Controller).
If evaluated in Backend, CLI, or Scheduler, these conditions will always resolve to false.
FE Context & Evaluation Lifecycle
Frontend conditions are available:
- After site resolution
- After language resolution
- During page rendering
They rely on:
- Active request object
- Resolved site and language
- Initialized TSFE instance
Frontend User & Authentication Conditions
Used to evaluate frontend user state and permissions.
[frontend.user.isLoggedIn][frontend.user.userId == 5][usergroup("12")][loginUser("*")][loginUser("3,7,9")]
Notes
- usergroup() and loginUser() evaluate FE users only
- Anonymous users always return false
Frontend Page & TSFE-Based Conditions
These conditions rely directly on the TSFE object.
[getTSFE().page["uid"] == 1][getTSFE().id in [17,24]][getTSFE().isBackendUserLoggedIn()]
Notes
- getTSFE() is Frontend-only
- Always evaluates to false in BE or CLI
Frontend Request-Based Conditions
Used to evaluate request data, headers, and routing arguments.
[request.getQueryParams()['foo'] == 1][request.getParsedBody()['foo'] == 1][request.getHeaders()['Accept'] == 'json'][request.getCookieParams()['foo'] == 1][request.getPageArguments().get('foo_id') > 0][request.getNormalizedParams().isHttps()][request.getNormalizedParams().getHttpHost() == "t3planet.com"]
Notes
- Request data is unavailable in CLI
- Use only during FE rendering
Frontend Site & Language Conditions
Available only after site configuration is resolved.
[site("identifier") == "t3terminal"][site("base").getHost() == "t3planet.com"][site("rootPageId") == 1][siteLanguage("languageId") == 0][siteLanguage("locale") == "de_CH"][siteLanguage("title") == "German"]
Notes
- site() and siteLanguage() may return null
- Safe only in FE context
Frontend Session Conditions
Used to read values from the TYPO3 FE session.
[session("session:foo|bar") == 1234567]
Notes
- Requires an active FE session
- Not available in BE or CLI
Backend-Only TypoScript Conditions
Backend-only conditions are evaluated inside TYPO3 Backend context, where TSFE does not exist.
They depend on:
- Authenticated backend user
- Backend request context
- Workspace configuration
Backend User & Permission Conditions
Used to control backend-specific TypoScript logic.
[backend.user.isLoggedIn][backend.user.isAdmin][backend.user.userId == 5][backend.user.userGroupList matches "/,1,/"]
Notes
- backend.user is undefined in FE
- Permission checks are BE-only
Backend Workspace Conditions
Used to differentiate live and non-live workspaces.
[workspace.isLive][workspace.workspaceId == 1]
Notes
- Workspace context exists only in BE
- FE rendering always assumes live workspace
Utility Functions for Frontend & Backend
These functions are context-agnostic but depend on available runtime data.
[date("d.m.") == "05.04.2019"][date("j") == 7][like("foobarbaz", "*bar*")][like("fooBarBaz", "/f[o]{2,2}[aBrz]+/")][traverse(request.getQueryParams(), 'tx_news_pi1/news') > 0][ip("172.18.*")][ip("devIP")][compatVersion("11.5")][getenv("VIRTUAL_HOST") == "t3planet.de"]
Common Errors with TypoScript Conditions
Most TypoScript condition issues fail silently. The following problems account for the majority of real-world bugs.
1. getTSFE() Always Returns false
What happens
Conditions using getTSFE() never match.
Why it happens
- Condition is evaluated in Backend, CLI, or Scheduler context
- TSFE is not initialized
How to avoid
- Use getTSFE() only in Frontend rendering
- Never rely on it in Backend logic
2. Frontend vs Backend Context Confusion
What happens
Conditions always evaluate to false.
Why it happens
frontend.*used in Backendbackend.*used in Frontend
How to avoid
- Keep FE and BE conditions in separate blocks
- Never mix contexts in the same condition
3. site() or siteLanguage() Returns null
What happens
Language or site-based conditions do not match.
Why it happens
- Site configuration not resolved
- Condition evaluated too early or in CLI
How to avoid
- Use site-related conditions only in FE
- Always assume null is possible
4. Type Mismatch (String vs Integer)
What happens
Condition looks correct but never matches.
Why it happens
- Comparing "1" with 1
- TypoScript constants evaluated as strings
How to avoid
- Match data types explicitly
- Be careful with quoted constants
5. Request Data Not Available
What happens
Request-based conditions fail unexpectedly.
Why it happens
- Condition evaluated in CLI or BE
- No HTTP request exists
How to avoid
- Use request.* only in FE
- Avoid during cache warmup or builds
Best Practices & Anti-Patterns for TypoScript Conditions
TypoScript conditions are powerful, but they are configuration tools, not a place for business logic. Using them correctly improves performance, upgrade safety, and long-term maintainability.
Best Practices for TypoScript Conditions
Use TypoScript conditions when you need to control configuration, not application behavior.
Recommended usage
- Enable or disable features
- Switch templates or assets
- Apply environment-specific configuration
- Control rendering based on page, site, or language
Guidelines
- Prefer deterministic checks (page, site, applicationContext)
- Keep expressions short and readable
- Separate Frontend and Backend conditions clearly
- Revalidate all conditions during TYPO3 upgrades (11 LTS, 12 LTS)
Anti-Patterns: When NOT to Use TypoScript Conditions
Avoid TypoScript conditions when logic becomes dynamic, complex, or data-dependent.
Do not use conditions for
- Business rules or workflows
- Complex decision trees
- User-specific personalization logic
- Performance-critical runtime decisions
- External API or service calls
Better alternatives
| Requirement | Recommended Solution |
| Business logic | PHP services |
| Personalization | Controllers / ViewHelpers |
| Runtime decisions | Middleware |
| Feature toggles | Configuration or feature flags |
| Heavy logic | Cached configuration |
Rule of thumb
If a condition:
- Is hard to read
- Needs comments to explain
- Depends on runtime data
It probably does not belong in TypoScript.
Creating Custom TypoScript Conditions with Symfony Expression Language
One of the biggest advantages of modern TypoScript conditions is the ability to define custom conditions. Unlike legacy userFunc–based conditions, Symfony Expression Language allows clean, reusable, and upgrade-safe extensions.
Legacy vs Modern Approach (Quick Context)
TYPO3 ≤ 9.3 (Legacy)
[userFunc = \Vendor\Extension\UserFunc\MyUserFunc('foo')]
TYPO3 ≥ 9.4 (Modern)
[variableA === 'valueB']
Modern conditions are:
- Declarative
- Readable
- Fully integrated into TYPO3 Core
Step 1: Register the Expression Language Provider
Register your custom provider inside the extension configuration.
File: Configuration/ExpressionLanguage.php
<?phpreturn ['typoscript' => [\Vendor\ExtensionName\ExpressionLanguage\CustomTypoScriptConditionProvider::class,]];
This makes your variables or functions available to TypoScript conditions.
Step 2: Implement the Custom Condition Provider
Create a provider that exposes variables to the expression language.
File: Classes/ExpressionLanguage/CustomTypoScriptConditionProvider.php
<?phpnamespace Vendor\ExtensionName\ExpressionLanguage;use TYPO3\CMS\Core\ExpressionLanguage\AbstractProvider;class CustomTypoScriptConditionProvider extends AbstractProvider{public function __construct(){$this->expressionLanguageVariables = ['variableA' => 'valueB',];}}
Key points
- Variables are read-only
- Values should be deterministic
- Avoid runtime-heavy logic here
Step 3: Use the Custom Condition in TypoScript
Once registered, the variable can be used like any built-in condition.
[variableA === 'valueB']page >page = PAGEpage.10 = TEXTpage.10.value = Matched[GLOBAL]
The condition is evaluated using Symfony Expression Language and behaves consistently across TYPO3 versions.
Best Practices for Custom Conditions
- Use custom conditions for configuration decisions only
- Keep logic simple and predictable
- Avoid database queries, API calls, or user-specific data
- Always re-test custom providers during TYPO3 upgrades
Why This Approach Is Preferred
- No deprecated APIs
- Fully compatible with TYPO3 11 & 12
- Cleaner than userFunc
- Easier to maintain in enterprise projects
Advanced Custom TypoScript Conditions with Symfony Expression Language
TYPO3 also allows you to register custom expression functions, not just variables. This is an advanced technique and should be used only when simple variables are not sufficient.
This approach is suitable for:
- Reusable condition logic
- Read-only lookups
- Controlled external checks (with caution)
When to Use a Custom Expression Function
Use a custom function when:
- A condition needs parameters
- Logic cannot be expressed as a static variable
- The result can be treated as configuration data
Do not use this for:
- Business logic
- User-specific decisions
- Performance-critical rendering paths
Step 1: Implement an Expression Function Provider
Create a provider that registers a custom function for TypoScript conditions.
<?phpnamespace Vendor\ExtensionName\TypoScript;use Symfony\Component\ExpressionLanguage\ExpressionFunction;use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;use TYPO3\CMS\Core\Utility\GeneralUtility;class CustomConditionFunctionsProvider implements ExpressionFunctionProviderInterface{public function getFunctions(): array{return [$this->getWebserviceFunction(),];}protected function getWebserviceFunction(): ExpressionFunction{return new ExpressionFunction('webservice',function () {// Compiler not required for TypoScript usage},function ($existingVariables, string $endpoint, int $uid) {return GeneralUtility::getUrl('https://t3planet.de/en/endpoint/' . $endpoint . '/' . $uid);});}}
Important notes
- Only the evaluator is used for TypoScript
- Return values must be predictable
- Avoid slow or unstable endpoints
Step 2: Use the Custom Function in TypoScript
Once registered, the function behaves like a native condition function.
[webservice('pages', 10)]page.10 >page.10 = TEXTpage.10.value = Matched[GLOBAL]
You can also compare the returned value explicitly.
[webservice('pages', 10) === 'Expected title']page.10 >page.10 = TEXTpage.10.value = Matched[GLOBAL]
Key Warnings (Read This Before Using)
- Conditions are evaluated frequently
- External requests can slow down rendering
- Failures may silently break conditions
Best practice
- Cache results aggressively
- Keep functions side-effect free
- Prefer static variables whenever possible
Why This Is an Advanced Pattern
- Powerful but easy to misuse
- Requires strong control over performance
- Best suited for enterprise projects with strict guidelines
If a condition becomes hard to reason about, it likely belongs in:
- PHP services
- Controllers
- Middleware
Conclusion
Modern TypoScript conditions based on Symfony Expression Language are the recommended and future-safe approach for configuring TYPO3 projects. They offer cleaner syntax, better readability, and a consistent evaluation model across Frontend and Backend.
If you’re maintaining existing TYPO3 sites, migrating legacy conditions to modern syntax should be part of every upgrade strategy. This reduces technical debt, prevents silent failures, and keeps your configuration aligned with current TYPO3 standards.
Use TypoScript conditions where they make sense, for configuration, not business logic, and always validate them during major TYPO3 upgrades. With the right structure and discipline, modern conditions become a powerful and reliable tool in everyday TYPO3 development.
FAQs
Modern TypoScript conditions use Symfony Expression Language (introduced in TYPO3 v9.4) to evaluate logic in a single, readable expression. They replace legacy condition syntax and are upgrade-safe.
Legacy conditions like [globalVar] and [userFunc] are deprecated. They may still work in older TYPO3 versions, but should not be used in new projects or upgrades.
Yes, but not all conditions work everywhere. Some are Frontend-only (e.g. getTSFE(), siteLanguage()), while others are Backend-only (e.g. backend.user.*, workspace.*).
getTSFE() is available only during Frontend rendering. If the condition runs in Backend, CLI, or Scheduler context, it will always evaluate to false.
Create custom conditions only for configuration-level decisions that cannot be expressed with built-in variables or functions. Avoid using them for business logic or performance-critical checks.
Yes. TypoScript conditions are evaluated frequently, which is why they should remain simple, deterministic, and fast. Heavy logic or external calls can negatively impact performance.

Wolfgang Weber
Brand & Communication LeadWolfgang Weber shapes TYPO3 with passion and expertise. As TYPO3 enthusiast, he has contributed to TYPO3 projects that make websites faster and more secure. Outside of TYPO3, you'll probably find him exploring local cafés and…
More From Author