Skip to main content
Back to all articles
Azure/August 27, 2026/7 min read

Deploying Synapse to Synapse: Moving from Dev to Prod

Promoting a pipeline is the easy part. Here's what it actually takes to move a Synapse workspace end to end - the objects, the schema, and the data that has to come with them.

AzureData Engineering

A Synapse Deployment Is Not One Thing

Ask a team how they deploy Synapse from dev to prod and most will point at one thing: the publish button, or the Azure DevOps (ADO) pipeline. Ask what that pipeline actually promotes and the answer narrows to Synapse objects like pipelines and notebooks; that's what Synapse's git integration is built for.

That's not wrong, but it's only part of the solution. A Synapse workspace is many things, it's orchestration logic, a database schema underneath it, and data that both of those things depend on. Deploy the first and skip the other two, and what you've promoted is a pipeline that runs successfully against a database it doesn't match, populated with stale data or nothing at all.

Many teams find this out the first time a "successful" deployment produces an empty dashboard.

The Three Things That Move Differently

Treating a Synapse deployment as one artifact is a big mistake. In practice, there are three separate things moving between environments, each with its own tooling, its own failure modes, and its own reason for not sharing a mechanism with the other two.

  • Workspace objects - pipelines, notebooks, linked services, datasets, triggers. Code, in the loose sense. This is what Synapse's publish branch and ARM template export handles.
  • Database objects - tables, views, stored procedures, schemas inside the dedicated SQL pool. This is schema, not code, and it needs a tool that understands schema drift.
  • Data - reference tables, lookup values, seed data that the pipelines and the schema both assume exists. This is the piece most CI/CD conversations forget entirely, because it isn't code and it isn't schema. It's state, and state deploys completely differently.

Collapse these into a single "deployment" step and you get exactly the failure mode above: pipelines run, the schema is close enough to work, and the report is empty because nobody moved the lookup table the pipeline was joining against.

1. Deploying Workspace Objects with Git

Synapse Studio's git integration is doing more work than it gets credit for, and most of the value disappears if a team treats it as optional.

Every pipeline, notebook, dataset, and linked service in the workspace lives as JSON in a git repo once git mode is switched on. Development happens on feature branches off collaboration, and nothing reaches the live Synapse service until it's published - which, critically, writes to a separate workspace_publish branch as ARM templates.

That branch is the actual deployable artifact. It's not the code you wrote; it's the compiled, parameterized representation of it.

That distinction matters for CI/CD specifically because it's what an Azure DevOps release pipeline or GitHub Actions workflow should be consuming - the ARM template output, not the collaboration branch directly. A release pipeline that picks up workspace_publish, applies environment-specific parameters (linked service connection strings, Key Vault references, integration runtime names), and deploys via the Synapse workspace deployment task is doing the same thing Synapse Studio's publish button does, just without a person clicking it and without the risk of someone publishing straight from a feature branch under deadline pressure.

2. Promoting Database Objects

The dedicated SQL pool underneath a Synapse workspace doesn't live in the git-integrated artifact set at all. Tables, views, and stored procedures are database objects, and deploying them by exporting ARM templates or copying JSON is the wrong tool for the job.

Inside Visual Studio, with SQL Server Data Tools installed, the SQL project is where the schema actually lives as source-controlled .sql files, and Schema Compare is the tool that reconciles it against a target. Point a comparison at the SQL project on one side and the target dedicated SQL pool on the other, and Visual Studio produces a full diff: every table, view, and stored procedure that's changed, been added, or been dropped, laid out object by object rather than as a wall of generated script.

That diff is the part that matters. You're not overwriting the target and hoping for the best, you're looking at exactly what's about to change before anything runs. Schema Compare lets you exclude individual objects from the update before generating the script, which is the difference between a stored procedure change going out cleanly and a DROP COLUMN on a fact table going out because it happened to be sitting in the same comparison.

The workflow that holds up in practice is to keep the SQL project as the source of truth in its own repo, separate from the Synapse workspace artifacts, run the comparison in Visual Studio against each target environment, review the generated update script, and only then execute it. For stored procedures and views this can move quickly.

For anything touching a table with real data behind it, that review step is the point, not friction to automate away. The reason this needs to be a separate step from pipeline deployment, not a follow-on script bolted to the end of it, is the same reason ingestion and ETL get split in the platform itself: when something breaks, you want the failure to be isolated to one layer. A pipeline deployment that "succeeds" while silently failing to apply a schema change is a debugging session that starts in the wrong place.

3. Moving Data With Pipeline Activities

Pipelines and schema get the CI/CD attention because they're the parts that look like code. Data doesn't get the same treatment, and that's exactly why it's usually the thing missing when a freshly deployed environment doesn't work.

Source and target tables need to exist and containg data within the target environment before the pipelines that depend on it will produce anything meaningful. None of this is exotic. A Copy Activity, the same tool used for the curated-to-staging hop inside the platform itself, is entirely sufficient for moving this kind of data between environments. What matters is treating it as a deployment step with its own place in the process, not as a one-time manual task someone did once when the prod environment was first stood up and never touched again.

In practice this means a small set of seed-data pipelines, version-controlled alongside everything else, that a release pipeline can trigger after the schema is in place and before the environment is considered ready.

Where This Actually Lives in CI/CD

None of the three pieces above need to be manual, and treating any of them as a manual step is where deployments start depending on whoever remembers to run them.

A release pipeline that does this properly has three stages, roughly in this order: publish and deploy the Synapse workspace ARM template with environment-specific parameters, run schema compare against the target dedicated SQL pool, then trigger the seed/reference-data pipelines if the target environment needs them populated. Gates between the stages matter; a schema deployment that fails silently and lets pipeline deployment proceed anyway produces pipelines that run against a database they don't match, and that failure mode is far harder to catch after the fact than a release that simply stopped.

Approval gates before the prod stage are worth keeping manual even once everything else is automated, particularly for schema changes. The goal of CI/CD here isn't to remove human judgment from a schema change with real data behind it; it's to remove the manual, error-prone parts - remembering which linked services need re-parameterizing, hand-writing ALTER statements, copying reference data by hand - so the human judgment that's left is aimed at the decision that actually needs it.

What Good Deployment Discipline Looks Like

Stripped of any specific tool, a Synapse deployment process that actually holds up has a few consistent traits:

  • Three separate deployment mechanisms, not one. Workspace objects through ARM templates, database objects through schema compare, data through pipeline activities.
  • A deployable artifact, not a branch. The workspace_publish branch and the .dacpac, not the collaboration branch or a live database connection, are what's needed.
  • Explicit parameterization, checked per environment rather than assumed correct because the template generated one.
  • Seed data treated as a deployment step, version-controlled and repeatable, not a manual task performed once and forgotten.
  • Gates between stages, so a failure in one layer stops the process instead of letting the next stage run against a target that isn't ready for it.

None of this requires exotic tooling. It requires treating a Synapse deployment as the three different problems it actually is, and solving each well.

Final Thoughts

The pattern here isn't unique to Synapse. Any platform that pairs orchestration with a database and reference data underneath it runs into the same split, and the teams that get bitten are almost always the ones that automated the part that looked like code and left everything else as a manual step someone remembers to do - until they don't.

Getting this right doesn't mean a bigger CI/CD platform or more tooling. It usually means three modest, well-scoped pipeline stages instead of a single large stage that does too much and hides failures.

If you're working through what a Synapse deployment process should look like for your environment, or trying to figure out why a "successful" deployment keeps producing something that doesn't quite work, I'm always happy to talk it through.