Self-hosted ecommerce platform. Keeping it simple with Node.js + SQLite.
- Node.js 22+ (
better-sqlite3requires it as of v13). 22 (LTS) is the tested baseline — CI, Docker, and.nvmrcall pin it — butbetter-sqlite3,argon2, andsharpall ship N-API prebuilt binaries now, so newer versions (e.g. 26) work fine too. - npm
If you're ever on a platform/Node combination with no prebuilt binary available, these fall back to a from-source compile, which needs a C++ toolchain (build-essential on Debian/Ubuntu, apk add python3 make g++ on Alpine). The Dockerfile sidesteps this by installing the toolchain in the build stage regardless.
git clone <this repo>
cd squaark
npm install
cp .env.example .env
npm run devOpen http://localhost:3000/admin. With no admin account yet you'll land on a setup page to create your credentials.
The database schema is created automatically on first boot, there is no separate migration step.
- Settings > Store - store name, currency, contact email, tagline. Toggle customer accounts on/off here.
- Settings > Email - how transactional emails get sent. Defaults to logging to the server console (fine for local dev). For real sending, pick Resend (API key only) or a custom SMTP provider. Use the test button to confirm it works.
- Settings > Payments - paste in Stripe and/or PayPal credentials. Both providers can be active at the same time.
- Settings > Logs - live view of payment events, sent emails, and server errors. Useful for debugging without touching the server.
- Emails - editable Handlebars templates for order confirmation, shipping, admin notifications, password reset. Live preview against sample data.
- Themes - the
linentheme is active by default. Customise colours, fonts, and layout from its config page, or upload a different theme. - Pages - build pages with a section builder (text, image, image + text, CTA, columns), or import from a WordPress export via Import.
- Navigation - edit the main and footer nav links.
- Users - add staff accounts with restricted access (products and orders only, no settings or theme access).
- Products / Collections -
npm run db:seedloads sample catalogue data, or add your own.
The dashboard shows basic traffic analytics (page views, unique visitors, top pages, referrers) collected from storefront requests. No external service or cookie consent needed — bots are filtered by user agent and IPs are hashed before storage.
| Command | Description |
|---|---|
npm run dev |
Start with hot reload |
npm start |
Start the built server (npm run build first) |
npm run build |
Compile TypeScript to dist/ |
npm run db:migrate |
Apply pending migrations manually |
npm run db:seed |
Seed with sample products/collections |
npm run db:backup |
Snapshot the database (safe while running) |
npm run db:restore <file> |
Restore the database from a snapshot |
The entire store — products, orders, customers, settings — lives in a single
SQLite file (DATABASE_PATH, default data/store.db). Back it up regularly.
# Snapshot now → backups/store-<timestamp>.db (uses SQLite's online backup,
# so it's safe to run against a live server — no downtime needed).
npm run db:backup
# …or to a specific path (e.g. a mounted volume):
npm run db:backup /mnt/backups/store.dbSchedule it with cron, e.g. hourly with 7-day retention:
0 * * * * cd /app && npm run db:backup >> /var/log/squaark-backup.log 2>&1
0 3 * * * find /app/backups -name 'store-*.db' -mtime +7 -deleteTo restore (stop the server first — this overwrites the live file; the
current database is copied to <db>.pre-restore as a safety net):
npm run db:restore backups/store-20260727-104512.dbCopy .env.example to .env:
| Variable | Default | Notes |
|---|---|---|
PORT |
3000 |
|
HOST |
0.0.0.0 |
|
NODE_ENV |
development |
Set to production when deploying |
THEME_DIR |
themes/linen |
Active theme directory |
UPLOADS_DIR |
uploads |
Product image uploads |
SESSION_SECRET |
(dev default) | Use a strong random value in production |
DATABASE_PATH |
data/store.db |
SQLite file location |
Store-level settings (name, currency, logo, email provider, etc.) are in the admin UI, not env vars.
GET /health returns 200 {"status":"ok"} when the process is up and the
database is reachable, or 503 otherwise. Point Docker healthchecks, load
balancers, or uptime monitors at it — it's excluded from session/cart handling
and analytics, so probing it has no side effects.
For a git-checkout deploy run under a supervisor, the admin shows an
"update available" banner when the checkout is behind origin/master, and
Settings → Server has a one-click Update now button. It pulls, npm install,
npm run build — all while the old code keeps serving — then exits so the
supervisor restarts into the new code. If any step fails it resets the checkout
to the previous commit and does not restart, so a bad commit can't take the
store down. A Revert button appears for 30 minutes afterwards (disabled when
the update changed the database schema, since migrations are forward-only).
Two requirements:
- The process must be restarted automatically on exit — e.g. a systemd unit
with
Restart=always, or pm2. Without that, the update builds but the server stays down. (Docker deploys update by pulling a new image, not via this button.) - A private repo needs a read deploy-key on the server for the background
git fetchto work.
The first time, dry-run it on a throwaway clone rather than production:
git clone <your-repo> /tmp/squaark-dryrun && cd /tmp/squaark-dryrun
git reset --hard HEAD~3 # pretend we're a few commits behind
git pull --ff-only origin master && npm install && npm run build && echo "clean update ✓"Manual equivalent if you'd rather not use the button:
git pull --ff-only && npm install && npm run build, then restart the service.
docker compose upMulti-stage build: compiles in a build stage, ships only compiled output and production node_modules. A volume is mounted for /data (the database). Uploaded images under /app/uploads aren't persisted across container recreation unless you add a volume for that path too.
src/routes/- Fastify routes:storefront/,admin/,api/src/commerce/- products, collections, cart, orderssrc/theme/- Handlebars engine, helpers, context builderssrc/email/- transactional email transports and templatessrc/db/migrations/- SQL migration files, applied on bootthemes/linen/- bundled default themeadmin/- admin panel Handlebars templates
See theme_engine_spec.md for the full technical spec.