Migrating Attachments and Notes Into Dataverse Without a Storage Bill Shock

A technical guide for the migration with several legacy sources and a long retention obligation: where files should live, notes as records with links, retention and legal hold, per source mechanics, reconciliation and a storage estimate before you commit.

Before migrating attachments and notes into Dataverse, decide where the files will live, because note and email attachments count against Dataverse file capacity, and a ten-year retention obligation only ever grows. Dataverse capacity is usually a far more expensive place to keep old documents than SharePoint or Azure Blob Storage, so check current Microsoft capacity add-on pricing before you load anything. Keep notes as Dataverse records, but store the files in SharePoint through document management, or in Blob Storage with a pointer record holding the link, size and hash. Document retention and legal hold where the files live, migrate each source with configured tools, reconcile counts, bytes and hashes, and estimate storage before committing.

Why do attachments and notes cause a storage bill shock in a Dataverse migration?

Because they are planned as a detail of the record migration and turn out to be most of the volume. A legacy CRM, a file share and an email archive can hold many times more bytes in documents than in every account, contact and case put together. Loaded straight into notes, those documents land in Dataverse capacity that is pooled across the tenant, and the first capacity report after go live is where the problem is noticed.

Long retention makes it worse. If a regulation or contract requires documents to be kept for ten years, nothing can be cleaned up during that period, and new documents keep arriving on top of the migrated ones. The decision about where files live is therefore a design decision to make before the first load, not a cleanup to schedule afterwards.

If you are already over capacity in a live environment, start with our Dataverse storage capacity cleanup guide, which covers finding the full bucket and moving existing attachments out safely. This page is about not creating the problem during a migration.

Where do migrated attachments and notes land in Dataverse capacity?

Dataverse capacity is split into database, file and log buckets, each with its own entitlement and its own add-on. The per unit price differs by bucket and Microsoft revises it, so check current Microsoft capacity add-on pricing and your own per table breakdown in the Power Platform admin center rather than relying on a figure from any article. The distinction that matters for a migration is which parts of a note or email go where.

What you migrateWhere it landsDesign consequence
Note text, subject, owner, dates and regarding record (annotation)Database capacity, as a rowSmall per note; keep notes as records
File attached to a noteFile capacity in the current storage modelThe main cost driver; move files out for long retention
Email activity body and metadataDatabase capacityLarge bodies add up; decide which emails need to be activities at all
Email attachments (activitymimeattachment)File capacity in the current storage modelSignatures and logos are often most of the count; filter them out
File and image columnsFile capacityConvenient, but the same cost consideration as note attachments
Pointer record to SharePoint or Blob StorageDatabase capacity, as a small rowThe file bytes are stored and retained outside Dataverse

What storage design holds ten years of attachments without filling Dataverse?

Separate the record from the file. Dataverse keeps what users search, filter and report on: the note, the email metadata and a reference to the document. The file bytes live in storage designed for documents and long retention. Choose the destination by how users need to open the files and what the retention policy demands.

DesignBest forTrade off
Files stay in Dataverse notes or file columnsSmall volumes, short retention, documents users open dailyEvery byte counts against Dataverse capacity for as long as it is kept
SharePoint document management integrationDocuments users still open from the record, with Microsoft Purview retention and holdsFolder structure and permissions need design; SharePoint permissions are separate from Dataverse security
Azure Blob Storage with a Dataverse pointer recordLarge archives opened rarely, strict immutability, lowest cost storage tiersOpening a file from the record needs a secure link to be generated, which is a small build rather than configuration
Archive only, outside the CRMClosed history nobody works on, kept only to satisfy retentionUsers search the archive rather than the record; agree this with them first
  • A pointer record is a custom table with a lookup to the parent record, the storage path or document location, file name, content type, size in bytes, a content hash, the source system and its original identifier, and the retention class.
  • With SharePoint integration, Dataverse holds document location records that point to a folder per record, and users see the documents on the record form.
  • Keep the hash and size on the pointer record from day one: they are what the reconciliation and any later integrity check rely on.

How should notes be migrated: as records with links rather than embedded files?

Migrate every note as a note, with its original text, author, created date and regarding record, and leave the file out of it. Where the source note had an attachment, put a link to the document in SharePoint or a reference to the pointer record into the note, so a user reading the timeline can still reach the file in one step.

Preserve the original created date and owner, because a timeline of notes all dated on migration weekend is useless as evidence. How overriddencreatedon and ownership are carried across is covered in our data migration guide, so it is not repeated here.

  • Convert rich text or HTML note bodies to the format your Dataverse note rendering supports, and test long notes for truncation.
  • Skip empty notes created only to carry a file, and represent those files as pointer records or documents instead.
  • Keep the source note identifier on the note or pointer record, so a rerun updates rather than duplicates.
  • Keep notes and emails that genuinely need to stay live in Dataverse, and move closed history the business agrees nobody works on to the archive.

How do retention and legal hold work across Dataverse, SharePoint and Azure Blob Storage?

Write the retention and legal hold policy before the design is final, because the storage choice decides which controls are available. The policy should state each document class, its retention period and trigger, who can place and release a hold, and where evidence of disposal is kept. Involve your records manager and data protection officer: keeping personal data for ten years has to be justified as well as enforced. This page is technical guidance, not legal advice, and how retention and erasure work for personal data in Dynamics 365 is covered in our guide to GDPR retention and erasure.

Where the files liveRetention controlsLegal hold
Dataverse notes and file columnsBulk deletion jobs and long-term data retention policies for inactive rows; check current Microsoft documentationNo native hold on individual rows comparable to SharePoint or Blob Storage; holds depend on process and on excluding rows from deletion jobs
SharePointMicrosoft Purview retention policies and retention labels applied to sites, libraries or documentsMicrosoft Purview eDiscovery holds preserve content even if a user deletes it
Azure Blob StorageLifecycle management rules and time-based retention policies on immutable storageLegal hold on immutable storage prevents deletion and modification until the hold is cleared

How do you estimate the storage before you commit to a design?

From an inventory of the real files, not from a guess based on record counts. The estimate is what turns the design choice into a decision finance can sign off, and it usually changes the scope before anything is loaded.

  • Inventory every source: file count, total bytes, sizes by file type and by year, and the parent record each file belongs to.
  • Hash every file and remove duplicates: the same contract attached to five emails and three records is one file.
  • Exclude noise such as signature images, logos, calendar files and zero byte files, and record the exclusion rule.
  • Split the inventory by retention class and by whether users still open the files, which maps directly to the design options.
  • Project growth over the retention period from the current rate of new documents, not only the migrated backlog.
  • Run a pilot load of a representative sample into a sandbox and compare the per table capacity before and after, allowing for the delay before capacity reporting refreshes.
  • Price each design option against current Microsoft capacity add-on pricing and your SharePoint and Azure storage costs, and record the assumptions next to the numbers.

How do you migrate attachments and notes from each legacy source?

Every source needs the same output: files in the chosen destination, a manifest per file, and notes or pointer records linked to the right parent. How you get there differs by source. Files always load after their parent records exist, as described in the load order in our data migration guide.

SourceHow files and notes come outHow they go in
SalesforceAttachment, Note, ContentNote and ContentVersion content with ContentDocumentLink rows naming the parent, through the Data Export service with files included or a data integration toolNotes into Dataverse on the Salesforce Id; files to SharePoint or Blob with pointer records resolved through the parent Id
File sharesFolder paths that encode the customer or case, plus file system metadataSharePoint Migration Manager or AzCopy for the files; a mapping from folder to parent record for document locations or pointer records
Email archivesMessages exported as individual files with sender, recipients, date and subject, using an archive or eDiscovery exportOnly business relevant threads as email activities; the rest stored as files with pointer records against the matched contact or account
Legacy CRMA database table of attachments holding binary content or a file path, joined to the parent keyExtracted to files with a manifest, then the same destination and pointer pattern
SpreadsheetsRows with note text and sometimes a file path or hyperlink columnNotes through a dataflow or import; linked files copied and turned into pointer records

What can be done without a developer, and where does code become necessary?

More than most teams expect, as long as someone owns the manifest. Configured tools cover the bulk movement; code is only unavoidable for a few specific jobs. Plan for that honestly rather than discovering it halfway through.

  • SharePoint Migration Manager and AzCopy move large file sets into SharePoint or Blob Storage without code, with their own logs.
  • Dataflows and the Dataverse import handle notes and pointer records from a manifest spreadsheet or table, using alternate keys on the source identifier.
  • Data integration tools with Dataverse, SharePoint and Blob components, such as KingswaySoft or Azure Data Factory, are configured rather than coded, and are compared in our data migration guide.
  • Power Automate cloud flows suit low volumes, such as a department's remaining files or the delta after cutover. Each file is a run, so check current Power Automate request limits before using it for a large archive.
  • Code is usually needed to extract binary content from a legacy CRM database, to generate secure links for opening Blob files from a record, and for very large volumes where throughput matters. Throttling and batching for that case are covered in the Dataverse bulk import strategy.

How do you reconcile the migration to prove no attachment or note was lost?

With a manifest built before the load and checked after it, so completeness is a number rather than a feeling. The manifest lists every file and note from the source with its identifier, parent key, size and hash, plus every exclusion with its reason. The full validation set for records is in our data migration guide; these are the checks specific to files and notes.

  • Counts: files and notes in the source equal files and notes loaded plus files and notes excluded by a recorded rule, per source.
  • Counts per parent: the number of notes and files on each parent record matches the source, so a correct total cannot hide files attached to the wrong record.
  • Bytes: total bytes per source and per parent table match the manifest.
  • Hashes: the hash of each file in its destination matches the hash recorded at extraction, which proves the content is unchanged.
  • Orphans: no pointer record without a file, and no file in the destination without a pointer record or document location.
  • Opening: a sample chosen by the business opens from the record in the app, including the oldest and largest files.
  • Evidence: the manifest, results and exclusion list are kept with the retention policy, because they are what an auditor will ask for.

Is Dataverse the right home for documents with a long retention obligation?

Dataverse is the right home for the records and the references; it is rarely the right home for a decade of document bytes. On Dynamics 365 and Power Platform the practical answer is almost always a split, with SharePoint or Azure Blob Storage holding the files under proper retention controls. How add-on capacity fits into licence decisions is covered in our guide to Dynamics 365 licensing costs and renewals.

We recommend the right solution - whether that's Microsoft Dynamics 365, Power Platform, or a custom-built CRM. Some businesses need the Microsoft ecosystem. Others need full control without licensing. We deliver both. Where storage and per-user licensing together no longer fit a document heavy process, a custom-built CRM on React, Node.js, PostgreSQL or .NET gives you direct control over where files are stored and what that storage costs.

How does Solzet help migrate attachments and notes into Dataverse?

We start with the inventory: every source, its file counts and bytes by type, year and parent, duplicates and noise, and the retention classes your records manager needs. From that we put the storage estimate and design options in writing, agree the retention and legal hold policy, then build the manifest, run the loads source by source with configured tools wherever they fit, and deliver the reconciliation evidence before the old sources are switched off.

The work is done by senior consultants and full-stack developers delivering remotely from Yerevan, Armenia, with 8+ years of Dynamics 365 Customer Engagement and Power Platform work, directly for your team or white-label for Microsoft partners. If capacity is already under pressure, our storage capacity cleanup guide is the place to start.

What do people ask us?

Do attachments count against Dataverse file capacity or database capacity?

In the current storage model, files attached to notes, email attachments and file and image columns count against file capacity, while the note text and email metadata are rows in database capacity. Microsoft has changed which tables count toward which bucket over time, so confirm it in the per table breakdown on the capacity page in the Power Platform admin center.

Should we migrate attachments into Dataverse notes or into SharePoint?

For small volumes that users open daily, notes are simple. For large volumes or long retention, store the files in SharePoint through the document management integration, or in Azure Blob Storage with a pointer record, and keep the notes in Dataverse with a link. Check current Microsoft capacity add-on pricing and estimate from a real file inventory before deciding.

How do we apply a legal hold to migrated documents?

Put documents that may need a hold where a hold is enforced by the platform. SharePoint content can be preserved with Microsoft Purview eDiscovery holds and retention policies, and Azure Blob Storage supports legal holds on immutable storage. Dataverse rows have no comparable native hold, so a hold there depends on process and on excluding records from deletion jobs. Involve your records manager and legal team.

How do we estimate Dataverse storage before migrating attachments?

Inventory the real files in every source by count, bytes, type, year and parent, remove duplicates by hash and noise such as signature images, split by retention class, and project growth over the retention period. Then load a representative sample into a sandbox, compare per table capacity before and after, and price each design against current Microsoft add-on pricing.

Can we migrate attachments without a developer?

Largely, yes. SharePoint Migration Manager and AzCopy move files, dataflows and imports load notes and pointer records from a manifest, and data integration tools are configured rather than coded. Power Automate suits low volumes. Code is usually needed to extract binary content from a legacy CRM database, to open Blob files securely from a record, and for very large volumes.

How do we prove no attachment was lost in the migration?

Build a manifest before the load with every file's identifier, parent, size and hash, plus every exclusion and its reason. After the load, reconcile counts per source and per parent, total bytes, file hashes in the destination, orphans in both directions, and a business chosen sample that opens from the record. Keep the results as evidence.

How do we migrate Salesforce files and notes into Dataverse?

Extract Attachment, Note, ContentNote and ContentVersion content together with the ContentDocumentLink rows that say which record each file belongs to. Load notes into Dataverse on the Salesforce Id after their parent records exist, and send files to SharePoint or Blob Storage with pointer records, or into notes for small volumes. Our Salesforce data migration guide covers the full load order.

Which solution is right for your business?

Tell us what you need. A senior consultant replies within one business day with a recommendation - Dynamics 365, Power Platform, or a custom-built CRM - not a sales script.