L Lazypock
Server · Elixir + Phoenix + PostgreSQL

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
  • zig and xz — 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

  1. Open Studio at http://localhost:5173/_/ (or /_ if served directly from Phoenix)
  2. You'll be redirected to the login page
  3. Click Setup to create the first superuser account
  4. 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:

  1. System migrations create its internal _-prefixed tables (_collections, _fields, _superusers, _request_logs, …) plus schema_migrations. These are namespaced and never touch your tables.
  2. Auto-registration: every public table that isn't already a LazyPock collection becomes a base collection, with columns inferred from the Postgres schema — so your existing tables appear in the Studio sidebar and are served through the dynamic /api/:collection routes immediately.
  3. Shape reconciliation so CRUD works out of the box: Ecto timestamps() columns are normalized (inserted_atcreated_at, a missing updated_at is added), and foreign-key columns become relation fields pointing at the referenced table — so the Studio shows a relation dropdown and the API supports expand on 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

VariableDescriptionExample
DATABASE_URLPostgreSQL connection stringecto://postgres:postgres@localhost:5432/lazypock_dev
SECRET_KEY_BASESecret for signing cookiesmix phx.gen.secret
PHX_HOSTPublic hostname (optional, defaults to example.com)localhost
PORTHTTP port (optional, defaults to 4000)4000
POOL_SIZEDB connection pool size (optional, defaults to 10)10
LAZYPOCK_SUPERUSER_EMAILAuto-create superuser on boot[email protected]
LAZYPOCK_SUPERUSER_PASSWORDAuto-create superuser on bootyour-password
LAZYPOCK_THUMBNAILSSet to 0 to disable thumbnail/scaling generation0
LAZYPOCK_DATA_DIRBase data dir for migrations/hooks/seeds (default: ~/.lazypock)/data/lazypock
LAZYPOCK_MIGRATIONS_DIRDirectory for migrations (default: ~/.lazypock/migrations)/data/lazypock/migrations
LAZYPOCK_AUTOMIGRATESet to 0 to disable auto-migrate on boot (then use lazypock migrate)0
LAZYPOCK_AUTOSEEDSet to 0 to disable boot-time seeding0
LAZYPOCK_HOOKS_DIRDirectory for user hooks (default: ~/.lazypock/hooks)/data/lazypock/hooks
LAZYPOCK_SEEDS_FILESeed 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.