SQL Server
Run Microsoft SQL Server next to your code, so your app and its migrations talk to the same engine as in production. The workbench gets the free Developer edition, and the database your code connects to is already there.
Check your platform first
Section titled “Check your platform first”Microsoft builds the SQL Server image for x86_64 (amd64) only. On an Apple Silicon Mac it runs through Rosetta, so your Docker runtime needs Rosetta turned on.
| Host | What you need |
|---|---|
| Linux or Windows (WSL2) on x86_64 | nothing, it runs natively |
| Apple Silicon Mac with Docker Desktop | Settings → General: choose the Apple Virtualization framework and turn on Use Rosetta for x86_64/amd64 emulation (with a screenshot) |
| Apple Silicon Mac with OrbStack | nothing, Rosetta is on by default |
| Apple Silicon Mac with Colima | a VM created with colima start --vm-type=vz --vz-rosetta |
| Docker Desktop with Docker VMM | does not work: Docker VMM has no Rosetta |
| Linux on ARM, Windows on ARM | does not work: there is no image for ARM |
Without Rosetta the service stops right after it starts. You see
qemu: uncaught target signal 11 (Segmentation fault) in its log:
monoceros logs acme mssqlMicrosoft does not support SQL Server under emulation. For local development it works. Apple plans to limit Rosetta from macOS 28 (2027). It is not known yet whether that affects Docker.
Add it
Section titled “Add it”At init:
monoceros init acme --with-services=mssqlOr to an existing workbench:
monoceros add-service acme mssqlNeed a second database server? Add it again under a different name with --as.
Each instance gets its own host, data volume and connection env:
monoceros add-service acme mssql --as=reportingThen build the workbench:
monoceros apply acmeRemove it
Section titled “Remove it”monoceros remove-service acme mssqlIts data volume monoceros-acme-data-mssql is removed with the workbench on
monoceros remove, which backs it up first.
The yml entry
Section titled “The yml entry”services: - name: mssql image: mcr.microsoft.com/mssql/server:2025-latest user: '0:0' port: 1433 env: MSSQL_SA_PASSWORD: ${MSSQL_SA_PASSWORD} MSSQL_DATABASE: ${MSSQL_DATABASE} ACCEPT_EULA: ${ACCEPT_EULA} MSSQL_PID: ${MSSQL_PID} volumes: - data:/var/opt/mssql healthcheck: test: [ 'CMD', '/opt/mssql-tools18/bin/sqlcmd', '-C', '-S', '127.0.0.1', '-U', 'sa', '-P${MSSQL_SA_PASSWORD}', '-b', '-Q', "IF DB_ID(N'${MSSQL_DATABASE}') IS NULL CREATE DATABASE [${MSSQL_DATABASE}]", ] interval: 10s timeout: 5s retries: 5 startPeriod: 30s connectionEnv: URL: 'sqlserver://sa:${MSSQL_SA_PASSWORD}@${host}:${port}?database=${MSSQL_DATABASE}&TrustServerCertificate=true' HOST: '${host}' PORT: '${port}' USER: 'sa' PASSWORD: '${MSSQL_SA_PASSWORD}' DB: '${MSSQL_DATABASE}'MSSQL_SA_PASSWORD=Monoceros-dev1MSSQL_DATABASE=monocerosACCEPT_EULA=YMSSQL_PID=DeveloperThe values live in acme.env, so the yml stays shareable without credentials
in it (see Workbench configuration).
Keep the user: '0:0' line. Without it, SQL Server cannot start on data that
monoceros restore brought back.
What your code sees
Section titled “What your code sees”Monoceros injects a connection env into the workspace container, prefixed with the service name:
| Variable | Value (defaults) |
|---|---|
MSSQL_URL | sqlserver://sa:Monoceros-dev1@mssql:1433?database=monoceros&TrustServerCertificate=true |
MSSQL_HOST | mssql |
MSSQL_PORT | 1433 |
MSSQL_USER | sa |
MSSQL_PASSWORD | Monoceros-dev1 |
MSSQL_DB | monoceros |
The connection uses the sa user. The prefix is the service name in
uppercase, so a second instance added with --as=reporting gets
REPORTING_URL and never collides.
Not every driver reads a sqlserver:// URL. For .NET and JDBC, build the
connection string from the single values. A .NET connection string with the
defaults:
Server=mssql,1433;Database=monoceros;User ID=sa;Password=Monoceros-dev1;TrustServerCertificate=TrueThe server uses a self-signed certificate. Drivers that encrypt by default
(Microsoft.Data.SqlClient, JDBC) reject it, so set TrustServerCertificate=true.
Things to know
Section titled “Things to know”The database comes a few seconds after the server
Section titled “The database comes a few seconds after the server”The image cannot create a database on its own, so the healthcheck creates
MSSQL_DATABASE. Until the first check has run, the server answers but the
database is not there yet.
The password must be complex
Section titled “The password must be complex”SQL Server needs at least 8 characters from three of these groups: uppercase,
lowercase, digits, symbols. With a weaker password in acme.env the server
stops on start.
You accept the license terms
Section titled “You accept the license terms”The image does not start without ACCEPT_EULA=Y, so the workbench sets it for
you. By adding the service you accept the
SQL Server license terms.
The Developer edition (MSSQL_PID=Developer) is for development and testing,
not for production.
Docker needs at least 2 GB of memory
Section titled “Docker needs at least 2 GB of memory”SQL Server does not start with less memory in your Docker runtime.
There is no sqlcmd in the workspace
Section titled “There is no sqlcmd in the workspace”Query the database through your project’s own driver. Or open a tunnel and use a client on your host:
monoceros tunnel acme mssqlSee Proxy and tunnels.
Import a database export (.bacpac)
Section titled “Import a database export (.bacpac)”A .bacpac file holds the schema and the data of a database. You import it
with sqlpackage, which Microsoft ships as a .NET tool. Your workbench needs the
dotnet language for it:
monoceros add-language acme dotnetmonoceros apply acmeCopy the export into the workbench’s projects folder on your host,
~/.monoceros/container/acme/projects/. Inside the workbench the same folder is
/workspaces/acme/projects/. Then open a shell in the workbench:
monoceros shell acmeInstall sqlpackage and put the .NET tools on your path:
dotnet tool install --global microsoft.sqlpackageexport PATH="$PATH:$HOME/.dotnet/tools"Import the file into the database. The target database must be empty, and
monoceros is empty after the first apply:
sqlpackage /Action:Import /SourceFile:/workspaces/acme/projects/shop.bacpac /TargetConnectionString:"Server=$MSSQL_HOST,$MSSQL_PORT;Database=$MSSQL_DB;User ID=$MSSQL_USER;Password=$MSSQL_PASSWORD;TrustServerCertificate=True"To export a database again, run the same command with /Action:Export,
/SourceConnectionString: and /TargetFile:.