Quickstart
Get a working app where people sign in with an emailed code and save data: one command, one install, about a dozen lines of code.
With your coding agent
Paste this one prompt into your coding agent (Claude Code, Cursor, Codex, or any agent that can read a URL). It reads the docs and builds against a local backend, free with no account or card.
Read https://docs.gemmein.com/llms.txt and take my app to its first paying customer.
The rest of this page is the same build by hand.
By hand
import { gemmein } from "@gemmein/sdk"
const g = gemmein("pk_test_...")
// Sign in with an emailed sign-in code, no passwords
await g.auth.sendEmailCode("user@example.com")
await g.auth.verifyEmailCode({ email: "user@example.com", code: "12345678" })
// Store data. The server enforces the collection's safety rule.
// Create the "tasks" collection first (see Collections below).
await g.collection("tasks").create({ title: "Buy milk", done: false })
const { records } = await g.collection("tasks").list()
Replace pk_test_... with your app key. On the local backend it is the
pk_local_... key the backend prints, passed with
{ apiUrl: "http://127.0.0.1:4545" } as the second argument to
gemmein(). In the cloud, every call needs an app key (pk_...),
shown on the Your app page.
This guide starts from an idea, with nothing built yet. If you already have an app, read the fit assessment at the top of llms.txt first. It compares what you have with what Gemmein refuses and gives a verdict before you install anything.
Run it locally
Building locally is free and needs no account. You write no server code and no security rules: you choose each collection's rule once, and Gemmein enforces it. Start the local backend in your project folder:
npx -y gemmein dev
This starts a local backend on http://127.0.0.1:4545, with no signup,
account or card. It prints sign-in codes in the terminal instead of emailing them and
simulates checkout, so your app and its data stay on your machine. Its boot card prints
the local app key.
The Gemmein CLI and local runtime send pseudonymous milestones —
for example, that an app's sign-in or payments were set up — so Gemmein can see where building
gets harder and fix it. What is stored is a random install ID (not derived from your machine),
the milestone's name, the CLI version and the first day it was seen; no code, app data or
personal details, and no IP address or user agent. Turn them off with
npx gemmein telemetry off, GEMMEIN_TELEMETRY=0 or
DO_NOT_TRACK=1, and nothing more is sent; nothing is sent in CI. See the
privacy policy.
Then install the SDK:
npm i @gemmein/sdk
The SDK is dependency-free pure ESM. With no bundler, copy
dist/index.js from the package next to your HTML and import it from a
<script type="module">. It works on any static host.
Move to the cloud
When the app works locally, run npx gemmein check to see what going live
still needs. Then run npx gemmein sync. It signs you in at
app.gemmein.com with a sign-in code, free and
with no card. A card is needed only when you go live.
Building with an AI tool: the Your app page gives you a ready-made prompt that covers the whole SDK. Paste it into your AI tool. The machine-readable package guide, which covers what your code calls, is also included in the package.
Collections
You create collections. The SDK never does, and a
new app has none. Locally, the first write to a collection that does not exist yet asks
you in the npx gemmein dev terminal which of the eight safety rules it follows, or you run
npx gemmein collection add <name> from a second terminal. In the
cloud, add it in the dashboard's Data (one click) or carry it there with
npx gemmein sync. There, a 404 unknown_collection means
the collection doesn't exist yet.
Names use lowercase letters, numbers and underscores only: saved_games
works and savedGames does not. A bad name throws the moment
collection() is called.
Record shape
Records come back wrapped, with your fields under .data:
const task = await tasks.create({ title: "Buy milk", done: false })
// { id, data: { title, done }, createdAt, updatedAt, ... }
task.data.title // ✓ "Buy milk"
task.title // ✗ undefined, and if your UI shows blanks this is why
Sessions
Sessions persist across page reloads. A person can be signed in on several devices at
once, up to 10; the 11th signs the oldest out. A token whose session has ended throws
auth_expired once and the SDK clears it; signing in again recovers. See
Devices.
Where next
- Data: pick the right safety rule for each collection.
- Sign-in & sessions: the full sign-in API.
- Payments: charge for things without building a webhook.
- Test your safety rules in CI: check your app's safety rules with live calls.
Thanks for telling us.
Thanks for telling us.
Last updated