This is an example application demonstrating the Bauhaus framework - a modular Clojure application framework built around Integrant for dependency injection and system lifecycle management.
Bauhaus is a collection of reusable Clojure modules that provide common application infrastructure:
- Setup modules: logging, CLI parsing, shutdown hooks
- Development tooling: configuration management, build tools
- Collection utilities: enhanced collection operations
The framework encourages a modular, component-based architecture where applications are composed of small, focused modules.
├── deps.edn # Project dependencies and aliases
├── src/ # Application source code
│ └── example/
│ ├── app.clj # Main application entry point
│ └── app/
│ ├── config.clj # Configuration accessors
│ └── system.clj # Integrant system configuration
├── dev/ # Development-only code
│ ├── user.clj # Dev REPL utilities
│ └── dev/
│ └── system.clj # Development system configuration
├── resources/
│ └── config.edn # Production configuration
└── dev-resources/
└── dev-config.edn # Development configuration overrides
- Java 21+
- Clojure CLI tools
- Start the application:
The application is usually run in production mode as an uberjar.
To build that uberjar, use the following command:
clj -T:build uberwhich will create a JAR file in the target/ directory.
Run the application with:
java -jar target/app-2yxdAjuN6gaFYoehTEO687fcXGR-main-4a8a304-1.0.0+12-dirty-standalone.jar -c resources/config.edn(you will have to adjust the JAR name based on the actual build output. The jar name is logged during the build process.)
The application will start and log output to ../example.logs/app.log:
cat ../example.logs/app.log
- Run with development profile:
clj -M:dev # Then in the REPL: user=> (go)
The project uses Integrant for system lifecycle management with a development-friendly REPL workflow:
-
Start development environment:
clj -M:dev
-
In the REPL, start the system:
user=> (go) ; Start the system user=> (reset) ; Reload code and restart system user=> (halt) ; Stop the system
-
The development system provides:
- Hot code reloading
- Enhanced logging
- Environment variable interpolation in config
- German language greeting (vs English in production)
| Alias | Purpose |
|---|---|
:start |
Run the production application |
:dev |
Start development environment with REPL |
:test |
Run tests |
:build |
Build application JAR |
:nrepl |
Start nREPL server on port 7880 |
:container-nrepl |
Start nREPL server bound to all interfaces |
The application uses Aero for configuration management:
- Production config:
resources/config.edn - Development overrides:
dev-resources/dev-config.edn
Development configuration supports environment variable interpolation:
{:who #envf ["who:%s, where:%s" USER PWD]}This application demonstrates several Bauhaus modules:
- logging: Configures Timbre logging with file output
- cli: Provides command-line argument parsing
- shutdown: Manages graceful application shutdown
- config: Configuration management utilities
- build: Build and deployment tools
- collection: Enhanced collection operations (e.g.,
deep-merge)
The application uses Integrant for dependency injection and system lifecycle:
{:example/hello-en {:who "World"}}{:example/hello-de {:who "user:root, where:/path"}}Key differences:
- Development uses "German" component
:example/hello-devs English:example/hello-enin production. (Not the best example, do not conflate with I18N. But it produces an output.) - Development provides additional debugging tools
-
Define the component in
system.clj:(defmethod ig/init-key :my-app/new-component [_ config] ;; Initialize your component )
-
Add to system configuration:
(defn system-config [config] {:my-app/new-component {:dependency-key value}})
-
For development overrides, modify
dev/system.clj
# Build JAR
clj -T:build uberLogs are written to ../example.logs/app.log relative to the working directory.
Development logging outputs to console with debug level enabled.
For nREPL development:
clj -M:nrepl # Local development
clj -M:container-nrepl # Container/remote development- Review the Integrant documentation for system lifecycle patterns
- Explore the Bauhaus modules in
../../modules/ - Add your own components following the established patterns
- Configure logging, CLI options, and shutdown hooks as needed