Build optimized 24/7 weekly rosters with configurable rules, availability, locks, and shift patterns.
Roster Scheduler is a self-hostable web application for creating a permanent one-week roster. It uses mixed-integer optimization to satisfy hard constraints and improve contract fulfillment, preferences, and fairness.
- Exact schedule optimization instead of greedy assignment
- Configurable shift names, colors, and start/end times
- Staff availability and preferred shifts
- Preset and custom scheduling rules
- Assignment locks preserved during regeneration
- Deterministic generation and alternative optimized rosters
- Rule violation and rest-period visualization
- JSON, CSV, and print-ready PDF exports
- Browser-local or Docker volume persistence
- Light, dark, and system themes
Create a file named compose.yaml:
services:
roster-scheduler:
image: ghcr.io/therealkraken/roster-scheduler:latest
ports:
- "3000:3000"
environment:
PERSISTENT_STORAGE: "true"
DATA_DIR: /data
volumes:
- roster-data:/data
restart: unless-stopped
volumes:
roster-data:Start the application:
docker compose up -dOpen http://localhost:3000.
Update later with:
docker compose pull
docker compose up -dDocker Compose enables shared persistent storage by default.
git clone https://github.com/TheRealKraken/roster-scheduler.git
cd roster-scheduler
docker compose up -dOpen http://localhost:3000.
Useful commands:
# View logs
docker compose logs -f
# Stop the application
docker compose down
# Update after pulling new code
git pull
docker compose pull
docker compose up -dThe named volume roster-scheduler_roster-data survives docker compose down. To also remove all persisted data, run docker compose down -v.
GitHub Actions publishes multi-architecture images for linux/amd64 and linux/arm64:
- Every push to
mainupdatesghcr.io/therealkraken/roster-scheduler:latest - A tag such as
v1.2.0publishesv1.2.0,1.2.0, and1.2 - Every build also receives an immutable commit SHA tag
Create a release image with:
git tag v1.0.0
git push origin v1.0.0After the first workflow completes, open the roster-scheduler package on GitHub, select Package settings, and change its visibility to Public. Anonymous users can then run docker compose up -d without logging in to GHCR.
Run with persistent shared storage:
docker volume create roster-data
docker run -d \
--name roster-scheduler \
--restart unless-stopped \
-p 3000:3000 \
-e PERSISTENT_STORAGE=true \
-e DATA_DIR=/data \
-v roster-data:/data \
ghcr.io/therealkraken/roster-scheduler:latestRun with separate browser-local storage instead:
docker run -d \
--name roster-scheduler \
--restart unless-stopped \
-p 3000:3000 \
-e PERSISTENT_STORAGE=false \
ghcr.io/therealkraken/roster-scheduler:latest| Mode | Setting | Behavior |
|---|---|---|
| Browser | PERSISTENT_STORAGE=false |
Every browser stores a separate roster in localStorage. |
| Server | PERSISTENT_STORAGE=true |
Every browser shares one JSON roster stored in the mounted volume. |
Persistent mode writes atomically to /data/roster-scheduler.json by default.
| Environment variable | Default | Description |
|---|---|---|
ROSTER_SCHEDULER_IMAGE |
ghcr.io/therealkraken/roster-scheduler:latest |
Image used by compose.yaml. Use a version tag to pin releases. |
PERSISTENT_STORAGE |
false |
Enables the server-backed JSON store. |
DATA_DIR |
/data |
Directory containing the persistent file. |
DATA_FILE |
roster-scheduler.json |
File name within DATA_DIR. |
PORT |
3000 |
HTTP port inside the container. |
HOST_PORT |
3000 |
Host port used by compose.yaml. |
To use a host directory instead of a named volume:
volumes:
- /path/on/host:/dataTo migrate browser data into persistent mode, export JSON in the application, enable persistent mode, then import the JSON file.
Requirements: Node.js 22+ and npm.
npm install
npm run devOpen http://localhost:5173.
Validation:
npm test
npm run lint
npm run build- React and TypeScript frontend built with Vite
- GLPK mixed-integer scheduling solver running in a browser worker
- Express production server for static files and optional persistence
- Atomic JSON writes for volume-backed deployments
- No external database required
For browser mode, use the JSON export in the application.
For a named Docker volume:
docker run --rm \
-v roster-scheduler_roster-data:/data \
-v "$PWD":/backup \
alpine tar czf /backup/roster-data-backup.tar.gz -C /data .Persistent mode provides one shared roster with last-write-wins behavior. It does not include authentication, authorization, audit history, or concurrent edit merging.
Do not expose the persistence API directly to the public internet without an authenticated reverse proxy or application-level authentication.
The optimizer uses glpk.js, distributed under GPL-3.0. Review its obligations and choose a compatible repository license before distributing the application.