Liking cljdoc? Tell your friends :D
Dynatus Logo

Dynatus

CI Tests Clojars Project

A Clojure library for managing DynamoDB table migrations and keeping table definitions in sync between local and production environments.


Highly inspired in migratus and how it is easy to use it.

Features

  • 📦 EDN-based table definitions
  • 🔄 Automatic table creation and updates
  • 🐳 Testcontainers support for integration testing
  • 🏠 Local DynamoDB support via interceptors
  • ⚡ Simple API for migrations

Installation

Add to your deps.edn:

;; From Clojars
{:deps {org.clojars.morita/dynatus {:mvn/version "0.1.0"}}}

;; Or from GitHub
{:deps {dynatus/dynatus {:git/url "https://github.com/yourusername/dynatus"
                          :git/sha "LATEST_SHA"}}}

Usage

Basic Migration

(require '[dynatus.core :as dynatus]
         '[cognitect.aws.client.api :as aws])

;; Create a DynamoDB client using AWS SDK
(def dynamo-client (aws/client {:api :dynamodb
                                :region "us-east-1"}))

;; Run migrations from resources/dynamo directory
(dynatus/migrate {:client dynamo-client
                  :path "resources/dynamo"})

The library is designed to work with any Cognitect AWS DynamoDB client, giving you full control over client configuration.

Table Definition Format

Create .edn files in your migrations directory:

;; resources/dynamo/users.edn
{:TableName "users"
 :KeySchema [{:AttributeName "user_id"
              :KeyType "HASH"}]
 :AttributeDefinitions [{:AttributeName "user_id"
                         :AttributeType "S"}
                        {:AttributeName "email"
                         :AttributeType "S"}]
 :BillingMode "PAY_PER_REQUEST"
 :GlobalSecondaryIndexes [{:IndexName "email-index"
                           :KeySchema [{:AttributeName "email"
                                        :KeyType "HASH"}]
                           :Projection {:ProjectionType "ALL"}}]
 :StreamSpecification {:StreamEnabled true
                       :StreamViewType "NEW_AND_OLD_IMAGES"}
 :Tags [{:Key "Environment"
         :Value "production"}]}

Local Development

For local development, you can configure your AWS client to connect to local DynamoDB:

(require '[cognitect.aws.client.api :as aws]
         '[cognitect.aws.interceptors :as interceptors])

;; Define interceptor for local DynamoDB
(defmethod interceptors/modify-http-request "dynamodb"
  [service http-request]
  (-> http-request
      (assoc :scheme :http
             :server-port 8000
             :server-name "localhost")
      (assoc-in [:headers "host"] "localhost:8000")))

;; Create client - interceptor will redirect to local
(def local-client (aws/client {:api :dynamodb
                               :region "us-east-1"}))

Testing with Testcontainers

(require '[dynamigrate.test-fixtures :as fixtures])

(use-fixtures :each fixtures/with-dynamodb-container)

(deftest my-test
  (testing "DynamoDB operations"
    ;; Use fixtures/*test-client* which is automatically connected
    ;; to a DynamoDB container
    (let [client fixtures/*test-client*]
      ;; Your test code here
      )))

Running Tests

# Run all tests
clojure -M:test -m kaocha.runner

# Run with specific test
clojure -M:test -m kaocha.runner --focus dynamigrate.core-test

Project Structure

dynamigrate/
├── deps.edn                 # Dependencies
├── src/
│   └── dynamigrate/
│       ├── core.clj        # Main migration logic
│       ├── loader.clj      # Table definition loader
│       ├── diff.clj        # Table comparison logic
│       └── apply.clj       # Apply migrations
├── test/
│   └── dynamigrate/
│       ├── core_test.clj      # Integration tests
│       ├── test_fixtures.clj  # Testcontainers setup
│       └── test_client.clj    # Test-specific client with interceptors
└── resources/
    └── dynamo/             # Table definitions
        ├── users.edn
        └── orders.edn

Environment Variables

  • IN_DOCKER - Set to "true" when running in Docker
  • DYNAMODB_LOCAL_ENDPOINT - Override local DynamoDB endpoint
  • AWS_PROFILE - AWS profile for credentials

Building and Deployment

Build JAR

# Build the JAR file
clojure -X:jar

# This creates target/dynamigrate.jar

Install Locally

# Install to local Maven repository (~/.m2)
clojure -X:install

Deploy to Clojars

First, configure your Clojars credentials in ~/.m2/settings.xml:

<settings>
  <servers>
    <server>
      <id>clojars</id>
      <username>your-username</username>
      <password>your-deploy-token</password>
    </server>
  </servers>
</settings>

Then deploy:

# Deploy to Clojars
clojure -X:deploy

# For snapshot versions
clojure -X:deploy :version '"0.1.0-SNAPSHOT"'

Using as a Dependency

Once deployed to Clojars:

;; deps.edn
{:deps {net.clojars.rafael-campo/dynamigrate {:mvn/version "0.1.0"}}}

;; Leiningen project.clj
[net.clojars.rafael-campo/dynamigrate "0.1.0"]

CI/CD

Continuous Integration

The project uses GitHub Actions for automated testing and deployment:

Test Workflows

ci.yml - Lightweight CI for every push/PR

  • Runs tests on Java 11 and 17
  • Caches dependencies for faster builds
  • Provides quick feedback on code changes

test.yml - Comprehensive test suite

  • Tests against Java 11, 17, and 21
  • Runs linting with clj-kondo
  • Checks code formatting with cljfmt
  • Uploads test artifacts for debugging

Deployment Workflow

deploy_clojars.yml - Automated deployment

  • Triggers on version tags (e.g., v0.1.0)
  • Uses jlesquembre/clojars-publish-action@v2 for deployment
  • Builds JAR and deploys to Clojars automatically
  • Creates GitHub releases with installation instructions
  • Requires CLOJARS_USERNAME and CLOJARS_TOKEN secrets

Running Tests Locally

# Run all tests
make test

# Run tests with specific Java version
JAVA_HOME=/path/to/java11 make test

# Run with verbose output
clojure -M:test -m kaocha.runner --reporter documentation

# Run specific test namespace
clojure -M:test -m kaocha.runner --focus dynamigrate.core-test

Making a Release

Automated Release (Recommended)

  1. Commit your changes: git commit -am "Prepare release v0.1.0"
  2. Tag the release: git tag v0.1.0
  3. Push with tags: git push origin main --tags
  4. GitHub Actions will automatically:
    • Build the JAR
    • Deploy to Clojars using jlesquembre/clojars-publish-action
    • Create a GitHub release with installation instructions

Manual Release

You can also trigger a deployment manually from GitHub Actions:

  1. Go to Actions → Deploy to Clojars
  2. Click "Run workflow"
  3. Enter the version number (e.g., 0.1.0)
  4. Click "Run workflow"

Setting up GitHub Secrets

For automated deployment, configure these secrets in your GitHub repository:

  1. Go to Settings → Secrets and variables → Actions
  2. Add the following secrets:

Deployment Action

This project uses jlesquembre/clojars-publish-action@v2 for automated Clojars deployment. This action:

  • Handles authentication with Clojars
  • Publishes the JAR with proper metadata
  • Supports both release and snapshot versions
  • Works seamlessly with GitHub Actions

The library includes a GitHub Actions workflow for automatic deployment to Clojars when a new release is created.

Setting up GitHub Actions

  1. Add your Clojars deploy token as a GitHub secret named CLOJARS_TOKEN
  2. Create a new release on GitHub
  3. The workflow will automatically build and deploy to Clojars

License

Copyright © 2025 MoritaHR

Distributed under the MIT License.

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close