Build an app
A Minca app keeps its data in the person's own spaces, not on a server of yours. On this page we'll build a small to-do list: connect, save a to-do, and show the list as it changes.
Connecting
Every app starts by asking the person for access, with
createMincaConnection. Wrap your app in MincaProvider, and use
useConnection to show a button until the person has said yes:
import { createRoot } from 'react-dom/client';
import { createMincaConnection } from '@minca/core/session';
import { MincaProvider, useConnection } from '@minca/react';
const connection = createMincaConnection({
home: 'https://home.minca.social/connect',
request: {
name: 'Todo',
access: 'write',
create: [{ name: 'Todos', visibility: 'private' }],
},
network: { relays: ['wss://relay.minca.social'] },
});
createRoot(root).render(
<MincaProvider connection={connection}>
<App />
</MincaProvider>,
);
function App() {
const { connection, state } = useConnection();
if (state.status !== 'ready') {
return <button onClick={() => connection.connect()}>Connect with Minca</button>;
}
return <Todos />;
}home is where the person's account lives. They see your app's name and what
it asks for, and pick which of their spaces to give it. create asks for a
new space just for your app, so there's somewhere to start.
Your app never sees the person's keys. It gets a key of its own, allowed into the spaces it was given and nowhere else.
The connection is remembered between visits, and lasts a week. When it runs
out, state.status is 'expired', and connecting again renews it.
The account home
The person's account, its settings and its other apps live at their home, not in your app. Open it from a click, for the account your app acts for:
connection.openHome(); // the account page
connection.openHome('notifications'); // at a section of itIt opens in a window of its own, centred on yours. The home holds the person's keys, so it is never shown inside your page.
A collection
Records live in collections, like rows in a table. Say what a to-do looks like:
import * as z from 'zod';
import { collection } from '@minca/core';
export const todos = collection({
name: 'app.todo.item',
title: 'To-do',
schema: z.object({ text: z.string().min(1), done: z.boolean() }),
});The definition is stored in the space itself, so any app that opens the space
knows what a to-do is. Add it once, with the node that useNode() gives
you in a component:
await node.collections.define(space.id, todos);We'll look at schemas, rules and the shared standard collections in Collections.
Saving a record
await node.records.put(space.id, todos, { text: 'Buy milk', done: false });The record is signed by the person, through your app's key, and syncs to
everyone else in the space. Because todos carries its schema, TypeScript
checks the body as you write it.
Showing records
useQuery gives the records, and runs again whenever they change, here or
on someone else's device. Todos, which App shows once connected, picks the
space from the ones the person gave:
import { useQuery, useSpaces } from '@minca/react';
export function Todos() {
const { spaces } = useSpaces();
const space = spaces[0];
return space ? <TodoList space={space.id} /> : null;
}
function TodoList({ space }: { space: string }) {
const { result } = useQuery(space, { collection: todos, sort: { '@createdAt': 'asc' } });
if (!result) return null;
return (
<ul>
{result.records.map((todo) => (
<li key={todo.key}>{todo.body.text}</li>
))}
</ul>
);
}That's a whole app. Share the space with a friend, and you both see the same list.
Next steps
- Records and queries: editing, deleting, filters and links between records.
- Collections: what a schema can say, and who may write what.
- Spaces: making spaces, and inviting people to them.
- Signing in: for an app that keeps the account itself, instead of connecting to a home.
- The node: every React hook.
Understand Minca
Minca apps keep their data in spaces that people own, not on a server you run. This page explains the few ideas everything else builds on. Read it first, then build a small app.
Build with agents
An agent can read and write in a person's spaces as them. It might be Claude in a chat app, a coding agent in your terminal, or a program you write. This page shows how to connect one, and what it…