This guide walks you through setting up shipyard in your Astro project. By the end, you’ll have a fully configured site with documentation and blog functionality.
Before you begin, make sure you have:
npm create astro@latestInstall the shipyard packages you need:
# Full-featured site (docs + blog)
npm install @levino/shipyard-base @levino/shipyard-docs @levino/shipyard-blog
# Documentation site only
npm install @levino/shipyard-base @levino/shipyard-docs
# Blog site only
npm install @levino/shipyard-base @levino/shipyard-blog
# Core components only
npm install @levino/shipyard-base
shipyard requires the following peer dependencies:
npm install tailwindcss daisyui @tailwindcss/typography @astrojs/tailwind
Before diving into the configuration details, here’s a quick checklist of the files you’ll need to create or modify:
| File | Purpose | Required? |
|---|---|---|
astro.config.mjs | Astro integrations and site settings | Yes |
tailwind.config.mjs | Tailwind CSS configuration | Yes |
src/content.config.ts | Content collection schemas and loaders | Yes |
docs/ directory | Documentation markdown files | Yes (for docs) |
blog/ directory | Blog post markdown files | Yes (for blog) |
The most commonly missed file is src/content.config.ts — without it, you’ll get errors like “The collection does not exist” when building your site.
Update your astro.config.mjs:
import tailwind from '@astrojs/tailwind'
import shipyard from '@levino/shipyard-base'
import shipyardDocs from '@levino/shipyard-docs'
import shipyardBlog from '@levino/shipyard-blog'
import { defineConfig } from 'astro/config'
export default defineConfig({
integrations: [
tailwind({ applyBaseStyles: false }),
shipyard({
brand: 'My Site',
title: 'My Awesome Site',
tagline: 'Built with shipyard',
navigation: {
docs: { label: 'Docs', href: '/docs' },
blog: { label: 'Blog', href: '/blog' },
},
}),
shipyardDocs(),
shipyardBlog(),
],
})
Important configuration notes:
| Setting | Why it’s needed |
|---|---|
tailwind({ applyBaseStyles: false }) | Prevents Tailwind’s base styles from conflicting with DaisyUI. Without this, you may see unstyled or broken components. |
| Integration order | Tailwind must come before shipyard integrations to ensure styles are processed correctly. |
Create or update tailwind.config.mjs:
import daisyui from 'daisyui'
import typography from '@tailwindcss/typography'
/** @type {import('tailwindcss').Config} */
export default {
content: [
'./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}',
'./docs/**/*.md',
'./blog/**/*.md',
'node_modules/@levino/shipyard-*/**/*.{astro,js,ts}',
],
theme: {
extend: {},
},
plugins: [typography, daisyui],
}
Create src/content.config.ts — this file is essential for shipyard to find and render your documentation and blog content:
import { defineCollection } from 'astro:content'
import { createDocsCollection } from '@levino/shipyard-docs'
import { blogSchema } from '@levino/shipyard-blog'
import { glob } from 'astro/loaders'
const docs = defineCollection(createDocsCollection('./docs'))
const blog = defineCollection({
schema: blogSchema,
loader: glob({ pattern: '**/*.md', base: './blog' }),
})
export const collections = { docs, blog }
After setup, your project should look like this:
my-site/
├── docs/ # Documentation markdown files
│ ├── index.md # Docs landing page
│ └── getting-started.md # Documentation pages
├── blog/ # Blog post markdown files
│ └── 2025-01-15-first-post.md
├── src/
│ ├── content.config.ts # Content collection config
│ └── pages/ # Additional pages
│ └── index.astro # Homepage
├── astro.config.mjs
├── tailwind.config.mjs
└── package.json
Create markdown files in the docs/ directory:
---
title: Introduction
sidebar:
position: 1
description: Learn about our project
---
# Introduction
Your documentation content here...
Key frontmatter options:
| Field | Type | Description |
|---|---|---|
title | string | Page title |
sidebar.position | number | Order in sidebar (lower = earlier) |
description | string | Page description for SEO |
See @levino/shipyard-docs for all frontmatter options.
Create markdown files in the blog/ directory:
---
title: My First Post
description: A brief description of this post
date: 2025-01-15
---
# My First Post
Your blog post content here...
Required frontmatter:
| Field | Type | Description |
|---|---|---|
title | string | Post title |
description | string | Post description/excerpt |
date | Date | Publication date (YYYY-MM-DD) |
See @levino/shipyard-blog for all frontmatter options.
For standalone pages that aren’t part of docs or blog collections, use shipyard’s layouts directly.
Markdown pages – Use the Markdown layout for pages with prose styling:
---
layout: '@levino/shipyard-base/layouts/Markdown.astro'
title: About Us
description: Learn about our team
---
# About Us
Your markdown content with nice typography styling...
Astro component pages – Import the Page layout for full control:
---
// src/pages/index.astro
import { Page } from '@levino/shipyard-base/layouts'
---
<Page title="Home" description="Welcome to our site">
<div class="hero min-h-[60vh] bg-base-200">
<div class="hero-content text-center">
<h1 class="text-5xl font-bold">Welcome!</h1>
<p>Your custom homepage content...</p>
</div>
</div>
</Page>
Landing pages – Use Splash layout for centered content without prose styling:
---
layout: '@levino/shipyard-base/layouts/Splash.astro'
title: Welcome
---
<div class="hero min-h-screen">
<h1 class="text-5xl font-bold">My Landing Page</h1>
</div>
See @levino/shipyard-base layouts for all available layouts and options.
shipyard supports Astro’s i18n features. Update your Astro config:
export default defineConfig({
i18n: {
defaultLocale: 'en',
locales: ['en', 'de', 'fr'],
routing: {
prefixDefaultLocale: true,
},
},
integrations: [
// ... your integrations
],
})
Organize content by locale:
docs/
├── en/
│ ├── index.md
│ └── getting-started.md
├── de/
│ ├── index.md
│ └── getting-started.md
blog/
├── en/
│ └── 2025-01-15-first-post.md
├── de/
│ └── 2025-01-15-erster-beitrag.md
Start the development server:
npm run dev
Build for production:
npm run build
shipyard consists of three packages that work together:
| Package | Purpose | Documentation |
|---|---|---|
@levino/shipyard-base | Core layouts, components, and configuration | Base Package |
@levino/shipyard-docs | Documentation features, sidebar, pagination | Docs Package |
@levino/shipyard-blog | Blog functionality, post listing, navigation | Blog Package |
Now that you have shipyard set up, explore these topics:
The collection "docs" does not exist or is empty.
Cannot read properties of undefined (reading 'render')
Cause: Missing or incorrectly configured src/content.config.ts file.
Solution: Create the content config file as shown in Content Collections above. Make sure:
src/content.config.ts (not in the root directory)collections object with your defined collectionsdocs for documentation, blog for blog posts)If you see TypeScript or build errors immediately after installation:
Check peer dependencies — Ensure all required peer dependencies are installed:
npm install tailwindcss daisyui @tailwindcss/typography @astrojs/tailwind
Verify Tailwind config — Make sure tailwind.config.mjs includes the shipyard packages in the content array
Check integration order — In astro.config.mjs, Tailwind must come before shipyard integrations
If components appear unstyled or broken:
Check applyBaseStyles — Ensure Tailwind is configured with applyBaseStyles: false:
tailwind({ applyBaseStyles: false })
Verify content paths — Make sure tailwind.config.mjs includes paths to shipyard packages and your content directories
docs/ at the project root, not in src/docs/'./docs')docs/index.md)