Skip to content
AstroCraft Docs
On this theme

Installation

Develi ships as a complete Astro project, not as an npm package or an integration you register. You clone the repository, install its dependencies, and start editing — there is no theme layer between you and the markup, and nothing is hidden inside node_modules. Every component, token, icon and animation is a file in src/ that you own from the first commit.

It runs with no configuration, no API keys and no accounts. pnpm install followed by pnpm dev gives you the whole site — home, about, services, work index, case studies, blog, contact, legal pages — populated with sample content. Configuration is what you do after you have looked around, not a prerequisite for seeing it work.

Requirements

  • Node.js 22.13.0 or newer. This is enforced by engines.node in package.json, and it is a real floor rather than a soft one: the test runner executes TypeScript directly through Node’s --experimental-strip-types flag. Check yours with node -v.
  • pnpm. packageManager pins [email protected], so with Corepack enabled the right version is selected for you. corepack enable pnpm is the shortest route if you do not have it.
  • Git, to clone the repository and to keep your own history from the first commit onward.

You do not need a hosting account, an email provider, a CMS or a domain to run the theme locally. Develi is a fully static site with no adapter — there is no server-rendered route anywhere in it, which is why the local requirements stop here.

Get the code

Clone the repository and drop the upstream history so your project starts with a clean log:

git clone https://github.com/Astro-Craft-Theme/develi.git my-studio
cd my-studio
rm -rf .git && git init

If you would rather keep the upstream remote so you can pull theme updates later, skip the rm -rf .git and rename the remote instead:

git remote rename origin upstream
git remote add origin [email protected]:you/my-studio.git

Keeping upstream is only worth it if you plan to merge theme changes. Because the theme is source you edit directly, a merge after heavy customization is a real merge — most people take the clean-slate route and treat the clone as a starting point.

Install dependencies

pnpm install

The runtime dependency list is eight packages, and the shape of that list is the whole design philosophy of the theme in one place:

"dependencies": {
  "@astrojs/mdx": "^7.0.3",
  "@astrojs/sitemap": "^3.7.3",
  "@fontsource-variable/host-grotesk": "^5.3.0",
  "@tailwindcss/vite": "^4.3.3",
  "astro": "^7.1.3",
  "tailwind-merge": "^3.6.0",
  "tailwind-variants": "^3.2.2",
  "tailwindcss": "^4.3.3"
}

Astro, Tailwind and its two class-composition helpers, one variable font, and two official Astro integrations. There is no UI kit, no animation library, no SEO package, no icon package and no CMS. Those five things are all implemented inside the theme rather than pulled in — the 46 UI primitives, the 87-utility motion catalog, the JSON-LD builders, the 572-icon registry and the typed config layer are source files in src/. That is why the surface you have to keep up to date stays small, and it is also why customizing any of them means editing a file rather than reading a plugin’s options.

Two settings in pnpm-workspace.yaml are worth knowing about before they surprise you:

  • allowBuilds denies post-install build scripts for @parcel/watcher, esbuild and sharp. None of the three needs to compile for the project to work, and denying them keeps installs fast and free of native toolchain requirements. If your install prints a notice about ignored build scripts, that is this setting working as designed.
  • minimumReleaseAgeExclude pins the Tailwind packages to the exact version set the theme was built and tested against, including every platform-specific @tailwindcss/oxide-* binary.

sharp itself is a devDependency. Develi builds fully static with no adapter, so image optimization happens at build time through Astro’s own image service — which is what sharp backs. It is in devDependencies rather than dependencies because nothing at runtime needs it: the output is plain files.

Start the dev server

pnpm dev

The site is at http://localhost:4321. Every route is available immediately with sample content in place:

  • / — the home page
  • /about/ and /services/
  • /work/ and /work/<slug>/ — six sample case studies
  • /blog/, /blog/<slug>/ and /blog/category/<slug>/ — eight sample posts, four authors, five categories
  • /contact/ — the enquiry form renders and validates natively
  • /terms/ and /privacy/ — placeholder legal copy
  • /rss.xml, /robots.txt, /llms.txt, /sitemap-index.xml — all generated, all deriving their absolute URLs from one setting

Sixteen route files produce 29 built pages, because three of those files are dynamic: the blog index paginates, the category route builds one branch per category, and /work/<slug>/ and /blog/<slug>/ each build one page per entry.

The primitive catalog

Before you start building pages, open http://localhost:4321/examples/ui. It is a development-only catalog rendering all 46 UI primitives in every variant, alongside the 87 motion utilities and the full 572-icon registry. It is the fastest way to find out what already exists rather than rebuilding it, and it is grouped into eight panels — foundations, form controls, disclosure and status, overlays and controls, navigation, site chrome, motion, icons.

The route is gated inside getStaticPaths:

export function getStaticPaths() {
  return import.meta.env.PROD ? [] : [{ params: { catalog: "ui" } }];
}

A production build emits no paths for it, so no HTML ships. You can leave it in place while you work. When you no longer need it, delete src/pages/examples/ and src/components/Sections/UiCatalog/ together — Tailwind still scans the catalog’s markup even though it builds no pages, so its demo classes sit in the stylesheet every real page loads. Removing both takes the shared CSS from 103,249 to 84,802 bytes and drops the @keyframes count from 93 to 2. See Deployment for the full pre-launch list.

Environment variables

One variable matters, and it is not required locally. Copy the example file if you want a place to keep it:

cp .env.example .env

.env and .env.production are already gitignored.

  • SITE_URL — your production domain. It feeds the canonical link, Open Graph tags, JSON-LD, the sitemap, robots.txt, llms.txt and the RSS feed, so one wrong value poisons seven things at once and none of them looks broken in review. It defaults to https://example.com.
  • DEPLOY_ENV — only needed on hosts that are neither Netlify nor Vercel. See below.

A fresh clone builds and runs on the placeholder domain, deliberately, so you can see the site before you own a domain. What you cannot do is deploy on it — astro.config.mjs throws:

const site = process.env.SITE_URL ?? "https://example.com";
const isProductionDeploy =
  process.env.CONTEXT === "production" ||        // Netlify
  process.env.VERCEL_ENV === "production" ||     // Vercel
  process.env.DEPLOY_ENV === "production";       // anything else

if (isProductionDeploy && site.includes("example.com")) {
  throw new Error("SITE_URL is unset or still the placeholder. …");
}

The theme is host-agnostic, so “is this a production deploy?” reads each host’s own build variable rather than assuming one. None of those three is set by a local pnpm build or by a deploy preview, so previews and local work build freely. On a host not listed there, set DEPLOY_ENV=production yourself — the gate is only as good as the signal it can see, and an unset signal means the guard silently does nothing.

Make it yours

With the site running, these are the first files to edit. All of them are typed, so a mistake fails the build with the offending value named rather than shipping quietly.

  1. src/config/siteData.json.ts — brand name, page title, description, the author block (name, email, Twitter handle for card attribution), the public contact details the footer renders, and the default OG image. The JSON-LD sameAs array is derived from navData.social, not written here, so the footer’s social links and your structured data cannot drift apart.
  2. src/config/navData.json.ts — the header and footer information architecture, plus the six services. Read the Configuration chapter before editing this one: it is the single most load-bearing config file in the theme, and several of its values are derived rather than typed twice.
  3. src/config/siteSettings.json.tssiteLang, siteLocale, and two switches: useViewTransitions and useAnimations (the master switch for decorative motion). prefers-reduced-motion is honored by a global CSS guard regardless of what useAnimations says; the flag is a design choice, not an accessibility one.
  4. src/config/legalData.json.ts — the terms and privacy copy. It is explicitly placeholder text. Have a professional review it; it is not legal advice.
  5. public/og.jpg, public/favicon.svg, public/favicon.ico — the shipped og.jpg is a placeholder. Replace it with a real 1200×630 image.
  6. src/data/ — replace the eight blog posts, four authors and six case studies. Each entry is a folder whose name is the URL slug, holding an index.md. Schemas live in src/content.config.ts, so bad frontmatter fails the build with the entry named.

Colors, type and spacing are not in that list because they are not in the config layer. They are CSS tokens in src/styles/tailwind-theme.css and src/styles/global.css, and the Colors and Typography chapters cover them.

Verify your install

pnpm lint && pnpm check && pnpm build && pnpm test
  • pnpm lint runs ESLint, including the Astro JSX accessibility rules.
  • pnpm check runs astro check across .astro and .ts files. On a clean checkout it reports 271 files with zero errors, warnings and hints.
  • pnpm build is the real check. Content-schema errors, config typos and broken references all surface here rather than in the browser.
  • pnpm test runs every *.test.ts file under src/ with Node’s type stripping — no framework, no fixtures, nothing to register. There are eleven today. If it ever finds zero it fails rather than passing, so the suite cannot quietly disappear.

There is also pnpm format, which runs eslint --fix and then Prettier. Class ordering is handled by prettier-plugin-tailwindcss, so let it sort and do not hand-order class lists.

Two things to know before you start building

The site is dark by default, and that default is server-rendered. BaseLayout ships class="dark" on <html>, so dark mode survives a scripting failure entirely. The inline pre-paint script in BaseHead only ever removes that class, for a visitor who has pinned light through the ThemeToggle primitive. The device prefers-color-scheme is deliberately not consulted. The consequence is worth internalising: a page that mounts no ThemeToggle is dark-only, so light-mode bugs on such a page are invisible until someone mounts one.

Eight links in the header and footer 404 out of the box. navData.json.ts ships the design’s complete information architecture so the chrome looks finished, but /careers/, /process/ and the six /services/<slug>/ detail pages have no routes. This is documented rather than hidden, and Deployment covers building or deleting them. It is the first thing to resolve on a real project.

Troubleshooting

The build throws about SITE_URL. You are running a production deploy with the placeholder domain still in place. Set SITE_URL in your host’s environment variables. This is intentional — it makes it impossible to ship canonical URLs and a sitemap pointing at example.com.

A renamed content entry keeps 404ing in dev. Astro’s content layer caches entries, and moving or renaming a folder while the dev server runs can leave the old entry in place and the new one missing. Restart pnpm dev; touching the file will not clear it.

A utility class has no effect in dev. In a long-running dev server, classes used only in newly created files can be missing from the generated stylesheet. Restart the dev server before you go looking for a bug in your markup.

Node version errors on install. The floor is 22.13.0. Older releases fail on the test runner even if the install itself appears to succeed.

More in Troubleshooting.

NEXT STEPProject Structure