Resources API 

TYPO3 projects and extensions can reference two types of resource files:

Public resources that should be accessible with a browser, such as CSS and JavaScript files, images and downloads.

Private resources that are used by server-side code, such as templates, configuration files and localization files.

Location for resources in Composer-mode installations 

By default, public resources must be put into the folder Resources/Public of an extension or somewhere within the web root folder in Composer-based installations. Private resources should reside in folder Resources/Private or Configuration of an extension or the folders config/sites or config/system.

Images and downloads may reside in folder public/fileadmin or custom file storage.

Resources in classic mode installations 

In TYPO3 classic mode, all files in extensions are already located within the document root. Restricting resources to default locations in classic mode therefore mainly follows coding guidelines and keeps compatibility with Composer mode.

Classic mode installations should use server side access restriction, for example by using .htaccess or Nginx configurations. .htaccess can be automatically tested and adjusted: Verify webserver configuration (.htaccess).

Configuring the resource folders of a package with resource definitions 

Resource definitions state which folders and files of a package resource identifiers can reference, and which of them TYPO3 publishes to the public/_assets folder.

By default, an extension has two resource definitions: the private folder Resources/Private, and the public folder Resources/Public if it exists. TYPO3 publishes Resources/Public the same way as before resource definitions existed.

Deprecated since version 14.2 Deprecation: #109409 - Access to arbitrary resources in extensions

A resource identifier that references a path of an extension outside its resource definitions triggers a deprecation message. Add a resource definition for the path, or move the file into a folder that is already defined. Configuration files that TYPO3 loads itself, such as YAML files or TypoScript and TSconfig includes, are not affected.

Resource definitions of an extension in Configuration/Resources.php 

To add resource definitions to an extension, create the file Configuration/Resources.php. It returns a closure that receives the Package and returns a list of resource definitions. TYPO3 adds them to the default definitions:

EXT:my_extension/Configuration/Resources.php
<?php

declare(strict_types=1);

use TYPO3\CMS\Core\Package\Package;
use TYPO3\CMS\Core\Package\Resource\Definition\PublicFileDefinition;
use TYPO3\CMS\Core\Package\Resource\Definition\PublicResourceDefinition;
use TYPO3\CMS\Core\Package\Resource\Definition\ResourceDefinition;

return static function (Package $package) {
  return [
    // Published below public/_assets/ in a folder with a hash name
    new PublicResourceDefinition('Build/Public'),
    // Published to public/_assets/my-vendor/my-extension-icons/
    new PublicResourceDefinition(
      relativePath: 'Build/Icons',
      publicPrefix: 'my-vendor/my-extension-icons',
    ),
    // Publishes this one file only
    new PublicFileDefinition(relativePath: 'Build/styles.css'),
    // Private: can be resolved on the server, is never published
    new ResourceDefinition('Build/Templates'),
  ];
};
Copied!
PublicResourceDefinition
A public folder. TYPO3 publishes it below public/_assets, in a folder with a hash as its name, unless publicPrefix names the folder.
PublicFileDefinition
A single public file. TYPO3 publishes it in a folder with a hash as its name, unless publicPrefix names the folder.
ResourceDefinition
A private folder. Resource identifiers can reference its files on the server side, but TYPO3 does not publish it.

The argument publicPrefix of PublicResourceDefinition::__construct() replaces the hash with a fixed path below public/_assets. A fixed public prefix must be unique across all packages. TYPO3 throws an exception if two packages use the same one.

Resource definitions of the project in config/system/resources.php 

The project itself is the virtual package typo3/app. By default, its resource definitions are these public folders:

  • public/_assets
  • public/uploads
  • public/typo3temp/assets

To add resource definitions to the project, create the file config/system/resources.php. The closure receives the virtual package and the path of the public folder relative to the project root. The paths of the definitions are relative to the project root as well:

config/system/resources.php
<?php

declare(strict_types=1);

use TYPO3\CMS\Core\Package\Resource\Definition\PublicResourceDefinition;
use TYPO3\CMS\Core\Package\VirtualAppPackage;

return static function (
  VirtualAppPackage $package,
  string $relativePublicPath,
) {
  return [
    // The folder lies outside the public folder and gets published
    new PublicResourceDefinition('assets/Public'),
  ];
};
Copied!

Do not put files into public/_assets yourself. Keep them in a folder outside the public folder and add a resource definition, so that TYPO3 publishes them. A publisher of a third-party extension can then publish them to another location, for example a CDN. TYPO3 does not publish a folder that is already inside the public folder.

Rules for both files 

  • In Composer mode, TYPO3 is not bootstrapped when it reads these files. Only autoloading works, there is no global state. Use plain PHP, and files inside the package folder.
  • A path must not start or end with a slash, and must not contain ../.
  • After you change a resource definition, run composer dumpautoload in Composer mode, or flush the caches in classic mode.

Referencing private resources on the server side 

The actual directory location where a file can be found varies from installation to installation. It depends on the mode (Composer / Classic) and on certain configuration, for example of the vendor folder. You should therefore avoid using absolute or large relative paths like ../../../../public/_assets/12345.

The EXT: syntax: referencing resources in extensions 

Most API functions in PHP and TypoScript expect files to reside in extensions and accept a syntax such as EXT:my_extension/Resources/Private/Page/Default.html.

They resolve the path internally. my_extension is the extension key as defined in extra.typo3/cms.extension-key in the extension's composer.json, the rest is the relative path from that extension's root folder.

Using API functionality to determine the path to a resource 

In some rare cases you may need the absolute or relative path to a resource from within your code.

GeneralUtility offers utility method GeneralUtility::getFileAbsFileName() to resolve file paths:

packages/my_extension/Classes/Something/MyClass.php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Something;

use TYPO3\CMS\Core\Utility\GeneralUtility;

class MyClass
{
  public function myFunction(): void
  {
    $absoluteFilePath = GeneralUtility::getFileAbsFileName(
      'EXT:my_extension/Resources/Private/SomeFile.xml',
    );
  }
}
Copied!

The Environment PHP API can be used to resolve paths to other locations within the project such as the path to the config folder.

Resource identifiers: referencing files with EXT:, PKG:, FAL: and URLs 

Where TYPO3 resolves a system resource, for example in the TypoScript property includeCSS , in the asset collector, in Fluid or in the PHP API, it accepts these resource identifiers:

PKG:my-vendor/my-extension:Resources/Public/Css/main.css
A file in a package, identified by its Composer name. This works in classic mode as well, if the extension has a composer.json. The EXT: syntax can still be used for extensions.
PKG:typo3/app:public/typo3temp/assets/style.css
A file of the project itself, with the virtual package name typo3/app and a path relative to the project root.
FAL:1:/templates/css/main.css
A file in the file storage with the UID 1.
https://example.org/css/main.css, //example.org/css/main.css or URI:/css/main.css
A URL, a protocol-relative URL, or a URL relative to the current host. An invalid URL never ends up in the HTML. The PHP API, for example the asset collector, throws an exception. The PAGE include properties, such as includeCSS , leave the file out.

Deprecated since version 14.0

Referencing a file by a path relative to the public folder, such as typo3temp/assets/style.css or _assets/vite/foo.css, is deprecated. A path such as fileadmin/file.svg is only resolved in the default file storage, which is configured in $GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir']. Use one of the identifiers above instead.

Referencing public resources 

Public resources such as JavaScript and CSS files are usually referenced using the Asset collector or f.assets.* ViewHelpers.

Public resources should not be referenced by their path in the _assets folder as these paths contain a hash that might change during updates.

Fluid ViewHelper f:uri.resource 

In Fluid you can use the Uri.resource ViewHelper <f:uri.resource> to reference resources. You can then provide the resource path in a data attribute:

packages/my_extension/Resources/Private/Content/Map.fluid.html
<div
  id="myMap"
  data-icon="{f:uri.resource(extensionName: 'my_extension', path: 'Icons/Map/marker.svg')}"
  data-addresses="{f:uri.resource(extensionName: 'my_extension', path: 'XML/addresses.xml')}"
></div>
Copied!

The file paths can then be used within JavaScript:

packages/my_extension/Resources/Public/JavaScript/Content/Map.js
const myMapElement= document.getElementById('myMap');

const addresses = myMapElement.dataset.addresses;
const iconPath = myMapElement.dataset.icon;
Copied!

The ViewHelper f:uri.resource accepts a resource identifier directly in its path attribute (path="PKG:..."). Alternatively, an identifier can be converted into a resource object using f:resource, for example when chaining ViewHelpers:

packages/my_extension/Resources/Private/Content/Map.fluid.html
<f:variable
  name="addresses"
  value="PKG:my-vendor/my-extension:Resources/Public/XML/addresses.xml"
/>
<div
  id="myMap"
  data-addresses="{addresses -> f:resource() -> f:uri.resource()}"
></div>
Copied!

If the assets lie within the same extension you can also use relative paths in the JavaScript and CSS files.

Generating the URL of a public resource in PHP 

To get the URL of a public resource in PHP, resolve its resource identifier with the \TYPO3\CMS\Core\SystemResource\SystemResourceFactory and pass the result to an implementation of \TYPO3\CMS\Core\SystemResource\Publishing\SystemResourcePublisherInterface . It returns a URL that works in Composer and classic mode alike, with a cache buster, because cacheBusting defaults to true:

packages/my_extension/Classes/Controller/MyMapController.php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Controller;

use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\SystemResource\Publishing\SystemResourcePublisherInterface;
use TYPO3\CMS\Core\SystemResource\Publishing\UriGenerationOptions;
use TYPO3\CMS\Core\SystemResource\SystemResourceFactory;

final readonly class MyMapController
{
  public function __construct(
    private SystemResourceFactory $systemResourceFactory,
    private SystemResourcePublisherInterface $resourcePublisher,
  ) {}

  public function getAddressesUrl(ServerRequestInterface $request): string
  {
    $resource = $this->systemResourceFactory->createPublicResource(
      'PKG:my-vendor/my-extension:Resources/Public/XML/addresses.xml',
    );
    return (string)$this->resourcePublisher->generateUri(
      $resource,
      $request,
      new UriGenerationOptions(absoluteUri: true),
    );
  }
}
Copied!

Pass null as request only where there is no request, for example in a console command. Absolute URLs cannot be generated then. To leave out the cache buster, pass new UriGenerationOptions(cacheBusting: false) .

createPublicResource() throws an exception if the resource is not public, for example a Fluid template in Resources/Private. Use createResource() to resolve such a resource, for example to read it on the server side.