---
title: "SaveToDatabase finisher"
manual: "Form"
version: "13.4"
permalink: "https://docs.typo3.org/permalink/typo3/cms-form:concepts-finishers-savetodatabasefinisher@13.4"
source: "I/Concepts/Finishers/ReadyToUseFinishers/SaveToDatabaseFinisher/Index.rst"
rendered: "2026-10-03T08:24:23+00:00"
---

# SaveToDatabase finisher {#concepts-finishers-savetodatabasefinisher}

The "SaveToDatabase finisher" saves the data of a submitted form into a
database table.

**Table of contents**

-   [Options of the SaveToDatabase finisher](https://docs.typo3.org/permalink/typo3/cms-form:options-of-the-savetodatabase-finisher@13.4)
-   [SaveToDatabase finisher in the YAML form definition](https://docs.typo3.org/permalink/typo3/cms-form:savetodatabase-finisher-in-the-yaml-form-definition@13.4)
-   [Example for adding uploads to ext:news (fal_related_files and fal_media):](https://docs.typo3.org/permalink/typo3/cms-form:example-for-adding-uploads-to-ext-news-fal-related-files-and-fal-media@13.4)
-   [Usage of the SaveToDatabase finisher in PHP code](https://docs.typo3.org/permalink/typo3/cms-form:usage-of-the-savetodatabase-finisher-in-php-code@13.4)
-   [Multiple database operations](https://docs.typo3.org/permalink/typo3/cms-form:multiple-database-operations@13.4)

> [!NOTE]
> This finisher cannot be used from the backend editor. It can only be
> inserted directly into the YAML form definition or programmatically.

> [!IMPORTANT]
> Finishers are executed in the order defined in your form definition.
>
> See [Finisher execution order](https://docs.typo3.org/permalink/typo3/cms-form:concepts-finishers-execution-order@13.4).

## Options of the SaveToDatabase finisher {#apireference-finisheroptions-savetodatabasefinisher-options}

The following options can be set directly in the form definition YAML or
programmatically in the options array:

-   **table**

    -   *Type:* string
    -   *Required:* true

    Insert or update values into this table.

-   **mode**

    -   *Type:* string
    -   *Default:* `'insert'`

    -   **`insert`**

        will create a new database row with the values from the submitted form
        and/or some predefined values. See also [elements](https://docs.typo3.org/permalink/typo3/cms-form:confval-savetodatabasefinisher-elements@13.4) and
        [databaseColumnMappings](https://docs.typo3.org/permalink/typo3/cms-form:confval-savetodatabasefinisher-databasecolumnmappings@13.4).

    -   **`update`**

        will update a given database row with the values from the submitted form
        and/or some predefined values. In this case [whereClause](https://docs.typo3.org/permalink/typo3/cms-form:confval-savetodatabasefinisher-whereclause@13.4) is required.

-   **whereClause**

    -   *Type:* array
    -   *Required:* true
    -   *Default:* `[]`

    This where clause will be used for a database update action.

-   **elements**

    -   *Type:* array
    -   *Required:* true

    Use `options.elements` to map form element values to existing database columns.
    Each key within `options.elements` has to match with a form element identifier.
    The value for each key within `options.elements` is an array with additional information.

-   **elements.\<formElementIdentifier>.mapOnDatabaseColumn**

    -   *Type:* string
    -   *Required:* true

    The value from the submitted form element with the identifier
    `<formElementIdentifier>` will be written into this database column.

-   **elements.\<formElementIdentifier>.skipIfValueIsEmpty**

    -   *Type:* bool
    -   *Default:* `false`

    Set this to true if the database column should not be written if the value from the
    submitted form element with the identifier `<formElementIdentifier>` is empty
    (e.g. for password fields). Empty means strings without content, whitespace is valid content.

-   **elements.\<formElementIdentifier>.hashed**

    -   *Type:* bool
    -   *Default:* `false`

    Set this to true if the value from the submitted form element should be hashed before
    writing into the database.

-   **elements.\<formElementIdentifier>.saveFileIdentifierInsteadOfUid**

    -   *Type:* bool
    -   *Default:* `false`

    By default, the uid of the FAL object will be written into the database column.
    Set this to true if you want to store the FAL identifier
    (e.g. `1:/user_uploads/some_uploaded_pic.jpg`) instead.

    This only applies for form elements which create a FAL object like
    `FileUpload` or `ImageUpload`.

-   **elements.\<formElementIdentifier>.dateFormat**

    -   *Type:* string
    -   *Default:* `'U'`

    If the internal datatype is `\DateTime` (true for the form element types
    `DatePicker` and `Date`), the object needs to be converted into a string.
    This option defines the format of the date. You can use any format accepted by
    the PHP `date()` function.
    Default is `'U'` (Unix timestamp).

-   **databaseColumnMappings**

    -   *Type:* array
    -   *Default:* `[]`

    Use this to map database columns to static values.
    Each key within `options.databaseColumnMappings` has to match an existing database column.
    The value for each key within `options.databaseColumnMappings` is an array with
    additional information.

    This mapping is done *before* the [elements](https://docs.typo3.org/permalink/typo3/cms-form:confval-savetodatabasefinisher-elements@13.4) mapping.
    If you map both, the value from [elements](https://docs.typo3.org/permalink/typo3/cms-form:confval-savetodatabasefinisher-elements@13.4) will override the
    [databaseColumnMappings.\<databaseColumnName>.value](https://docs.typo3.org/permalink/typo3/cms-form:confval-savetodatabasefinisher-databasecolumnmappings-value@13.4) value.

-   **databaseColumnMappings.\<databaseColumnName>.value**

    -   *Type:* string
    -   *Required:* true

    The value which will be written to the database column.
    You can also use the [FormRuntime accessor feature](https://docs.typo3.org/permalink/typo3/cms-form:concepts-finishers-customfinisherimplementations-accessingoptions-formruntimeaccessor@13.4)
    to access properties from the `FormRuntime`, e.g. `{<formElementIdentifier>}`.

-   **databaseColumnMappings.\<databaseColumnName>.skipIfValueIsEmpty**

    -   *Type:* bool
    -   *Default:* `false`

    Set this to true if the database column should not be written if the value from
    [databaseColumnMappings.\<databaseColumnName>.value](https://docs.typo3.org/permalink/typo3/cms-form:confval-savetodatabasefinisher-databasecolumnmappings-value@13.4) is empty.

-   **translation.propertiesExcludedFromTranslation**

    -   *Type:* array
    -   *Default:* `[]`

    Defines a list of finisher option properties that should be excluded from
    translation.

    When specified, the listed properties are not processed by the
    `\TYPO3\CMS\Form\Service\TranslationService` during translation
    of finisher options. This prevents their values from being replaced by
    translated equivalents, even if translations exist for those options.

    This option is usually generated automatically as soon as FlexForm overrides
    are in place and normally does not need to be set manually in the form
    definition.

    See [Skip translation of overridden form finisher options](https://docs.typo3.org/permalink/typo3/cms-form:concepts-finishers-confirmationfinisher-yaml-propertiesexcludedfromtranslation@13.4)
    for an example.

## SaveToDatabase finisher in the YAML form definition {#concepts-finishers-savetodatabasefinisher-yaml}

This finisher saves the data from a submitted form into a database table.

**public/fileadmin/forms/my_form.yaml**

```yaml
identifier: example-form
label: 'example'
type: Form

finishers:
  -
    identifier: SaveToDatabase
    options:
      table: 'fe_users'
      mode: update
      whereClause:
        uid: 1
      databaseColumnMappings:
        tstamp:
          value: '{__currentTimestamp}'
        pid:
          value: 1
      elements:
        textfield-identifier-1:
          mapOnDatabaseColumn: 'first_name'
        textfield-identifier-2:
          mapOnDatabaseColumn: 'last_name'
        textfield-identifier-3:
          mapOnDatabaseColumn: 'username'
        advancedpassword-1:
          mapOnDatabaseColumn: 'password'
          skipIfValueIsEmpty: true
          hashed: true

```

## Example for adding uploads to ext:news (fal_related_files and fal_media): {#concepts-finishers-savetodatabasefinisher-example-news}

**public/fileadmin/forms/my_form_with_multiple_finishers.yaml**

```yaml
-
  identifier: SaveToDatabase
  options:
    -
      table: tx_news_domain_model_news
      mode: insert
      elements:
        my-field:
          mapOnDatabaseColumn: bodytext
        imageupload-1:
          mapOnDatabaseColumn: fal_media
        fileupload-1:
          mapOnDatabaseColumn: fal_related_files
      databaseColumnMappings:
        pid:
          value: 3
        tstamp:
          value: '{__currentTimestamp}'
        datetime:
          value: '{__currentTimestamp}'
        crdate:
          value: '{__currentTimestamp}'
        hidden:
          value: 1
    -
      table: sys_file_reference
      mode: insert
      elements:
        imageupload-1:
          mapOnDatabaseColumn: uid_local
          skipIfValueIsEmpty: true
      databaseColumnMappings:
        tablenames:
          value: tx_news_domain_model_news
        fieldname:
          value: fal_media
        tstamp:
          value: '{__currentTimestamp}'
        crdate:
          value: '{__currentTimestamp}'
        showinpreview:
          value: 1
        uid_foreign:
          value: '{SaveToDatabase.insertedUids.0}'
    -
      table: sys_file_reference
      mode: insert
      elements:
        fileupload-1:
          mapOnDatabaseColumn: uid_local
          skipIfValueIsEmpty: true
      databaseColumnMappings:
        tablenames:
          value: tx_news_domain_model_news
        fieldname:
          value: fal_related_files
        tstamp:
          value: '{__currentTimestamp}'
        crdate:
          value: '{__currentTimestamp}'
        uid_foreign:
          value: '{SaveToDatabase.insertedUids.0}'
    -
      table: sys_file_reference
      mode: update
      whereClause:
        uid_foreign: '{SaveToDatabase.insertedUids.0}'
        uid_local: 0
      databaseColumnMappings:
        pid:
          value: 0
        uid_foreign:
          value: 0

```

## Usage of the SaveToDatabase finisher in PHP code {#apireference-finisheroptions-savetodatabasefinisher}

Developers can create a confirmation finisher by using the key `SaveToDatabase`:

```php
<?php

use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Form\Domain\Finishers\ClosureFinisher;
use TYPO3\CMS\Form\Domain\Model\FormDefinition;
class SomeClass
{
    private function addDeleteUploadsFinisherWithMessage(FormDefinition $formDefinition, string $message)
    {
        $formDefinition->createFinisher('SaveToDatabase', [
            'table' => 'fe_users',
            'mode' => 'update',
            'whereClause' => [
                'uid' => 1,
            ],
            'databaseColumnMappings' => [
                'pid' => ['value' => 1],
            ],
            'elements' => [
                'textfield-identifier-1' => ['mapOnDatabaseColumn' => 'first_name'],
                'textfield-identifier-2' => ['mapOnDatabaseColumn' => 'last_name'],
                'textfield-identifier-3' => ['mapOnDatabaseColumn' => 'username'],
                'advancedpassword-1' => [
                    'mapOnDatabaseColumn' => 'password',
                    'skipIfValueIsEmpty' => true,
                    'hashed' => true
                ],
            ],
        ]);
    }
}

```

This finisher is implemented in `\TYPO3\CMS\Form\Domain\Finishers\SaveToDatabaseFinisher`.

## Multiple database operations {#concepts-finishers-savetodatabasefinisher-multiple}

You can write options as an array to perform multiple database operations.

Usage within form definition.

**public/fileadmin/forms/my_form_with_multiple_finishers.yaml**

```yaml
-
  identifier: SaveToDatabase
  options:
    -
      table: tx_news_domain_model_news
      mode: insert
      elements:
        my-field:
          mapOnDatabaseColumn: bodytext
        imageupload-1:
          mapOnDatabaseColumn: fal_media
        fileupload-1:
          mapOnDatabaseColumn: fal_related_files
      databaseColumnMappings:
        pid:
          value: 3
        tstamp:
          value: '{__currentTimestamp}'
        datetime:
          value: '{__currentTimestamp}'
        crdate:
          value: '{__currentTimestamp}'
        hidden:
          value: 1
    -
      table: sys_file_reference
      mode: insert
      elements:
        imageupload-1:
          mapOnDatabaseColumn: uid_local
          skipIfValueIsEmpty: true
      databaseColumnMappings:
        tablenames:
          value: tx_news_domain_model_news
        fieldname:
          value: fal_media
        tstamp:
          value: '{__currentTimestamp}'
        crdate:
          value: '{__currentTimestamp}'
        showinpreview:
          value: 1
        uid_foreign:
          value: '{SaveToDatabase.insertedUids.0}'
    -
      table: sys_file_reference
      mode: insert
      elements:
        fileupload-1:
          mapOnDatabaseColumn: uid_local
          skipIfValueIsEmpty: true
      databaseColumnMappings:
        tablenames:
          value: tx_news_domain_model_news
        fieldname:
          value: fal_related_files
        tstamp:
          value: '{__currentTimestamp}'
        crdate:
          value: '{__currentTimestamp}'
        uid_foreign:
          value: '{SaveToDatabase.insertedUids.0}'
    -
      table: sys_file_reference
      mode: update
      whereClause:
        uid_foreign: '{SaveToDatabase.insertedUids.0}'
        uid_local: 0
      databaseColumnMappings:
        pid:
          value: 0
        uid_foreign:
          value: 0

```

Usage through code:

```php
<?php

use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Form\Domain\Finishers\ClosureFinisher;
use TYPO3\CMS\Form\Domain\Model\FormDefinition;
class SomeClass
{
    private function addDeleteUploadsFinisherWithMessage(FormDefinition $formDefinition, string $message)
    {
        $formDefinition->createFinisher('SaveToDatabase', [
            'table' => 'fe_users',
            'mode' => 'update',
            'whereClause' => [
                'uid' => 1,
            ],
            'databaseColumnMappings' => [
                'pid' => ['value' => 1],
            ],
            'elements' => [
                'textfield-identifier-1' => ['mapOnDatabaseColumn' => 'first_name'],
                'textfield-identifier-2' => ['mapOnDatabaseColumn' => 'last_name'],
                'textfield-identifier-3' => ['mapOnDatabaseColumn' => 'username'],
                'advancedpassword-1' => [
                    'mapOnDatabaseColumn' => 'password',
                    'skipIfValueIsEmpty' => true,
                    'hashed' => true
                ],
            ],
        ]);
    }
}

```

This performs 2 database operations.

One insert and one update.

You can access the inserted UIDs through '{SaveToDatabase.insertedUids.\<theArrayKeyNumberWithinOptions>}'
If you perform an insert operation, the value of the inserted database row will be stored within the FinisherVariableProvider.
\<theArrayKeyNumberWithinOptions> references to the numeric options.\* key.
