Table of Contents
Overview
In the previous post Why I Migrated from Jekyll to Astro, I shared the background behind moving from Jekyll to Astro. In this post, I’ll explain step by step how to actually install Astro and set up a blog project.
Prerequisites
Since Astro is Node.js-based, you need to have Node.js installed first.
Installing Node.js
Install the LTS version from the Node.js official website. Using nvm (Node Version Manager) makes it easy to manage multiple versions.
# Install Node.js with nvm
nvm install --lts
nvm use --lts
# Check versions
node -v
npm -v
Creating a .nvmrc file in the project root lets you keep the Node.js version consistent across team members.
Creating an Astro Project
Astro provides an official CLI tool to quickly create projects.
npm create astro@latest
Follow the CLI prompts to select a project name, template, and more. I recommend starting with an empty project (Empty), since designing the blog structure from scratch helps you better understand the project.
# Navigate to the project after creation
cd my-blog
# Install dependencies
npm install
# Start the development server
npm run dev
Once the dev server starts, you can view the site at http://localhost:4321. Thanks to Vite-based HMR, changes to files are instantly reflected in the browser.
Project Directory Structure
The directory structure of this blog project is as follows:
/
├── public/ # Static files (images, robots.txt, etc.)
│ ├── assets/
│ │ └── images/
│ ├── robots.txt
│ ├── ads.txt
│ ├── CNAME
│ └── .nojekyll
├── src/
│ ├── components/ # Reusable Astro components
│ │ ├── Head.astro
│ │ ├── Navbar.astro
│ │ ├── Footer.astro
│ │ ├── Breadcrumbs.astro
│ │ ├── Comments.astro
│ │ ├── SearchBar.astro
│ │ ├── SearchPage.astro
│ │ ├── Pagination.astro
│ │ ├── CategoryCard.astro
│ │ ├── PostCard.astro
│ │ └── ads/ # Ad components
│ ├── content/ # Blog posts (Content Collections)
│ │ ├── astro/
│ │ ├── react/
│ │ ├── jekyll/
│ │ └── ...
│ ├── data/ # Static data
│ │ └── categories.ts
│ ├── i18n/ # Multilingual translations
│ │ └── translations.ts
│ ├── layouts/ # Layout templates
│ │ ├── BaseLayout.astro
│ │ └── PostLayout.astro
│ ├── pages/ # Route pages
│ │ ├── [...path].astro # Japanese (default)
│ │ ├── ko/ # Korean
│ │ └── en/ # English
│ ├── plugins/ # Custom rehype plugins
│ │ ├── rehype-picture.mjs
│ │ └── rehype-in-feed-ads.mjs
│ └── styles/ # Global styles
│ └── global.scss
├── scripts/ # Build/deploy scripts
│ └── share.mjs
├── astro.config.mjs # Astro configuration
├── package.json
└── tsconfig.json
Key Directory Descriptions
Here’s a closer look at the key directories:
| Directory | Role |
|---|---|
public/ | Static files copied as-is during build. Images, fonts, verification files, etc. |
src/components/ | Reusable .astro components. Head, Navbar, Footer, etc. |
src/content/ | Markdown blog posts managed by Content Collections |
src/data/ | Static data like category definitions |
src/i18n/ | Multilingual translations and helper functions |
src/layouts/ | Page layout templates |
src/pages/ | File-based routing. Directory structure maps directly to URL structure |
src/plugins/ | Custom rehype/remark markdown processing plugins |
src/styles/ | Global SCSS styles |
astro.config.mjs Configuration
This is Astro’s core configuration file. Let’s look at the actual configuration used in this blog.
// @ts-check
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';
import rehypeExternalLinks from 'rehype-external-links';
import rehypeCallouts from 'rehype-callouts';
import rehypeInFeedAds from './src/plugins/rehype-in-feed-ads.mjs';
import rehypePicture from './src/plugins/rehype-picture.mjs';
export default defineConfig({
site: 'https://deku.posstree.com',
output: 'static',
build: {
inlineStylesheets: 'always',
},
trailingSlash: 'always',
integrations: [
sitemap({
serialize(item) {
item.lastmod = new Date();
return item;
},
i18n: {
defaultLocale: 'ja',
locales: {
ja: 'ja',
ko: 'ko',
en: 'en',
},
},
}),
],
markdown: {
shikiConfig: {
theme: 'material-theme-darker',
},
rehypePlugins: [
[rehypeCallouts, { theme: 'github' }],
[
rehypeExternalLinks,
{ target: '_blank', rel: ['nofollow', 'noreferrer'] },
],
rehypeInFeedAds,
[
rehypePicture,
{ publicDir: new URL('./public', import.meta.url).pathname },
],
],
},
vite: {
css: {
preprocessorOptions: {
scss: {
silenceDeprecations: ['import', 'global-builtin', 'color-functions'],
},
},
},
},
});
Key Configuration Items
site
site: 'https://deku.posstree.com',
The final deployment URL of the site. Used for sitemap generation, canonical URLs, OG tags, and more.
output
output: 'static',
Builds as a static site. This must be set to 'static' for deploying to GitHub Pages.
build.inlineStylesheets
build: {
inlineStylesheets: 'always',
},
Includes all CSS inline in the HTML. This reduces separate CSS file requests and improves initial load speed.
trailingSlash
trailingSlash: 'always',
Ensures all URLs end with /. So it becomes /astro/installation/ instead of /astro/installation. This was configured to maintain the URL format used in Jekyll.
integrations
integrations: [
sitemap({ ... }),
],
Automatically generates a multilingual sitemap with the @astrojs/sitemap plugin. Details are covered in the SEO Implementation post.
markdown
Configuration for markdown processing.
- shikiConfig: Uses the
material-theme-darkertheme for code block syntax highlighting - rehypePlugins: Plugins applied when converting markdown to HTML
rehype-callouts: Supports GitHub-style callout blocksrehype-external-links: Automatically addstarget="_blank",rel="nofollow noreferrer"to external linksrehype-in-feed-ads: Converts<!-- ad -->comments in markdown to ad blocksrehype-picture: Automatically converts images to<picture>elements with AVIF/WebP formats
package.json Scripts
Here are the npm scripts used in the blog project.
{
"name": "deku-blog",
"type": "module",
"version": "1.0.0",
"scripts": {
"dev": "astro dev",
"build": "astro build && npx pagefind --site dist",
"prepreview": "npm run build",
"preview": "astro preview",
"predeploy": "npm run share:sync",
"deploy": "gh-pages -d dist -r git@personal:posstree/deku.posstree.com.git -t"
},
"dependencies": {
"@astrojs/rss": "^4.0.0",
"@astrojs/sitemap": "^3.3.0",
"astro": "^5.17.1",
"rehype-callouts": "^2.1.2",
"rehype-external-links": "^3.0.0",
"sass": "^1.80.0",
"sharp": "^0.33.0"
},
"devDependencies": {
"dotenv": "^16.6.1",
"gh-pages": "^6.3.0",
"pagefind": "^1.4.0"
}
}
Key Script Descriptions
Here are the main functions of each script:
| Script | Description |
|---|---|
npm run dev | Start dev server. Instantly reflects changes with HMR |
npm run build | Production build + Pagefind search index generation |
npm run preview | Preview the built site locally |
npm run deploy | Deploy to GitHub Pages |
The key point in the build script is running npx pagefind --site dist after astro build. Since Pagefind analyzes the built HTML files to generate search indexes, it must be run after the build.
Key Dependency Descriptions
Here are the main packages used in the Astro project and their roles:
| Package | Role |
|---|---|
astro | Core framework |
@astrojs/sitemap | Automatic multilingual sitemap generation |
@astrojs/rss | RSS feed generation |
sass | SCSS preprocessor |
sharp | Image conversion (AVIF/WebP) |
rehype-callouts | GitHub-style callouts |
rehype-external-links | External link handling |
gh-pages | GitHub Pages deployment |
pagefind | Static search |
SCSS Setup
This blog uses SCSS for style management. Since Astro has Vite built in, you can use SCSS with no additional configuration — just install the sass package.
npm install sass
However, if you’re using features deprecated in the latest version of Sass, warnings may occur. You can suppress these in the vite configuration of astro.config.mjs.
vite: {
css: {
preprocessorOptions: {
scss: {
silenceDeprecations: ['import', 'global-builtin', 'color-functions'],
},
},
},
},
Global styles are managed in src/styles/global.scss and imported in the layout component.
---
// BaseLayout.astro
import '../styles/global.scss';
---
Conclusion
In this post, we looked at installing and setting up an Astro project. To summarize:
- Create a project with
npm create astro@latest - Configure site URL, static build, sitemap, and markdown plugins in
astro.config.mjs - Set up build, dev, and deploy scripts in
package.json - Configure
SCSSand handle deprecation warnings
In the next post Content Collections and Markdown Migration, we’ll cover how to migrate Jekyll’s markdown files to Astro’s Content Collections.
Series Guide
This post is part of the Jekyll to Astro migration series.
- Why I Migrated from Jekyll to Astro
- Astro Installation and Project Setup
- Content Collections and Markdown Migration
- Multilingual (i18n) Implementation
- SEO Implementation
- Image Optimization — Custom rehype Plugin
- Comment System (Utterances)
- Ad Integration (Google AdSense)
- Search Implementation with Pagefind
- Layout and Component Architecture
- GitHub Pages Deployment
- Social Share Automation Script
- Troubleshooting and Tips
Was my blog helpful? Please leave a comment at the bottom. it will be a great help to me!
App promotion
Deku.Deku created the applications with Flutter.If you have interested, please try to download them for free.