How to Export Data from TYPO3: Methods, API Limits & Portability
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.
Planning a migration?
Get a free 30-min call with our engineers. We'll review your setup and map out a custom migration plan — no obligation.
Schedule a free call- 1,500+ migrations completed
- Zero downtime guaranteed
- Transparent, fixed pricing
- Project success responsibility
- Post-migration support included
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.
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 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:
- Identifying which
CType/list_typecombinations use FlexForms (defined in TCA) - Parsing the XML structure for each plugin type individually
- 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)
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)
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.
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.
# 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-configurationsOptions 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.xmllarger than 10MB. In this case the only option left is going withdata.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_flexformis 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.
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)
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
# 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.sqlThe 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:
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:
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:
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 —
@importdirectives insys_templatepoint to files intypo3conf/ext/orconfig/; not captured by DB dump alone - Site configuration — stored in
config/sites/*/config.yamlon disk since TYPO3 v9+ - Extension code — lives in
typo3conf/ext/(classic) orvendor/(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
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:
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:
- Run the query above to get the
file_path(e.g.,/user_upload/hero-image.jpg). - Download the physical files from
fileadmin/via rsync, scp, or archive. - Check
sys_file_storagefor non-default storages (cloud, private, off-server). - In your migration script, map the physical file to the new CMS and update content references with the new media URL.
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.
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_linkpages.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:
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. But your throughput is constrained by server architecture:
- CPU overhead:
EXT:headlessrelies 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:
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/jsonThis 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.
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_timelimits) - 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_flexformXML 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:
- Field-level translation (like Contentful): Group the default record and all its
l10n_parentchildren into a single object before export. - 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:
- Identify custom tables via the TYPO3 backend (System > Configuration > TCA) or by querying:
SELECT DISTINCT table_name FROM information_schema.tables WHERE table_name LIKE 'tx_%'; - Write specific SQL queries for each table, applying the same
deleted=0,hidden=0, and workspace filters. - Join against category tables if they use TYPO3's native categorization system (
sys_category_record_mm). - Extract FAL relations using the same
sys_file_referencequery, changing thetablenamesparameter: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-redirectsis installed, rules live insys_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:impexpor 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
- Missing FAL records: Relying on
EXT:impexpalone, then discovering after import that file references are broken becausesys_filerecords at pid=0 weren't included. - 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.
- 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.
- 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.
- Ignoring MM relation tables: Content-to-category, content-to-file, and other many-to-many relationships are stored in separate MM tables. Exporting
tt_contentwithout its MM tables produces orphaned data. - 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. - Mixing live and workspace content: Raw SQL exports without filtering
t3ver_wsidor checking forpid = -1silently include draft and workspace content alongside live records. - Only copying
fileadmin/: TYPO3 supports additional, private, and off-server FAL storages. Checksys_file_storagefor non-default storage configurations. - Unresolved t3:// internal links: Exporting
bodytextor FlexForm values containingt3://page?uid=Nort3://file?uid=Nwithout resolving them produces link-broken content in any non-TYPO3 target. - Unparsed FlexForm XML: Treating
pi_flexformas 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. - Missed TypoScript filesystem includes: Dumping only
sys_templaterows without exporting the@import-referenced files fromtypo3conf/ext/orconfig/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
CTypeandlist_typevalues in use (run the GROUP BY query above) - Identify all
list_typeplugins using FlexForms and document their XML schemas - Verify
EXT:impexpis installed (composer show typo3/cms-impexp) - Check total database size and page count to determine if CLI export is required
- Inventory
fileadmin/size and checksys_file_storagefor non-default storages - Identify all configured languages and translation modes (connected vs. free)
- Document site configurations in
config/sites/ - Export
config/system/settings.phpfor global settings - Identify and export TypoScript filesystem includes from sitepackage
- Decide whether you need backend users, frontend users, or both
- Map all
CTypevalues 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:solris 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 covers why CSV is often the last step, not the first. If you're comparing export challenges across CMS platforms, our Plone export guide 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.
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.