---
title: "How to Export Data from Umbraco: Methods, API Limits & Portability"
slug: how-to-export-data-from-umbraco-methods-api-limits-portability
date: 2026-10-12
author: Abdul Aleem
categories: [Umbraco]
excerpt: "How to export content, media, and schema from Umbraco. Covers the Content Delivery API, Management API, uSync, IContentService, direct SQL, and key portability traps."
tldr: "Umbraco has no single export button. Use the Content Delivery API (v12+), Management API (v14+), uSync, IContentService, or direct SQL. Each method has coverage gaps — most migrations combine multiple tools."
canonical: https://clonepartner.com/blog/how-to-export-data-from-umbraco-methods-api-limits-portability
---

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


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

**Umbraco has no single "Export Everything" button.** Your extraction path depends on your Umbraco version, your hosting model (self-hosted vs. Umbraco Cloud vs. Heartcore), and whether you're migrating to another Umbraco instance or leaving the ecosystem entirely.

Umbraco stores content in a **relational database** (SQL Server for production, SQLite for local development), but the content model follows an **Entity-Attribute-Value (EAV)** pattern. Content isn't stored in a table called `dbo.BlogPosts` with columns for `Title`, `Author`, and `Body`. Instead, it's fragmented across interconnected tables — `umbracoNode`, `umbracoContentVersion`, `umbracoPropertyData`, `cmsPropertyType`, `cmsContentType` — and modern layout tools like the Block Grid Editor store nested, proprietary JSON strings inside those property data columns.

The consequence of the EAV pattern for extraction: you cannot write a single SQL query that returns "all blog posts with their properties" the way you could with a flat CMS schema. You must either use application-layer APIs (which resolve the EAV relationships for you) or write complex pivot queries and post-process the results. A migration-ready extract almost always requires combining more than one tool.

> [!NOTE]
> **TL;DR:** Use the **Content Delivery API** (Umbraco 12+) for paginated JSON extraction of published content — but watch the 10,000-item pagination ceiling. Use the **Management API** (Umbraco 14+) for full CRUD access to content, media, and schema. Use a **custom C# `IContentService` script** for legacy versions (v7–11) or unpublished content. Use **uSync** for serialized XML exports across Umbraco instances. Use **direct SQL** when APIs don't cover what you need — but expect heavy transformation work. Each method has coverage gaps.

## Umbraco Export Methods Compared

| Method | Published Content | Drafts / Version History | Media Files | Users / Members | Schema (Doc Types) | Output Format | Best For |
|--------|------------------|--------------------------|-------------|----------------|-------------------|---------------|----------|
| **Content Delivery API** | ✅ (paginated JSON) | ❌ (published only) | URLs only | ❌ | ❌ | JSON | Headless extraction, cross-platform migrations |
| **Management API** (v14+) | ✅ | ✅ | ✅ | ✅ | ✅ | JSON (OpenAPI) | Full programmatic extraction |
| **C# `IContentService`** | ✅ | ✅ | Via IMediaService | ✅ | ✅ | Custom (JSON/CSV) | Legacy v7–11, complex transformations |
| **uSync / ContentEdition** | ✅ (with Content Edition) | ❌ | Separate copy | ❌ | ✅ | XML files on disk | Cross-environment sync, version migrations |
| **Umbraco Deploy** | ✅ | ❌ | Optional (ZIP) | ❌ | ✅ (.uda files) | ZIP archive | Umbraco-to-Umbraco transfers |
| **Heartcore REST API** | ✅ | Via Management API | ✅ | ✅ | ✅ | JSON (HAL) | Heartcore-hosted projects |
| **Direct SQL** | ✅ | ✅ | References only | ✅ | ✅ | SQL/CSV | Emergency recovery, full control |

## How does the Content Delivery API work for data extraction?

The **Content Delivery API** is a read-only REST API built into Umbraco, introduced in version 12. It delivers headless capabilities and returns published content items as structured JSON — the cleanest method for extracting published content when migrating away from Umbraco to another platform.

The API is disabled by default. Enable it in `appsettings.json`:

```json
{
  "Umbraco": {
    "CMS": {
      "DeliveryApi": {
        "Enabled": true,
        "PublicAccess": true
      }
    }
  }
}
```

Once enabled, query the `/umbraco/delivery/api/v2/content` endpoint. Pagination uses `skip` and `take` query parameters, with support for `fetch`, `filter`, `sort`, `expand`, and `fields` parameters. Retrieve descendants of a specific node with `fetch=descendants:{guid}` — useful for exporting an entire content branch.

```bash
curl -X GET "https://yourdomain.com/umbraco/delivery/api/v2/content?skip=0&take=100" \
     -H "Accept: application/json"
```

### The 10,000-item pagination ceiling

This is the most consequential limitation for bulk extraction. The Content Delivery API has a hard ceiling of 10,000 documents when using pagination — requests beyond this threshold return no additional results, regardless of how you construct the `skip`/`take` parameters. The pagination mechanism appears to work correctly up to the 10,000-item threshold, then silently stops.

This was reported as a bug against Umbraco 13.7.1 and targeted for the 13.8.0 release. **If your site exceeds 10,000 content items, you will not get a complete export from this API alone.** Partition your extraction by content type, date range, or subtree GUID — or fall back to the Management API, `IContentService`, or direct SQL.

### Rate limits on self-hosted Umbraco

Self-hosted Umbraco **does not impose built-in API rate limits** on the Content Delivery or Management APIs. ASP.NET Core 7+ includes rate limiting middleware you can configure yourself, but Umbraco does not enable it by default. The bottleneck on a self-hosted instance is your database and server capacity, not an API throttle.

That said, requesting hundreds of nodes in a single call will still cause problems. Keep `take` at **100 or below** to avoid memory exhaustion and HTTP 500 errors. For sites with 50,000+ nodes, even paged requests at 100 items can consume significant memory if the content type has many properties.

### Multi-language and culture variant extraction

The Content Delivery API handles culture-variant content through the `Accept-Language` header. To extract all language variants of a content node, you must issue a separate request per culture:

```bash
# English variant
curl -H "Accept-Language: en-US" "https://yourdomain.com/umbraco/delivery/api/v2/content?skip=0&take=100"

# Danish variant
curl -H "Accept-Language: da-DK" "https://yourdomain.com/umbraco/delivery/api/v2/content?skip=0&take=100"
```

**This is a critical gap for multilingual sites.** A single extraction pass without specifying language headers will return only the default culture variant. You must iterate through every configured language to get a complete export.

### What the Content Delivery API does NOT export

- **Unpublished content or drafts** — only the current published version is returned (unless you use the preview endpoint with authentication)
- **Version history**
- **Users, members, or permissions**
- **Document type definitions or schema**
- **Media binaries** — the response includes URLs and metadata, not the files themselves
- **Block List / Block Grid properties** are returned as complex nested JSON arrays that your target CMS must be able to parse and map
- **Non-default culture variants** unless explicitly requested per language

## What can the Management API extract?

The **Management API**, introduced in Umbraco 14, is a full CRUD RESTful API that powers the entire backoffice. All endpoints used by the backoffice combine to form the Management API, with a Swagger specification available at `{yourdomain}/umbraco/swagger`. It provides programmatic control over the full content model: Users, Members, Document Types, Media, Content, relations, languages, and dictionary items.

For data export, this means you can extract:

- All content nodes (published **and** unpublished)
- Media items and their binaries
- Document types, data types, and the complete schema
- Users and members
- Relations, languages, and dictionary items

### Server-to-server authentication (Umbraco 15+)

Umbraco 15 introduces a dedicated API user type that enables Client Credentials authentication (OAuth2) for server-to-server access to the Management API — eliminating the need for interactive browser-based login flows. This is the cleanest approach for automated extraction scripts.

```
POST /umbraco/management/api/v1/security/back-office/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&client_id=your-client-id&client_secret=your-secret
```

**Version matrix for Management API access:**
- **Umbraco 15+**: Management API with Client Credentials (API users) — cleanest for automation
- **Umbraco 14**: Management API available, but authentication requires OAuth2 with PKCE — functional but more complex for scripts
- **Umbraco 12–13**: Management API does not exist — use Content Delivery API or `IContentService`
- **Umbraco 7–11**: Neither API exists — `IContentService` or direct SQL only

## Custom C# Extraction via IContentService (All Versions)

For Umbraco 7, 8, 9, 10, and 11 — or any scenario where you need unpublished content and version history on versions that lack the Management API — writing a custom API controller or background task using **`IContentService`** is the most reliable method.

The `IContentService` interacts directly with the Umbraco database but abstracts away the EAV complexity, returning strongly typed objects with fully resolved property values.

### Paged content extraction with error handling

Never use `_contentService.GetRootContent()` and recursively load the entire content tree into memory. This will crash large sites. Use `GetPagedDescendants` with a checkpoint mechanism so the extraction can resume if it fails mid-run:

```csharp
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Models;

public class UmbracoExportService
{
    private readonly IContentService _contentService;
    private const string CheckpointFile = "extraction_checkpoint.json";

    public UmbracoExportService(IContentService contentService)
    {
        _contentService = contentService;
    }

    public void ExtractWithCheckpoint(int rootNodeId, int pageSize = 100)
    {
        int startPage = LoadCheckpoint();
        int pageIndex = startPage;
        long totalRecords;

        do
        {
            var pagedContent = _contentService.GetPagedDescendants(
                rootNodeId,
                pageIndex,
                pageSize,
                out totalRecords
            );

            foreach (var node in pagedContent)
            {
                // Serialize and write each node; clear references to avoid memory buildup
                ProcessNode(node);
            }

            SaveCheckpoint(pageIndex);
            pageIndex++;

        } while (pageIndex * pageSize < totalRecords);
    }

    private int LoadCheckpoint()
    {
        if (!File.Exists(CheckpointFile)) return 0;
        var json = File.ReadAllText(CheckpointFile);
        return JsonSerializer.Deserialize<int>(json);
    }

    private void SaveCheckpoint(int pageIndex)
    {
        File.WriteAllText(CheckpointFile, JsonSerializer.Serialize(pageIndex));
    }

    private void ProcessNode(IContent node)
    {
        // Serialize node properties to your target format
        // Set node = null after processing to encourage GC
    }
}
```

The checkpoint pattern saves the last successfully processed page index to disk. If the extraction crashes at page 400 of 500, you restart from page 400 rather than page 0.

### IMediaService paged extraction

The `IMediaService` provides the equivalent paged extraction pattern for media metadata:

```csharp
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Models;

public class UmbracoMediaExportService
{
    private readonly IMediaService _mediaService;

    public UmbracoMediaExportService(IMediaService mediaService)
    {
        _mediaService = mediaService;
    }

    public void ExtractMedia(int mediaRootId, int pageSize = 100)
    {
        int pageIndex = 0;
        long totalRecords;

        do
        {
            var pagedMedia = _mediaService.GetPagedDescendants(
                mediaRootId,
                pageIndex,
                pageSize,
                out totalRecords
            );

            foreach (var mediaItem in pagedMedia)
            {
                var umbracoFile = mediaItem.GetValue<string>("umbracoFile");
                var width = mediaItem.GetValue<int>("umbracoWidth");
                var height = mediaItem.GetValue<int>("umbracoHeight");
                var bytes = mediaItem.GetValue<long>("umbracoBytes");

                // umbracoFile is a JSON string: {"src":"/media/abc/file.jpg","crops":[...]}
                // Parse and queue for binary download
            }

            pageIndex++;

        } while (pageIndex * pageSize < totalRecords);
    }
}
```

Note that `umbracoFile` is stored as a JSON string even for simple images — parse it to extract the `src` path. Crop configurations for the Image Cropper are embedded in the same JSON object.

### Memory management for large sites

When iterating through `IContent`, Umbraco loads the full object graph for each node. For sites with 50,000+ nodes, you must explicitly clear the internal runtime cache during your extraction loop to prevent memory exhaustion. The `IRuntimeCacheProvider` can be cleared periodically (every 500–1,000 nodes) to release cached property data. In Umbraco 7 and 8, the `PublishedContentCache` is particularly aggressive about holding objects in memory and requires explicit flushing for large extractions.

### Event-based extraction for delta migrations

For near-real-time delta migrations — where you need to capture changes made during a long-running migration without re-exporting everything — Umbraco's notification system (`INotificationHandler`) lets you react to content events:

```csharp
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Notifications;

public class ContentPublishedHandler : INotificationHandler<ContentPublishedNotification>
{
    public void Handle(ContentPublishedNotification notification)
    {
        foreach (var content in notification.PublishedEntities)
        {
            // Queue this node ID for delta export
            // Write to a staging table or message queue
        }
    }
}
```

Register the handler in `Startup.cs` and use it during the final cutover phase to capture any content published between your bulk migration and go-live.

## How does uSync work for Umbraco exports?

[uSync](https://jumoo.co.uk/usync/) is a free, open-source community package. The uSync export process takes everything from your Umbraco site and writes settings, content, and media to disk in the uSync folder as XML files — one file per item. These can form the basis of imports on other Umbraco sites.

The key packages:

- **uSync** (free): Exports document types, data types, media types, macros, and templates
- **uSync.ContentEdition** (free): Adds content, media, and dictionary item export
- **uSync.Publisher**: Push and pull content between Umbraco sites from within the backoffice
- **uSync.Exporter**: Export whole sites or sections into portable "sync-pack" files

### Why uSync is a poor choice for cross-platform migrations

uSync's XML is highly proprietary. It mirrors Umbraco's internal architecture, mapping exact GUIDs (UDIs) and Data Type configurations:

```xml
<Content Key="a1b2c3d4-e5f6-a7b8-c9d0-1234567890ab" Alias="Home" Level="1">
  <Info>
    <Parent Key="00000000-0000-0000-0000-000000000000" />
    <Path>-1,1045</Path>
    <ContentType>homePage</ContentType>
  </Info>
  <Properties>
    <bodyText>
      <Value><![CDATA[{"layout":{"Umbraco.BlockList":[{"contentUdi":"umb://element/xyz"}]}}]]></Value>
    </bodyText>
  </Properties>
</Content>
```

If you're migrating to Contentful, WordPress, or any non-Umbraco system, writing a parser for this XML is significantly harder than working with JSON from an API. Much like [Kentico's native export packages](https://clonepartner.com/blog/blog/how-to-export-data-from-kentico-extraction-methods-api-limits-portability), **use uSync for Umbraco-to-Umbraco scenarios only.**

### Scale limits with uSync

For large sites, uSync exports can be slow. One community-reported benchmark: a partial content tree of approximately 16,000 nodes took 2–3 hours to export. Disabling dependency checking — which normally verifies every datatype, doctype, and related content/media item within all properties — significantly reduces export time. For sites above 10,000 nodes, test export performance in a non-production environment before committing to uSync as your migration path.

### uSync for cross-version migrations

uSync is particularly valuable when migrating between major Umbraco versions. The uSync Migrations package includes migrators that convert content from legacy formats into modern equivalents, then uses uSync Content Edition in the target version to import the migrated content. A typical path from Umbraco 7 to a modern version:

1. Upgrade to Umbraco 7.14/7.15 (latest v7 patch)
2. Export with uSync / Jumoo Migration Pack
3. Create a new Umbraco 12+ site
4. Install uSync and uSync Migrations
5. Import and convert
6. Upgrade to target version (13, 14, etc.)

## How does Umbraco Deploy work?

**Umbraco Deploy** is the official deployment tool, primarily for Umbraco Cloud but available for self-hosted instances. The Import and Export feature transfers content and schema between Umbraco environments via a ZIP file exported from one environment and imported into another.

Deploy provides two primary workflows: schema (document types, data types) is transferred as `.uda` files serialized to disk, while content and media are transferred by editors using backoffice operations.

### Version constraints

Import and export features are available for Umbraco Deploy supporting Umbraco 8 and above — it has not been ported back to Umbraco 7. For Umbraco 7 exports, you need custom code to generate an export archive in the Deploy format.

### Media file warning

Including content file dependencies (media files) for a large site can produce a very large ZIP file. Even with the media inclusion option enabled, direct transfer between cloud storage accounts (Azure Storage Explorer, AzCopy) or FTP is preferable for sites with media libraries above a few gigabytes.

## How to export from Umbraco Heartcore

Umbraco Heartcore is the managed headless SaaS variant. It provides REST API endpoints divided into Content Delivery (read-only, at `cdn.umbraco.io`) and Content Management (full CRUD, at `api.umbraco.io`).

### Heartcore rate limits

Heartcore enforces soft rate limits on delivery API requests, tiered by plan:

| Plan | Delivery API Limit | Management API Limit |
|------|--------------------|----------------------|
| Starter | 25 requests/second | No limit |
| Standard | 50 requests/second | No limit |
| Professional | 75 requests/second | No limit |
| Enterprise | 75+ requests/second | No limit |

Rate limits apply independently to the GraphQL, Content Delivery, and Preview APIs. **For bulk extraction, use the Content Management API** — it has no rate limit. Authenticate with a backoffice user's API key. The Content Delivery API (rate-limited) is the wrong choice for migration workloads.

## Direct SQL: The EAV Reality

Direct SQL gives you the most control and the fewest artificial limitations, but Umbraco's EAV schema—a structural pattern it shares with [Sitecore](https://clonepartner.com/blog/blog/how-to-export-data-from-sitecore-extraction-methods-api-limits-portability)—makes it painful to work with.

Content is not stored in a flat relational structure. To reconstruct a single content item, you must join multiple tables:

1. **`umbracoNode`** — structural ID, path, tree position, creation date
2. **`cmsContentType`** — document type schema and aliases
3. **`umbracoContentVersion`** — specific revisions; `current = 1` identifies the active version; `published = 1` identifies the published version
4. **`umbracoPropertyData`** — actual property values, with separate columns per data type (`varcharValue`, `textValue`, `intValue`, `dateValue`); also contains `languageId` and `segment` columns for culture variants
5. **`cmsPropertyType`** — maps property aliases to content types

Because `umbracoPropertyData` uses different columns based on the data type, writing a unified SQL query across multiple content types requires careful pivoting.

### Handling culture variants in SQL

**This is the most common correctness error in direct SQL extractions.** The `umbracoPropertyData` table has `languageId` and `segment` columns that distinguish culture-variant property values. The simplified query below will return only invariant (non-culture-specific) property values and silently omit all localized content:

```sql
-- WARNING: Incomplete for multilingual sites
SELECT 
  n.id,
  n.uniqueId,
  n.text AS nodeName,
  n.path,
  n.level,
  pt.alias AS propertyAlias,
  pd.varcharValue,
  pd.textValue,
  pd.intValue,
  pd.dateValue
FROM umbracoNode n
INNER JOIN umbracoContentVersion cv ON n.id = cv.nodeId AND cv.[current] = 1
INNER JOIN umbracoPropertyData pd ON cv.id = pd.versionId
INNER JOIN cmsPropertyType pt ON pd.propertyTypeId = pt.id
WHERE n.nodeObjectType = 'C66BA18E-EAF3-4CFF-8A22-41B16D66A972'
ORDER BY n.path
```

For multilingual sites, add language joins:

```sql
SELECT 
  n.id,
  n.uniqueId,
  n.text AS nodeName,
  n.path,
  n.level,
  pt.alias AS propertyAlias,
  l.languageISOCode,
  pd.segment,
  pd.varcharValue,
  pd.textValue,
  pd.intValue,
  pd.dateValue
FROM umbracoNode n
INNER JOIN umbracoContentVersion cv ON n.id = cv.nodeId AND cv.[current] = 1
INNER JOIN umbracoPropertyData pd ON cv.id = pd.versionId
INNER JOIN cmsPropertyType pt ON pd.propertyTypeId = pt.id
LEFT JOIN umbracoLanguage l ON pd.languageId = l.id
WHERE n.nodeObjectType = 'C66BA18E-EAF3-4CFF-8A22-41B16D66A972'
ORDER BY n.path, l.languageISOCode
```

A `NULL` `languageId` indicates an invariant property (not culture-specific). A non-null `languageId` is a culture-variant value for the language identified by that ID.

> [!WARNING]
> **Proceed with caution.** Interacting directly with the Umbraco tables isn't officially supported and could cause issues — Umbraco recommends working with the built-in APIs and services instead. Direct SQL is appropriate for read-only extraction, not for modifying data in a running instance.

### What direct SQL captures that APIs miss

- **Version history**: All `umbracoContentVersion` rows, not just the current published version
- **Unpublished drafts**: The `published` flag on content versions distinguishes draft from published
- **Recycle bin items**: Content in the recycle bin still exists in the database (nodes with `trashed = 1`)
- **User accounts and audit trails**: `umbracoUser`, `umbracoAudit`, and related tables
- **Custom tables**: Any extension or package that created its own database tables

### What direct SQL still misses

- **Media binaries**: The database stores file paths, not files. On Umbraco Cloud, media files are stored in Azure Blob Storage containers (one per environment). On self-hosted instances, they're typically in `wwwroot/media/`
- **Razor templates and views**: Stored on the filesystem, not in the database
- **Compiled assets and configuration**: `appsettings.json`, custom middleware, etc.
- **Examine indexes**: Umbraco's Lucene-based search indexes (managed via Examine) are rebuilt from the database but are not themselves a content source — they can, however, be useful for surfacing indexed content faster than paging the database during large-scale exports

### Backoffice XML export for small content sets

For non-technical users or small content sets, Umbraco's backoffice includes a built-in XML export accessible through the content tree (right-click → Export). This generates a basic XML file suitable for simple Umbraco-to-Umbraco transfers. It has no API rate limits and requires no code, but it does not handle media, schema, or large volumes — treat it as a convenience tool for fewer than a few hundred nodes.

## Handling Media and Files

Extracting text content is only half the migration. Umbraco handles media differently depending on the hosting configuration.

By default, media files are stored on disk in `~/wwwroot/media/` (or `~/media/` in older versions). The database holds a reference to the file path. If the site uses **UmbracoFileSystemProviders.Azure**, the files live in Azure Blob Storage.

### Media extraction strategy

1. **Extract metadata first.** Query the Media Delivery API endpoint, the Management API, or `IMediaService` to get file paths, alt text, dimensions, focal points, and media node IDs. The `umbracoFile` property is stored as a JSON string — parse it to extract `src` and any crop definitions.
2. **Download binaries separately.** Do not Base64-encode images into your JSON export — it bloats the payload and causes timeout errors. Export the absolute URL of each media item and have your target system's migration script download files via HTTP during the import phase.
3. **For Umbraco Cloud**, use AzCopy or Azure Storage Explorer to bulk-transfer between Azure Blob Storage containers. This is orders of magnitude faster than downloading through HTTP for large media libraries.
4. **Verify media references after transfer.** Media URLs in rich text content are stored as relative paths. After transferring files to the target system, you'll need a pass over all rich text fields to rewrite media paths.

## Umbraco Cloud vs. self-hosted: how the export path differs

| Factor | Self-Hosted | Umbraco Cloud | Heartcore |
|--------|-------------|---------------|----------|
| Database access | Full SQL Server access | Via `.bacpac` export or Cloud portal | No direct access |
| Media files | Local filesystem or Azure Blob | Azure Blob Storage (per environment) | Managed CDN |
| Content Delivery API | Available (v12+) | Available (v12+) | Dedicated CDN endpoint |
| Management API | Available (v14+) | Available (v14+) | Content Management API |
| API rate limits | None by default | None by default | 25–75 req/sec on Delivery |
| Umbraco Deploy | Install manually | Built-in | N/A |
| uSync | Install via NuGet | Install via NuGet | N/A |

For Umbraco Cloud database exports, creating a `.bacpac` file requires that the project use a SQL Server database — if the project uses SQLite, you need an external conversion tool or Umbraco Deploy to transfer content.

## What are Umbraco's biggest data portability traps?

### Block List and Block Grid editors

Umbraco's modern page builders don't output flat HTML. They store configuration and content as complex JSON objects inside `umbracoPropertyData`. If you export a page built with the Block Grid, the `bodyText` field won't contain `<p>Hello World</p>`. It will contain a JSON array referencing internal Element Types and UDIs (`umb://element/...`).

**The fix:** Your extraction script must parse this JSON, walk the `layout` and `contentData` arrays, resolve each `contentUdi` reference to its corresponding element content, map individual Umbraco blocks (e.g., "Hero Banner", "Two Column Text") to their equivalents in your new CMS, and reconstruct the HTML or target JSON structure. This is a custom transformation, not a generic operation — it requires knowledge of your specific Block types.

### Internal links (UDIs)

Umbraco uses Unique Data Identifiers (UDIs) for relationships. An internal link in the rich text editor looks like this:

```html
<a href="https://clonepartner.com/blog/{localLink:umb://document/12345...}">Click Here</a>
```

**The fix:** Run a regex pass over all rich text content during extraction. Match the UDI, query the Umbraco database or API for the node's actual URL slug, and replace the `{localLink:...}` tag with the resolved URL before sending data to the new system. The same resolution step applies to media picker values that store `umb://media/...` references instead of file paths.

### Razor templates

Umbraco's presentation layer uses Razor views (`.cshtml` files). These are .NET-specific and cannot be ported to non-.NET platforms. When migrating to WordPress, Webflow, or any non-.NET CMS, templates must be rebuilt from scratch. There is no automated conversion path.

### Third-party packages

Packages like Umbraco Forms, Umbraco Commerce, or custom property editors create their own database tables and data structures. The migration may extract data stored in third-party editors, but if the property editor structure has changed between versions or the editor doesn't exist on the target, the data will be in the database but not accessible through the backoffice or APIs. Identify all third-party packages and their database schemas before starting any extraction.

### Members and passwords

Member passwords are hashed and cannot be exported in a usable format. You can export member profiles and metadata, but a password reset flow will be required on the target platform. Plan this as a user communication and support item, not just a technical one.

### Culture variant completeness

Any site with culture-variant content requires multiple extraction passes — one per configured language — through all API methods. The SQL query, IContentService calls, and Content Delivery API requests must all account for language variants explicitly. Missing this step is the most common cause of incomplete [migrations for multilingual Umbraco sites](https://clonepartner.com/blog/cms-migration/umbraco).

## Recommended extraction strategy by scenario

**Migrating to another Umbraco instance (same or newer version):**
Use **Umbraco Deploy** (if on Umbraco Cloud) or **uSync** (self-hosted). These preserve the Umbraco content model and handle document type migration between versions. For large media libraries, transfer files separately via Azure Storage Explorer, AzCopy, or filesystem copy.

**Migrating to a non-Umbraco CMS:**
Use the **Content Delivery API** (v12+) or **Management API** (v14+) to extract structured JSON. Supplement with direct SQL for version history, unpublished drafts, culture variants, and data the APIs don't expose. Copy media files from Azure Blob Storage or the local filesystem. Budget significant time for template rebuilds — there is no automated path from Razor to another templating system. Block Grid properties require custom transformation code per Block type.

**Migrating from Umbraco 7–11 (no Management API):**
Use **`IContentService`** with paged extraction and checkpoint resumability. Add **`IMediaService`** for media metadata. Use uSync Migrations for the schema conversion layer if the target is a newer Umbraco version.

**Building a headless frontend against existing Umbraco content:**
Enable the **Content Delivery API** and use it directly. No extraction needed — the API serves published content in real time.

**Creating a disaster recovery backup:**
A database backup (`.bak` for SQL Server, file copy for SQLite) plus a media folder snapshot is the fastest full-fidelity backup. This is a restore artifact, not a migration-ready export — much like raw database backups in [systems like Plone](https://clonepartner.com/blog/blog/how-to-export-data-from-plone-methods-api-limits-portability), another platform cannot ingest it directly.

**Large-scale extraction (50,000+ nodes):**
No single API method is sufficient. Use `IContentService.GetPagedDescendants` with a checkpoint file. Process in batches of 100. Clear runtime caches every 500–1,000 nodes. Separate the media binary transfer entirely (AzCopy or filesystem). Expect the bulk extraction phase alone to take hours, not minutes. Use the event notification system to capture delta changes during the migration window.

---

> **Disclosure:** This guide is produced by ClonePartner, an Umbraco migration vendor. Recommendations reflect operational experience with Umbraco exports across self-hosted and Cloud installations. Verify specifics against official Umbraco documentation for your version.

## Frequently asked questions

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

There is no single "export all" button. For published content, enable the Content Delivery API (Umbraco 12+) and paginate through /umbraco/delivery/api/v2/content. For full access including drafts and schema, use the Management API (v14+), a custom IContentService script, or direct SQL. Each method misses something — combine as needed.

### What is the Content Delivery API pagination limit in Umbraco?

The Content Delivery API has a hard pagination ceiling of 10,000 items. Regardless of your skip/take values, you cannot retrieve more than 10,000 documents through this endpoint. For larger sites, partition by content type or subtree, or use the Management API or direct SQL.

### Does Umbraco have API rate limits?

Self-hosted Umbraco and Umbraco Cloud have no built-in API rate limits — the bottleneck is your server and database capacity. Umbraco Heartcore (SaaS) imposes soft rate limits on the Content Delivery API: 25 req/sec (Starter) up to 75+ req/sec (Enterprise). The Heartcore Content Management API is not rate-limited.

### Can I use a SQL dump to migrate away from Umbraco?

You can, but it's painful. Umbraco uses an Entity-Attribute-Value (EAV) database schema where content is fragmented across multiple tables (umbracoNode, umbracoPropertyData, umbracoContentVersion, etc.). Reconstructing usable content from raw SQL requires complex multi-table joins and pivoting. API or IContentService extraction is far easier when available.

### Can I export Umbraco content to CSV?

Umbraco has no native CSV export for page content. You must write a custom C# script using the IContentService to iterate through nodes, flatten the property data, and serialize it to CSV — or extract JSON via the Content Delivery API and convert it to CSV externally.
