Building My First Blog with Astro: A Learning Journey
When I decided to create a personal technical blog to document my learning journey, I knew I wanted something fast, modern, and developer-friendly. After exploring various options, I settled on Astro, a relatively new static site generator that promised excellent performance and a great developer experience. This post chronicles my three-hour journey from zero to a fully functional blog, including all the stumbles, revelations, and valuable lessons learned along the way.
Why Astro Over Other Frameworks?
Before diving into the build process, I evaluated several options. I could have used WordPress for ease, Next.js for flexibility, or Jekyll for simplicity. However, I was drawn to Astro for several compelling reasons. First, it generates truly static sites by default, shipping minimal JavaScript to the browser, which translates to blazing-fast load times. Second, it supports multiple UI frameworks, though I ultimately stuck with vanilla Astro components and Tailwind CSS. Finally, Astro has excellent support for content-focused sites like blogs, with built-in markdown processing and content collections.
The decision to use Astro meant I would be learning something new, but that aligned perfectly with my goal of documenting my learning journey. If I was going to write about learning new technologies, why not start by learning the very framework powering my blog?
Understanding Static Site Generation
One of the first concepts I needed to grasp was the fundamental difference between static and dynamic websites. In a dynamic site, when you visit a page, the server processes code and generates HTML on the fly for each request. In contrast, a static site generates all HTML files during a build process, and the server simply sends these pre-built files to visitors.
This revelation had profound implications for my blog. The JavaScript code I write in Astro’s frontmatter runs during the build process, not in the visitor’s browser. When I added a console log statement in my page component, I initially expected to see it in the browser console. Instead, it appeared in my terminal where the development server was running. This was my first “aha” moment - understanding that build-time and runtime are completely separate concepts in static site generation.
This architecture choice made perfect sense for a blog. My content doesn’t change with every visitor, so why regenerate the same HTML repeatedly? I publish a new post, trigger a rebuild, and every visitor gets the pre-generated, optimized HTML. The result is exceptional performance and a better experience for readers.
Setting Up the Development Environment
Getting started required Node.js, which I already had installed. Running the Astro setup command created a project structure that initially seemed mysterious but quickly became clear. The project contained several key directories: src for my code, public for static assets, and node_modules for dependencies.
The src directory itself had a logical structure. The pages directory uses file-based routing, meaning any file I create there automatically becomes a route on my website. Creating pages/about.astro generates a /about page - elegant and intuitive. The layouts directory houses reusable templates, while components stores smaller, reusable UI pieces.
One concept that took a moment to understand was the structure of Astro files themselves. Each file has two sections separated by triple dashes. The frontmatter section between the dashes contains server-side JavaScript that runs during build time. Below that sits the template section with HTML and embedded expressions. This separation makes it crystal clear what runs when and where.
The Tailwind CSS Integration Challenge
Installing Tailwind CSS presented my first real obstacle. Astro provides an automated command to add integrations, but I encountered permission errors with npm. The issue stemmed from npm’s cache folder having incorrect permissions on my system. After resolving this with a simple ownership change command, I faced another challenge: Tailwind v4, the latest version, has a different setup process than the widely documented v3.
Initially, my Tailwind classes weren’t generating any CSS. Text size and spacing worked, but colors didn’t apply. This led to debugging the integration. I learned that Tailwind v4 requires importing it through a CSS file rather than directly in component files. Creating a global CSS file with the Tailwind import and loading it through my layout component solved the issue. This experience reinforced an important lesson: when using cutting-edge versions of tools, expect some differences from existing tutorials and documentation.
Mastering Layouts and Component Composition
The layout system in Astro proved to be one of its most powerful features. I created a main layout component that includes the header navigation, footer, and a special <slot /> element. This slot is where page-specific content gets inserted. Think of it like a picture frame - the frame stays the same, but different pictures can be placed inside it.
This pattern eliminated repetition beautifully. Instead of copying header and footer code to every page, I wrap each page’s content with my layout component. When I later wanted to add a meta description or update the navigation, I changed it once in the layout, and every page inherited the update. This is component-based architecture at its finest.
The layout also accepts props, allowing each page to pass in custom data like the page title. This keeps the layout flexible while maintaining consistency across the site.
Building the Blog Functionality
The blog itself required understanding Astro’s content collections feature. I created a content/blog directory for my markdown posts, each with frontmatter containing metadata like title, description, publication date, and tags. A configuration file defines the schema for this metadata, ensuring consistency and providing TypeScript type safety.
Creating dynamic routes for individual blog posts introduced me to Astro’s getStaticPaths function. This function runs at build time, fetches all blog posts, and generates a static HTML file for each one. The filename [...slug].astro creates a catch-all route that matches any URL under the blog path.
Implementing syntax highlighting for code blocks was surprisingly straightforward. Astro includes Shiki, a syntax highlighter, out of the box. A simple configuration in the Astro config file enabled it with the GitHub Dark theme. Seeing my code examples beautifully highlighted with proper colors was incredibly satisfying.
Adding reading time estimates required a bit of logic - counting words in the blog post content and dividing by an average reading speed. These small touches make the blog feel polished and professional.
The Typography Challenge
Getting markdown content to render beautifully required the Tailwind Typography plugin. However, integrating it with Tailwind v4 had its quirks. After installing the plugin, I needed to import it using Tailwind v4’s new plugin syntax in my global CSS file. This took some trial and error, as most documentation still references v3’s approach.
Once working, the typography plugin transformed my markdown content. Headings gained proper hierarchy, paragraphs had appropriate spacing, and links received styling - all automatically. The prose classes handled all the heavy lifting, making my blog posts readable and aesthetically pleasing without writing custom CSS for every element.
SEO Optimization and Meta Tags
Making the blog discoverable required proper SEO setup. I added meta descriptions, Open Graph tags for social media sharing, and canonical URLs to each page. The layout component accepts a description prop, defaulting to a site-wide description if not provided. This ensures every page has appropriate metadata without requiring manual input for each one.
I also added semantic HTML, proper heading hierarchy, and descriptive link text throughout the site. These seemingly small details significantly impact how search engines understand and rank content.
Deployment Strategy and Automation
Initially, I considered hosting on a VPS to learn server management. However, I realized that for a static blog, this would be overkill and potentially problematic. If I used the same server for experimental projects and something broke, my blog would go down too. The principle of separation of concerns suggested keeping the blog separate from other projects.
Instead, I chose Vercel for deployment. The process was remarkably simple: connect my GitHub repository, and Vercel automatically detects Astro and configures the build. The killer feature is automatic deployments. Every time I push a new blog post to GitHub, Vercel rebuilds and deploys the site automatically. No manual intervention required.
This workflow is incredibly efficient: I write a blog post in markdown, commit it to Git, push to GitHub, and within minutes, it’s live on the internet. The entire deployment pipeline runs automatically in the background.
Key Learnings and Takeaways
Building this blog taught me several valuable lessons beyond just Astro specifics. First, understanding when code runs - build time versus runtime - is crucial in static site generation. This mental model affects how you architect your application and what’s possible within the framework’s constraints.
Second, modern web development increasingly favors file-based conventions over configuration. Astro’s routing, content collections, and component structure all follow intuitive file-system patterns. This reduces cognitive load and makes projects easier to navigate.
Third, the ecosystem matters tremendously. Astro’s integration with Tailwind CSS, its markdown processing, and its deployment to platforms like Vercel all work together seamlessly. Choosing tools that integrate well saves countless hours of configuration and troubleshooting.
Finally, I learned the value of starting with constraints. By committing to finish in three hours, I focused on core functionality rather than perfection. I can always iterate and improve, but having a working blog to iterate on is far better than an incomplete, over-engineered project.
What’s Next?
The blog is live, but the journey continues. I plan to add more features incrementally: implementing the newsletter signup with an email service provider, adding search functionality, creating an RSS feed for readers who prefer feed readers, and possibly implementing view counts and analytics.
More importantly, I’m excited to populate this blog with content documenting my learning journey across AI, machine learning, Android development, Flutter, and the many other technologies I explore. Each post will be a snapshot of my understanding at that moment, creating a living record of my growth as a developer.
If you’re considering building your own blog, I highly recommend Astro. The learning curve is gentle, the performance is exceptional, and the developer experience is delightful. Start simple, deploy early, and iterate based on your needs. Your future self will thank you for documenting your journey.
Conclusion
Building this blog from scratch in a single focused session proved that modern web development tools have reached an impressive level of maturity. What might have taken days or weeks with older technologies took just hours with Astro, Tailwind, and Vercel. The resulting site is fast, maintainable, and perfectly suited to its purpose.
More than just creating a blog, this process reinforced the importance of learning by doing. Reading about static site generation is one thing; experiencing the build-time versus runtime distinction firsthand creates genuine understanding. Every challenge faced and overcome - from permission errors to Tailwind v4 quirks - deepened my knowledge and problem-solving skills.
If there’s one piece of advice I’d offer to anyone starting a similar journey, it’s this: don’t wait for perfect. Start building, encounter problems, solve them, and learn from the experience. The blog you ship today, imperfect as it may be, is infinitely more valuable than the perfect blog you never launch.
Now, it’s time to write the next post. The blog is ready, the deployment pipeline is humming, and the learning journey continues.