---
title: "How to Export Data from TYPO3: Methods, API Limits & Portability"
slug: how-to-export-data-from-typo3-methods-api-limits-portability
date: 2026-08-27
author: Abdul Aleem
categories: [Migration Guide, Knowledge Base, TYPO3]
excerpt: "Complete guide to exporting TYPO3 data: EXT:impexp, direct database dumps, REST APIs, CLI commands, and FAL file handling. Covers limits, edge cases, and migration-ready extraction."
tldr: "TYPO3 has no single export button. Use EXT:impexp (CLI) for TYPO3-to-TYPO3, database dumps for cross-platform migrations, and REST extensions or custom CLI commands for JSON extraction. FAL files require separate handling."
canonical: https://clonepartner.com/blog/how-to-export-data-from-typo3-methods-api-limits-portability
---

# How to Export Data from TYPO3: Methods, API Limits & Portability


**TYPO3 has no single "Export Everything" button.** Your extraction path depends on your TYPO3 version, whether you're migrating to another TYPO3 instance or leaving the ecosystem entirely, and how much data you need. The built-in `EXT:impexp` handles TYPO3-to-TYPO3 transfers in proprietary formats (T3D/XML), but it breaks down for large sites and cannot produce output another CMS can ingest. For migration-ready exports, you need direct database access, CLI tooling, or community REST API extensions.

Because TYPO3 stores all content in a **relational database** (MySQL/MariaDB or PostgreSQL) organized around a **page-tree hierarchy** with `uid`/`pid` relationships and governed by the **Table Configuration Array (TCA)**, the data is queryable with SQL. But the data model is spread across dozens of interconnected tables — `pages`, `tt_content`, `sys_file_reference`, MM relation tables, extension-specific `tx_*` tables — and a raw `mysqldump` gives you everything without structural interpretation. A migration-ready extract typically requires combining multiple tools.

> **Disclosure:** This guide is produced by ClonePartner, a TYPO3 migration vendor. Recommendations reflect operational experience with TYPO3 exports; verify specifics against official documentation for your version.

> [!NOTE]
> **TL;DR:** Use `EXT:impexp` (CLI mode) for TYPO3-to-TYPO3 transfers. Use direct MySQL/MariaDB dumps for cross-platform migrations. Use `EXT:headless` or `EXT:t3api` for programmatic JSON extraction. Use custom Symfony CLI commands or `in2code/migration` for large-scale exports with complex transformation needs. Every method has coverage gaps — especially around FAL file metadata, FlexForm plugin configuration, TypoScript configuration, and extension-specific data.

## TYPO3 Export Methods Compared

| Method | Content Records | Files / Media | Users | Translations | Extension Data | Output Format | Best For |
|--------|----------------|--------------|-------|-------------|---------------|--------------|----------|
| **EXT:impexp (Backend UI)** | ✅ | ✅ (optional) | ❌ (excluded by default) | ✅ | Partial | T3D, XML | Small-to-medium TYPO3-to-TYPO3 transfers |
| **EXT:impexp (CLI)** | ✅ | ✅ (optional) | ❌ (excluded by default) | ✅ | Partial | T3D, XML | Larger page trees without PHP time limits |
| **Direct database dump** | ✅ (all tables) | Metadata only | ✅ | ✅ | ✅ | SQL | Full backup, migration to non-TYPO3 target |
| **EXT:headless** | ✅ (rendered JSON) | URLs only | ❌ | ✅ | Plugin output only | JSON | Programmatic content extraction |
| **EXT:t3api** | ✅ (Extbase models) | Via FAL serialization | ❌ | Configurable | Model-dependent | JSON-LD/Hydra | Custom API-based extraction |
| **Custom Symfony CLI** | ✅ | Configurable | Configurable | ✅ | ✅ | JSON, CSV | Complex transformations before export |
| **in2code/migration** | ✅ | ✅ | Configurable | ✅ | Configurable | JSON | Large-scale cross-version migrations |

The split to remember: `EXT:impexp` is for TYPO3-aware content transport; database/file extraction is for real data portability. If your destination is not TYPO3, plan on a multi-part export.

## What Counts as "All Data" in TYPO3

Before writing extraction scripts, understand what TYPO3 stores and where. Unlike simpler CMS platforms that keep an entire page's content in a single database column, TYPO3 uses a block-based, highly relational model.

### Pages and Content Records

The `pages` table defines the site hierarchy (the page tree). It contains metadata, routing information, and SEO fields, but **no actual page content**. Content lives in `tt_content`. Every paragraph, image block, or custom plugin is a separate row in `tt_content`, linked to a page via the `pid` (Page ID) column. To reconstruct a single page, query `tt_content` where `pid = [page_uid]` and order results by the `sorting` column.

For each record, the `pid` field contains a reference to the page where that record is stored. For pages, the `pid` field behaves as a reference to their parent pages. This hierarchical relationship is how you reconstruct the page tree from flat SQL data.

### Soft Deletes and Enable Fields

TYPO3 rarely hard-deletes data. When a user deletes a page or content element in the backend, TYPO3 sets `deleted=1`. Content can also be hidden (`hidden=1`), scheduled (`starttime`/`endtime`), or restricted by user group (`fe_group`). A blind `SELECT * FROM tt_content` will include years of deleted drafts, expired promotions, and hidden test pages.

### Workspaces and Versioning

Enterprise TYPO3 setups use Workspaces for staging content. If a record has `t3ver_wsid > 0`, it is a draft version residing in a workspace, not live production content. In older TYPO3 versions, workspace offline rows are identified by `pid = -1`. Raw SQL exports can silently mix live and offline content if you don't filter explicitly.

### FlexForm Fields — The Hidden Complexity

One of the most underestimated export challenges in TYPO3 is the `pi_flexform` column in `tt_content`. When a content element has `CType = list` (meaning it renders a plugin), plugin-specific configuration is stored in `tt_content.pi_flexform` as **serialized XML inside a single database column**.

A typical FlexForm value looks like this:

```xml
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<T3FlexForms>
  <data>
    <sheet index="sDEF">
      <language index="lDEF">
        <field index="settings.listPid">
          <value index="vDEF">42</value>
        </field>
        <field index="settings.limit">
          <value index="vDEF">10</value>
        </field>
      </language>
    </sheet>
  </data>
</T3FlexForms>
```

This means a raw SQL dump of `tt_content` gives you an opaque XML blob per plugin instance. Migrating plugin configuration requires:

1. Identifying which `CType`/`list_type` combinations use FlexForms (defined in TCA)
2. Parsing the XML structure for each plugin type individually
3. Mapping the FlexForm field values (often page UIDs, category UIDs, or storage folder UIDs) to equivalent identifiers in your target system

There is no universal FlexForm parser — each plugin has its own schema. Extensions like `EXT:news` use FlexForms for list configuration; `EXT:powermail` uses them for form routing. A migration engineer hitting a `list` CType without accounting for FlexForms will produce incomplete or broken plugin exports.

### Relations, Categories, and Files

MM tables such as `sys_category_record_mm` and file relations in `sys_file_reference` carry structure your target system needs. Exporting `tt_content` without its related MM tables produces orphaned data.

**FAL (File Abstraction Layer)** tracks files, metadata, and references separately through `sys_file`, `sys_file_metadata`, and `sys_file_reference`. Physical files typically live in `fileadmin/`, but TYPO3 supports additional, private, read-only, and off-server storages. If your script only crawls `fileadmin/`, you can still miss valid media.

### Site and System Configuration

TYPO3 site configuration is filesystem-based since v9+, stored in `config/sites/<identifier>/config.yaml`. Global settings live in `config/system/settings.php`. Neither is in the database — a database dump alone won't capture them. ([docs.typo3.org](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/SiteHandling/Basics.html))

Since TYPO3 v9, TypoScript can also be loaded from filesystem files via `@import` directives — for example, `@import 'EXT:my_sitepackage/Configuration/TypoScript/setup.typoscript'`. These includes are **not captured by a database dump** of `sys_template`. A complete TypoScript export requires both the `sys_template` database records and the referenced filesystem files.

### Extension-Owned Data

Extensions like `EXT:news`, `EXT:powermail`, `EXT:tt_address`, and shop extensions create their own `tx_*` database tables. Redirects live in `sys_redirect` if the redirects extension is installed. Forms are version-sensitive: TYPO3 14.2 added database-backed `form_definition` storage and deprecated file-mount form storage. On older installs, forms may live as YAML in FAL or inside extensions. ([docs.typo3.org](https://docs.typo3.org/c/typo3/cms-core/main/en-us/Changelog/14.2/Feature-108653-DatabaseStorageForFormExtension.html))

Sites using `EXT:solr` for search indexing maintain a Solr core that is **entirely separate from the TYPO3 database**. This indexed content — boosted fields, synonyms, stop words, and the index itself — will not appear in any database or filesystem export and must be rebuilt from scratch in the target environment.

> [!WARNING]
> **A SQL dump without files is incomplete. A `fileadmin/` copy without the database is incomplete.** And both are incomplete if you omit `config/sites/`, `config/system/`, TypoScript filesystem includes, or extension-specific storage outside the default file area.

## Method 1: EXT:impexp — TYPO3's Built-in Import/Export

The system extension `EXT:impexp` allows content to be exported from one TYPO3 installation and imported into another. Exported data includes content from multiple tables including `tt_content` as well as images and other files stored in `fileadmin/`.

### Backend UI Export

In the page tree, right-click the page from which you want to start the export and select "More options ... > Export." On the first tab of the export module you can fine-tune the export. If you want to export all data of the selected page including its subpages, select the "Infinite" option in the Levels selection box.

The output format is either **T3D** (a serialized PHP array, optionally compressed) or **XML**. Both are proprietary to TYPO3 — no other CMS can read them.

### CLI Export (Recommended for Large Sites)

The advantage of using the CLI is that there is no PHP time limit, therefore larger page trees can be exported and imported.

```bash
# Composer-based installation
vendor/bin/typo3 impexp:export my_export --type=xml --pid=1 --levels=999 --table=_ALL

# With additional filtering and file options
vendor/bin/typo3 impexp:export my_export --type=xml --pid=1 --levels=999 \
  --table=pages --table=tt_content --include-related=_ALL \
  --exclude-disabled-records --save-files-outside-export-file

# TYPO3 14.2+: include site configurations when exporting a root page
vendor/bin/typo3 impexp:export my_export --type=xml --pid=1 --levels=999 \
  --include-site-configurations
```

Options include `--type` (xml, t3d, t3d_compressed — default is "xml"), `--pid` (the root page of the exported page tree, default -1), and `--levels` (the depth of the exported page tree).

### EXT:impexp Version Compatibility

TYPO3 documents same-major-version T3D/XML export and re-import as the supported path. Cross-version behavior varies:

| Export version | Import to v11 | Import to v12 | Import to v13 | Import to v14 |
|---------------|--------------|--------------|--------------|--------------|
| TYPO3 v11 | ✅ Supported | ⚠️ Requires DB compare + cleanup | ⚠️ Requires DB compare + cleanup | ⚠️ Requires DB compare + cleanup |
| TYPO3 v12 | ❌ Not supported | ✅ Supported | ⚠️ Requires DB compare + cleanup | ⚠️ Requires DB compare + cleanup |
| TYPO3 v13 | ❌ Not supported | ❌ Not supported | ✅ Supported | ⚠️ Requires DB compare + cleanup |
| TYPO3 v14 | ❌ Not supported | ❌ Not supported | ❌ Not supported | ✅ Supported |

Cross-version imports typically require running the TYPO3 Upgrade Wizard and database schema compare after import. Extension table schemas may also differ between versions, causing broken relations unless the target instance has compatible extension versions installed.

### Known Limitations of EXT:impexp

- **10MB XML import ceiling:** A TYPO3 issue prevents loading `data.xml` larger than 10MB. In this case the only option left is going with `data.t3d`.
- **Root-level records excluded:** Records stored on root level (such as `sys_file`) records don't get exported automatically. Your FAL file index will be incomplete unless you handle it separately.
- **No extension code:** This method won't copy any of your installed extensions. You have to take care of moving them yourself.
- **Backend users excluded by default:** Including them is explicitly discouraged for distribution-style exports.
- **PHP memory limits (backend UI):** There is also the `memory_limit`, which often only allows a few hundred MB per process. Large page trees will hit this ceiling — use CLI instead.
- **Broken relations:** When the relation to records are lost these will be marked with an orange exclamation mark. Reasons for lost relations include records stored outside the page tree to be exported and excluded tables.
- **FlexForm configuration not transformed:** Plugin configuration stored in `pi_flexform` is exported as raw XML. UIDs embedded in FlexForm values (page IDs, category IDs) are not remapped during import — if the target instance has different UIDs, plugin configuration will silently point to wrong or missing records.
- **Same-major-version only guaranteed:** See the compatibility table above.

> [!WARNING]
> **T3D and XML are TYPO3-only formats.** If you're migrating to WordPress, Drupal, or any non-TYPO3 platform, `EXT:impexp` output is not directly usable. You'll need to parse the XML programmatically or use a different extraction method.

### Security Note

Server-side exports are stored in `fileadmin/user_upload/_temp_/importexport/`. TYPO3 writes an `.htaccess` to block access, but this protection does not work on Nginx. TYPO3 recommends deactivating the extension when not in use. ([docs.typo3.org](https://docs.typo3.org/c/typo3/cms-impexp/13.4/en-us/Security/Index.html))

### Export Permissions

The export functionality is only available for admin users and backend users for which the Page TSconfig option `options.impexp.enableExportForNonAdminUser` has been enabled.

## Method 2: Direct Database Export

For teams migrating away from TYPO3 or needing a complete data snapshot, a direct database dump is the fastest and most complete extraction path. Because TYPO3 is self-hosted, you have direct access to the database.

### Database Dump Commands

```bash
# MySQL / MariaDB — full dump with transaction consistency
mysqldump --single-transaction -u db_user -p typo3_database > typo3_full_dump.sql

# Exclude cache and session tables to reduce size
mysqldump --single-transaction -u db_user -p typo3_database \
  --ignore-table=typo3_database.be_sessions \
  --ignore-table=typo3_database.fe_sessions \
  --ignore-table=typo3_database.cache_treelist \
  > typo3_clean_dump.sql

# PostgreSQL
pg_dump -Fc typo3db > typo3.dump

# Via typo3_console (if installed)
vendor/bin/typo3cms database:export > typo3_full_dump.sql
```

The `database:export` command exports the database (all tables) directly to stdout. The `mysqldump` binary must be available in the path for this command to work. This only works when MySQL is used as DBMS.

Note: MySQL's `--single-transaction` only guarantees consistency for InnoDB tables. MyISAM and MEMORY tables can still drift during the dump. PostgreSQL's `pg_dump` produces consistent exports even under concurrent use.

### Key Tables for Content Migration

| Table | Contains |
|-------|----------|
| `pages` | Page tree structure, titles, slugs, metadata |
| `tt_content` | All content elements (text, images, plugins) |
| `tt_content.pi_flexform` | Plugin configuration as serialized XML (per row) |
| `sys_file` | FAL file index (metadata pointers to physical files) |
| `sys_file_reference` | Relations between files and content records |
| `sys_file_metadata` | Extended file metadata (title, description, copyright) |
| `sys_category` / `sys_category_record_mm` | Category assignments |
| `fe_users` / `fe_groups` | Frontend users and groups |
| `be_users` / `be_groups` | Backend users and groups |
| `sys_redirect` | URL redirects |
| `sys_template` | TypoScript records (inline TypoScript only; filesystem includes separate) |
| `tx_*` tables | Extension-specific data (news, forms, shops, etc.) |

### Extracting Clean, Live Content

A raw dump includes everything: deleted drafts, hidden test pages, workspace versions. To extract only live production content, filter explicitly:

```sql
SELECT 
  c.uid as content_id,
  c.pid as page_id,
  p.title as page_title,
  c.CType as content_type,
  c.list_type as plugin_type,
  c.header as content_header,
  c.bodytext as content_body,
  c.pi_flexform as plugin_config,
  c.sorting
FROM tt_content c
JOIN pages p ON c.pid = p.uid
WHERE c.deleted = 0 
  AND c.hidden = 0
  AND p.deleted = 0
  AND p.hidden = 0
  AND c.t3ver_wsid = 0 -- Exclude workspace drafts
ORDER BY c.pid, c.sorting;
```

You can verify how much workspace content your database contains before deciding how to filter:

```sql
SELECT COUNT(*) AS versioned_rows
FROM tt_content
WHERE pid = -1 OR t3ver_oid <> 0;
```

### Understanding CTypes and pi_flexform

The `CType` column dictates how content data should be interpreted. Common mappings:

| CType | Data location | Notes |
|-------|--------------|-------|
| `text` | `bodytext` (RTE HTML) | Standard text block |
| `textpic` | `bodytext` + `sys_file_reference` | Text plus image relations |
| `image` | `sys_file_reference` only | Image-only block |
| `list` | `pi_flexform` (XML) | Plugin; actual data in `tx_*` tables |
| `bullets` | `bodytext` (line-separated) | Bullet list |
| `table` | `bodytext` (pipe-delimited) | Simple table |
| `shortcut` | `records` column | Content reference to another element |
| `div` | None | Section divider |
| `html` | `bodytext` (raw HTML) | Raw HTML block |

For `CType = list`, the `list_type` column identifies which plugin is rendering (e.g., `news_pi1`, `powermail_pi1`). The plugin's configuration lives in `pi_flexform` as serialized XML. You must parse each plugin's FlexForm XML separately — there is no single schema.

You must map every `CType` and `list_type` used in your installation to your target system's component model before writing your extraction script. Run this query to inventory what you have:

```sql
SELECT CType, list_type, COUNT(*) as count
FROM tt_content
WHERE deleted = 0
GROUP BY CType, list_type
ORDER BY count DESC;
```

### What a Database Dump Misses

- **TypoScript filesystem includes** — `@import` directives in `sys_template` point to files in `typo3conf/ext/` or `config/`; not captured by DB dump alone
- **Site configuration** — stored in `config/sites/*/config.yaml` on disk since TYPO3 v9+
- **Extension code** — lives in `typo3conf/ext/` (classic) or `vendor/` (Composer)
- **Physical files** — only metadata and references are in the database; actual media files are on the filesystem
- **Processed files** — generated image variants in `_processed_/` folders; not needed for migration
- **Solr index** — entirely external to TYPO3; must be rebuilt in the target environment

> [!TIP]
> **Don't forget `fileadmin/`.** A database dump only gives you metadata and references. The actual media files live on the filesystem. Copy this directory separately and match `sys_file` records to physical paths to reconstruct file relationships in your target system.

## Understanding TYPO3's File Abstraction Layer (FAL)

File export is one of the most overlooked parts of a TYPO3 migration. Content-related assets — mostly videos and images — are accessible through a file abstraction layer API and never referenced directly throughout the system.

TYPO3 does not store image URLs in `tt_content`. When a user adds an image to a content element, TYPO3 creates a record in `sys_file_reference` linking the content element (`uid_foreign`) to the physical file record in `sys_file` (`uid_local`).

Whenever a file is used — for example an image attached to a content element — a reference is created in the database between the file and the content element. This reference can hold additional information like an alternative title to use for this file just for this reference.

To extract all file references associated with your content:

```sql
SELECT 
  fr.uid_foreign as content_element_id,
  fr.tablenames as related_table,
  fr.fieldname as related_field,
  f.identifier as file_path,
  f.name as file_name,
  fm.title as file_title,
  fm.description as file_description,
  s.configuration as storage_config
FROM sys_file_reference fr
JOIN sys_file f ON fr.uid_local = f.uid
JOIN sys_file_storage s ON f.storage = s.uid
LEFT JOIN sys_file_metadata fm ON f.uid = fm.file
WHERE fr.deleted = 0 
  AND fr.hidden = 0
  AND f.missing = 0;
```

**Extraction strategy:**

1. Run the query above to get the `file_path` (e.g., `/user_upload/hero-image.jpg`).
2. Download the physical files from `fileadmin/` via rsync, scp, or archive.
3. Check `sys_file_storage` for non-default storages (cloud, private, off-server).
4. In your migration script, map the physical file to the new CMS and update content references with the new media URL.

> [!WARNING]
> **Missing files:** The `f.missing = 0` clause matters. If a server admin manually deleted a file from `fileadmin/` without using the TYPO3 backend, TYPO3 flags it as `missing=1`. Don't attempt to export these — the physical asset no longer exists.

> [!WARNING]
> **EXT:impexp does not export `sys_file` records stored at root level (pid=0) automatically.** This is a documented limitation. If you rely solely on `EXT:impexp`, your file index will be incomplete. Handle FAL records separately via database export or scripted extraction.

## Method 3: Resolving Internal Links Before Export

TYPO3 stores internal links in a non-standard URI format: `t3://page?uid=123`, `t3://file?uid=45`, or `t3://folder?uid=7`. These appear in:

- `tt_content.bodytext` (RTE content)
- `tt_content.header_link`
- `pages.url` (for external redirect pages)
- FlexForm XML values
- TypoScript constants and setup (when referencing pages by UID)

If you export content containing `t3://` URIs without resolving them first, your target system will receive broken links that no browser or CMS can parse.

### Resolving t3:// URIs Programmatically

TYPO3 provides a LinkService API to resolve these references to absolute URLs. In a custom Symfony CLI command:

```php
use TYPO3\CMS\Core\LinkHandling\LinkService;
use TYPO3\CMS\Frontend\Service\TypoLinkCodecService;

// Resolve a t3://page?uid=42 reference to an absolute URL
$linkService = GeneralUtility::makeInstance(LinkService::class);
$linkData = $linkService->resolve('t3://page?uid=42');
// Returns: ['type' => 'page', 'pageuid' => 42]

// To get the full URL, use UriBuilder in a frontend context
$uriBuilder = $this->uriBuilder;
$url = $uriBuilder->reset()
    ->setTargetPageUid(42)
    ->setCreateAbsoluteUri(true)
    ->buildFrontendUri();
```

For bulk resolution during export, iterate over all `bodytext` fields, extract `t3://` patterns with a regex, resolve each, and replace before writing the export file. This step is essential for cross-platform migrations — it converts TYPO3-internal references to portable absolute URLs your target system can store and display.

**Link types to resolve:**

| t3:// pattern | Resolves to |
|--------------|-------------|
| `t3://page?uid=N` | Page URL based on site configuration |
| `t3://file?uid=N` | Public URL of the file from FAL |
| `t3://folder?uid=N` | Folder path (rarely used in frontend content) |
| `t3://url?url=...` | External URL (pass through unchanged) |
| `t3://email?email=...` | `mailto:` URL (pass through unchanged) |

## Method 4: REST API Extraction

TYPO3 does **not ship with a built-in REST API** for content extraction. Several community extensions fill this gap.

### EXT:headless — JSON Content API

The headless extension provides a JSON API that serves as an endpoint for various types of applications. It utilizes standard TYPO3 features to render the page tree structure and page content into JSON format. The JSON response object and content elements can be customized using TypoScript.

This extension was designed for decoupled frontend architectures (PWAs), not migrations. But it can be repurposed as an extraction tool:

- Returns **rendered content** as JSON with the page tree hierarchy intact
- Supports multilanguage, multidomain, forms, frontend login, workspaces, and more
- Content structure is customizable via TypoScript to match your target system's requirements

The tradeoff: you get the **presentation layer's view** of the data, not raw database records. Relationships between records, internal metadata, FlexForm configuration, and backend-only fields aren't included unless explicitly configured.

**Performance constraints:** Because TYPO3 is self-hosted, there are no vendor-imposed API rate limits—a characteristic shared with other self-hosted platforms like [October CMS](https://clonepartner.com/blog/blog/how-to-export-data-from-october-cms-methods-limits-portability). But your throughput is constrained by server architecture:

- **CPU overhead:** `EXT:headless` relies on TypoScript rendering. Every API call forces TYPO3 to boot its frontend rendering engine, parse TypoScript, and serialize the output.
- **PHP-FPM workers:** High-concurrency extraction scripts will exhaust your PHP-FPM worker pool, causing 502 errors.
- **No bulk endpoints:** The API doesn't natively support "dump all pages." You must crawl the page tree recursively, fetching one page at a time.

For large sites, throttle API extraction scripts to 5–10 concurrent requests to maintain server stability.

### EXT:t3api (sourcebroker/t3api)

Supports Extbase models with GET, POST, PATCH, PUT, DELETE operations. Built-in filters: boolean, numeric, order, range, and text (partial, match against, and exact strategies). Built-in pagination. Responses in Hydra/JSON-LD format.

This requires annotating your Extbase models with API resource configuration — it doesn't magically expose all TYPO3 tables. For a migration, you need to create or configure endpoints for each content type you want to extract.

### Custom TypoScript JSON Endpoints

You can build JSON endpoints using core TYPO3 routing without installing any extension:

```typoscript
jsonview = PAGE
jsonview.typeNum = 26
jsonview.10 = USER
jsonview.10.userFunc = MyVendor\MyExtension\Controller\JsonPageController->renderAction
jsonview.config.disableAllHeaderCode = 1
jsonview.config.additionalHeaders.10.header = Content-Type: application/json
```

This gives you control over the JSON shape but requires custom development. Output completeness depends entirely on what your endpoint exposes.

### When API Extraction Makes Sense

- You need **incremental or filtered exports** (e.g., only pages modified after a certain date)
- You're building a **continuous sync** pipeline between TYPO3 and another system
- You need **transformed JSON output** rather than raw database rows
- You don't have direct database access (rare for self-hosted TYPO3, but possible in managed hosting)

## Method 5: Custom Symfony CLI Commands

For enterprise migrations requiring complex data transformation before export, writing a custom CLI command within TYPO3 is the most robust approach.

Since TYPO3 v10, the core uses Symfony Console. By writing a custom command, you can leverage TYPO3's Extbase Repositories and the `DataHandler` API to extract data. Reading through Extbase repositories is preferable to raw SQL for content records because Extbase automatically applies TCA-defined visibility constraints — filtering deleted, hidden, and expired records — without manual WHERE clauses. `DataHandler` is TYPO3's authoritative write path and applies the same constraint logic for reads when used through the repository layer.

```php
protected function execute(InputInterface $input, OutputInterface $output): int
{
    // Extbase automatically ignores deleted/hidden records
    $pages = $this->pageRepository->findAll();
    
    $exportData = [];
    foreach ($pages as $page) {
        $exportData[] = [
            'id' => $page->getUid(),
            'title' => $page->getTitle(),
            'slug' => $page->getSlug(),
            'content' => $this->extractContentForPage($page->getUid()),
            'files' => $this->extractFilesForPage($page->getUid()),
            'links' => $this->resolveInternalLinks($page->getUid()),
        ];
    }

    file_put_contents(
        'typo3_export.json', 
        json_encode($exportData, JSON_PRETTY_PRINT)
    );
    return Command::SUCCESS;
}
```

**Advantages of CLI extraction:**

- Bypasses web server timeouts (no `max_execution_time` limits)
- Respects TYPO3's complex TCA permissions natively via Extbase repositories
- Allows you to resolve `t3://` internal link formats into absolute URLs before exporting
- Allows you to parse and transform `pi_flexform` XML per plugin type
- Can batch-process pages in chunks to manage memory
- Full access to TYPO3's domain model and relation handling

## Method 6: in2code/migration Framework

For large-scale migrations — especially cross-version TYPO3 upgrades — the `in2code/migration` package is purpose-built. It operates via CLI (bypassing PHP time limits) and handles the scenarios where `EXT:impexp` breaks down — large page trees, complex extension data, and cross-version compatibility. It's configurable through a separate extension's configuration file.

In addition to a large number of useful migration tools, `EXT:migration` can also be used to export very large page trees as JSON and then import them again. It also offers CLI functions to export large page trees with all data records and files as JSON and then import them again.

## Handling Translations and Multi-Language Content

If your TYPO3 instance is multilingual, extraction complexity doubles. TYPO3 handles translations via the `sys_language_uid` and `l10n_parent` columns (or `l18n_parent` in older versions).

The default language is always `sys_language_uid = 0`. Translated records have a specific language ID (e.g., `1` for German, `2` for French) and reference the original default language record via `l10n_parent`.

When exporting, decide your target system's translation architecture:

1. **Field-level translation (like Contentful):** Group the default record and all its `l10n_parent` children into a single object before export.
2. **Tree-level translation (like WordPress Multisite):** Export each language as a separate, distinct page tree.

The edge case to watch for: **free mode translations**, where translated content elements don't have a 1:1 relationship with the default language. A naive export that only maps `l10n_parent` will miss independently created translated content. In connected mode, each translated record has a non-zero `l10n_parent`. In free mode, translated records have `l10n_parent = 0` even though they belong to a translated page — you must identify them by `sys_language_uid` and `pid` alone.

Ensure your SQL or API extraction explicitly queries `sys_language_uid` and maps translations together. Otherwise you risk exporting translated content as orphaned pages in your new system.

## Handling Extension-Specific Data (tx_* Tables)

TYPO3's Extbase framework powers custom data models — news articles, products, job postings, form submissions. These records live in custom `tx_*` tables, not in `tt_content`.

To export these:

1. **Identify custom tables** via the TYPO3 backend (System > Configuration > TCA) or by querying:
   ```sql
   SELECT DISTINCT table_name 
   FROM information_schema.tables 
   WHERE table_name LIKE 'tx_%';
   ```
2. **Write specific SQL queries** for each table, applying the same `deleted=0`, `hidden=0`, and workspace filters.
3. **Join against category tables** if they use TYPO3's native categorization system (`sys_category_record_mm`).
4. **Extract FAL relations** using the same `sys_file_reference` query, changing the `tablenames` parameter:
   ```sql
   WHERE fr.tablenames = 'tx_news_domain_model_news'
   ```

**EXT:impexp** can include extension table records if you manually select them — under "Include tables" you can limit the types of records to be exported. But extension records stored outside the exported page tree (or at root level) will be missed.

**Database dumps** capture all `tx_*` tables completely. This is the safest path for extension data, but you need to understand each extension's schema to transform it for your target platform.

Specific extensions to watch:

- **Redirects:** If `typo3/cms-redirects` is installed, rules live in `sys_redirect`. If SEO continuity matters, export these early and validate for redirect loops.
- **Forms:** On TYPO3 14.2+, form definitions can live in `form_definition`; file-mount form storage is deprecated. On older installs, forms may still live as YAML in FAL or inside extensions.
- **Site packages:** Extension and sitepackage code (PHP, TypoScript, Fluid templates) is not captured by `EXT:impexp` or database dumps. If your business logic lives there, a content-only export is not enough.
- **Solr:** The search index is external to TYPO3 entirely. Export is not applicable — rebuild from scratch in the target environment after migrating content.

## Which Export Method Should You Use?

**Migrating to another TYPO3 instance (same or newer version)?**
Start with `EXT:impexp` via CLI. For sites with more than a few thousand pages, use `in2code/migration` instead. Supplement with a `fileadmin/` copy. For cross-version migrations, run the Upgrade Wizard and database schema compare after import.

**Migrating to a different CMS (WordPress, Drupal, Contentful)?**
Use a direct database dump + `fileadmin/` copy. Parse the SQL tables programmatically to transform data into your target format. T3D/XML formats are useless here. Resolve all `t3://` internal links to absolute URLs before writing your final export. For complex transformations — especially FlexForm XML and extension data — write a custom Symfony CLI command to produce clean JSON.

**Building a sync pipeline or headless frontend?**
Install `EXT:headless` or `EXT:t3api` and configure endpoints for the content types you need.

**No backend or database access (decommissioned hosting)?**
Web scraping with `wget` or Screaming Frog is your fallback. You get rendered HTML only — no structured data, no metadata, no user accounts, no FlexForm configuration, no translation relations.

**Archival / compliance export?**
Full database dump + filesystem archive. Include `config/sites/`, `config/system/`, `typo3conf/ext/` (or Composer `vendor/`), all of `fileadmin/`, and TypoScript filesystem includes from your sitepackage.

## Common Failure Modes

1. **Missing FAL records:** Relying on `EXT:impexp` alone, then discovering after import that file references are broken because `sys_file` records at pid=0 weren't included.
2. **PHP timeouts on large exports:** Using the backend UI instead of CLI for sites with 10,000+ pages. Always use CLI for production-scale exports.
3. **Assuming T3D is portable:** Teams export to T3D, then realize their target platform can't read it. T3D is a serialized PHP format — it only works with TYPO3's import tool.
4. **Forgetting site configuration:** Since TYPO3 v9, site configuration (domains, languages, routing) lives in YAML files on disk, not in the database. A database dump alone won't capture it.
5. **Ignoring MM relation tables:** Content-to-category, content-to-file, and other many-to-many relationships are stored in separate MM tables. Exporting `tt_content` without its MM tables produces orphaned data.
6. **Extension data left behind:** `tx_news_domain_model_news`, `tx_powermail_*`, and other extension tables contain business-critical data that won't appear unless explicitly included.
7. **Mixing live and workspace content:** Raw SQL exports without filtering `t3ver_wsid` or checking for `pid = -1` silently include draft and workspace content alongside live records.
8. **Only copying `fileadmin/`:** TYPO3 supports additional, private, and off-server FAL storages. Check `sys_file_storage` for non-default storage configurations.
9. **Unresolved t3:// internal links:** Exporting `bodytext` or FlexForm values containing `t3://page?uid=N` or `t3://file?uid=N` without resolving them produces link-broken content in any non-TYPO3 target.
10. **Unparsed FlexForm XML:** Treating `pi_flexform` as an opaque blob rather than parsing each plugin's schema produces incomplete plugin migrations — plugin configuration is silently lost or corrupted in the target system.
11. **Missed TypoScript filesystem includes:** Dumping only `sys_template` rows without exporting the `@import`-referenced files from `typo3conf/ext/` or `config/` produces an incomplete TypoScript configuration.

## Pre-Export Checklist

- [ ] Identify your TYPO3 version (v11 LTS, v12 LTS, v13 LTS, or v14)
- [ ] List all installed extensions with custom database tables (`tx_*`)
- [ ] Inventory all `CType` and `list_type` values in use (run the GROUP BY query above)
- [ ] Identify all `list_type` plugins using FlexForms and document their XML schemas
- [ ] Verify `EXT:impexp` is installed (`composer show typo3/cms-impexp`)
- [ ] Check total database size and page count to determine if CLI export is required
- [ ] Inventory `fileadmin/` size and check `sys_file_storage` for non-default storages
- [ ] Identify all configured languages and translation modes (connected vs. free)
- [ ] Document site configurations in `config/sites/`
- [ ] Export `config/system/settings.php` for global settings
- [ ] Identify and export TypoScript filesystem includes from sitepackage
- [ ] Decide whether you need backend users, frontend users, or both
- [ ] Map all `CType` values to your target system's component model
- [ ] Plan `t3://` internal link resolution strategy before export
- [ ] Plan redirect extraction from `sys_redirect`
- [ ] Verify Solr index rebuild plan (if `EXT:solr` is installed)
- [ ] Test export on a staging environment before running against production

For teams transforming extracted data into intermediate formats, our guide on [using CSVs for SaaS data migrations](https://clonepartner.com/blog/blog/csv-saas-data-migration) covers why CSV is often the last step, not the first. If you're comparing export challenges across CMS platforms, our [Plone export guide](https://clonepartner.com/blog/blog/how-to-export-data-from-plone-methods-api-limits-portability) covers similar architectural extraction patterns.

## When to Bring in Help

TYPO3 exports are straightforward when your site is small, uses standard content elements, and targets another TYPO3 instance. They get complicated when:

- You have heavily customized extensions with proprietary data models
- The site has 10,000+ pages across multiple languages
- You're migrating to a fundamentally different platform (headless CMS, SaaS)
- FAL storage uses non-default drivers (cloud storage, DAM systems)
- You need to preserve URL structures, redirects, and SEO metadata
- Internal links use `t3://` format and need converting to absolute URLs
- Plugins use FlexForms with embedded UID references that must be remapped
- TypoScript configuration is split across database records and filesystem files

The framework's reliance on the Table Configuration Array, soft deletes, FlexForm serialization, and the File Abstraction Layer means that simple database dumps result in corrupted, bloated migrations. The hard part is not copying rows — it's preserving relationships, files, localization, FlexForm configuration, internal link resolution, redirects, and the pieces TYPO3 stores on disk instead of in SQL.

> Migrating away from TYPO3? ClonePartner's engineering team specializes in untangling complex relational databases and FAL architectures. We write custom extraction scripts that map `tt_content` structures to target schemas, resolve `t3://` internal links, parse FlexForm XML per plugin type, and handle extension data. Book a 30-minute call to scope your migration.
>
> [Talk to us](https://cal.com/clonepartner/meet?duration=30)

## Frequently asked questions

### How do I export all content from TYPO3?

Use the EXT:impexp CLI command (vendor/bin/typo3 impexp:export) with --levels=999 and --table=_ALL for a full page tree export to XML or T3D. For a complete extraction including extension data and FAL file records, supplement with a direct MySQL database dump and a copy of the fileadmin/ directory.

### What is a T3D file in TYPO3?

T3D is TYPO3's proprietary export format — a serialized (and optionally compressed) PHP array containing page tree records, content elements, and file references. It can only be imported by another TYPO3 instance using EXT:impexp. Other CMS platforms cannot read T3D files.

### Can I export TYPO3 data to JSON?

TYPO3 has no built-in JSON export. Install EXT:headless for a JSON content API, EXT:t3api for Extbase model endpoints, or in2code/migration for CLI-based JSON page tree exports. You can also build custom JSON endpoints using TypoScript PAGE types. Each requires configuration before use.

### Why are my TYPO3 file references broken after export?

EXT:impexp does not automatically export sys_file records stored at root level (pid=0). This means your FAL file index may be incomplete after import. Export sys_file, sys_file_reference, and sys_file_metadata tables separately via database dump, and copy the fileadmin/ directory.

### Does TYPO3 have a REST API for data extraction?

TYPO3 core does not include a REST API. Community extensions EXT:t3api and EXT:nnrestapi add REST endpoints with pagination and filtering, but require installation and model-level configuration. EXT:headless provides a JSON content API designed for decoupled frontends that can be repurposed for extraction.
