MarketBridge is a self-hosted web app (Next.js) to prepare sale listings once, store them locally with multiple images, and quickly reuse them across marketplaces.
The app is designed for personal use or small teams on private infrastructure.
- Create listings with structured fields: title, category, condition, size, price, description
- Handle real image uploads (JPG/PNG/WEBP), up to 10 images per listing
- Persist data in SQLite storage
- Edit and delete saved listings
- Expose copyable image URLs
- Export and import ZIP backups
- Installable as a PWA (manifest + service worker)
- Optional full purge mode (enabled only via environment variable)
- Next.js 16 (App Router)
- React 19
- Tailwind CSS 4
- SQLite via
better-sqlite3 - ZIP backup handling via
jszip - Server runtime: Node.js 20
Default persistent paths:
- SQLite database:
data/marketbridge.db - Uploaded images:
data/uploads/
In the provided Docker setup, all data/ content is mounted to the Docker named volume marketbridge_data (container path: /app/data).
- Node.js
20.x - npm
- Docker (optional, recommended for production)
npm install
npm run devOpen: http://localhost:3000
Available scripts:
npm run dev: development servernpm run build: production buildnpm run start: run production buildnpm run lint: ESLint checksnpm run typecheck: TypeScript checks
docker compose up --buildOpen: http://localhost:3001
Ready-to-use images are also available:
ghcr.io/gioxx/marketbridge:latestgfsolone/marketbridge:latest
docker run -d \
--name marketbridge \
-p 3001:3000 \
-e NODE_ENV=production \
-e NEXT_TELEMETRY_DISABLED=1 \
-e SQLITE_PATH=/app/data/marketbridge.db \
-v marketbridge_data:/app/data \
--restart unless-stopped \
ghcr.io/gioxx/marketbridge:latestdocker run -d \
--name marketbridge \
-p 3001:3000 \
-e NODE_ENV=production \
-e NEXT_TELEMETRY_DISABLED=1 \
-e SQLITE_PATH=/app/data/marketbridge.db \
-v marketbridge_data:/app/data \
--restart unless-stopped \
gfsolone/marketbridge:latestservices:
marketbridge:
container_name: marketbridge
image: ghcr.io/gioxx/marketbridge:latest
environment:
NODE_ENV: production
NEXT_TELEMETRY_DISABLED: "1"
PORT: "3000"
SQLITE_PATH: /app/data/marketbridge.db
# Optional dangerous action:
# MARKETBRIDGE_ENABLE_PURGE_ALL: "1"
ports:
- "3001:3000"
volumes:
- data:/app/data
restart: unless-stopped
volumes:
data:
name: marketbridge_dataYou can switch to Docker Hub by replacing:
image: ghcr.io/gioxx/marketbridge:latestwith:image: gfsolone/marketbridge:latest
Supported variables:
| Variable | Default | Description |
|---|---|---|
NODE_ENV |
production (in Docker) |
Node runtime mode |
NEXT_TELEMETRY_DISABLED |
1 |
Disable Next.js telemetry |
PORT |
3000 |
Internal app port |
SQLITE_PATH |
./data/marketbridge.db |
SQLite database path |
MARKETBRIDGE_ENABLE_PURGE_ALL |
unset | If declared, enables UI button and API for full purge |
About MARKETBRIDGE_ENABLE_PURGE_ALL: any declared value enables it. If unset, full purge is disabled and API returns 403.
These routes are used by the UI and do not include built-in authentication.
GET /api/listings: list listingsPOST /api/listings: create listing (multipart/form-data)PUT /api/listings/:id: update listingDELETE /api/listings/:id: delete listing and linked imagesGET /api/uploads/:name: serve stored imageGET /api/backup/export: export ZIP backupPOST /api/backup/import?mode=replace|merge: import ZIP backupGET /api/maintenance/purge: full purge feature statusDELETE /api/maintenance/purge: full purge (only if enabled)
Backup structure:
manifest.jsonlistings.jsonimages/folder with all linked images
Key constraints:
- Max import backup size:
50 MB replacemode: fully replaces current datamergemode: merges backup data into current data- Image names are validated server-side
Operational recommendation:
- Run exports regularly
- Keep at least one offsite copy
- Periodically test restore on a separate environment
MarketBridge does not include built-in authentication, authorization, or user roles.
If you expose the app publicly without protection, anyone can:
- read listings and images
- create/update/delete listings
- import backups and overwrite data
- if enabled, trigger full purge
For production, run MarketBridge behind:
- a reverse proxy
- authentication (Basic Auth, SSO, OAuth2 Proxy, or equivalent)
- HTTPS/TLS
Example Caddyfile:
marketbridge.example.com {
encode zstd gzip
basic_auth {
admin $2a$14$REPLACE_WITH_BCRYPT_HASH
}
reverse_proxy 127.0.0.1:3001
}Generate bcrypt hash with Caddy:
caddy hash-password --plaintext 'STRONG_PASSWORD'Example server block:
server {
listen 443 ssl http2;
server_name marketbridge.example.com;
ssl_certificate /etc/letsencrypt/live/marketbridge.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/marketbridge.example.com/privkey.pem;
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
location / {
proxy_pass http://127.0.0.1:3001;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Create .htpasswd (example):
htpasswd -c /etc/nginx/.htpasswd admin- Do not expose
3001directly to the public Internet - Allow access only through an authenticated reverse proxy
- Use strong passwords and rotate them periodically
- Restrict access by IP where possible (VPN or allowlist)
- Keep base images and containers updated
- Run regular backups and restore drills
- Enable
MARKETBRIDGE_ENABLE_PURGE_ALLonly when truly needed
If you declare this in docker-compose.yml:
environment:
MARKETBRIDGE_ENABLE_PURGE_ALL: "1"the UI shows a dangerous action button that removes:
- all records in the SQLite database
- all stored uploaded images in
data/uploads/
Use only in controlled environments.
src/app/page.tsx: main UIsrc/app/api/listings/route.ts: listing list + createsrc/app/api/listings/[id]/route.ts: listing update + deletesrc/app/api/uploads/[name]/route.ts: image servingsrc/app/api/backup/export/route.ts: backup exportsrc/app/api/backup/import/route.ts: backup importsrc/app/api/maintenance/purge/route.ts: feature flag + full purgesrc/lib/db.ts: SQLite accesssrc/lib/uploads.ts: image file managementdocker-compose.yml: container deployment + persistent volume
- Manifest:
public/manifest.webmanifest - Service worker:
public/sw.js
For reliable install behavior on mobile, HTTPS is required.
See LICENSE.