Database as Code for SQL Server – Synchronize SQL Server schemas with Git through bidirectional, dependency-aware synchronization. Export canonical DDL to version control and apply changes deterministically with intelligent ordering and safe table evolution.
Adous is a Spring Boot service for managing and synchronizing multiple database instances with a Git repository. It enables version control for database objects (stored procedures, functions, views, triggers, tables, synonyms, sequences, user-defined types) and provides bidirectional synchronization between databases and Git.
- Quick Start Guide - Step-by-step tutorial
- Architecture - How Adous works internally
- Usage Guide - API reference and examples
- Contributing - How to contribute
- Examples - Sample configurations and schemas
- 🔄 Bidirectional Sync: Sync database objects to Git and vice versa
- 🗄️ Multi-Database Support: Manage multiple SQL Server databases simultaneously
- 🌿 Git Integration: Full Git integration with commit, tag, and branch support
- 🔍 SQL Equivalence Checking: Smart comparison of SQL statements
- 🚀 Parallel Processing: Efficient synchronization using virtual threads
- 📝 OpenAPI Documentation: Integrated Swagger UI for API exploration
- 🔒 Security: Configurable authentication (API Key)
- 🎯 Dry Run Mode: Preview changes before applying them
- 📊 Monitoring: Built-in metrics and health checks with Prometheus support
- 🚫 Sync Ignore Patterns: Exclude specific database objects using .syncignore file
- 🐳 Docker Support: Production-ready Docker image with multi-stage build
- SynchronizerController: REST API endpoints for synchronization operations
- DatabaseRepositorySynchronizerService: Orchestrates sync operations between DB and Git
- GitService: High-level Git operations abstraction
- MSSQLDatabaseService: SQL Server-specific database operations
- SqlEquivalenceCheckerService: Compares SQL statements for equivalence
- Spring Boot 3.5.7: Modern Spring Boot framework
- Java 25: Latest Java features including virtual threads
- JGit 7.3.0: Git operations in Java
- SQL Server: Primary database support
- SpringDoc OpenAPI 2.7.0: API documentation and Swagger UI
- Micrometer: Metrics and monitoring with Prometheus support
- Testcontainers: Integration testing with real database instances
Configure your databases and Git repository in application.yml:
spring:
application:
name: Adous
authentication:
type: APIKEY # Authentication type: APIKEY
api-key: your-api-key # For APIKEY authentication
datasources:
dbs:
myDatabase:
url: jdbc:sqlserver://localhost:1433;databaseName=MyDB
username: sa
password: yourPassword
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
# Git repository configuration
github:
remote-uri: https://github.com/your-org/your-repo.git # Can be set via GIT_REMOTE_URI env var
token: your-github-token # Can be set via GIT_TOKEN env var
base-root-path: base
diff-root-path: diff
prefix-path: "" # Optional prefix for Git paths (GIT_PREFIX_PATH)
commit-username: "Adous System" # Git commit author (GIT_COMMIT_USERNAME)
commit-email: "adous@mail.com" # Git commit email (GIT_COMMIT_EMAIL)
default-branch: main # Default branch name (GIT_DEFAULT_BRANCH)
sync-ignore-file: "" # Path to custom .syncignore file (GIT_SYNC_IGNORE_FILE)
# Actuator endpoints for monitoring
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheusCreate a .syncignore file in src/main/resources/ to exclude specific database objects from synchronization:
# Ignore all stored procedures starting with 'temp_'
**/PROCEDURE/*/temp_*.sql
# Ignore specific view
**/VIEW/dbo/internal_view.sql
# Ignore all objects in a specific schema
**/FUNCTION/internal/*
- APIKEY: API Key authentication
Use in
export AUTH_TYPE=APIKEY export API_KEY=your-api-key
X-API-Keyheader:X-API-Key: your-api-key
./gradlew build./gradlew bootRunThe application will start on http://localhost:8080
Build the Docker image:
docker build -t adous:latest .Run the container:
docker run -d \
-p 8080:8080 \
-e GIT_REMOTE_URI=https://github.com/your-org/your-repo.git \
-e GIT_TOKEN=your-github-token \
-e GIT_PREFIX_PATH="" \
-e GIT_COMMIT_USERNAME="Adous System" \
-e GIT_COMMIT_EMAIL="adous@mail.com" \
-e GIT_DEFAULT_BRANCH=main \
--name adous \
adous:latestThe Docker image includes:
- Multi-stage build for minimal image size
- Non-root user for security
- Health checks via actuator endpoint
- Optimized JVM settings for container environments
Access Swagger UI at: http://localhost:8080/swagger-ui.html
-
Initialize Repository (first time setup):
curl -X POST http://localhost:8080/api/synchronizer/init-repo/myDatabase
This creates the initial commit with all database objects.
-
Make changes to your database (create/modify stored procedures, functions, views, triggers)
-
Sync database to repository:
curl -X POST "http://localhost:8080/api/synchronizer/db-to-repo/myDatabase?dryRun=false" -
Sync repository to other databases:
curl -X POST http://localhost:8080/api/synchronizer/repo-to-db \ -H "Content-Type: application/json" \ -d '{"commitish": "main", "dbs": ["testDatabase", "stagingDatabase"], "dryRun": false, "force": false}'
Initializes an empty Git repository with all database objects from a specified database. This is typically the first operation when setting up Adous:
POST /api/synchronizer/init-repo/{dbName}Parameters:
dbName(path): Name of the database to initialize the repository from
Example:
curl -X POST http://localhost:8080/api/synchronizer/init-repo/myDatabaseResponse:
{
"dbName": "myDatabase",
"dryRun": false,
"result": "[list of all objects added]",
"message": "Repository initialized successfully"
}Note: This operation can only be performed on an empty repository. Use this when setting up a new Git repository for the first time.
Synchronizes database objects to the Git repository:
POST /api/synchronizer/db-to-repo/{dbName}?dryRun=falseParameters:
dbName(path): Name of the database to syncdryRun(query, optional): If true, previews changes without committing (default: false)
Example:
curl -X POST "http://localhost:8080/api/synchronizer/db-to-repo/myDatabase?dryRun=false"Synchronizes Git repository commit to one or more databases:
POST /api/synchronizer/repo-to-db
Content-Type: application/json
{
"commitish": "main",
"dbs": ["database1", "database2"],
"dryRun": false,
"force": false
}Request Body:
commitish: Git commit, branch, or tag reference to sync fromdbs: List of database names to syncdryRun: Preview changes without applying (default: false)force: Force sync even if database is out of sync (default: false)
Example:
curl -X POST http://localhost:8080/api/synchronizer/repo-to-db \
-H "Content-Type: application/json" \
-d '{
"commitish": "main",
"dbs": ["database1", "database2"],
"dryRun": false,
"force": false
}'Database objects are stored in the following structure:
base/
{objectType}/
{schema}/
{objectName}.sql
diff/
{prefix-path}/
{databaseName}/
{objectType}/
{schema}/
{objectName}.sql
- base/: Contains the canonical version of database objects
- diff/: Contains database-specific overrides
- DB → Repo: Detects changes in database, creates/updates files in Git, commits and pushes
- Repo → DB: Reads Git commit, applies changes to database(s), tags commit with database name
Each database is tagged in Git when synchronized, allowing tracking of which commit each database is synced to.
Adous includes built-in monitoring capabilities via Spring Boot Actuator:
- Health:
http://localhost:8080/actuator/health- Application health status - Info:
http://localhost:8080/actuator/info- Application information - Metrics:
http://localhost:8080/actuator/metrics- Application metrics - Prometheus:
http://localhost:8080/actuator/prometheus- Prometheus-compatible metrics
The application exports metrics including:
- HTTP request/response metrics
- JVM memory and GC metrics
- Database connection pool metrics
- Custom synchronization operation metrics
When running in Docker, the container includes a health check that polls the actuator health endpoint every 30 seconds.
Adous follows Semantic Versioning (SemVer):
- MAJOR.MINOR.PATCH (e.g.,
1.2.3)- MAJOR: Breaking changes
- MINOR: New features (backward-compatible)
- PATCH: Bug fixes (backward-compatible)
Git tags mark stable releases:
# List all releases
git tag --list "v*"
# Check out a specific version
git checkout v1.0.0Docker images are published to GitHub Container Registry with multiple tags:
ghcr.io/owner/adous:latest- Latest build from main branchghcr.io/owner/adous:0.0.1-SNAPSHOT- Specific version from build.gradleghcr.io/owner/adous:abc123def456- Specific commit SHA (short)ghcr.io/owner/adous:v1.0.0- Specific release tag
Use specific version tags in production for reproducibility.
Each database sync creates a Git tag:
{databaseName}/{timestamp}
Example: production-db/20231205-143022
This tracks which commit each database is synced to, enabling:
- Out-of-sync detection
- Rollback capability
- Audit trail
- Always use dry-run first: Preview changes before applying
- Regular syncs: Keep databases and repository in sync
- Use force carefully: Only when you understand the implications
- Review out-of-sync warnings: They prevent data loss
- Leverage .syncignore: Exclude objects you don't want to sync
Run tests with:
./gradlew testIntegration tests use Testcontainers for SQL Server.
The project includes GitHub Actions workflow for continuous integration:
Located in .github/workflows/build-test.yaml, this workflow:
- Runs on pull requests and pushes to main branch
- Sets up Java 25 with Temurin distribution
- Builds the application with Gradle
- Executes all tests including integration tests
The workflow ensures code quality and test coverage on every change.
We welcome contributions! Please see CONTRIBUTING.md for detailed guidelines.
Quick Start for Contributors:
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature - Make your changes following our coding standards
- Add tests for new functionality
- Run tests:
./gradlew test - Commit with descriptive messages (Conventional Commits format)
- Push and create a Pull Request
Before contributing:
- Read the Code of Conduct
- Check existing issues and PRs
- Use issue templates for bugs and feature requests
- Follow the PR template checklist
- Issues: Report bugs or request features
- Discussions: Ask questions and share ideas
- Documentation: Help improve docs in docs/ directory
See LICENSE file for details.