Server Guide
How to run and operate a Lazypock server. The repo is a monorepo with two
parts: the core backend (Elixir + Phoenix + PostgreSQL) and the Studio admin UI (SvelteKit, served by the backend at /_/). Your app talks to the
server through one of the SDKs — no backend code required.
Prerequisites
- Elixir 1.17+ and Erlang/OTP 26+ (only for running from source)
- PostgreSQL 15+
- Node.js 20+ (only for the Studio dev server and the SDKs)
- ImageMagick 7+ (
magick/convert) — required for image thumbnails and on-demand scaling; uploads still work without it, thumbnails just won't be generated zigandxz— only needed for Burrito production release builds
The Docker quick start below skips the Elixir/Node prerequisites entirely — just Docker and a prebuilt binary.
Quick start — Docker Compose
No Elixir, Erlang, or source checkout needed — just Docker (for Postgres)
and a prebuilt binary. Clone the repo and start Postgres with its docker-compose.yml (Postgres 16: postgres/postgres@localhost:5432, database lazypock_dev):
# 1. Start Postgres (the repo's docker-compose.yml runs Postgres 16:
# postgres/postgres@localhost:5432, database lazypock_dev)
docker compose up -d 2. Grab the prebuilt binary for your platform from Releases (macOS arm64 + Linux x86_64; checksums included) — or see Option B below:
# 2. Grab the prebuilt binary for your platform from Releases:
# https://github.com/gnuzd/lazypock/releases
# (macOS arm64 + Linux x86_64; checksums included) 3. Run it — the superuser is auto-created on first boot:
DATABASE_URL="ecto://postgres:postgres@localhost:5432/lazypock_dev" \
SECRET_KEY_BASE="$(openssl rand -base64 48)" \
[email protected] \
LAZYPOCK_SUPERUSER_PASSWORD=admin123 \
./lazypock - Server + Studio admin UI:
http://localhost:4000(login at/_/with the superuser above) - REST API:
http://localhost:4000/api/...
To reset everything (including the database):
docker compose down -v Prefer no Docker at all? Any PostgreSQL 15+ works — just point DATABASE_URL at it. Or run
from source — see Manual setup below.
Ready to connect an app? Follow the TypeScript SDK quick start.
Prebuilt binary
No Docker, no Elixir toolchain — grab a prebuilt single-binary release (built with Burrito) straight from GitHub Releases and run it directly:
# Download the latest release for your platform from:
# https://github.com/gnuzd/lazypock/releases/latest
chmod +x lazypock_macos_silicon # or the binary matching your OS/arch
export DATABASE_URL="ecto://postgres:postgres@localhost:5432/lazypock"
export SECRET_KEY_BASE="$(openssl rand -base64 48)"
[email protected] LAZYPOCK_SUPERUSER_PASSWORD=changeme \
./lazypock_macos_silicon You still need a reachable PostgreSQL 15+ instance (e.g. via docker run -p 5432:5432 postgres:16-alpine). The binary handles migrations, seeding, and serving the Studio UI on
its own — see Releases for available platforms and checksums.
Manual setup (from source)
1. Run the backend (Phoenix)
git clone [email protected]:gnuzd/lazypock.git
cd lazypock/core
export DATABASE_URL="ecto://postgres:postgres@localhost:5432/lazypock_dev"
mix setup # install deps, create DB, run migrations, seed
mix phx.server # starts Phoenix on http://localhost:4000 The REST API and realtime channels are served at http://localhost:4000.
2. Run Studio (Admin UI)
cd lazypock/studio
npm install
npm run dev # starts Vite dev server on http://localhost:5173 The SvelteKit dev server proxies /api requests to the Phoenix backend on port 4000. Studio itself is served at http://localhost:5173/_/.
Then connect an app with one of the SDKs — see the TypeScript SDK install.
First-time setup
- Open Studio at
http://localhost:5173/_/(or/_if served directly from Phoenix) - You'll be redirected to the login page
- Click Setup to create the first superuser account
- Log in and start creating collections — every collection you create in Studio gets an instant REST API + realtime channel + rules, ready to call from any SDK
Connect an existing PostgreSQL database
LazyPock is designed to run on top of a database you already have —
point it at an existing Postgres (15+) instance and its tables show up
in the Studio automatically. Just set DATABASE_URL to your
database:
export DATABASE_URL="ecto://user:password@db-host:5432/my_existing_db"
export SECRET_KEY_BASE="$(openssl rand -base64 48)"
[email protected] LAZYPOCK_SUPERUSER_PASSWORD=changeme ./lazypock_macos_silicon On boot LazyPock does three things to the database:
- System migrations create its internal
_-prefixed tables (_collections,_fields,_superusers,_request_logs, …) plusschema_migrations. These are namespaced and never touch your tables. - Auto-registration: every public table that isn't
already a LazyPock collection becomes a
basecollection, with columns inferred from the Postgres schema — so your existing tables appear in the Studio sidebar and are served through the dynamic/api/:collectionroutes immediately. - Shape reconciliation so CRUD works out of the box:
Ecto
timestamps()columns are normalized (inserted_at→created_at, a missingupdated_atis added), and foreign-key columns become relation fields pointing at the referenced table — so the Studio shows a relation dropdown and the API supportsexpandon them.
Internal _-prefixed tables
and schema_migrations are
never registered. Set LAZYPOCK_AUTOMIGRATE=0 if
you'd rather run migrations manually with lazypock migrate — note
that auto-registration runs as part of every migrate, so tables added
later by other tools are picked up on the next lazypock migrate (or
restart). Log in to the Studio with the superuser created on first boot
(or via the env vars above) and your data is ready to browse, query,
and edit.
Production release (single binary)
Lazypock ships as a single binary via Burrito:
cd core
MIX_ENV=prod mix release
# Binary: core/burrito_out/lazypock_macos_silicon Minimal production run example:
export DATABASE_URL="ecto://postgres:postgres@localhost:5432/lazypock"
export SECRET_KEY_BASE="$(mix phx.gen.secret)"
export PHX_HOST="localhost"
[email protected] LAZYPOCK_SUPERUSER_PASSWORD=changeme \
./core/burrito_out/lazypock_macos_silicon The HTTP server is always started — no PHX_SERVER needed; just run the binary (or bin/lazypock start).
The release runs with RUNTIME_CONFIG=false, so config is baked in at build time; environment variables are still
read at boot via the Elixir config provider.
Environment variables
| Variable | Description | Example |
|---|---|---|
DATABASE_URL | PostgreSQL connection string | ecto://postgres:postgres@localhost:5432/lazypock_dev |
SECRET_KEY_BASE | Secret for signing cookies | mix phx.gen.secret |
PHX_HOST | Public hostname (optional, defaults to example.com) | localhost |
PORT | HTTP port (optional, defaults to 4000) | 4000 |
POOL_SIZE | DB connection pool size (optional, defaults to 10) | 10 |
LAZYPOCK_SUPERUSER_EMAIL | Auto-create superuser on boot | [email protected] |
LAZYPOCK_SUPERUSER_PASSWORD | Auto-create superuser on boot | your-password |
LAZYPOCK_THUMBNAILS | Set to 0 to disable thumbnail/scaling
generation | 0 |
LAZYPOCK_DATA_DIR | Base data dir for migrations/hooks/seeds (default: ~/.lazypock) | /data/lazypock |
LAZYPOCK_MIGRATIONS_DIR | Directory for migrations (default: ~/.lazypock/migrations) | /data/lazypock/migrations |
LAZYPOCK_AUTOMIGRATE | Set to 0 to disable
auto-migrate on boot (then use lazypock migrate) | 0 |
LAZYPOCK_AUTOSEED | Set to 0 to disable boot-time
seeding | 0 |
LAZYPOCK_HOOKS_DIR | Directory for user hooks (default: ~/.lazypock/hooks) | /data/lazypock/hooks |
LAZYPOCK_SEEDS_FILE | Seed file path (default: ~/.lazypock/seeds.exs) | /data/lazypock/seeds.exs |
Migrations and hooks live in user-writable directories on disk (~/.lazypock/migrations, ~/.lazypock/hooks) rather than
inside the binary — bundled defaults are copied there on first boot and
applied automatically, and you can drop in new .exs migration files or Elixir
hook modules after a release without rebuilding. See lazypock migrate / lazypock migrations / lazypock seed in the lazypock README for the full CLI.