Getting started

Quickstart

From zero to a deployed schema, a published entry, and a public read — with the CLI and SDK.

This walkthrough takes you from nothing to a deployed schema, a published entry, and a public read. You need Node.js and a GitHub account.

Install and sign in

$ npm install --global @myna-sh/cli
$ myna login
# Opens app.myna.sh/device — sign in with GitHub and approve the device code.

myna login uses a browser device-authorization flow. The credential is stored in the macOS Keychain when available, otherwise in a user-only config file.

$ myna organizations list
$ myna projects create --name "My site" --organization my-org
$ myna link my-site
# Writes .myna/project.json (no secrets) so later commands know the project.

Define a schema

myna init scaffolds a myna/ directory with an example collection:

import { collection, field } from "@myna-sh/sdk/schema";

export const posts = collection({
  name: "posts",
  label: "Blog posts",
  visibility: "public",
  titleField: "title",
  path: "/blog/{slug}",
  fields: {
    title: field.text({ required: true, maxLength: 120 }),
    slug: field.slug({ from: "title", required: true }),
    description: field.text({ multiline: true }),
    body: field.markdown({ required: true }),
    cover: field.asset({ allowed: ["image/*"] }),
    publishedAt: field.datetime(),
  },
});

Schemas are code-owned: the dashboard displays them but the source of truth is this file. Deploy it:

$ myna schema diff
$ myna schema push

diff shows a stable plan and classifies each operation; destructive changes require --allow-destructive. Every push creates an immutable schema version.

Create and publish an entry

$ myna entries create posts --set title="Hello world" --set body="First post."
# Creates a draft revision on an implicit change set. Nothing is public yet.

$ myna changes list
$ myna changes publish <chs_id> --confirm-publish

Writes are drafts until a change set is published. Publishing validates every item and updates all published pointers in one transaction.

Read published content

import { createMyna } from "@myna-sh/sdk";

const myna = createMyna({ project: "my-site" });

const { data } = await myna.entries.list("posts", {
  order: "-publishedAt",
  limit: 10,
});

const post = await myna.entries.get("posts", "hello-world");

In a React app, @myna-sh/react wraps the same client with hooks that share requests, carry loading and error state, and pass a preview token through the tree:

const { data, error, isLoading } = useMynaEntries("posts", { order: "-publishedAt" });

Public collections need no credentials. Or use plain HTTP:

$ curl https://api.myna.sh/v1/projects/my-site/collections/posts/entries

Generate types

$ myna types generate --out src/myna.generated.ts

Emits deterministic TypeScript interfaces for your collections — same input, byte-identical output, safe to commit.

Pass the generated registry to createMyna and reads are typed end to end:

import { createMyna } from "@myna-sh/sdk";
import type { MynaCollections } from "./myna.generated";

const myna = createMyna<MynaCollections>({ project: "my-site" });

const { data } = await myna.entries.list("posts", { order: "-publishedAt" });
data[0].fields.title; // string

Collection keys, field names, and sortable fields are all checked — see generated types.

Next