---
title: "Migration to the TCA registration for scheduler tasks"
manual: "Scheduler"
version: "main"
permalink: "https://docs.typo3.org/permalink/typo3/cms-scheduler:task-migration@main"
source: "DevelopersGuide/CreatingTasks/Migration.rst"
rendered: "2026-10-08T06:49:14+00:00"
---

# Migration to the TCA registration for scheduler tasks {#task-migration}

<!-- TODO: no Markdown rendering for "deprecated" -->

Registering tasks via
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'] has
been deprecated. It will stop working in TYPO3 v16.

<!-- TODO: no Markdown rendering for "versionchanged" -->

\TYPO3\CMS\Scheduler\AdditionalFieldProviderInterface and
\TYPO3\CMS\Scheduler\AbstractAdditionalFieldProvider were
removed.

Tasks in general and additional fields for tasks are registered via TCA.

**Table of contents**

-   [Migrating tasks with AdditionalFieldProviders to TCA registration](https://docs.typo3.org/permalink/typo3/cms-scheduler:migrating-tasks-with-additionalfieldproviders-to-tca-registration@main)

## Migrating tasks with AdditionalFieldProviders to TCA registration {#additional-fields-migration}

Scheduler tasks should now be registered as native task types using TCA.
This provides a more integrated and maintainable approach to task configuration.

### Migration steps: {#additional-fields-migration-steps}

1.  Remove the registration from [`ext_localconf.php`](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ExtensionArchitecture/FileStructure/ExtLocalconf.html#file-extension-ext-localconf-php)
1.  Create a TCA override file in [`Configuration/TCA/Overrides/scheduler_my_task_type.php`](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ExtensionArchitecture/FileStructure/Configuration/TCA/Index.html#file-extension-configuration-tca-overridessomefile-php)
1.  Update your task class to implement the new parameter methods
1.  Remove the `AdditionalFieldProvider` class if it exists

> [!NOTE]
> The new TCA-based approach automatically migrates existing task data.
> When upgrading, existing task configurations are preserved through the
> `getTaskParameters()` and `setTaskParameters()` methods.

### Example migration: Scheduler task with additional fields suppporting TYPO3 13 and 14 {#additional-fields-migration-example}

Remove the registration from [`ext_localconf.php`](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ExtensionArchitecture/FileStructure/ExtLocalconf.html#file-extension-ext-localconf-php) once TYPO3 13 support is
dropped:

**packages/my_extension/ext_localconf.php**

```php
<?php

declare(strict_types=1);

use MyVendor\MyExtension\Task\MyTask;

if ((new \TYPO3\CMS\Core\Information\Typo3Version())->getMajorVersion() < 14) {
    // Todo: Remove when TYPO3 13 support is dropped
    $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][MyTask::class] = [
        'extension' => 'my_extension',
        'title' => 'LLL:EXT:my_extension/Resources/Private/Language/locallang.xlf:myTask.title',
        'description' => 'LLL:EXT:my_extension/Resources/Private/Language/locallang.xlf:myTask.description',
        'additionalFields' => \MyVendor\MyExtension\Task\MyTaskAdditionalFieldProvider::class,
    ];
}

```

And also remove the `MyTaskAdditionalFieldProvider` class once
TYPO3 13 support is dropped.

Create a TCA override file in [`Configuration/TCA/Overrides/scheduler_my_task_type.php`](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ExtensionArchitecture/FileStructure/Configuration/TCA/Index.html#file-extension-configuration-tca-overridessomefile-php):

**EXT:my_extension/Configuration/TCA/Overrides/scheduler_my_task_type.php**

```php
<?php

declare(strict_types=1);

use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use MyVendor\MyExtension\Task\MyTask;

defined('TYPO3') or die();

if (isset($GLOBALS['TCA']['tx_scheduler_task'])) {
    // Add custom fields to the tx_scheduler_task table
    ExtensionManagementUtility::addTCAcolumns(
        'tx_scheduler_task',
        [
            'my_extension_field' => [
                'label' => 'LLL:EXT:my_extension/Resources/Private/Language/locallang.xlf:field.label',
                'config' => [
                    'type' => 'input',
                    'size' => 30,
                    'required' => true,
                    'eval' => 'trim',
                    'placeholder' => 'Enter value here...',
                ],
            ],
            'my_extension_email_list' => [
                'label' => 'LLL:EXT:my_extension/Resources/Private/Language/locallang.xlf:emailList.label',
                'config' => [
                    'type' => 'text',
                    'rows' => 3,
                    'required' => true,
                    'placeholder' => 'admin@example.com',
                ],
            ],
        ]
    );

    // Register the task type
    ExtensionManagementUtility::addRecordType(
        [
            'label' => 'Some title or LLL:EXT reference',
            'description' => 'Some description or LLL:EXT reference',
            'value' => MyTask::class,
            'icon' => 'mimetypes-x-tx_scheduler_task_group',
            'iconOverlay' => 'content-clock',
            'group' => 'my_extension',
        ],
        '
            --div--;core.form.tabs:general,
                tasktype,
                task_group,
                description,
                my_extension_field,
                my_extension_email_list,
            --div--;core.form.tabs:timing,
                --palette--;;execution,
            --div--;core.form.tabs:access,
                disable,
            --div--;core.form.tabs:extended,',
        [],
        '',
        'tx_scheduler_task'
    );
}

```

Update your (existing) task class to implement the new methods:

**packages/my_extension/Classes/MyTask.php**

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Task;

use MyVendor\MyExtension\BusinessLogic;
use TYPO3\CMS\Core\Messaging\FlashMessage;
use TYPO3\CMS\Core\Messaging\FlashMessageService;
use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Scheduler\Task\AbstractTask;

final class MyTask extends AbstractTask
{
    protected string $myField = '';
    protected string $emailList = '';

    public function execute(): bool
    {
        # Dependency injection cannot be used in scheduler tasks
        $businessLogic = GeneralUtility::makeInstance(BusinessLogic::class);
        return $businessLogic->run($this->myField, $this->emailList, '…');
    }

    /**
     * Return current field values as associative array.
     * This method is called during migration from old serialized tasks
     * and when displaying task information.
     */
    public function getTaskParameters(): array
    {
        return [
            'my_extension_field' => $this->myField,
            'my_extension_email_list' => $this->emailList,
        ];
    }
    /**
     * Set field values from associative array.
     * This method handles both old and new parameter formats for migration.
     *
     * @param array $parameters Values from either old AdditionalFieldProvider or new TCA fields
     */
    public function setTaskParameters(array $parameters): void
    {
        // Handle migration: check old parameter names first, then new TCA field names
        $this->myField = $parameters['myField'] ?? $parameters['my_extension_field'] ?? '';
        $this->emailList = $parameters['emailList'] ?? $parameters['my_extension_email_list'] ?? '';
    }

    /**
     * Validate task parameters.
     * Only implement this method for validation that cannot be handled by FormEngine.
     * Basic validation like 'required' should be done via TCA 'eval' configuration.
     */
    public function validateTaskParameters(array $parameters): bool
    {
        $isValid = true;

        // Example: Custom email validation (beyond basic 'required' check)
        $emailList = $parameters['my_extension_email_list'] ?? '';
        if (!empty($emailList)) {
            $emails = GeneralUtility::trimExplode(',', $emailList, true);
            foreach ($emails as $email) {
                if (!GeneralUtility::validEmail($email)) {
                    GeneralUtility::makeInstance(FlashMessageService::class)
                        ->getMessageQueueByIdentifier()
                        ->addMessage(
                            GeneralUtility::makeInstance(
                                FlashMessage::class,
                                'Invalid email address: ' . $email,
                                '',
                                ContextualFeedbackSeverity::ERROR
                            )
                        );
                    $isValid = false;
                }
            }
        }

        return $isValid;
    }
    public function getAdditionalInformation(): string
    {
        $info = [];
        if ($this->myField !== '') {
            $info[] = 'Field: ' . $this->myField;
        }
        if ($this->emailList !== '') {
            $info[] = 'Emails: ' . $this->emailList;
        }
        return implode(', ', $info);
    }

}

```

The new TCA-based approach uses three key methods for parameter handling:

-   ****getTaskParameters(): array****

    This method is already implemented in `AbstractTask` to handle task class
    properties automatically, but can be overridden in task classes for custom
    behavior.

    The method is primarily used:

    -   For migration from old serialized task format to new TCA structure
    -   For non-native (deprecated) task types to store their values in the legacy `parameters` field

    For native TCA tasks, this method is typically no longer needed in custom
    tasks after the migration has been done, since field values are then stored
    directly in database columns.

-   ****setTaskParameters(array $parameters): void****

    Sets field values from an associative array. This method handles:

    -   Migration from old AdditionalFieldProvider field names to new TCA field names
    -   Loading saved task configurations when editing or executing tasks
    -   Parameter mapping during task creation and updates
    -   The method should always be implemented, especially for native tasks

    The migration pattern is: `$this->myField = $parameters['oldName'] ?? $parameters['new_tca_field_name'] ?? '';`

-   ****validateTaskParameters(array $parameters): bool****

    *Optional method.* Only implement this for validation that cannot be handled by FormEngine.

    -   Basic validation (required, trim, etc.) should be done via TCA configuration (`required` property and `eval` options)
    -   Use this method for complex business logic validation (e.g., email format validation, external API checks)
    -   Return `false` and add FlashMessage for validation errors
    -   FormEngine automatically handles standard TCA validation rules

For a complete working example, see `\TYPO3\CMS\Reports\Task\SystemStatusUpdateTask`
and its corresponding TCA configuration in
[`EXT:reports/Configuration/TCA/Overrides/scheduler_system_status_update_task.php`](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ExtensionArchitecture/FileStructure/Configuration/TCA/Index.html#file-extension-configuration-tca-overridessomefile-php).
