Giving Every Developer a Dedicated Development Database

One developer changes a column and everyone else's test breaks. A dedicated development database gives each developer an isolated schema and a predictable starting point. The shared contract then lives in approved scripts, with a small data set and a rebuild process that anyone on the team can follow.

A community garden of separate raised beds, each with its own tools, a red trowel in one

Put the Schema Contract Outside the Database

The database is a working copy. Keep the authoritative schema as ordered scripts in the team's approved source-control system or versioned script store. Record the release identifier and dependencies. A change made only in one development database has no durable definition for another developer to rebuild.

I ask a new team member to rebuild from the approved package before relying on the setup. What extra knowledge did that person need? Every undocumented manual step becomes a future mismatch. Include database options, schemas, tables, constraints, indexes, and modules. Separate environment-specific users and file locations from portable application objects.

Name and Provision Each Dedicated Development Database

Use a recognizable development prefix and a stable owner suffix. The sample name is fixed so the script cannot point at a different database through an unchecked substitution. Give each developer a distinct name and record its owner. Prefer a development-only instance with no production data or credentials.

USE master;
IF DB_ID(N'Dev_Billing_Ava') IS NOT NULL
    THROW 50000,'This development database already exists; inspect it first.',1;
CREATE DATABASE Dev_Billing_Ava;
GO
USE Dev_Billing_Ava;
GO
EXEC sys.sp_addextendedproperty @name=N'DevelopmentOwner',@value=N'Ava';
EXEC sys.sp_addextendedproperty @name=N'ApprovedSchemaVersion',@value=N'billing-1.0';

Choose actual owner and release values before provisioning. This creates a new database rather than replacing an existing one. I verify server identity and database name before every reset. A helpful name reduces confusion, but permissions and environment separation provide the real boundary.

Rebuild the Dedicated Development Database in Dependency Order

A small rebuild script can reset the complete sample schema in place. Drop dependent tables first, then recreate parents before children. The database-name guard stops an accidental run against another database. This script is destructive to the two sample tables, so use it only for the dedicated development copy after preserving any work that matters.

USE Dev_Billing_Ava;
GO
IF DB_NAME()<>N'Dev_Billing_Ava'
    THROW 50000,'Wrong database for this rebuild.',1;
SET XACT_ABORT ON;
BEGIN TRANSACTION;
DROP TABLE IF EXISTS dbo.Invoice;
DROP TABLE IF EXISTS dbo.Customer;
CREATE TABLE dbo.Customer
(
    CustomerID int NOT NULL PRIMARY KEY,
    DisplayName nvarchar(80) NOT NULL
);
CREATE TABLE dbo.Invoice
(
    InvoiceID int NOT NULL PRIMARY KEY,
    CustomerID int NOT NULL,
    Total decimal(12,2) NOT NULL,
    CONSTRAINT FK_Invoice_Customer FOREIGN KEY(CustomerID)
        REFERENCES dbo.Customer(CustomerID)
);
INSERT dbo.Customer VALUES(1,N'Sample Customer A'),(2,N'Sample Customer B');
INSERT dbo.Invoice VALUES(100,1,25.00),(101,2,0.00);
COMMIT TRANSACTION;

Save the approved script as a local SQL file in the team's package. Larger schemas need an explicit dependency sequence and module batch separators. Do not delete unknown objects silently during a partial rebuild. Report them as drift and decide how the full reset should handle them.

Keep Seed Data Small and Purposeful

Use synthetic or irreversibly sanitized records. Copying production into development can expose private data through laptops, logs, and screenshots. A masked display column does not sanitize every linked table. Remove secrets, access tokens, real contact details, and free-form fields through a reviewed process. The small fixture above is fictional.

Include useful edge cases: no invoices, multiple invoices, zero totals, Unicode text, and boundary dates where the application needs them. Keep a deterministic seed script so a failure can be reproduced. I prefer a tiny fixture with named cases over a huge dump nobody understands. Sample data should test the application rather than test how much disk the team can fill.

One contract, many working copies: a diagram about the dedicated development database

Make the Rebuild Command Stop on Errors

A Windows command can run the approved SQL file against the explicit development instance. Use sqlcmd's error-exit behavior so a failed statement does not become a success message in the wrapper. Check the process exit code. Authentication and access should follow the development environment's policy.

REM Command line
sqlcmd -S "DEVHOST\INSTANCE" -E -C -b -i "C:\DevDatabase\Rebuild.sql" -o "C:\DevDatabase\Rebuild-output.txt"
IF ERRORLEVEL 1 EXIT /B 1

Replace the instance and file paths with the approved package locations. The -C switch trusts the server certificate. Current sqlcmd refuses a development instance with a self-signed certificate without it, so drop it where the certificate is trusted. The command is a runner, not the schema definition. Preserve backslashes and inspect the output file. Rebuilds should produce the same schema and seed state each time, including when the preceding run failed partway through.

Compare Metadata With the Approved Manifest

A version label tells you what was intended. It does not prove the database still matches. Generate a metadata manifest from a clean approved rebuild and compare columns, data types, nullability, keys, indexes, and module definitions. For the small example, the following query checks the expected column contract in both directions.

CREATE TABLE #Expected
(TableName sysname,ColumnName sysname,TypeName sysname,MaxLength smallint,
 PrecisionValue tinyint,ScaleValue tinyint,IsNullable bit);
INSERT #Expected VALUES
(N'Customer',N'CustomerID',N'int',4,10,0,0),
(N'Customer',N'DisplayName',N'nvarchar',160,0,0,0),
(N'Invoice',N'InvoiceID',N'int',4,10,0,0),
(N'Invoice',N'CustomerID',N'int',4,10,0,0),
(N'Invoice',N'Total',N'decimal',9,12,2,0);
SELECT t.name AS TableName,c.name AS ColumnName,
       TYPE_NAME(c.user_type_id) AS TypeName,c.max_length AS MaxLength,
       c.precision AS PrecisionValue,c.scale AS ScaleValue,c.is_nullable AS IsNullable
INTO #Actual
FROM sys.tables AS t JOIN sys.columns AS c ON c.object_id=t.object_id
WHERE t.schema_id=SCHEMA_ID(N'dbo') AND t.name IN(N'Customer',N'Invoice');
SELECT * FROM #Expected EXCEPT SELECT * FROM #Actual;
SELECT * FROM #Actual EXCEPT SELECT * FROM #Expected;

Run this in the sample database in a clean query session. This includes storage length, precision, and scale. Extend the manifest to defaults, keys, constraints, indexes, and modules before treating it as a full schema check. A query that checks only a version string cannot catch an unrecorded column edit. I also run application-level smoke tests after a clean rebuild.

Isolate Permissions and Shared Resources

Database isolation does not isolate every instance-level feature. Agent jobs, logins, linked servers, tempdb, and CPU remain shared on a common host. Prevent one developer's test from changing shared server configuration. Use separate schemas only when that weaker boundary actually fits the application; separate databases are clearer for schema-changing work.

Grant development rights in the isolated environment according to the tasks required. Do not reuse production credentials or enable cross-database trust to bypass a test failure. Review scripts that reference another database by name. A hard-coded shared database can defeat the isolation while every local object looks correct.

Retire Each Dedicated Development Database by Owner and Date

Give the approved package a smoke-test script. It should verify seed counts, required constraints, and a simple application transaction. Run it after every rebuild and fail the setup when it fails. Keep expected fixtures tied to the same schema version. A database that was created successfully can still contain the wrong default, missing index, or stale module.

Keep an inventory of development database names, owners, last use, and agreed retention. Ask the owner before retiring a copy that holds unpublished work. Preserve approved scripts and useful fixtures, then remove the reviewed database through the normal development process. Do not delete every name with a matching prefix automatically.

SELECT name,create_date,state_desc
FROM sys.databases
WHERE name LIKE N'Dev[_]Billing[_]%'
ORDER BY create_date,name;

I review that list regularly with the team. A fresh copy should be easier to recreate than an abandoned copy is to explain. Give each dedicated development database the same reset and comparison process. That makes isolation repeatable rather than a collection of personal snowflakes.

Related reading on this blog: Putting a Database Under Source Control and What You May and May Not Do With SQL Server Developer Edition.

Before anyone relies on the copy: a checklist on the dedicated development database

A private database is not the schema authority, it is a rebuildable working copy of an approved contract.

Published by Pinal Dave on SQLAuthority. More of my work at pinaldave.com.

Best Practices, Database, Developer, Software Development
Previous Post
SQL SERVER – Starting / Stopping SQL Server Agent Services using PowerShell
Next Post
SQL SERVER 2016 – InMemory OLTP support for Foreign Key

Related Posts

2 Comments. Leave new

  • what about scripting to release in prod?
    what about scripting default values in some tables?
    what about preventing the loss of data? (when a column name has been renamed)
    what about partitioned tables? (when each dedicated database can have a different number of partition in place)

    Reply
  • Or, apply changes from a schema compare between the versionned DB project and your local sandbox. It works well and it is free!

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.