Environment-Aware Deployments in Fabric SQL Database (Without SQLCMD Variables)

If you’ve worked with SQL Server Database Projects in a traditional CI/CD setup, you’ve probably solved the “which environment am I deploying to?” problem with SQLCMD variables. You define an $(Environment) variable, set it to DEV, TEST, or PROD in separate publish profiles, and branch on it in your post-deployment script. Simple and reliable.

Then you move to SQL database in Microsoft Fabric, and that pattern stops working.

The problem

Fabric SQL database comes with built-in Git integration and deployment pipelines. Under the hood it still uses a SQL project (.sqlproj), but Fabric owns that file. Any manual edits you make to the .sqlproj in your repository are reset the next time Fabric commits to source control. There’s no publish profile to edit either, because you’re not running sqlpackage yourself. Fabric does the deployment for you.

That means no custom SQLCMD variables and no easy way to tell your scripts which environment they’re running in.

The good news is that Fabric now supports pre- and post-deployment scripts as part of its built-in CI/CD. You create a query under Shared Queries, open its menu, and select Set as Post-deployment Script. From then on, it runs automatically whenever the database is updated from Git or deployed through a deployment pipeline.

So we have a hook that runs on every deployment. What we still need is a way for that script to figure out where it’s running.

Asking the database where it lives

Every environment in Fabric typically lives in its own workspace: one for dev, one for test, one for prod. If the database can tell us which workspace it belongs to, we can branch on it.

It turns out it can. Let’s see what SERVERPROPERTY('ServerName') returns in a Fabric SQL database:

sql

SELECT SERVERPROPERTY('ServerName') AS ServerName;

The result looks something like this:

3f7a1c92-5b4e-4d8a-9c21-7e6f0b8d4a15-a91d4e27-0c6b-4f3e-8b75-2d9c1e6f8a03.database.fabric.com

The server name is made up of two GUIDs joined by a hyphen, followed by the .database.fabric.com suffix:

<tenant-id>-<workspace-id>.database.fabric.com
3f7a1c92-5b4e-4d8a-9c21-7e6f0b8d4a15 - a91d4e27-0c6b-4f3e-8b75-2d9c1e6f8a03 .database.fabric.com
└──────────── Tenant ID ─────────────┘ └─────────── Workspace ID ────────────┘

The first GUID is your Microsoft Entra tenant ID. It’s the same for every database in your organization, so it’s useless for telling environments apart. The second GUID is the ID of the Fabric workspace the database lives in, and that’s exactly the environment fingerprint we’re after.

Tip: To find out which workspace ID belongs to which environment, open each workspace in the Fabric portal and look at the URL: app.fabric.microsoft.com/groups/<workspace-id>/.... That’s the same GUID you’ll see in the server name.

Extracting the workspace ID

Rather than comparing the full server name string, extract the workspace ID. Each GUID is 36 characters long, so the tenant ID occupies positions 1 to 36, and the workspace ID starts at position 38 (after the separating hyphen):

sql

DECLARE @server NVARCHAR(256) = CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(256));

SELECT
    LEFT(@server, 36)          AS TenantId,
    SUBSTRING(@server, 38, 36) AS WorkspaceId;

Branching in the post-deployment script

Now you can write a post-deployment script that behaves differently depending on the workspace:

sql

DECLARE @workspaceId CHAR(36) =
    SUBSTRING(CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(256)), 38, 36);

IF @workspaceId = 'a91d4e27-0c6b-4f3e-8b75-2d9c1e6f8a03'
BEGIN
    PRINT 'Production workspace detected';
    -- Production-only logic
END
ELSE IF @workspaceId = '5c2e8b14-9f7a-4d61-a3c8-0e4b7d2f9a6c'
BEGIN
    PRINT 'Test workspace detected';
    -- Load test data, enable diagnostics, etc.
END
ELSE
BEGIN
    PRINT 'Development or unknown workspace';
    -- Safe default behavior
END

Notice the ELSE branch. It matters more than it looks, as we’ll see below.

Things to watch out for

Workspace IDs are not permanent. If a workspace is deleted and recreated, it gets a new ID, and your script will silently fall into the ELSE branch. Keep that in mind when restructuring workspaces.

Branch-out creates new workspaces. Fabric’s “branch out to a new workspace” feature gives each feature branch its own workspace, each with its own ID. You can’t list these in advance, so make sure the fallback branch behaves safely. Treating unknown workspaces as development is usually the right call. Never let an unknown workspace fall through to production behavior.

Compare full GUIDs. It’s tempting to write LIKE '%a91d4e27%', but partial matching invites subtle mistakes. Extract the exact workspace ID and compare it with equality.

This relies on the server name format. Microsoft doesn’t document this format as a contract, so it could change in the future. Keep the parsing logic in one place so it’s easy to fix if it does.

A more durable alternative: a configuration table

If hard-coding workspace IDs feels brittle, there’s another approach that leans on a useful property of Fabric’s deployment model: it updates schema but leaves existing data in place.

Define a configuration table in your project so the schema is source-controlled:

sql

CREATE TABLE dbo.EnvironmentConfig (
    ConfigKey   NVARCHAR(50)  NOT NULL PRIMARY KEY,
    ConfigValue NVARCHAR(200) NOT NULL
);

Then, manually and once per workspace, insert the environment value:

sql

INSERT INTO dbo.EnvironmentConfig (ConfigKey, ConfigValue)
VALUES ('Environment', 'PROD');

This row lives only in that database. It isn’t in Git, and deployments won’t touch it. One important rule: don’t put this INSERT in your post-deployment script. The script runs identically everywhere, so it would overwrite your per-environment values.

Combining both approaches

You can also use both: read from the config table first, and fall back to the workspace ID if the table is empty. This handles freshly branched workspaces that haven’t been configured yet:

sql

DECLARE @env NVARCHAR(200) =
    (SELECT ConfigValue FROM dbo.EnvironmentConfig WHERE ConfigKey = 'Environment');

IF @env IS NULL
BEGIN
    DECLARE @workspaceId CHAR(36) =
        SUBSTRING(CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(256)), 38, 36);

    SET @env = CASE @workspaceId
        WHEN 'a91d4e27-0c6b-4f3e-8b75-2d9c1e6f8a03' THEN 'PROD'
        WHEN '5c2e8b14-9f7a-4d61-a3c8-0e4b7d2f9a6c' THEN 'TEST'
        WHEN 'e8b3f607-1d4c-4a92-b5e7-6c0a9f3d2b81' THEN 'DEV'
        ELSE 'DEV'
    END;
END

PRINT CONCAT('Deploying to: ', @env);

Wrapping up

Fabric’s managed Git integration takes away SQLCMD variables, but it doesn’t take away your ability to write environment-aware deployments. The server name of every Fabric SQL database follows the <tenant-id>-<workspace-id>.database.fabric.com pattern, which gives your scripts a reliable way to know which workspace they’re running in. Combine that with Fabric’s data-preserving deployments, which make a configuration table viable, and you have two solid building blocks. Pick the one that fits your workflow, or combine them, and make sure unknown environments always fall back to safe behavior.