bitsql — SQL Server tests, lighter.

bitsql

4 min read Original article ↗

SQL SERVER 2025 · BUILT FOR APPLICATION CI

Your SQL Server tests.
A fraction of the weight.

Swap your SQL Server container for bitsql, a memory-only emulator that speaks TDS. Keep your SQL, your clients, and your connection settings.

Open source · Public domain · Written in MoonBit

compose.yaml− heavyweight setup

services:
  db:
−   image: mcr.microsoft.com/mssql/server:2025-latest
+   image: mirek/bitsql:0.1
+   command: ["--auto-create-databases"]
    ports: ["1433:1433"]

Same TDS connection. Ready in ~121 ms.

43×smaller image

39.3 MiB vs 1.64 GiB

22×faster cold start

121 ms vs 2.70 seconds · median of three

271×less idle memory

4.4 MiB vs 1.17 GiB

25,520passing tests & client checks

23,728 client checks + 1,792 MoonBit tests
Release 0.1.29 · three additional skips

Explore the test coverage ↓

01 / LESS WAITING. MORE TESTING.

Small where it counts.

Start a fresh database for a test run without paying for a full database server. Every chart uses a linear scale. Lower is better.

bitsqlSQL Server 2025

The honest comparison. Every measured row beat SQL Server in this run, point reads included (92 vs 107 ms); in two other runs that day point reads won again while one query shape tied or lost once. The biggest gains are startup, footprint, logins, schema churn, and writes. Measured on linux/amd64, Ryzen 9 7950X3D, Docker 29.1.3, October 26, 2026, using tedious over loopback with TLS. Cold start is the median of three starts per target on a shared host. The tested profile-guided release image includes statement-history collection; compressed download size is 13.7 MiB in the published registry manifest. Point reads are the median of five batches; inserts are one workload run. These are test-workload measurements, not a production capacity claim.

FAMILIAR ON PURPOSE

Your stack already
speaks bitsql.

Real clients connect over the SQL Server wire protocol. Behavior is checked against captures from SQL Server 2022 and 2025.

tediousmssqlKnexSequelizeTypeORMPrisma

0.1.29 validation: 23,728 client checks and 1,792 MoonBit tests passed, with three existing skips.

Explore compatibility coverage ↗

02 / MAKE THE SWAP

One lighter container.

Use bitsql for local development and application CI. Start here, then run your existing suite.

Run it now

docker run --rm -p 1433:1433 \
  mirek/bitsql:0.1 --auto-create-databases

Or change your Compose service

services:
  db:
    image: mirek/bitsql:0.1
    command: ["--auto-create-databases"]
    ports: ["1433:1433"]
    environment:
      ACCEPT_EULA: "Y"
      MSSQL_SA_PASSWORD: "Your_password123"

Existing MSSQL_* environment variables are accepted and ignored. For reproducible runs, pin mirek/bitsql:0.1.29. This release publishes native-validated amd64. Other architectures require validation on their native hosts.

Keep the connection. Check the setup.

01Credentials & TLSExisting usernames and passwords work. With encryption enabled, keep trustServerCertificate: true for the built-in self-signed certificate.

02Database creation--auto-create-databases creates databases on login. Use --database app to create a named database at startup instead.

03Health checksThe image has no shell or sqlcmd. Replace SQL Server health checks with a TCP/login probe. Testcontainers users should use GenericContainer and a listening-port wait.

04Fresh state, every timeEverything lives in memory. Remove persistence volumes. Seed once, then use EXEC emulator.snapshot 'seed' and EXEC emulator.restore 'seed' for fast test isolation.

GitHub Actions & Testcontainers examples ↗

03 / NO CONTAINER REQUIRED

Meet the engine. In your browser.

The same MoonBit SQL executor, compiled to JavaScript. Queries and data stay in this tab. No account, server, or installation.

⌘ / Ctrl + Enter to run · State persists between queries

Choose an example or write a query.

Browser demo: one session, no TDS socket, HTTP integrations, or scheduled waits. Waiting requests reset the demo with a notice. Stop or a 10-second timeout also resets the database. Results display at most 200 rows per set. For client and concurrency testing, use the container.

FAITHFULNESS FIRST

Built to catch failures.

bitsql targets the SQL Server behavior that application tests depend on: SQL, result metadata, TDS, and ORM workflows. Unsupported features raise explicit Emulator: … errors instead of plausible results.

Some core arithmetic is formally verified, not just tested. On every gate run, moon prove uses SMT solvers to check that the TDS packet reader’s bounds check never overflows or accepts a truncated packet; that date ↔ day-number conversion stays inside 0001–9999; that rounding to datetime2/time scales is exact half-up and never leaves the day; and that legacy datetime 1/300 s rounding round-trips and carries midnight into the next day. Writing these specs exposed two bugs, both now fixed: a packet that could crash the server, and a GETDATE() that could return 24:00. What is proved ↗

Inspect bitsql plans with emulator.explain or run one query with emulator.profile to see index access and execution choices. Explicit profiles are on demand. Native query/index diagnostics now retain execution history; Query Store captures outer statements in ALL mode. Query diagnostics ↗ · History limits ↗

This is an in-memory test database. It does not replace SQL Server’s durability, operational backups, replication, or production query optimizer. Add ORDER BY wherever row order matters, and validate your application against SQL Server before release.

Read the release boundary & deferred work ↗