Get your first Boundary API endpoint running in 5 minutes.
brew install clojure/tools/clojure or install guide)Quick check:
java -version # Should show 11 or higher
clojure -version
# Clone the repository
git clone https://github.com/yourusername/boundary.git
cd boundary
# Install dependencies (downloads once, cached after)
clojure -P -M:dev
Option A: SQLite (Easiest)
# Already configured in conf/dev/config.edn
# No setup needed!
Option B: PostgreSQL (Recommended for production)
# 1. Create database
createdb boundary_dev
# 2. Set connection string
export DATABASE_URL="postgresql://localhost:5432/boundary_dev"
# 3. Update conf/dev/config.edn
# (Or just use the environment variable - it works!)
Option C: H2 (In-memory)
;; Edit conf/dev/config.edn
:active {:h2 {:memory true}}
# Initialize migration system
clojure -M:migrate init
# Run migrations
clojure -M:migrate migrate
# Verify
clojure -M:migrate status
# Should show: "Applied migrations: 5"
# Start HTTP server on port 3000
clojure -M:dev -m boundary.cli server start
# Or use the REPL (recommended for development)
clojure -M:repl-clj
;; In REPL:
(require '[integrant.repl :as ig-repl])
(require '[boundary.system])
(ig-repl/set-prep! #(boundary.system/system-config))
(ig-repl/go)
;; Server started at http://localhost:3000
Expected output:
INFO boundary.server - Starting HTTP server on port 3000
INFO boundary.server - Swagger UI available at http://localhost:3000/api-docs/
INFO boundary.server - Server started successfully
Check health endpoint:
curl http://localhost:3000/health
Expected response:
{
"status": "healthy",
"service": "boundary",
"version": "0.1.0",
"timestamp": "2026-01-03T14:30:00Z"
}
View API documentation:
# Open in browser
open http://localhost:3000/api-docs/
You'll see an interactive Swagger UI with all available endpoints!
Create your first user:
curl -X POST http://localhost:3000/api/v1/users \
-H "Content-Type: application/json" \
-d '{
"email": "developer@example.com",
"name": "Developer",
"password": "securepass123",
"role": "admin"
}'
Expected response:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "developer@example.com",
"name": "Developer",
"role": "admin",
"active": true,
"createdAt": "2026-01-03T14:30:00Z"
}
Login to get a JWT token:
curl -X POST http://localhost:3000/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "developer@example.com",
"password": "securepass123"
}'
Expected response:
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresIn": 3600,
"userId": "550e8400-e29b-41d4-a716-446655440000"
}
Let's create a "tasks" module using the scaffolder:
clojure -M:dev -m boundary.scaffolder.core \
--name tasks \
--fields title:string,description:string,completed:boolean \
--http true \
--web true
What this creates:
src/boundary/tasks/
├── core/
│ ├── task.clj # Pure business logic
│ └── validation.clj # Validation rules
├── ports.clj # Port definitions
├── schema.clj # Data schemas
└── shell/
├── http.clj # HTTP handlers & routes
├── persistence.clj # Database adapter
└── service.clj # Shell orchestration
Generated files: 12
Generated tests: 473
Lines of code: ~2,500
Wire up the module:
;; In src/boundary/system.clj, add to routes:
(require '[boundary.tasks.shell.http :as tasks-http])
(defn all-routes [config]
(concat
(user/user-routes config)
(tasks-http/task-routes config))) ;; ADD THIS
Restart server and test:
# In REPL
(ig-repl/halt)
(ig-repl/go)
# Or restart the process
Create a task:
curl -X POST http://localhost:3000/api/v1/tasks \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN_HERE" \
-d '{
"title": "Learn Boundary Framework",
"description": "Complete the quickstart guide",
"completed": false
}'
In 5 minutes you've:
✅ Set up a production-ready Clojure web framework ✅ Connected to a database with automated migrations ✅ Started an HTTP server with Swagger UI ✅ Created and authenticated a user ✅ Generated a complete CRUD module with tests ✅ Made API calls to your new endpoints
open http://localhost:3000/api-docs/
# Run all tests
clojure -M:test
# Run specific module tests
clojure -M:test --focus boundary.tasks
VSCode + Calva:
# Install Calva extension
code --install-extension betterthantomorrow.calva
# Open project
code .
# Connect to REPL: Ctrl+Alt+C Ctrl+Alt+J
# Choose "deps.edn" and "dev" profile
IntelliJ + Cursive:
:dev aliasEmacs + CIDER:
;; M-x cider-jack-in
;; Choose "clojure-cli"
;; Add alias: ":dev"
See IDE Setup Guide for detailed instructions.
# Explore example applications
cd examples/
# Simple REST API
cd todo-api/
clojure -M:dev
# Full-stack web app
cd ../blog/
clojure -M:dev
# Find and kill process using port 3000
lsof -ti:3000 | xargs kill -9
# Or use a different port
export PORT=8080
# Check database is running
pg_isready # PostgreSQL
# Verify connection string
echo $DATABASE_URL
# Check conf/dev/config.edn configuration
# Clear Clojure cache
rm -rf .cpcache/
# Re-download dependencies
clojure -P -M:dev
# Try again
clojure -M:repl-clj
# Run with verbose output
clojure -M:test --reporter documentation
# Check test database is clean
clojure -M:migrate reset # WARNING: Deletes all data
clojure -M:migrate migrate
;; Hot reload on file save (in REPL)
(require '[clojure.tools.namespace.repl :refer [refresh]])
;; Make code changes, then:
(refresh)
;; Restart system with new code
(ig-repl/halt)
(ig-repl/go)
# Create new migration
clojure -M:migrate create add-task-priority
# Edit migrations/TIMESTAMP-add-task-priority.up.sql
# Edit migrations/TIMESTAMP-add-task-priority.down.sql
# Apply migration
clojure -M:migrate migrate
# Rollback if needed
clojure -M:migrate rollback
;; In src/boundary/tasks/shell/http.clj
;; Add to normalized-api-routes:
{:path "/tasks/:id/complete"
:methods {:post {:handler (complete-task-handler task-service)
:summary "Mark task as complete"
:tags ["tasks"]
:parameters {:path [:map [:id :string]]}}}}
;; In test/boundary/tasks/core/task_test.clj
(deftest complete-task-test
(testing "completing a task"
(let [task {:id "123" :title "Test" :completed false}
result (task/complete task)]
(is (= true (:completed result))))))
docs/ directoryexamples/ directory#boundary-framework channelcore/ - no side effects, easy to testshell/ - I/O, database, HTTPReady to build production applications? 🚀
Next: Full Tutorial - Build a complete task management API from scratch
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |