AstroCraft — home
AstroCraft
Buy a licence
All documentation

Install AstroCraft

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

Last updated

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 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 emptysrc/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, 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:

git clone --depth 1 --branch v1.0.1 \
  [email protected]: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:

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
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:

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:

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:

"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:

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:

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:

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.

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 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.