A self-hosted pomodoro timer with Spotify integration and a lofi aesthetic. Focus on your work while your favorite playlists play in the background.
- Timer presets: Short (15/3), Classic (25/5), Long (50/10)
- Overtime mode - timer counts up after completion, you decide when to switch
- Stop button to end sessions without auto-transitioning to the next phase
- Session statistics with contribution graph - track your focus time, streaks, and overtime
- Spotify integration with playlist selection and Web Playback SDK (play directly in the browser without needing an external Spotify app)
- Structured logging with configurable levels and format (pretty or JSON)
- Light/dark theme toggle
- Keyboard-first controls
- Go to Spotify Developer Dashboard
- Click "Create App"
- Fill in the details:
- App name: Spotify Pomodoro
- Redirect URI: See setup options below
- APIs used: Check "Web API" and "Web Playback SDK"
- Copy the Client ID from your app's settings
Spotify allows HTTP only for localhost or 127.0.0.1. Use this for local testing:
# .env
PUBLIC_SPOTIFY_CLIENT_ID=your_client_id_here
PUBLIC_SPOTIFY_REDIRECT_URI=http://127.0.0.1:2500/callbackAdd http://127.0.0.1:2500/callback to your Spotify app's Redirect URIs.
For deployment on a server (Coolify, VPS, etc.), you need HTTPS. Set up a domain with SSL:
# .env
PUBLIC_SPOTIFY_CLIENT_ID=your_client_id_here
PUBLIC_SPOTIFY_REDIRECT_URI=https://pomodoro.yourdomain.com/callbackAdd https://pomodoro.yourdomain.com/callback to your Spotify app's Redirect URIs.
Note: Spotify requires HTTPS for any redirect URI that isn't
localhostor127.0.0.1. If deploying to a local network IP (e.g.,192.168.x.x), you must set up SSL via a reverse proxy or use a domain with DNS pointing to your server.
docker compose up -dOpen your configured URL in a browser.
docker compose pull
docker compose up -dYour session data persists in the pomodoro_data volume.
- Create a new service from this repository
- Set environment variables in Coolify's UI:
PUBLIC_SPOTIFY_CLIENT_IDPUBLIC_SPOTIFY_REDIRECT_URI(use your Coolify domain:https://pomodoro.yourdomain.com/callback)
- Update your Spotify app's redirect URI to match
- Deploy
For VPS deployments, you can enable authentication to protect your instance:
# .env
AUTH_ENABLED=true
AUTH_PASSWORD=your-secure-password
AUTH_SECRET=random-32-character-string-for-signing- Username: Always
admin(pre-filled in login form for password manager compatibility) - Password: Your chosen password from
AUTH_PASSWORD - Secret: Any random string used for signing cookies (keep this secret!)
When enabled, all routes require login. The login page appears at /login.
Tip: Generate a secure secret with
openssl rand -base64 32
| Key | Action |
|---|---|
Space / Enter |
Start timer |
E |
End (stop) current session |
B |
Skip to break (during focus) |
F |
Skip to focus (during break) |
R |
Reset timer (when stopped) |
See CONTRIBUTING.md for development setup.
# Without Docker
bun install
bun run db:migrate
bun run dev
# With Docker
docker compose -f docker-compose.dev.yml upSession data is stored in SQLite. When using Docker, data persists in the pomodoro_data volume.
To reset your data:
# Docker
docker compose down -v
docker compose up -d
# Local
bun run db:clean- Runtime: Bun
- Framework: Astro with React (SSR)
- Database: SQLite with Drizzle ORM
- Styling: Tailwind CSS v4 + shadcn/ui
- State Management: Effect-TS
Ensure the redirect URI in your Spotify app settings exactly matches PUBLIC_SPOTIFY_REDIRECT_URI in your environment.
The app includes a built-in Web Playback SDK player, so playback works directly in the browser. If you see this error, make sure the browser tab has focus and try refreshing. Alternatively, open Spotify on your computer or phone to use it as the playback device.
Check logs with docker compose logs. Ensure port 2500 is not in use by another service.
MIT