--- name: sqlpackage-import-export description: >- Moves a whole Azure SQL Database as a portable file with SqlPackage, choosing between the Extract, Publish, Export and Import actions, stating what each one carries, and giving the command line for each. Use when asked to export a database to a bacpac, extract or publish a dacpac, clone or move a database between servers, move the database itself from the local Azure SQL Database container up to Azure SQL Database, explain dacpac versus bacpac, or diagnose a failed sqlpackage run such as SQL71627, or SQL71659 when an Import stops because the target database is not empty. Application connection changes and first-time local-container setup are separate workflows. --- # Move a whole database with SqlPackage: dacpac and bacpac Verified 2026-09-02 against SqlPackage 170.4.83.3, and the engine behaviour below measured 2026-08-29 against a container reporting `EngineEdition` 5, `12.0.2000.8`. This owns the four-action decision for moving an entire existing database as a portable file, and the command line for each action. Building a dacpac from a source-controlled SQL project, shipping it through CI, its refactorlog and its pre and post deployment scripts are `sql-database-projects`. Azure SQL Database's own automated backups and point-in-time or geo-restore are `restore-and-recover`. Loading rows into a table that already exists is `bulk-load-and-bulk-copy`. Vector indexes themselves are `vector-search-azure-sql`. ## Read the property list for the action before you write the command Properties are per action. `ExtractAllTableData` is an Extract property and is not accepted by Export. There is no catalog of properties that spans the actions, so ask the build in front of you: ```bash sqlpackage /version:True sqlpackage /Action:Export /? ``` An unknown property is refused before any connection is attempted: ```text $ sqlpackage /Action:Export /p:ExportAllTableData=true /TargetFile:app.bacpac /SourceServerName:your-server.database.windows.net /SourceDatabaseName:app *** 'ExportAllTableData' is not a valid argument for the 'Export' action. ``` A property can also be real, documented and still unavailable: `/p:Storage=File` is the .NET Framework build's default, and Learn records `Memory` as the only option on the cross-platform build. Every parameter in this skill is written in long form. The same help output gives each one a short form, `/Action` as `/a`, `/SourceFile` as `/sf`, `/TargetFile` as `/tf`, and the two forms are interchangeable. ## The four actions, as four commands | Action | Direction | Default contents | File | |---|---|---|---| | Extract | database to file | schema only | writes `.dacpac` | | Publish | file to database | schema only | reads `.dacpac` | | Export | database to file | schema and every base table's rows | writes `.bacpac` | | Import | file to database | schema and every base table's rows | reads `.bacpac` | Extract: ```bash sqlpackage /Action:Extract /TargetFile:app.dacpac /DiagnosticsFile:extract.log \ /SourceServerName:your-server.database.windows.net /SourceDatabaseName: \ /SourceUser: /SourcePassword:"$SQLPACKAGE_PASSWORD" \ /p:ExtractAllTableData=false /p:VerifyExtraction=true ``` Export: ```bash sqlpackage /Action:Export /TargetFile:app.bacpac /DiagnosticsFile:export.log \ /SourceServerName:your-server.database.windows.net /SourceDatabaseName: \ /SourceUser: /SourcePassword:"$SQLPACKAGE_PASSWORD" \ /p:VerifyExtraction=true /p:LongRunningCommandTimeout=0 ``` Import: ```bash sqlpackage /Action:Import /SourceFile:app.bacpac /DiagnosticsFile:import.log \ /TargetServerName:your-server.database.windows.net /TargetDatabaseName: \ /TargetUser: /TargetPassword:"$SQLPACKAGE_PASSWORD" \ /p:DatabaseEdition=Standard /p:DatabaseServiceObjective=S1 ``` Publish: ```bash sqlpackage /Action:Publish /SourceFile:app.dacpac \ /TargetServerName:your-server.database.windows.net /TargetDatabaseName: \ /TargetUser: /TargetPassword:"$SQLPACKAGE_PASSWORD" \ /p:BlockOnPossibleDataLoss=true /p:DropObjectsNotInSource=false ``` `/p:DatabaseEdition` and `/p:DatabaseServiceObjective` are accepted by Import and Publish and are how the database they create is sized. Extract and Export do not accept them. ## Both Import and Publish can create the target; only Publish can rerun Microsoft Learn states it for each. Publish: if the database doesn't exist on the server, the publish operation creates it, otherwise an existing database is updated. Import: a new database can be created by the import action when the authenticated user has create database permissions. What Import will not do is load into a target that already holds a user object: ```text Error SQL71659: Data cannot be imported into target because it contains one or more user objects. ``` It refuses before any statement runs against the target, and retrying the same Import against the same name refuses again, every time, until that database is dropped and recreated or a new name is chosen. Publish diffs instead: rerun it against a target it already published to and it reports `Update complete` with nothing to apply. ## The property decides what is in the file, not the extension An Extract of a database with one table and one view produced a `.dacpac` carrying no data entry of any kind, and an Export of the same database produced a `.bacpac` carrying `Data/dbo.Widget/TableData-000-00000.BCP`, one entry per base table holding rows. Then the same Extract with one property added: ```bash sqlpackage /Action:Extract /TargetFile:app-with-data.dacpac \ /SourceServerName:your-server.database.windows.net /SourceDatabaseName: \ /SourceUser: /SourcePassword:"$SQLPACKAGE_PASSWORD" /p:ExtractAllTableData=true ``` That file is still named `.dacpac`, is still the output of Extract, and now carries `Data/dbo.Widget/TableData-000-00000.BCP` as well. `/p:TableData` is the narrower form, accepted by both Extract and Export, naming one table per occurrence: ```bash sqlpackage /Action:Extract /TargetFile:app-two-tables.dacpac \ /SourceServerName:your-server.database.windows.net /SourceDatabaseName: \ /SourceUser: /SourcePassword:"$SQLPACKAGE_PASSWORD" \ /p:TableData=dbo.Widget /p:TableData=dbo.WidgetAudit ``` Open the file and look rather than reading the name: ```bash unzip -l app-with-data.dacpac ``` ## An export is not a backup, and is not consistent by default Microsoft Learn states plainly that bacpac files aren't intended to be used for backup and restore operations. `BACKUP DATABASE app TO DISK='/tmp/x.bak'` against this engine returns `Msg 40510`, and there is no RESTORE either. Learn again, on Export: for an export to be transactionally consistent, either no write activity is occurring during the export, or the export is taken from a transactionally consistent copy of the database. Nothing in the output of a successful export says which of those was true. Export from a database copy, or from a database nothing is writing to, or state in the answer that the file may be internally inconsistent. ## Before an Export or Extract from a database with operating history Export is limited to the Azure SQL Database surface area, so a source carrying an element outside it fails with `SQL71627` after the whole schema model has already been built, discarding the entire attempt rather than the one object. The usual carriers are Windows-authenticated users and logins, such as an inherited `NT AUTHORITY\SYSTEM`, and leftover Service Broker or query notification permissions, most often a `RECEIVE` grant on `QueryNotificationErrorsQueue`. Open [references/preflight-and-sql71627.md](references/preflight-and-sql71627.md) before running an export against a database you did not create yourself: it holds the queries that find both classes and the remediation for each. Extract accepts two properties that drop the offending model elements, and Export accepts neither: ```bash sqlpackage /Action:Extract /TargetFile:app.dacpac \ /SourceServerName:your-server.database.windows.net /SourceDatabaseName: \ /SourceUser: /SourcePassword:"$SQLPACKAGE_PASSWORD" \ /p:IgnoreUserLoginMappings=true /p:IgnorePermissions=true ``` So when a database will not export, extracting the schema and moving the rows separately is the route that still runs. ## Read the plan before a Publish that could drop something DeployReport writes XML and Script writes T-SQL. Neither one changes the target database. ```bash sqlpackage /Action:DeployReport /SourceFile:app.dacpac /DeployReportPath:deploy-report.xml \ /TargetServerName:your-server.database.windows.net /TargetDatabaseName: \ /TargetUser: /TargetPassword:"$SQLPACKAGE_PASSWORD" ``` ```bash sqlpackage /Action:Script /SourceFile:app.dacpac /DeployScriptPath:publish.sql \ /TargetServerName:your-server.database.windows.net /TargetDatabaseName: \ /TargetUser: /TargetPassword:"$SQLPACKAGE_PASSWORD" ``` `/p:BlockOnPossibleDataLoss` defaults to True and is what stops a publish that would drop data. Leave it on. `/p:CreateNewDatabase=true` does not mean "create it if it is missing", which Publish already does: Learn describes it as whether the target database should be updated or whether it should be dropped and re-created. Setting it against a populated target destroys that target. ## A vector index breaks the round trip, and the export looks fine Check before planning anything around a bacpac: ```sql SELECT OBJECT_NAME(object_id) AS table_name, name FROM sys.indexes WHERE type_desc = 'VECTOR'; ``` An import creates schema objects before it loads data, so a vector index is created against an empty table. Measured 2026-08-31 against `12.0.2000.8`: a vector index needs at least 100 rows carrying non-null vectors, 99 is refused with `Msg 42266` and 100 succeeds. Drop the vector indexes before exporting and recreate them after the data is loaded. `TRUNCATE TABLE` is refused while a vector index exists (`Msg 42232`), so reloading in place hits the same wall one step earlier. ## Check it worked Exit code 0 says the action SqlPackage attempted finished. It does not say the rows arrived. ```bash unzip -l app.bacpac | grep TableData ``` Expect one `Data/./TableData-000-00000.BCP` entry per base table that held rows, and none for a view. Then compare the target against the source: ```sql SELECT SUM(p.rows) AS row_count, COUNT(DISTINCT t.object_id) AS table_count FROM sys.tables AS t JOIN sys.partitions AS p ON p.object_id = t.object_id AND p.index_id IN (0, 1); ``` Run it on both databases. Equal numbers, or a stated reason they differ, is the check. A schema only dacpac publishes to zero rows and that is correct, not a failure. ## References - [Measured runs, file listings, exit codes and provenance](references/dacpac-bacpac-contents-and-errors.md): open it when a claim above disagrees with what you are seeing, or to reproduce a measurement. - [The SQL71627 pre-flight scan](references/preflight-and-sql71627.md) - The property reference per action, and the only authority on whether a property exists: [Extract](https://learn.microsoft.com/sql/tools/sqlpackage/sqlpackage-extract), [Export](https://learn.microsoft.com/sql/tools/sqlpackage/sqlpackage-export), [Import](https://learn.microsoft.com/sql/tools/sqlpackage/sqlpackage-import), [Publish](https://learn.microsoft.com/sql/tools/sqlpackage/sqlpackage-publish), [Script](https://learn.microsoft.com/sql/tools/sqlpackage/sqlpackage-script) and [DeployReport](https://learn.microsoft.com/sql/tools/sqlpackage/sqlpackage-deploy-drift-report).