---
order: 1
section: start
title: Primeiros passos
description: >-
  Instale o scribe-cms, defina um schema, escreva seu conteúdo e consuma os
  dados totalmente tipados em cinco passos.
noindex: false
canonicalPath: /pt-BR/docs/getting-started
---
## Instalação

```bash
pnpm add scribe-cms zod better-sqlite3
```

Requisitos: Node 20+, Zod v4. O Scribe não depende de frameworks específicos e funciona com qualquer stack baseada em Node. O `better-sqlite3` é um módulo nativo, então mantenha-o externo ao seu bundler (consulte a página de [API em runtime](/docs/runtime-api)).

## 1. Crie o `scribe.config.ts`

Coloque-o na raiz do seu projeto:

```ts
import { z } from "zod";
import { defineConfig, defineContentType, field } from "scribe-cms";

const blogSchema = z.object({
  title: field.translatable(z.string().min(1)),
  description: field.translatable(z.string().min(50).max(250)),
  author: field.relation("author"),
  tags: field.structural(z.array(z.string()).default([])),
});

const authorSchema = z.object({
  name: field.structural(z.string().min(1)),
});

export default defineConfig({
  rootDir: ".", // relativo a este arquivo (CLI) / process.cwd() (runtime)
  locales: ["en", "fr", "de"],
  types: [
    defineContentType({
      id: "blog",
      path: "/blog/{slug}",
      schema: blogSchema,
      slugStrategy: "localized",
      orderBy: "-publishedAt",
    }),
    defineContentType({
      id: "author",
      contentDir: "authors",
      schema: authorSchema,
    }),
  ],
});
```

As funções `defineConfig` e `defineContentType` são funções de identidade que preservam os tipos literais. Elas são responsáveis por garantir que `scribe.blog` e `related(doc, "author")` fiquem totalmente tipados mais tarde.

## 2. Escreva o conteúdo

```text
content/
  blog/
    hello-world.mdx
  authors/
    jane.mdx
```

```mdx
---
title: "Hello, world"
description: "A first post that says hello to the world, at length, because the schema demands fifty characters."
author: jane
publishedAt: "2026-01-15"
---

The body is MDX. **Markdown** and components both work.
```

O nome do arquivo (`hello-world`) é o slug em inglês. O `publishedAt` é um dos campos integrados disponíveis em todos os tipos. Consulte [modelo de conteúdo](/docs/content-model) para saber mais.

## 3. Valide

Após rodar `pnpm install`, a CLI `scribe` estará no seu PATH (igual ao `next`):

```bash
pnpm scribe validate
pnpm scribe status
```

Adicione-o antes do seu build:

```json
{
  "scripts": {
    "build": "scribe validate && <o build do seu framework>"
  }
}
```

## 4. Leia o conteúdo

```ts
import { createScribe } from "scribe-cms/runtime";
import config from "./scribe.config";

const scribe = createScribe(config);

const posts = scribe.blog.list(); // BlogDoc[], os mais recentes primeiro
const { document } = scribe.blog.resolve("hello-world", "fr");
const author = scribe.blog.related(document!, "author"); // AuthorDoc, não-nulo
```

O `document.frontmatter` é tipado a partir do seu schema do Zod. Veja a [API em runtime](/docs/runtime-api) para conferir todas as possibilidades.

## 5. Traduza

```bash
export GEMINI_API_KEY=...   # ou coloque no seu .env
npx scribe translate --locale fr
```

O Scribe encontra todas as páginas ausentes ou desatualizadas em francês, traduz os campos que você marcou com `field.translatable()` e armazena o resultado em `.scribe/store.sqlite`. **Faça o commit desse diretório**. Nunca adicione `.scribe/` ao seu `.gitignore`. Mais detalhes na seção de [tradução](/docs/translation).
