---
title: "Creating a custom scheduler task"
manual: "Scheduler"
version: "main"
permalink: "https://docs.typo3.org/permalink/typo3/cms-scheduler:creating-tasks@main"
source: "DevelopersGuide/CreatingTasks/Index.rst"
rendered: "2026-10-03T08:20:15+00:00"
---

# Creating a custom scheduler task {#creating-tasks}

> [!IMPORTANT]
> <!-- TODO: no Markdown rendering for "versionchanged" -->
>
> Custom scheduler tasks can be registered as TCA types in table
> tx_scheduler_task.See also: Changelog Feature: #107526 - Custom TCA types for scheduler tasks.

**Table of contents**

-   [Implementation of a custom scheduler task](https://docs.typo3.org/permalink/typo3/cms-scheduler:implementation-of-a-custom-scheduler-task@main)
-   [Scheduler task registration and configuration](https://docs.typo3.org/permalink/typo3/cms-scheduler:scheduler-task-registration-and-configuration@main)
-   [Providing additional fields for scheduler task](https://docs.typo3.org/permalink/typo3/cms-scheduler:providing-additional-fields-for-scheduler-task@main)

-   [Migration](https://docs.typo3.org/permalink/typo3/cms-scheduler:migration-to-the-tca-registration-for-scheduler-tasks@main)

> [!NOTE]
> **See also**
>
> Symfony console commands can also be executed as scheduler task:
> See [Create and use Symfony commands in TYPO3](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/CommandControllers/Index.html#symfony-console-commands).

## Implementation of a custom scheduler task {#creating-tasks-implementation}

All scheduler task implementations **must** extend
`\TYPO3\CMS\Scheduler\Task\AbstractTask`.

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

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Task;

use MyVendor\MyExtension\BusinessLogic;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Scheduler\Task\AbstractTask;

final class MyTask extends AbstractTask
{
    /**
     * MUST be implemented by all tasks
     */
    public function execute(): bool
    {
        # Dependency injection cannot be used in scheduler tasks
        $businessLogic = GeneralUtility::makeInstance(BusinessLogic::class);
        return $businessLogic->run('arg1', 'arg2', '…');
    }

    public function getAdditionalInformation()
    {
        $this->getLanguageService()->sL('LLL:EXT:my_extension/Resources/Private/Language/locallang.xlf:myTaskInformation');
    }
}

```

A custom task implementation **must** override the method `execute(): bool`.
It is the main method that is called when a task is executed.
This method Should return `true` on successful execution, `false` on error.

> [!NOTE]
> There is no error handling by default, errors and failures are expected
> to be handled and logged by the client implementation.

Method `getAdditionalInformation()` **should** be implemented to provide
additional information in the schedulers backend module.

Scheduler task implementations that provide [additional fields](https://docs.typo3.org/permalink/typo3/cms-scheduler:additional-fields@main)
**should** implement additional methods, expecially `getTaskParameters()`.

## Scheduler task registration and configuration {#creating-tasks-registration}

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

Registering tasks and additional field providers via
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'] has
been deprecated.

Custom scheduler tasks can be registered via TCA overrides, for example in
`EXT:my_extension/Configuration/TCA/Overrides/tx_scheduler_my_task.php`

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

```php
<?php

declare(strict_types=1);

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

defined('TYPO3') or die();

if (isset($GLOBALS['TCA']['tx_scheduler_task'])) {
    ExtensionManagementUtility::addRecordType(
        [
            'label' => 'My Custom Task',
            'description' => 'Description of what this task does',
            'value' => MyTask::class,
            'icon' => 'my-custom-icon',
            'iconOverlay' => 'content-clock',
            'group' => 'my_extension',
        ],
        $GLOBALS['TCA']['tx_scheduler_task']['types']['0']['showitem'],
        [],
        '',
        'tx_scheduler_task'
    );
}

```

> [!TIP]
> Using the `iconOverlay` option on task type registration, an icon
> overlay can be added, which is then displayed in the wizard. This can
> be useful for similar task types that use the same "base" `icon`, but
> still have to be differentiated.

> [!WARNING]
> If your extension overrides the TCA of the scheduler extension, it **must**
> be loaded **after** [`typo3/cms-scheduler`](https://packagist.org/packages/typo3/cms-scheduler), otherwise the
> configuration might take no effect.
>
> See [Extension loading order](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ExtensionArchitecture/BestPractices/ExtensionLoadingOrder.html#extension-loading-order)

## Providing additional fields for scheduler task {#additional-fields}

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

Registering tasks and additional field providers via
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'] has
been deprecated.The AdditionalFieldProviderInterface and
AbstractAdditionalFieldProvider have also
been deprecated.Tasks in general and additional fields for tasks are registered via TCA
instead.See also: Migrating tasks with AdditionalFieldProviders to TCA registration

Additional fields for scheduler tasks are handled via FormEngine and can be
configured via TCA.

If the task should provide additional fields for configuration options in
the backend module, you need to implement a second class, extending
`\TYPO3\CMS\Scheduler\AbstractAdditionalFieldProvider`.

The task needs to be registered via TCA override:

**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,
                execution_details,
                nextexecution,
                --palette--;;lastexecution,
            --div--;core.form.tabs:access,
                disable,
            --div--;core.form.tabs:extended,',
        [],
        '',
        'tx_scheduler_task'
    );
}

```

And implemented the following methods in your scheduler task if needed:

**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, '…');
    }

    /**
     * Set field values from associative array.
     *
     * @param array $parameters Values from TCA fields
     */
    public function setTaskParameters(array $parameters): void
    {
        $this->myField = $parameters['my_extension_field'] ?? '';
        $this->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
    {
        return sprintf(
            'Field: %s, Emails: %s',
            $this->myField,
            $this->emailList
        );
    }
}

```

> [!NOTE]
> Method `getTaskParameters()` should be implemented when
> [migrating tasks](https://docs.typo3.org/permalink/typo3/cms-scheduler:additional-fields-migration@main)
>
> 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.

> [!NOTE]
> **See also**
>
> There are additional examples in described in the
> [Changelog Feature: #107526 - Custom TCA types for scheduler tasks](https://docs.typo3.org/c/typo3/cms-core/main/en-us/Changelog/14.0/Feature-107526-CustomTCATypesForSchedulerTasks.html#feature-107526-1747816234).
