TYPO3 Data Seeder 

Extension key

data_seeder

Package name

km2/data-seeder

Version

main

Language

en

Author

KM2 >> GmbH

License

This document is published under the Creative Commons BY-NC-SA 4.0 license.

Rendered

Fri, 31 Jul 2026 09:05:14 +0000

This extension provides the option to import static data sets into the TYPO3 database. This can be used to provide data for development teams or frontend tests. No static UIDs are used.

Introduction 

What is this extension about?

Installation 

Install the data seeder extension.

Configuration 

What configuration options are available?

Commands 

What commands are provided?

Developers 

Developer corner for extending the extension.

Table of Contents

Introduction 

This extension provides the option to import static data sets into the TYPO3 database. This can be used to provide data for development teams or frontend tests.

Motivation 

Working in teams provides some challenges. One of them is the distribution of development data. As there are many ways to tackle this challenge, we decided to provide static data that can grow during project progression and can be handled by VCS.

Installation 

Install km2/data-seeder with Composer 

Install the extension via Composer:

composer req km2/data-seeder
Copied!

See also Installing extensions, TYPO3 Getting started.

Install km2/data-seeder in Classic Mode 

Or download the extension from https://extensions.typo3.org/extension/data_seeder and install it in the Extension Manager.

Quick start 

This extension provides example data for creating a root page with a content element of type text. To trigger the seed, run the following command.

vendor/bin/typo3 database:seed --config "EXT:data_seeder/Resources/Private/Example/seeder.yaml"
Copied!

Configuration file 

This extension requires a configuration file in YAML format. By default the extension is looking for a seeder.yaml file in your projects root directory. This path can be overwritten when running the CLI command.

<project-root>/seeder.yaml
data:
  loader: yaml
  options:
    type: 'folder'
    path: 'data/database/'

fal:
  storages:
    - identifier: default
      storagePath: fileadmin/

ordering:
  fe_users:
    after: [ "fe_groups" ]
  tt_content:
    after: [ "sys_category" ]

operations:
  envFileGenerator:
    envFiles:
      pids:
        path: pids.env
        values:
          PID_404: "{pages:404:uid}"
Copied!
Name Type Required
DataLoader true
object true
array true
array true
object true

data

data
Type
DataLoader
Required

true

Configuration for how the static data should be loaded. See DataLoader options

fal

fal
Type
object
Required

true

FAL configuration. By now only the key storages is supported.

fal.storages

fal.storages
Type
array
Required

true

Configuration for FAL resource storages that should be created. See FAL storage options for more details.

ordering

ordering
Type
array
Required

true

An array of database tables for setting the ordering of record processing. Any table can be used as a key and might have two properties: before and after . Both keys are arrays themself and contain database table names.

fe_users:
  after: [ "fe_groups" ]
tt_content:
  after: [ "sys_category" ]
Copied!

operations

operations
Type
object
Required

true

There can be additional operations before and after the seeding. See operations page.

DataLoader options 

Name Type Required
string true
array true
string true
string true

loader

loader
Type
string
Required

true

Name of the registered data loader. Available loaders provided by this extension: yaml . Additional loaders can be registered using dependency injection.

options

options
Type
array
Required

true

An array of options given to the data loader.

type: 'folder'
path: 'data/database/'
Copied!

options.type

options.type
Type
string
Required

true

Either folder or file .

Using folder value, the loader will iterate through all subdirectories and load *.yaml files.

Using file value, the riles needs to provide all data for seeding (imports can be used).

options.path

options.path
Type
string
Required

true

Relative path to the yaml file or folder, based on the type configuration.

FAL storage options 

Name Type Required
string true
string true
string

identifier

identifier
Type
string
Required

true

Unique identifier for this storage. Is used to assign files to this storage.

storagePath

storagePath
Type
string
Required

true

Relative or absolute path for the storage. Is used as basePath in storage configuration. When starting with a / , that path is considered to be absolute.

baseUri

baseUri
Type
string

Set the bashUri configuration for this storage.

Variables 

Variables can be defined for usage in records. They are stored below the property _variables .

Variables can be accessed by the keyword {variable:<variable-name>} .

_variables:
  paragraph: "<p>Lorem ipsum dolor sit amet, <a href=\"t3://page?uid={pages:home}\">consetetur</a> sadipscing elitr</p>"

tt_content:
  - identifier: example
    pid: "{pages:home}"
    CType: text
    bodytext: "{variable:paragraph}"
Copied!

References 

Without providing fixed UIDs, records can be referenced by their identifiers. They follow the scheme {<tablename>:<identifier>:<fieldname>} . The fieldname is optional. If not given, the UID field is ised for replacement.

There are some reserved / special identifiers:

  • {variable:<variable-name>} : See variables.
  • {pages:root} : Will be replaced with 0 .
pages:
  - identifier: home
    pid: "{pages:root}"
    sorting: 100
    doktype: 1
    title: Home
    is_siteroot: 1

tt_content:
  - identifier: example
    pid: "{pages:home}"
    CType: heaader
    header: My example content
    header_layout: 1
Copied!

Records and files 

Creating new records follows a default scheme. A table is defined as a property type on the root level and contains an array of records. Properties for each record can be added using the database column names.

pages:
  - identifier: home
    pid: "{pages:root}"
    sorting: 100
    doktype: 1
    title: Home
    # Slugs are generated automatically for pages
    is_siteroot: 1

tt_content:
  - identifier: example
    pid: "{pages:home}"
    CType: heaader
    header: My example content
    header_layout: 1
Copied!

Files 

Defining files is a special case. All files are added to the defined storage using FAL method including meta data extractors.

Assuming the source file is located at <project-root>/data/files/example.jpg
sys_file:
  - identifier: example_jpg
    source: 'data/files/example.jpg'
    storage: default
    folder: placeholder/
Copied!
Name Type Required
string true
string true
string true
string true

identifier

identifier
Type
string
Required

true

A unique identifier for this file.

source

source
Type
string
Required

true

Path to the file relative to project root or with EXT: prefix.

storage

storage
Type
string
Required

true

The identifier for the storage that should be used. See FAL storage options.

folder

folder
Type
string
Required

true

The target directory where the file is copied. Relative to storage base path. Directory is created if is does not exist.

Relations 

Relations can be handled by defining each record with properties referencing the parent record. This is even possible for MM database relations. But there is an easier and shorter way doing it. Relations can be defined as array values for a property. Below are examples for each relation type

File references 

File references require the property file to contain a sys_file reference. Additional properties for sys_file_reference fields can be added.

sys_file:
  - identifier: example_jpg
    source: 'data/files/example.jpg'
    storage: default
    folder: /

tt_content:
  - identifier: example
    pid: "{pages:home}"
    CType: image
    image:
      - file: "{sys_file:example_jpg}"
        alternative: "Lorem ipsum"
        title: "My fantastic title"
Copied!

Relations to existing records 

Relations to existing records, no matter if its one-to-many, or many-to-many can be defined as an array of combined identifiers.

sys_category:
  - identifier: main-category-1
    pid: "{pages:home}"
    title: Main category 1
  - identifier: main-category-2
    pid: "{pages:home}"
    title: Main category 2

pages:
  - identifier: home
    pid: "{pages:root}"
    title: Homepage
    doktype: 1
    is_siteroot: 1
    categories:
      - "{sys_category:main-category-1}"
      - "{sys_category:main-category-2}"
Copied!

Relations to new records 

Relations to records that do not exist and should created by the relations can also be defined a a simplified version. The definition is done like every other records but as a property of the parent record.

pages:
  - identifier: home
    pid: "{pages:root}"
    title: Homepage
    doktype: 1
    is_siteroot: 1
    categories:
      sys_category:
        - identifier: main-category-1
          title: Main category 1
        - identifier: main-category-2
          title: Main category 2
Copied!

Operations 

Operations make it possible to execute before or after the data seeding happens. The configuration is done inside the main configuration file and not along the seed data. This extension provides the following operations by default:

Operations are configured below the operations property. Each operation requires a unique identifier that contains the operation configuration.

For creating custom operations, see Operations page.

DotEnv Generator 

This operation generates an env-file with configurable contents. Mostly used to get UIDs mapped to an env variable that can be used in TYPO3 (e.g. for 404 page).

operations:
    envFileGenerator:
      envFiles:
        pids:
          path: pids.env
          values:
            PID_404: "{pages:404:uid}"
Copied!
Name Type Required
object true
string true
object true

envFiles

envFiles
Type
object
Required

true

Can contain multiple key/identifiers. Each key represents one env-file.

envFiles.<identifier>.path

envFiles.<identifier>.path
Type
string
Required

true

Relative path and filename for the env-file that should be generated.

envFiles.<identifier>.values

envFiles.<identifier>.values
Type
object
Required

true

An object containing key/value pairs that are put into the env-file. Values can use variables and combined identifiers as well as static values.

values:
  IS_SEEDED_DATA: "1"
  PID_404: "{pages:404:uid}"
Copied!

Seed Command 

The command database:seed will process the static data configured in the configuration file.

Options 

Name Type Default Required
string seeder.yaml
boolean false
boolean false

config

config
Type
string
Default
seeder.yaml

Path to the configuration file relative to project root.

reset

reset
Type
boolean
Default
false

When given, the database is flushed before seeding data onto it.

no-interaction

no-interaction
Type
boolean
Default
false

When set together with reset flag, no user confirmation is needed.

Flush Command 

The command database:flush flush all database data. Command needs to be confirmed by user interaction in order to finish.

Options 

Name Type Default Required
boolean false
string Default
boolean false

delete-tables

delete-tables
Type
boolean
Default
false

When set, tables will not only be flush (truncated) but also deleted.

connection

connection
Type
string
Default
Default

What connection should be used for running this command.

no-interaction

no-interaction
Type
boolean
Default
false

When set, no user confirmation is needed.

Developers 

This extension can be extended in multiple places.

Events 

List of events provided by the extension.

Operations 

Build new operations that can be run before or after data seeding.

Loaders 

Register new loaders for loading seeding data.

Processors 

Register new processors for processing seeding data.

Property Converters 

Register new property converters.

Events 

This extension provides multiple PSR-14 events for modifying runtime behavior.

Before building node 

Event: \KM2\DataSeeder\Event\BeforeNodeBuildingEvent

This event is fired before the system builds the node tree that us used for importing. All records for a recordType are passed to this event and can be modified.

Initialize node 

Event: \KM2\DataSeeder\Event\InitializeRecordNodeEvent

This event is fired after Before building node event but before the node is actional build. The raw data that is used for building the node is passend. A node can be created by a listener and set in the event. The default node building is skipped and the passend node is used. Passed node needs to implement \KM2\DataSeeder\DataHandling\Node\NodeInterface interface.

Before processing node 

Event: \KM2\DataSeeder\Event\BeforeProcessingNodeEvent

This event is fired before a node is processed by a processor. Each node is passed to the event and can be can be modified.

Operations 

See Operations for explanation.

Custom operations can be registered using the PHP attribute \KM2\DataSeeder\Attribute\Operation . Operation can not be used to manipulate seeding data. See Events for data manipulation.

Operation is executed before data seeding.
<?php

namespace MyVendor\MyExtension\Operation;

use KM2\DataSeeder\Attribute\Operation;
use KM2\DataSeeder\Operation\OperationInterface;

#[Operation(identifier: 'my-custom-operation', beforeDataSeeding: true)]
class MyCustomOperation implements OperationInterface
{
    public function run(Configuration $configuration, VariableCollection $variables, ?RootNode $rootNode): void
    {
        // $rootNode is null for operations executed before data seeding.
        echo "This operation is executed before data seeding.";
    }
}
Copied!
Operation is executed after data seeding.
<?php

namespace MyVendor\MyExtension\Operation;

use KM2\DataSeeder\Attribute\Operation;
use KM2\DataSeeder\Operation\OperationInterface;

#[Operation(identifier: 'my-custom-operation')]
class MyCustomOperation implements OperationInterface
{
    public function run(Configuration $configuration, VariableCollection $variables, ?RootNode $rootNode): void
    {
        echo "This operation is executed after data seeding.";
    }
}
Copied!

Loaders 

Additional loaders can be registered for loading seeding data. By default this extension ship a YAML loader. See Configuration file for an example.

Additional loaders can be registered using the PHP attribute \KM2\DataSeeder\Attribute\DataLoader .

Custom loader class example
<?php

namespace MyVendor\MyExtension\Loaders;

use KM2\DataSeeder\Attribute\DataLoader;
use KM2\DataSeeder\DataHandling\Loader\DataLoaderInterface;

#[DataLoader(identifier: 'myLoader')]
class MyCustomOperation implements OperationInterface
{
    public function load(array $options = []): SeedingData
    {
        $variables = new VariableCollection($options['variables']);
        $staticData = [
            'pages' => [
                [
                    'identifier' => 'home',
                    'pid' => '{pages:root}',
                    'title' => 'Home',
                    'doktype' => '{variable:defaultPageType}',
                ],
            ],
        ];

        return new SeedingData($staticData, $variables);
    }
}
Copied!
Custom loader configuration
data:
  loader: myLoader
  options:
    variables:
      defaultPageType: 1
Copied!

Processors 

Processors are used to process single nodes and write data to the database. By default, this extension ships three processors:

  • \KM2\DataSeeder\DataHandling\Processors\FilesProcessor (sys_file)
  • \KM2\DataSeeder\DataHandling\Processors\PagesProcessor (pages)
  • \KM2\DataSeeder\DataHandling\Processors\RecordProcessor (records)

These processors are checked and executed in displayed order for each node.

New processors can be registered by using the PHP attribute \KM2\DataSeeder\Attribute\SeedingProcessor .

Custom processor class example
<?php

namespace MyVendor\MyExtension\Processors;

use KM2\DataSeeder\Attribute\SeedingProcessor;
use KM2\DataSeeder\Configuration\DataTransferObject\Configuration;
use KM2\DataSeeder\DataHandling\Processors\ProcessorInterface;
use KM2\DataSeeder\DataHandling\RuntimeValues;

#[SeedingProcessor(identifier: 'categoryProcessor', before: ['records'], after: ['pages', 'sys_file'])]
class MyCustomOperation implements ProcessorInterface
{
    protected Configuration $configuration;

    protected RuntimeValues $runtimeValues;

    public function setConfiguration(Configuration $configuration): void
    {
        $this->configuration = $configuration;
    }

    public function setRuntimeValues(RuntimeValues $runtimeValues): void
    {
        $this->runtimeValues = $runtimeValues;
    }

    public function canProcess(NodeInterface $node): bool
    {
        return $node->getRecordType() === 'sys_category';
    }

    public function process(NodeInterface $node): void
    {
        // Write node properties to database.

        // Mark node as processed to skip further processing.
        $node->setProcessed(true);
    }
}
Copied!

Property Converters 

Property converters are executed for each property of a node. They are used to resolve references or to process relations.

Custom property converters can be registered by using the PHP attribute \KM2\DataSeeder\Attribute\PropertyConverter .

Custom property converter class example
<?php

namespace MyVendor\MyExtension\PropertyConverters;

use KM2\DataSeeder\Attribute\PropertyConverter;
use KM2\DataSeeder\Configuration\DataTransferObject\Configuration;
use KM2\DataSeeder\DataHandling\Property\Converter\PropertyConverterInterface;
use KM2\DataSeeder\DataHandling\Property\Property
use KM2\DataSeeder\DataHandling\RuntimeValues;

#[PropertyConverter(identifier: 'replace-placeholder-property-converter', before: ['variable-property-converter'])]
class MyCustomOperation implements PropertyConverterInterface
{
    protected Configuration $configuration;

    protected RuntimeValues $runtimeValues;

    public function setConfiguration(Configuration $configuration): void
    {
        $this->configuration = $configuration;
    }

    public function setRuntimeValues(RuntimeValues $runtimeValues): void
    {
        $this->runtimeValues = $runtimeValues;
    }

    public function convert(Property $property, NodeInterface $node): bool
    {
        $propertyValue = $property->getValue();
        if (!str_contains($propertyValue, '--placeholder--')) {
            return false;
        }

        $newPropertyValue = (string)str_replace('--placeholder--', 'Lorem ipsum', $propertyValue);
        $property->setValue($newPropertyValue);

        // When true is returned, property conversion is stopped for this property.
        return true;
    }
}
Copied!