Develop locally
The SDK package includes a local Maypop host for Vite, Rsbuild and Next.js.
Your dev server wraps the app the way Maypop does, so maypop.ready(),
maypop.kv, maypop.drive and the rest work without signing in or
publishing anything.
pnpm add @basilica-digital/maypop-sdkYour app code needs no special branch for local development:
import { maypop } from "@basilica-digital/maypop-sdk";
await maypop.ready();const records = await maypop.kv.list({ prefix: "record/" });Add the host to your dev server
Section titled “Add the host to your dev server”Vite — vite.config.ts:
import { maypop } from "@basilica-digital/maypop-sdk/vite";import { defineConfig } from "vite";
export default defineConfig({ plugins: [maypop()],});Rsbuild — rsbuild.config.ts:
import { defineConfig } from "@rsbuild/core";import { maypop } from "@basilica-digital/maypop-sdk/rsbuild";
export default defineConfig({ plugins: [maypop()],});Next.js — next.config.ts:
import { withMaypop } from "@basilica-digital/maypop-sdk/next";
export default withMaypop({ output: "export",});The host only runs in development; production builds are untouched. Start your usual dev command and open its usual URL.
Local data
Section titled “Local data”You are signed in as an admin named Developer. Everything that belongs to
your machine lives in .maypop/local/ and survives restarts:
| Path | Holds |
|---|---|
.maypop/local/kv.json |
KV data |
.maypop/local/drive/ |
Drive files and their metadata |
.maypop/local/notifications.json |
notifications your app sent |
.maypop/local/dev.json |
who you are testing as (below) |
.maypop/local/mcp.json |
mock MCP servers (below) |
The dev server gives .maypop/local/ its own .gitignore, so none of it
reaches Git. Your saved-data policies,
.maypop/kv-policy.json and .maypop/drive-policy.json, sit next to it and
are committed: Maypop applies them with each published version.
To try a second person or a separate dataset, give each dev server its own directory (one directory can’t be used by two servers at once):
maypop({ username: "Alice", dataDirectory: ".maypop/alice" });withMaypop(nextConfig, { username: "Alice", dataDirectory: ".maypop/alice" });Simulate visitors and teammates
Section titled “Simulate visitors and teammates”.maypop/local/dev.json describes who is looking at the app:
{ "mode": "sandbox", "viewer": { "username": "Guest", "role": "reader", "anonymous": true, "signInGrantsWrite": true, "signedInUsername": "Alice", "signedInRole": "writer" }, "members": [{ "username": "Bob", "role": "editor", "connected": true }], "guestCount": 2, "strictStorage": true}- With
signInGrantsWrite, callingmaypop.signIn()switches the viewer to the signed-in identity and reloads — a way to test the “Sign in to save” path. - Writes always enforce production size limits.
strictStoragealso applies your committed.maypop/kv-policy.json. - Open
/_maypop/notificationsto see who eachmaypop.notify()call addressed, with its text and deep link. Nothing is delivered. - The local Share card marks its link as unpublished.
maypop.link.to()and notification paths open inside the local host the way Maypop opens them, so routing you test here works once published.
Mock MCP servers
Section titled “Mock MCP servers”.maypop/local/mcp.json lets you test maypop.mcp and agent
tools without calling a real service:
{ "schemaVersion": 1, "servers": [ { "id": "search", "name": "Fixture search", "url": "mock://search", "account": "developer@example.com", "tools": [ { "name": "lookup", "description": "Return a fixed search fixture.", "inputSchema": { "type": "object", "properties": { "query": { "type": "string" } } }, "result": { "content": [{ "type": "text", "text": "Fixture result" }] } } ] } ]}A tool without a result echoes its arguments back.
Use real services
Section titled “Use real services”Two more modes reach Maypop through the account you signed in with
maypop auth. Add "profile": "<name>" to pick a
profile. The dev server mints a short-lived
app session itself and never hands the CLI’s credential to the page.
Hybrid keeps KV and Drive local and forwards the capabilities you list:
{ "mode": "hybrid", "remoteCapabilities": ["ai", "members", "link", "mcp", "multiplayer"], "notifications": "inspect"}ai spends your real AI allowance. mcp uses the integrations linked to
the app (see Connect external tools) — don’t combine
it with .maypop/local/mcp.json mocks.
Connected talks to the real app — its data, files and integrations. The
repository must be connected with maypop init:
{ "mode": "connected", "notifications": "inspect"}Set "notifications": "live" in connected mode to really deliver
notifications, or "disabled" to turn them off.
What only works inside Maypop
Section titled “What only works inside Maypop”Opening another app with maypop.apps.open() and opening group settings need
the surrounding Maypop shell, so they are unavailable locally. Check them in
Maypop before release.
The local host is a development tool, not a security boundary: keep the dev server on a trusted network.