# Wren > Self-hosted versioned JSON storage and static site deployment. Every write creates a new immutable version. Deploy files and data together, preview before going live, promote when ready. Postgres-backed, deployed with Docker. This file is the LLM-friendly index for Wren. It is intended for AI agents and tools that want a fast orientation; follow the links below for full detail. Wren is an open-source backend service that combines versioned JSON storage with static site deployment. Deploy a directory of HTML/CSS/JS files with `wren deploy`, version every change, preview via labels, and promote to published when ready. Collections store structured JSON data alongside your files — one system, one tree, one label controls what's live. Each organisation gets its own isolated Postgres schema. ## Key concepts - **Collections** — named document namespaces; schema-free by default, optionally validated with JSON Schema - **Documents** — JSON objects stored with a UUID; every mutation creates a new version - **Versions** — immutable snapshots; list, diff, or roll back to any point in history - **Labels** — named pointers to a specific version (`published`, `draft`, `staging`, etc.) - **Trees** — hierarchical path assignment (`/site/about`, `/blog/2026/hello`) for CMS navigation and static site serving - **Deploy** — `wren deploy ./dist --tree mysite` uploads files, assigns tree paths, and serves the site. `wren promote` moves the published label atomically. - **Binary assets** — collections can store files (HTML, CSS, JS, images, PDFs) alongside JSON metadata - **Multi-tenancy** — each org is isolated in its own Postgres schema; invite collaborators with role-based access - **Permissions** — fine-grained rules per principal (user or API key) per resource, with optional label and data filters - **API keys** — long-lived Bearer tokens for programmatic access ## Documentation - [Deploy tutorial](/tutorial/deploy): Deploy a static site, preview, promote — 10-minute walkthrough - [Full tutorial](/tutorial): Complete step-by-step walkthrough — Admin UI, CLI, TypeScript client, Python client - [API Reference](/docs): Interactive Scalar UI over the OpenAPI 3.1 spec; live request examples for every endpoint - [OpenAPI spec](/openapi.json): Machine-readable OpenAPI 3.1 specification - [Full LLM reference](/llms-full.txt): Complete API and client library reference in plain text ## Client libraries - **TypeScript / JavaScript**: `npm install @wren/client` — Node ≥18, Bun, Browser; zero runtime dependencies; full types - **Python**: `pip install wren-client` — Python ≥3.9; sync (`WrenClient`) and async (`AsyncWrenClient`) via httpx; dataclasses ## Authentication Two methods: 1. **Bearer token** (API key): `Authorization: Bearer wren_…` — create keys in Admin UI → API Keys 2. **Session cookie**: `better-auth.session_token=…` — set after POST `/api/auth/sign-in/email` ## Quick API reference ``` # Documents GET /collections list collections GET /{collection} list documents (?label=, ?filter=, ?limit=, ?cursor=, ?facets=) POST /{collection} create document → {id, version:1, data, …} GET /{collection}/{id} get document (?label=) PUT /{collection}/{id} update → new version DELETE /{collection}/{id} soft delete GET /{collection}/by-key/{value} get document by natural key (collection must declare naturalKey) PUT /{collection}/by-key/{value} idempotent upsert by natural key — create if absent, update if present DELETE /{collection}/by-key/{value} soft delete by natural key # Versions GET /{collection}/{id}/versions list all versions GET /{collection}/{id}/versions/{n} get specific version POST /{collection}/{id}/rollback/{n} roll back (creates new version) GET /{collection}/{id}/diff?v1=N&v2=N diff two versions # Labels POST /{collection}/{id}/labels {label, version?} → pin label # Schemas GET /{collection}/_schema PUT /{collection}/_schema {schema, displayName, collectionType, naturalKey?} DELETE /{collection}/_schema POST /{collection}/_schema/validate dry-run: validate a schema against existing docs before writing # Trees GET /tree list trees GET /tree/{name}?full=true full tree snapshot GET /tree/{name}/{path} node + children PUT /tree/{name}/{path} {documentId} → assign DELETE /tree/{name}/{path} unassign # Identity GET /api/me principal, org, role, applicable permission rules (self-check) # Projects (public, no auth) GET /api/v1/projects list all orgs with public permissions, collections, trees, entry URLs # Management GET /api/keys list API keys POST /api/keys {name} → create key (shown once) DELETE /api/keys/{id} revoke GET /api/members list org members DELETE /api/members/{id} remove member GET /api/invites list sent invites POST /api/invites {email, role?} → invite DELETE /api/invites/{id} revoke invite POST /api/invites/accept {token} → accept by token GET /api/permissions list permission rules POST /api/permissions create rule PUT /api/permissions/{id} update rule DELETE /api/permissions/{id} delete rule ``` ## Optional - [llms-full.txt](/llms-full.txt): Expanded reference with request/response shapes, error codes, and client library usage