Koffan: The 2.5MB RAM Grocery Revolution for Self-Hosted Families
The average self-hosted application devours 500MB+ RAM. Koffan uses 2.5MB. That's not a typo—it's a revolution in efficient software design.
If you're running a home server on a Raspberry Pi or a modest VPS, you know the struggle. Every megabyte counts. Most modern web frameworks throw resource efficiency out the window, leaving you with bloated containers and sluggish performance. Koffan shatters this paradigm. Built with Go and clever architecture choices, this self-hosted grocery list delivers real-time sync, offline capabilities, and a gorgeous mobile interface while using less memory than a single browser tab.
In this deep dive, you'll discover how PanSalut's minimalist masterpiece achieves its impossible performance, explore its powerful feature set, and get a complete deployment guide with real code examples. Whether you're a seasoned DevOps engineer or a privacy-conscious family looking to escape Big Tech's shopping apps, Koffan proves that less is exponentially more.
What is Koffan?
Koffan is a free, open-source shopping list application engineered for couples, families, and shared households who refuse to sacrifice their data privacy or server resources. Created by developer PanSalut, this isn't another Electron monstrosity or memory-hungry Node.js app—it's a purpose-built solution that prioritizes speed, simplicity, and sovereignty.
The project emerged from genuine frustration. PanSalut needed a collaborative grocery list for his family but found existing solutions either too complex, too resource-intensive, or too invasive. His first attempt using Next.js consumed hundreds of megabytes of RAM—unacceptable for a server running multiple services. The breakthrough came when he rewrote the entire application in Go 1.21 with the Fiber framework, slashing memory usage to an almost unbelievable ~2.5 MB.
This architectural decision transformed Koffan from a simple side project into a technical statement. At a time when developers accept bloat as inevitable, Koffan demonstrates what's possible when you choose the right tool for the job. The app has gained significant traction in the self-hosting community, trending on GitHub for its radical efficiency and practical design philosophy.
Beyond its performance, Koffan delivers a polished user experience. It features real-time WebSocket synchronization, progressive web app capabilities, offline-first design, and multi-language support—all while maintaining a tiny 16MB disk footprint. The SQLite database ensures zero-configuration setup, and the HTMX + Alpine.js + Tailwind CSS frontend stack provides modern interactivity without the JavaScript framework bloat.
Key Features That Redefine Lightweight Excellence
Ultra-Minimal Resource Footprint The headline feature is undeniable: ~2.5 MB RAM usage. This isn't achieved through cheap tricks but through deliberate technology choices. Go's compiled nature eliminates runtime overhead, while Fiber's lightning-fast HTTP handling ensures minimal memory allocation per request. The entire application binary is a single, self-contained executable—no interpreter, no virtual machine, no dependency hell.
Real-Time Synchronization via WebSockets Unlike traditional polling-based apps, Koffan uses WebSocket connections for instant updates across devices. When your partner checks off "milk" in the store, your phone updates immediately. This is implemented with Go's native concurrency model (goroutines), making it efficient enough to handle hundreds of simultaneous connections on that same 2.5MB memory budget.
Progressive Web App (PWA) with Offline Mode Koffan isn't just mobile-friendly—it's a first-class PWA. Install it on iOS or Android directly from your browser, and it behaves like a native app. The offline mode leverages browser storage APIs, allowing you to add items, edit quantities, and mark purchases without connectivity. When you reconnect, the delta sync algorithm automatically merges changes without conflicts.
Intelligent Auto-Completion Engine The app learns your shopping patterns. Start typing "toothpaste" and Koffan suggests it instantly using fuzzy search against your purchase history. It even remembers which store section you typically find items in, automatically categorizing "bananas" under "Fruits & Vegetables." This is powered by SQLite's FTS5 full-text search extension, delivering sub-millisecond queries.
Multi-List Architecture with Custom Icons Create separate lists for different stores, occasions, or family members. Each list supports custom emoji icons and independent product databases. The data model uses normalized SQLite tables with foreign key constraints, ensuring referential integrity while maintaining query performance.
Enterprise-Grade Security Features Despite its size, Koffan doesn't skimp on protection. Rate limiting prevents brute-force attacks on the login endpoint. The simple password system (no email registration required) eliminates credential stuffing risks. Environment variables control login lockout policies, with configurable attempt limits and lockout durations.
REST API for Power Users
The comprehensive REST API (documented in the project's Wiki) enables integrations with home automation systems, voice assistants, or migration scripts. Enable it with a single API_TOKEN environment variable and access endpoints for products, lists, and sync status. The API uses JWT-style token authentication and returns JSON responses with proper HTTP status codes.
Dark Mode & Multi-Language Support The interface automatically adapts to your system's theme preferences using CSS media queries. With 11 languages supported (including Polish, German, Spanish, French, and more), Koffan serves global households. The i18n system uses JSON translation files loaded on-demand, avoiding memory bloat.
Real-World Use Cases Where Koffan Dominates
The Budget-Conscious Family Sarah and Tom run their entire smart home on a single Raspberry Pi 4. They can't afford to waste 500MB on a grocery app. Koffan's 2.5MB footprint means they can sync shopping lists, run Pi-hole, host Nextcloud, and manage their Home Assistant instance—all simultaneously. The offline mode is crucial when Tom shops in the supermarket's basement-level dead zone.
The Privacy-First Household Mark refuses to let corporations data-mine his family's shopping habits. He self-hosts Koffan on a VPS in Switzerland, ensuring GDPR compliance and zero third-party analytics. The simple authentication model means no personal data ever leaves his control. He uses the REST API to automatically add items from his meal planning script, creating a fully private food management ecosystem.
The Multi-Generational Family Grandparents, parents, and teenagers share one Koffan instance across three households. Each family unit has its own list with custom icons. The teenagers use the PWA on their phones, grandparents bookmark it on their iPad, and parents manage it from their laptops. The real-time sync means when grandma adds "flour" for Sunday baking, everyone sees it instantly—no more duplicate purchases.
The Minimalist DevOps Engineer
Alex maintains a homelab with strict resource quotas. He deploys Koffan in a Docker container with memory limits set to 10MB (just to be safe). The SQLite database backs up automatically to his NAS via a cron job. He appreciates that the entire application state lives in one file (shopping.db), making migrations and disaster recovery trivial. The Alpine.js frontend means no build step—just raw HTML served directly.
Step-by-Step Installation & Setup Guide
Local Development Setup (No Docker Required)
Running Koffan natively with Go gives you maximum performance and is perfect for development or lightweight servers.
Step 1: Install Go 1.21+
Choose your operating system:
# macOS with Homebrew (recommended)
brew install go
# Debian/Ubuntu Linux
sudo apt install golang-go
# Windows
# Download installer from https://go.dev/dl/
Verify installation with go version. You should see go1.21 or higher.
Step 2: Clone and Launch
# Clone the repository
git clone https://github.com/PanSalut/Koffan.git
cd Koffan
# Run with default password (shopping123)
go run main.go
# Or set a custom password immediately
APP_PASSWORD=your-secure-password go run main.go
Your application is now live at http://localhost:3000. The first launch creates the SQLite database automatically.
Production Docker Deployment (Recommended)
Docker provides isolation and simplifies updates. Koffan's official image is optimized for size.
Quick Start with Single Command:
docker run -d \
--name koffan \
-p 3000:80 \
-e APP_PASSWORD=your-secure-password \
-v koffan-data:/data \
ghcr.io/pansalut/koffan:latest
What this command does:
-druns the container detached in background-p 3000:80maps host port 3000 to container port 80-e APP_PASSWORDsets your authentication credential-v koffan-data:/datacreates a persistent volume for the SQLite databaseghcr.io/pansalut/koffan:latestpulls the latest stable image
Build from Source with Docker Compose:
For custom modifications or to pin a specific version:
# Clone repository
git clone https://github.com/PanSalut/Koffan.git
cd Koffan
# Build and start with docker-compose
docker-compose up -d
# App available at http://localhost:80
The docker-compose.yml file (included in the repo) defines the service configuration and volume mounts automatically.
Environment Configuration Mastery
Koffan's behavior is controlled through environment variables. Here are the critical ones:
# Security & Authentication
APP_PASSWORD=complex-password-here # REQUIRED for production
DISABLE_AUTH=false # Set true only behind reverse proxy with auth
LOGIN_MAX_ATTEMPTS=5 # Brute force protection
LOGIN_WINDOW_MINUTES=15 # Attempt tracking window
LOGIN_LOCKOUT_MINUTES=30 # Temporary ban duration
# Performance & Paths
APP_ENV=production # Enables secure cookies
PORT=80 # Container port (3000 for local Go)
DB_PATH=./shopping.db # SQLite file location
DEFAULT_LANG=en # UI language on first load
# API Access
API_TOKEN=your-secret-api-key # Enables REST API endpoints
Pro Tip: Store these in a .env file when using Docker Compose, but never commit secrets to version control.
Real Code Examples from the Repository
Example 1: Basic Docker Deployment Command
This is the exact command from the README, explained line-by-line:
docker run -d -p 3000:80 -e APP_PASSWORD=yourpassword -v koffan-data:/data ghcr.io/pansalut/koffan:latest
Breakdown:
docker runcreates and starts a new container-d(detach) runs it in the background without blocking your terminal-p 3000:80maps your server's port 3000 to the container's internal port 80 where Koffan listens-e APP_PASSWORD=yourpasswordinjects the authentication credential as an environment variable-v koffan-data:/datamounts a named volumekoffan-datato the container's/datadirectory, ensuring your SQLite database persists across container restarts and updatesghcr.io/pansalut/koffan:latestspecifies the image from GitHub Container Registry with the latest tag
Example 2: Custom Password with Local Go Execution
APP_PASSWORD=secure-family-password go run main.go
Technical Explanation:
This shell command sets an environment variable only for the duration of the go run process. When Koffan's Go code executes, it reads os.Getenv("APP_PASSWORD") during initialization. If no password is set, it falls back to the default shopping123. The password is hashed using bcrypt and stored in the SQLite database on first run. Subsequent logins compare hashed values, never storing plaintext.
Example 3: Docker Compose Configuration
While the README shows the command, here's what the docker-compose.yml likely contains (based on standard patterns):
version: '3.8'
services:
koffan:
build: .
ports:
- "80:80"
environment:
- APP_ENV=production
- APP_PASSWORD=${KOFPASS} # Load from .env file
volumes:
- koffan-data:/data
restart: unless-stopped
volumes:
koffan-data:
Implementation Details:
build: .tells Docker to build using the Dockerfile in the current directory${KOFPASS}uses variable substitution, reading from a.envfile for better securityrestart: unless-stoppedensures the container auto-recovers after crashes or server reboots- The named volume
koffan-datais managed by Docker and stored in/var/lib/docker/volumes/on the host
Example 4: API Token Authentication Header
Based on the REST API documentation mentioned in the Wiki:
curl -X GET https://your-koffan.com/api/v1/lists \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json"
Usage Pattern:
When you set API_TOKEN=your-secret-key in your environment, Koffan exposes REST endpoints under /api/v1/. The Fiber backend middleware intercepts requests, extracts the Bearer token from the Authorization header, and validates it against the environment variable. This stateless authentication is perfect for integrating with Home Assistant, Node-RED, or custom automation scripts that need to add grocery items programmatically.
Example 5: Persistent Volume Backup Script
Since all data lives in one SQLite file, backup is trivial:
#!/bin/bash
# koffan-backup.sh - Daily backup for Koffan SQLite database
BACKUP_DIR="/mnt/nas/koffan-backups"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
CONTAINER_NAME="koffan"
# Copy database from running container
docker cp ${CONTAINER_NAME}:/data/shopping.db ${BACKUP_DIR}/shopping.db.${TIMESTAMP}
# Keep only last 30 backups
ls -t ${BACKUP_DIR}/shopping.db.* | tail -n +31 | xargs -r rm
echo "Koffan backup completed: ${TIMESTAMP}"
Operational Excellence:
This script demonstrates Koffan's operational simplicity. Because the database is a single file, you don't need complex database dump tools. The docker cp command extracts the live SQLite file (safe for read-copy due to SQLite's file locking). Run this via cron daily, and you have point-in-time recovery capability with minimal storage overhead.
Advanced Usage & Best Practices
Reverse Proxy Integration with Authentication If you run Nginx or Traefik with OAuth2/OIDC, disable Koffan's built-in auth:
DISABLE_AUTH=true APP_ENV=production go run main.go
Security Note: Only do this if your reverse proxy handles authentication. Koffan will trust all requests, exposing your grocery data otherwise.
Multi-Instance Deployment for Extended Families Run separate Koffan containers for different households on the same server:
# Instance for Family A
docker run -d -p 3001:80 -e APP_PASSWORD=famA-pass -v koffan-famA:/data --name koffan-famA ghcr.io/pansalut/koffan:latest
# Instance for Family B
docker run -d -p 3002:80 -e APP_PASSWORD=famB-pass -v koffan-famB:/data --name koffan-famB ghcr.io/pansalut/koffan:latest
Each instance is completely isolated, with separate databases and authentication.
Performance Tuning for Low-Power Devices On Raspberry Pi Zero or similar constrained hardware:
- Set
APP_ENV=production- Disables debug logging that writes to disk - Use a RAM disk for SQLite: Mount
/datato tmpfs for lightning-fast queries - Limit concurrent connections: Fiber handles this automatically, but you can add reverse proxy rate limiting
- Disable unused languages: Remove translation files from
static/lang/you don't need
API-Driven Automation Workflows Integrate with Home Assistant:
# configuration.yaml example
rest_command:
add_to_grocery:
url: "http://koffan.local/api/v1/products"
method: POST
headers:
authorization: "Bearer YOUR_API_TOKEN"
content-type: "application/json"
payload: '{"name": "{{ item_name }}", "list_id": 1}'
Now you can say "Hey Google, add milk to my grocery list" and trigger this automation.
Comparison: Koffan vs. The Competition
| Feature | Koffan | Grocy | Mealie | Bring! |
|---|---|---|---|---|
| RAM Usage | 2.5 MB | 300-500 MB | 400-600 MB | N/A (proprietary) |
| Self-Hosted | ✅ Yes | ✅ Yes | ✅ Yes | ❌ No |
| Real-Time Sync | ✅ WebSockets | ✅ Server-Sent Events | ❌ Polling | ✅ Proprietary |
| Offline Mode | ✅ Full PWA | ❌ Limited | ❌ No | ✅ Yes |
| Database | SQLite (file-based) | MySQL/PostgreSQL | PostgreSQL | Cloud-only |
| Setup Complexity | Extremely Low | High | Medium | Zero (but no control) |
| API | ✅ REST | ✅ REST | ✅ REST | ❌ Limited |
| Resource Footprint | ~16 MB disk | ~1 GB disk | ~800 MB disk | N/A |
| Mobile App | ✅ PWA (installable) | ❌ Web only | ✅ PWA | ✅ Native |
| Multi-Language | ✅ 11 languages | ✅ 20+ languages | ✅ 10 languages | ✅ 15 languages |
Why Koffan Wins:
- Unbeatable efficiency: Nothing else comes close to 2.5MB RAM
- Zero-maintenance database: SQLite requires no running server process
- Instant deployment: Single binary or one Docker command
- True privacy: No telemetry, no accounts, no data mining
When to Choose Alternatives:
- Grocy: If you need full pantry management, meal planning, and chore tracking (but accept the resource cost)
- Mealie: If recipe management is your primary need with grocery lists as secondary
- Bring!: If you absolutely must have native mobile apps and don't care about self-hosting
Frequently Asked Questions
Q: Is the 2.5MB RAM claim accurate under real load? A: Yes. This is measured with 5 active WebSocket connections and a database of 200+ products. Go's garbage collector and Fiber's zero-allocation design maintain consistent memory usage even during sync operations.
Q: Can I run Koffan on a Raspberry Pi Zero W?
A: Absolutely. The ARMv6 binary runs flawlessly on Pi Zero. Deployment takes under 30 seconds, and performance is snappy even on that single-core 1GHz processor. Use the Docker image ghcr.io/pansalut/koffan:latest which includes ARM support.
Q: How does offline mode handle conflicts? A: Koffan uses a last-write-wins strategy with client timestamps. When reconnecting, the client sends a changeset with timestamps. The server merges these, preferring newer operations. If two devices edit the same item offline, the most recent change persists—simple and effective for grocery lists.
Q: Is my data secure without HTTPS?
A: Never run without HTTPS in production. Koffan supports reverse proxy setups where your Nginx/Traefik handles TLS termination. The APP_ENV=production flag enables secure cookies, but you must provide the encryption layer. Use Let's Encrypt for free certificates.
Q: Can I sync multiple households with one instance? A: Not securely. Use separate Docker containers with different ports and volumes, as shown in the Advanced Usage section. Each household gets isolated data and authentication. The Wiki documents this multi-instance pattern.
Q: What happens if the SQLite database grows very large? A: Even with 10,000+ products and years of history, the database rarely exceeds 50MB. SQLite performance remains excellent. For archival, use the API to export old data, then delete via the web interface. The database file can be vacuumed using the SQLite CLI if needed.
Q: How do I update to the latest version?
A: For Docker: docker pull ghcr.io/pansalut/koffan:latest then recreate the container. Your volume persists data. For Go: git pull origin main then go run main.go. The database schema auto-migrates on startup.
Conclusion: The Future of Self-Hosted Apps is Lean
Koffan isn't just a grocery list—it's a manifesto against software bloat. In an era where developers ship 500MB container images for simple CRUD apps, PanSalut's 2.5MB masterpiece proves we can have modern features without modern waste. The combination of Go's performance, SQLite's simplicity, and HTMX's progressive enhancement creates an application that respects both your server resources and your time.
For families seeking digital sovereignty, Koffan delivers privacy without compromise. For developers, it serves as a blueprint for efficient architecture. The REST API opens infinite automation possibilities, while the PWA approach eliminates app store gatekeeping.
The self-hosting community has embraced Koffan because it solves a real problem with elegance. No complex setup. No database administration. No monthly fees. Just a fast, reliable shopping list that works everywhere, uses almost nothing, and keeps your data where it belongs—in your control.
Ready to reclaim your server's memory and your family's privacy?
⭐ Star the repository to show support: https://github.com/PanSalut/Koffan
🚀 Deploy in 30 seconds using the Docker command above
📖 Explore the Wiki for API docs and advanced patterns
💬 Join the discussion in GitHub Issues for feature requests
Your grocery list should be the leanest app you run. With Koffan, it finally can be.