What is a DACPAC?
A DACPAC - short for Data-tier Application Package - is a single file that captures the entire schema of a SQL Server database. Tables, views, stored procedures, functions, indexes, users, roles, and the deployment settings that go with them. It is the artifact most teams ship when they want to version-control a database the same way they version-control their application code.
The file has a .dacpac extension. Underneath it is a regular ZIP archive containing XML and metadata - if you rename one to .zip you can open it and look inside. The format is owned by Microsoft and supported across SQL Server, Azure SQL Database, and Azure SQL Managed Instance.
A DACPAC is the schema of a database, packaged as a single, versioned file you can build, store, diff, and deploy.- the working definition
The important word in that definition is schema. A DACPAC describes the shape of the database - it does not contain rows. If you need the data too, the format you want is the BACPAC, covered later in this article.
What is inside the file
A DACPAC is not a runnable SQL script. It is a declarative description of the database, plus the model the tools need to compare it against a live target. Inside the archive you will typically find:
model.xml- the canonical, normalized definition of every object in the database (tables, columns, types, constraints, indexes, views, procedures, functions, users, roles, permissions).Origin.xml- metadata about how the package was produced, the source server collation, and the database compatibility level.DacMetadata.xml- the package's name, version, and description - the bits a deployment tool uses to record what was deployed.- Pre- and post-deployment scripts, if the project defined them - free-form T-SQL that runs before or after the schema diff is applied.
You do not edit these files by hand. You build them from a SQL Server Database Project, or extract them from an existing database. The file is the deployable artifact; the project is the source.
State-based deployment
There are two well-known patterns for evolving a database over time. DACPACs sit squarely in one of them.
- Migration-based. You write an ordered list of small change scripts - add column X, create table Y, rename Z to W - and the deployment tool runs the ones the target has not seen yet. Entity Framework migrations, Flyway, and Liquibase work this way. The source of truth is the history.
- State-based. You describe the database you want, in full, as if you were creating it from scratch. The deployment tool reads the current state of the target, diffs it against your description, and generates the upgrade script on the fly. The source of truth is the destination.
DACPACs are the state-based model. Your project is always written as here is what the database should look like. The diffing - the figuring out of which ALTER statements to emit - is done by the deployment engine (a library called DacFx) when you publish.
The win is that your source code reads like a database, not like a transaction log. The cost is that some changes - renames, splits, data motion - cannot be inferred safely from a diff and need pre/post-deployment scripts or refactor-log entries to land correctly.
How you create one
The canonical way to produce a DACPAC is from a SQL Server Database Project - a .sqlproj in Visual Studio, Azure Data Studio, or VS Code with the SQL Database Projects extension. Each object in the database is one file:
MyDb.sqlproj
├── Tables/
│ ├── Customer.sql
│ └── Order.sql
├── Views/
│ └── CustomerOrders.sql
├── Procedures/
│ └── PlaceOrder.sql
└── Scripts/
├── Pre-Deployment.sql
└── Post-Deployment.sql
Each .sql file contains a single CREATE statement - CREATE TABLE Customer (...), CREATE PROCEDURE PlaceOrder (...). You never write ALTER. The project compiles the files into the model, validates references between them, and emits the DACPAC.
Building is a normal .NET build:
$ dotnet build MyDb.sqlproj
# produces ./bin/Debug/MyDb.dacpac
The other path to a DACPAC is extracting one from a live database. This is how you bring an existing database under source control - point SqlPackage at it, get the file out, then create a project from it.
$ sqlpackage /Action:Extract \
/SourceConnectionString:"Server=..;Database=MyDb;..." \
/TargetFile:MyDb.dacpac
How you deploy one
The companion tool to the DACPAC is SqlPackage - a cross-platform .NET CLI for everything DACPAC-related. There are three actions you reach for most often.
Publish- the headline action. SqlPackage connects to the target database, builds a model of its current state, compares it against the DACPAC, and applies the difference. If the target does not exist, it creates it. If it does, it runs the upgrade.Script- the same diff, but written to a.sqlfile instead of executed. This is what you review in a pull request, or hand to a DBA for a controlled production run.DeployReport- an XML summary of what would change. Useful in CI as a gate.
A typical local run looks like this:
$ sqlpackage /Action:Publish \
/SourceFile:./bin/Debug/MyDb.dacpac \
/TargetServerName:localhost \
/TargetDatabaseName:MyDb \
/p:BlockOnPossibleDataLoss=true
The /p: flags are publish properties - dozens of switches that control how aggressively the engine will alter the target. The one above is the safety net you want on by default: refuse to run if the diff would drop a column, drop a table, or shrink a type.
DACPAC vs BACPAC
The two formats are siblings and the names get confused all the time. The distinction is simple.
- DACPAC - schema only. The shape of the database. Used to deploy and upgrade.
- BACPAC - schema plus data. A full export of the database content, intended for moving a database between servers or environments.
A DACPAC is what you ship from CI on every commit. A BACPAC is what you take when you need a portable snapshot - migrating from on-premises SQL Server to Azure SQL, archiving a database before decommissioning it, copying production into a lower environment. BACPACs are larger, slower to produce, and not designed for incremental upgrades.
Where DACPACs fit in CI/CD
The reason teams adopt DACPACs is the same reason they adopt any deployable artifact: the file you build is the file you ship. The pipeline looks the same as for an application:
- Build -
dotnet buildon the database project producesMyDb.dacpac. The build itself catches a class of errors - unresolved references, invalid syntax, broken view dependencies - before anything touches a real database. - Publish as artifact - the
.dacpacis stored next to the application binaries it accompanies. Same version number, same retention. - Deploy - in each environment, the pipeline calls SqlPackage
Publishwith that environment's connection string and its own publish profile (a.publish.xmlfile holding the per-environment/p:flags).
The artifact is environment-agnostic. The publish profile carries the environment-specific behavior. The same DACPAC promotes through dev, staging, and production - you change the target, not the file.
Trade-offs and caveats
DACPACs are a strong default for SQL Server work, but the model has rough edges worth knowing before you commit.
- Renames are diffs of drops and creates. The engine cannot tell rename column A to B from drop A, create B. Without a refactor-log entry or a pre-deployment script, you lose the data in that column. The
BlockOnPossibleDataLossflag is the guardrail. - Some objects are not modelled in full. Server-level objects, certain Azure-specific features, and a handful of advanced SQL Server features either need workarounds or are unsupported. The list shrinks every release, but check before you bet on it.
- Large diffs against busy databases can be slow. SqlPackage takes locks while it works. For very large schemas or hot production tables, generating the script with
/Action:Scriptand running it in a controlled window is safer than lettingPublishdo it live. - The build is a single artifact, not a history. If you need to know how a schema got to where it is - audit, reproducibility, surgical rollback - migration-based tools give you that for free; DACPACs do not.
None of these is a reason to avoid the format. They are the trade-offs you take on when you choose state-based deployment, and they are the ones every team adopting DACPACs eventually learns by hitting them.