Skymmich is a self-hosted photo gallery and management system designed specifically for astrophotographers. Built to integrate seamlessly with your Immich photo library, it provides intelligent plate solving, equipment tracking, and comprehensive metadata management tailored for deep-sky imaging workflows.
Perfect for organizing, analyzing, and showcasing your astrophotography collection with full control over your data and infrastructure.
Disclaimer: Skymmich is an independent project and is not affiliated with, endorsed by, or officially connected to Immich or its developers. Skymmich is a third-party application that integrates with Immich's public API.
- Immich Integration: Seamless synchronization with your self-hosted Immich photo library
- Interactive Sky Map: Explore your collection on a high-fidelity celestial atlas powered by Aladin Lite v3
- Astrophotography Filtering: Filter by telescopes, cameras, targets, constellations, and acquisition details
- Deep Zoom Viewer: High-resolution exploration of your deep-sky images with OpenSeaDragon
- Metadata Preservation: Automatic EXIF handling for astrophotography workflows
Note: XMP sidecar generation is currently experimental and may not work as intended in all configurations. Configure
IMMICH_MAPPING_PATHandLOCAL_MAPPING_PATHenvironment variables to map Immich volume paths to local paths for sidecar file placement. - Zero Duplication: View images directly from Immich without storage overhead
- Location Editing: Save and reuse observing sites with map picker; coordinate changes sync back to the original Immich asset automatically
- Built-in OpenNGC Catalog: Browse, search, and filter thousands of deep-sky objects by type, constellation, magnitude, and angular size
- DSS Thumbnails: Cached Digitized Sky Survey preview images for catalog objects
- Target Wishlists: Annotate catalog objects with personal notes and tags on the Targets page
- Target Backfill: Automatically match plate-solved images to catalog objects via the admin panel
- Per-Filter Tracking: Record exposure details per filter including frame count, exposure time, gain, offset, binning, and sensor temperature
- Integration Summary: Automatic calculation of total frames, total integration time, and filter breakdown per image
- Astrometry.net Integration: Automatic coordinate solving for your images
- Background Processing: Non-blocking worker processes with job queuing
- Real-time Updates: Live progress tracking via WebSocket connections
- Batch Processing: Handle multiple images simultaneously
- Results Storage: Persistent RA/Dec coordinates and field information
- Telescope Catalog: Manage your telescopes, mounts, and accessories with specifications
- Camera Database: Track sensors, filters, and imaging configurations specific to astrophotography
- Equipment Groups: Bundle equipment into reusable presets and apply them to images in one click
- Session Logging: Automatic equipment association from EXIF metadata and manual tagging
- Configuration Management: Secure API key and integration settings
- Automated Sync: Cron jobs automatically sync images from Immich and clean up old notifications on a configurable schedule
- Worker Supervisor: Background plate-solving workers automatically restart on failure with exponential backoff when Auto mode is enabled
- Database Backup: One-click SQLite database download from the admin panel (PostgreSQL users should use
pg_dump) - Catalog Management: Load, reload, and check for OpenNGC catalog updates; backfill target names for existing images
- Live Updates: WebSocket-powered notifications for plate-solving results, Immich sync completions, and other events
- Manual Sync: Trigger an Immich sync at any time from the header bar
- Notification Badge: Unacknowledged notification count displayed in the navigation
- Docker Ready: Multi-stage containerization with health checks
- UnRAID Support: Ready-to-use container templates
- Database Options: Built-in SQLite (default), optional PostgreSQL support
Prerequisites: Skymmich requires a running Immich instance for photo management. Ensure you have Immich set up and accessible before proceeding.
Single container setup with built-in SQLite database — no external database needed:
# Download production compose file
curl -o docker-compose.prod.yml https://raw.githubusercontent.com/mstelz/Skymmich/main/docker-compose.prod.yml
# Start Skymmich
docker compose -f docker-compose.prod.yml up -d
# Access the application
open http://localhost:5000What this includes:
- Skymmich application from GitHub Container Registry
- Built-in SQLite database with persistent storage
- Health checks and automatic restarts
- Volume mounts for configuration, logs, and database
PostgreSQL option: If you prefer PostgreSQL, download
docker-compose.postgres.ymland layer it on:echo "POSTGRES_PASSWORD=your_secure_password" > .env docker compose -f docker-compose.prod.yml -f docker-compose.postgres.yml up -d
Single container deployment using GitHub Container Registry:
# Pull the latest image
docker pull ghcr.io/mstelz/skymmich:latest
# Run with Docker (uses built-in SQLite database)
docker run -d \
--name skymmich \
-p 5000:5000 \
-e NODE_ENV=production \
-v skymmich-config:/app/config \
-v skymmich-cache:/app/cache \
ghcr.io/mstelz/skymmich:latest
# Access the application
open http://localhost:5000To use PostgreSQL instead, add
-e DATABASE_URL="postgresql://user:password@host:5432/skymmich"to the command above.
Coming Soon: Skymmich will be available in UnRAID Community Applications for easy one-click installation.
For now, manual installation:
- Install Skymmich: Add container using template URL
https://raw.githubusercontent.com/mstelz/Skymmich/main/docker/unraid-templates/skymmich.xml - Configure: Optionally set Immich URL and API keys (can also be done via admin UI)
- Access: Navigate to
http://your-server:2284
No external database needed — Skymmich uses a built-in SQLite database stored in the config directory. To use PostgreSQL instead, set the
DATABASE_URLfield in the template.
# Clone and install dependencies
git clone https://github.com/mstelz/Skymmich.git
cd Skymmich
npm install
# Option A: Build and run with Docker Compose (builds from source)
# Edit docker-compose.yml environment section with your settings
docker compose up -d
# Option B: Local development server
cp .env.example .env.local
# Edit .env.local with your development settings (uses SQLite by default)
npm run dev
# Option C: Worker-only deployment (standalone)
cp .env.worker.example .env.worker
# Edit .env.worker with database and API settings
npm run dev:worker:standalone
# Access at http://localhost:5000 (Docker) or http://localhost:5173 (local)- Immich Server: Self-hosted photo management server (currently the only supported photo source)
- Docker: 20.10+ (for containerized deployment)
- Database: Built-in SQLite (default, no setup required). PostgreSQL 15+ optionally supported.
- Automatic schema management with Drizzle ORM
- Migration script included for moving data between SQLite and PostgreSQL (see Docker docs)
- Node.js: 20+ (for building from source)
- Astrometry.net API Key: For automated plate solving capabilities
Note: Support for additional photo sources beyond Immich is planned for future releases, but Immich is currently required as the primary photo library.
| Variable | Default | Description |
|---|---|---|
DATABASE_URL |
(empty) | Optional PostgreSQL connection string. Leave empty to use built-in SQLite. |
PORT |
5000 |
HTTP server port |
NODE_ENV |
development |
Application environment |
IMMICH_URL |
(optional) | Immich server base URL |
IMMICH_API_KEY |
(optional) | Immich API authentication key |
ASTROMETRY_API_KEY |
(optional) | Astrometry.net API key |
ENABLE_PLATE_SOLVING |
true |
Enable background worker |
PLATE_SOLVE_MAX_CONCURRENT |
3 |
Max simultaneous jobs |
XMP_SIDECAR_PATH |
/app/sidecars |
Directory for XMP sidecar files |
After startup, access the admin interface at /admin to configure:
- Immich Integration: Server URL, API keys, album picker, sync schedules
- Astrometry Settings: API credentials, job limits, auto-processing
- Worker Management: Enable/disable background processing
- Sync Scheduling: Automated Immich synchronization frequency
Tip: Configuration via admin interface takes precedence over environment variables and persists across container restarts.
Skymmich includes a bidirectional migration script for moving data between SQLite and PostgreSQL:
# PostgreSQL → SQLite
node tools/scripts/migrate-db.js \
--from postgresql://user:pass@host:5432/skymmich \
--to sqlite:path/to/skymmich.db
# SQLite → PostgreSQL
node tools/scripts/migrate-db.js \
--from sqlite:path/to/local.db \
--to postgresql://user:pass@host:5432/skymmichInside a Docker container:
node /app/dist/tools/scripts/migrate-db.js \
--from postgresql://... \
--to sqlite:/app/config/skymmich.dbTo avoid running the command manually inside the container, set the AUTO_DB_MIGRATE_FROM environment variable (and optional AUTO_DB_MIGRATE_TO) on the Skymmich service. The Docker startup script runs the migration before launching the app, deletes any existing SQLite target file (unless AUTO_DB_MIGRATE_RESET_SQLITE=false), and writes a marker to /app/config/.auto-db-migrated so it only happens once unless you delete that file or set AUTO_DB_MIGRATE_ONCE=false.
The script handles all type conversions (timestamps, booleans, JSON, arrays) and respects foreign key ordering automatically. SQLite targets run the bundled Drizzle migrations during the copy; PostgreSQL targets should be initialized once beforehand so the schema exists.
Skymmich provides ready-to-use container images through GitHub Container Registry:
- Latest Release:
ghcr.io/mstelz/skymmich:latest - Specific Version:
ghcr.io/mstelz/skymmich:v1.x.x - Development:
ghcr.io/mstelz/skymmich:main
linux/amd64(x86_64)linux/arm64(ARM64/Apple Silicon)
latest- Latest stable releasev*.*.*- Semantic version tags (e.g.,v1.0.0)main- Latest development build from main branchsha-*- Specific commit builds
All images are automatically built, tested, and scanned for vulnerabilities using GitHub Actions.
┌─────────────────────────────────────┐
│ Skymmich Container │
├─────────────────────────────────────┤
│ Frontend (React + TypeScript) │
│ ├─ Vite build system │ ┌─────────────────────┐
│ ├─ Tailwind CSS + shadcn/ui │ │ External APIs │
│ └─ Real-time WebSocket client │ ├─────────────────────┤
├─────────────────────────────────────┤◄──►│ Immich Server │
│ Backend (Hono + Node.js) │ │ Astrometry.net │
│ ├─ RESTful API endpoints │ │ Image Sources │
│ ├─ WebSocket server (ws) │ └─────────────────────┘
│ ├─ Image proxy & thumbnails │
│ └─ Session management │ ┌─────────────────────┐
├─────────────────────────────────────┤ │ PostgreSQL │
│ Worker Manager │ │ (optional) │
│ ├─ Background job processing │◄──►│ External database │
│ ├─ Plate solving automation │ │ for advanced use │
│ ├─ Crash recovery & monitoring │ └─────────────────────┘
│ └─ Graceful shutdown handling │
├─────────────────────────────────────┤
│ SQLite (built-in, default) │
│ └─ /app/config/skymmich.db │
└─────────────────────────────────────┘
Skymmich/
├── apps/
│ ├── client/ # React frontend application
│ │ ├── src/
│ │ │ ├── components/ # UI components (shadcn/ui)
│ │ │ ├── pages/ # Route components
│ │ │ ├── lib/ # Utilities and API clients
│ │ │ └── hooks/ # Custom React hooks
│ │ └── dist/ # Built frontend assets
│ └── server/ # Node.js backend application
│ ├── src/
│ │ ├── routes/ # API route handlers
│ │ ├── services/ # Business logic services
│ │ ├── workers/ # Background job processors
│ │ └── db.ts # Database configuration
│ └── dist/ # Compiled backend code
├── packages/
│ └── shared/ # Shared types and schemas
│ ├── src/
│ │ ├── db/ # Database schemas (SQLite/PostgreSQL)
│ │ ├── schemas/ # Zod validation schemas
│ │ └── types/ # TypeScript type definitions
├── docker/ # Containerization files
│ ├── Dockerfile # Multi-stage container build
│ ├── docker-compose.yml # Service orchestration
│ ├── startup.sh # Container entry point
│ └── unraid-templates/ # UnRAID deployment templates
├── tools/ # Development and migration tools
│ ├── scripts/ # Utility scripts
│ └── migrations/ # Database migration files
├── docs/ # Documentation
└── assets/ # Static assets and examples
# Install Node.js 20+
node --version # v20+
npm --version # 10+
# Clone repository
git clone https://github.com/mstelz/Skymmich.git
cd Skymmich# Install dependencies
npm install
# Setup environment (choose one based on your needs)
cp .env.example .env.local # Main application settings
cp .env.worker.example .env.worker # Worker-only deployment
# Configure your development settings
# Database schema is managed automatically on startup via Drizzle ORM# Start development server (SQLite database by default)
npm run dev # Full stack: server + frontend + worker
npm run dev:server:watch # Server only with file watching
npm run dev:worker # Worker process only
npm run dev:worker:standalone # Standalone worker (uses .env.worker)
# Build for production
npm run build # Build frontend and backend
npm run build:docker # Build with Docker assets
# Docker development (uses SQLite by default)
docker compose up -d # Full stack via DockerSkymmich includes comprehensive end-to-end testing using Playwright:
# Run all tests
npm run test:e2e # Run Playwright end-to-end tests
# Interactive testing
npm run test:e2e:ui # Run tests with Playwright UI mode
npm run test:e2e:debug # Debug tests with Playwright inspector
npm run test:e2e:headed # Run tests in headed browser modeTest Structure:
tests/e2e/- End-to-end test specificationstests/e2e/pages/- Page Object Model classes for maintainable testsplaywright.config.ts- Playwright configuration with multiple browsers
Prerequisites for Testing:
- Skymmich application running on
http://localhost:5173 - Test database with sample data
- All dependencies installed via
npm install
# Type checking
npm run check # TypeScript compilation checkSkymmich uses GitHub Actions for continuous integration and deployment. All builds are automatically tested, scanned for vulnerabilities, and containerized.
- Build & Push: Automatic Docker image builds on main branch commits
- PR Testing: Validates all pull requests with build tests and security scans
- Release: Semantic versioning releases with tagged Docker images
- All images are scanned with Trivy for vulnerabilities
- Critical vulnerabilities block deployments
- SBOM (Software Bill of Materials) generated for each build
For detailed CI/CD documentation, see docs/CI_CD.md.
We welcome contributions! Please see our Contributing Guide for details.
- Additional Photo Sources: Support for photo libraries beyond Immich (direct uploads, other self-hosted solutions)
- Interactive Sky Map: Celestial atlas visualization for plate-solved image collections
- Advanced image statistics and analytics for astrophotography sessions
- Equipment usage reporting and session tracking
- XMP sidecar generation for astrophotography metadata
- XMP sidecar viewer and editor for astrophotography metadata
- NINA Plugin: Sync session data (targets, equipment, acquisition details) directly from N.I.N.A. to Skymmich
- Local Plate Solving: Integration with local solvers (ASTAP, PixInsight) for offline solving without Astrometry.net
- Advanced search and filtering with saved queries
- Bulk image processing workflows and batch operations
- View saved/tagged targets on the Sky Map
- Raw data and calibration frame management
- Mobile app companion for field use
- Community features (sharing, public galleries)
- Bug Reports: GitHub Issues
- Feature Requests: GitHub Discussions
This project is licensed under the MIT License - see the LICENSE file for details.
- Immich - Inspiration and integration for photo management
- Astrometry.net - Plate solving service and algorithms
- shadcn/ui - Beautiful and accessible React components
- Drizzle ORM - Type-safe database toolkit
Built for the astrophotography community

