# Install AstroCraft

> Requirements, the five directories you copy, the fourteen packages they need, and the decision about the test suite that comes with them.

Source: https://editor.astrocraftthemes.com/docs/installation/

AstroCraft installs by copying source into a site you already have. There is no npm package to add and no `node_modules` layer between you and the markup — every route, component, token and icon lands in `src/` and you own it from the first commit.

That is also the cost, and it is worth stating before you start: updates are a re-copy of three named directories rather than a version bump, and two directories become yours the moment you install and must never be re-copied. [Updating](/docs/updating/) covers both halves.

There are two ways in. If you bought the template and want the demo site to look at, clone it whole. If you have a site already, copy the CMS into it — that is the path this page describes, and the one most people are on.

## Requirements

- **Node.js 22.12.0 or newer**, enforced by `engines.node`. The first-account CLI runs under plain `node --experimental-strip-types`, which is a 22.12 feature, so this is a hard floor rather than a recommendation.
- **pnpm.** The lockfile is `pnpm-lock.yaml`. `corepack enable pnpm` is the shortest route if you do not have it.
- **An Astro 7 site that already builds**, with at least one content collection declared in `src/content.config.ts` and its directory present under `src/content/`. The CMS edits collections; it cannot create the first one for you.
- **A git repository with at least one commit.** The CMS is a git layer — a save _is_ a commit — so a directory that is not a repository has nothing for it to write to. `git init` plus one commit is enough to start. A remote can wait until you want to publish.
- **Two directories that must exist, even if empty** — `src/components/sections/` and `src/layouts/`. `src/admin.config.ts` names both, and the composer walks them at request time. An empty `src/layouts/` is exactly what a fresh install has.
- **An adapter and `output: 'server'`.** Covered in [Mounting](/docs/mounting/), where it is also explained why this one is not negotiable.

You do not need a database, a Resend account, a licence key or a domain to run it locally. Each of those unlocks one specific thing and is covered where it becomes relevant.

## Get the source

Clone the release you want beside your project rather than into it:

```bash
git clone --depth 1 --branch v1.0.1 \
  git@github.com:Astro-Craft-Theme/astro-starter.git /tmp/astrocraft
```

A failing clone here almost always means the GitHub invitation from your purchase has not been accepted yet. Check your email or `github.com/notifications` — an unaccepted invite looks exactly like no purchase.

## Copy these in

Five paths, and the comments matter as much as the names:

```text
src/admin/                    the whole CMS — pages, layouts, components, logic, middleware
src/components/primitives/    46 UI primitives (siblings of your own ui/, no collision)
src/components/svg/           the icon registry
src/styles/                   the violet dark theme and its motion utilities
src/assets/                   the logo and the sign-in artwork (both yours to replace)
src/site.domain.ts            your public host, stated once
```

```bash
cp -r /tmp/astrocraft/src/admin                  src/admin
cp -r /tmp/astrocraft/src/components/primitives  src/components/primitives
cp -r /tmp/astrocraft/src/components/svg         src/components/svg
```

The first three are **ours** and an update replaces them wholesale. `src/styles/` and `src/assets/` are **yours** from this moment — copy them across if your site has no equivalent, merge them if it does, and never re-copy them afterwards. `src/site.domain.ts` states your public host as a bare string; it is also the one file the CMS itself rewrites, when Settings → Site connects a domain.

`src/admin/` is a package with counted edges. It may import seven things outside itself, and exactly four host files may name it — both asserted by `boundary.test.ts` on every run. Everything on this page is on that list and nothing else is, which is why the adoption cost is a number rather than a feeling.

## Install what the source imports

Assuming you already have `astro` and `tailwindcss`, it is fourteen packages and none of them is optional:

```bash
pnpm add @astrojs/node @fontsource-variable/inter @libsql/client @noble/hashes db0 \
  remark-gfm remark-parse remark-stringify sharp tailwind-merge tailwind-variants \
  unified unstorage yaml
```

Eleven of those you could have found by grepping the copied files for `import`. **Three you could not**, and they are the ones that fail at runtime rather than at build:

- `@libsql/client` is reached through `createRequire("db0/connectors/libsql/node")`, and only when a database URL is set.
- `@fontsource-variable/inter` is reached through a `url()` inside `src/styles/fonts.css`.
- `@astrojs/node` is named by the adapter line in your config rather than by anything you copied.

That is why the list is typed out rather than described as "whatever the imports say".

## The tests come with it

Every one of those directories carries a `__tests__/` beside almost every module — around two thousand cases, including the boundary and layering self-checks that keep `src/admin/` a package.

They are **not optional to decide about**, and this is the single most common way a fresh install goes wrong. `astro check` reads those files whether you run them or not, so a copy with no test runner installed reports **246 errors** on your first `pnpm check`: 115 × `ts(2307) Cannot find module 'vitest'` and 129 × `ts(7006)` implicit-`any` fallout from the same cause. Nothing in that output contains the word _vitest_.

Two lines take it to zero:

```bash
pnpm add -D vitest happy-dom
cp /tmp/astrocraft/vitest.config.ts .
```

`vitest.config.ts` is portable as-is; nothing in it is specific to the template. Add the scripts to run them, since your `package.json` will not have any:

```json
"scripts": {
  "pretest": "astro sync",
  "test": "vitest run",
  "check": "astro check"
}
```

`pretest: astro sync` is not decoration — the suite reads the content store, and `astro sync` is what fills it.

If you would rather not carry them, delete them **on purpose** rather than by leaving them broken:

```bash
find src -path '*__tests__*' -prune -exec rm -rf {} +
```

That is a real loss and worth knowing what you are giving up: `boundary.test.ts` printing the exact cost of adopting, the layering rules, the round trip that keeps Settings → Site from corrupting `src/site.domain.ts`, and the check that the first-admin command still runs.

## One pnpm setting worth checking

The template's `pnpm-workspace.yaml` carries:

```yaml
allowBuilds:
  esbuild: true
```

pnpm does not run a dependency's install scripts unless they are allowed, and it prints an ignored-builds notice for the ones it skipped. `sharp` appears in that notice. On a platform with a prebuilt binary — which is most of them, and both installs this page was checked against — sharp loads fine regardless, so the notice is not a failure. Adding it is how you silence the notice and how you stay safe on a platform that has to compile:

```yaml
allowBuilds:
  esbuild: true
  sharp: true
```

## What this costs your public pages

Astro bundles scripts per page, so **none of the editor's JavaScript reaches your marketing pages** — it only loads on the editor's own routes. For the record, the editor route itself ships 201,390 bytes raw / 61,812 gzipped, most of which is the markdown round trip that has to run in the browser.

The one thing that _is_ shared is CSS. Tailwind scans all sources, so editor classes land in your site-wide stylesheet unless you scope `@source`.

## Then mount it

Copying is only half. The CMS does nothing until it is registered as an integration and handed its actions — three edits, covered in [Mounting](/docs/mounting/).

## Troubleshooting

**`pnpm check` reports hundreds of `Cannot find module 'vitest'` errors.** You copied the tests and did not install the runner. See _The tests come with it_ above; two lines fix all 246.

**The build dies with `[MISSING_EXPORT] "RESEND_API_KEY" is not exported by "\0astro:env/server"`.** Your config is missing the `env.schema` block. The values are optional; the schema is structurally required. [Mounting](/docs/mounting/) has the exact block.

**The test suite reports your collections as empty**, around thirty failures. You are missing `cacheDir: './.astro/'` in `astro.config.mjs`. Astro writes the content store to `.astro/` in dev and to `cacheDir` everywhere else, so `astro sync` and Vitest otherwise fill and read different files.

**`git clone` fails.** The GitHub invitation has not been accepted. Nothing else can work until it is.