close button
 How We Cut Astro Build Time from 30 Minutes to 5 Minutes (⚡ 83% Faster!)
profile picture Mohammed khan
5 min read Apr 1, 2025
aws

How We Cut Astro Build Time from 30 Minutes to 5 Minutes (⚡ 83% Faster!)

aws

Reducing build times can be a challenging task, especially when working with static site generation (SSG) in frameworks like Astro. Increased build times can have serious consequences, such as delaying small changes from reaching production, sometimes taking several hours to deploy changes across different environments.

We faced this issue while using Astro + React with AWS Amplify, where everything was statically generated (SSG). With over 200+ pages being generated during each build, the process took over 30 minutes on AWS Amplify, which, unlike Vercel, does not support Incremental Static Regeneration (ISR). At one point, a particular section required 900+ pages, further increasing the build times.

As we investigated, we discovered some common mistakes that contributed to these delays. In this blog, we will share optimization techniques that significantly reduced our build times.

Avoid API Calls in Child Components

One of the key issues we identified was related to API calls in child components within the [slug].astro file. In Astro, slugs are generated using getStaticPaths, which is executed once to fetch all the data required for generating pages.

However, if a child component inside [slug].astro includes an API call to fetch data for the component, the request will be triggered individually for each page when the page is being generated. For example, if the request takes 300ms to resolve, the build time for that page will be 300ms plus the actual time required to build the page. Now, imagine your site has 100 pages under this slug—this means the API calls alone would add 30 seconds (100 × 300ms) to your total build time, even before considering other processing delays, thus significantly increasing build times from milliseconds to seconds per page.

Solution

  • Avoid making API calls in child components whenever possible. Instead, pass data via props to ensure that the component does not make unnecessary API calls to fetch data.
  • If an API call is necessary, use client:only="{framework}". This skips server-side HTML rendering and ensures the component renders only on the client. In place of {framework}, specify the correct framework for the component. Since Astro does not execute the component during the build or on the server, it needs explicit information about the framework being used. Alternatively, you can use the <script> tag within the Astro component to run JavaScript for API calls on the client side.

Example: src/pages/blogs/[slug].astro

---
import PageLayout from "@layouts/PageLayout.astro";
import ChildComponent from "@components/ChildComponent.astro";

export async function getStaticPaths() {
   const response = await fetch("https://api.example.com/posts");
   const posts = await response.json();

   return posts.map((post) => ({
   params: { slug: post.slug },
   props: { post },
 }));
}

const { post } = Astro.props;
---
<PageLayout>
   <ChildComponent client:only="react" /> <!-- here we are using react framework -->
   <ChildComponent data={post} /> <!-- Pass data as props to avoid API calls in child components -->
</PageLayout>


Optimize API Calls in Layout Components

Another common issue was API calls inside layout components.For example, if the Navbar fetches data (e.g., latest blogs, case studies), then every time a page with this layout is built, the layout component makes the API call again.

When used inside [slug].astro, this causes multiple API calls, further increasing build times.

Solution

Implement a build-time caching mechanism to prevent repeated API calls.

Cache the data in a local build folder instead of fetching it every time If the cache exists, use cached data instead of making a new API call. Ignore the cache folder in .gitignore to ensure fresh builds on hosting platforms.If you ever see outdated data in local builds, delete the cache folder and refresh.

Example: Build-Time Caching Mechanism

import fs from "fs/promises";
import path from "path";
import { getAllBlogsForHomePage } from "src/services/blogs";

const CACHE_DIR = path.join(process.cwd(), "cache");
const BLOGS_CACHE_FILE = path.join(CACHE_DIR, "blogs.json");

// Ensure the cache directory exists
async function ensureCacheDirectoryExists() {
  try {
    await fs.mkdir(CACHE_DIR, { recursive: true });
  } catch (error) {
    console.error("Error creating cache directory:", error);
  }
}

// Fetch and cache blogs
async function fetchAndCacheBlogs() {
  try {
    await ensureCacheDirectoryExists();

    const cacheFileExists = await fs
      .access(BLOGS_CACHE_FILE)
      .then(() => true)
      .catch(() => false);

    if (cacheFileExists) {
      return JSON.parse(await fs.readFile(BLOGS_CACHE_FILE, "utf-8"));
    }

    const res = await getAllBlogsForHomePage();
    const blogData = res.data?.blogs?.data;

    await fs.writeFile(BLOGS_CACHE_FILE, JSON.stringify(blogData), "utf-8");

    return blogData;
  } catch (error) {
    console.error("Error fetching or caching blog data:", error);
    return null;
  }
}
export { fetchAndCacheBlogs };
  • Cache Setup:
    Defines a specific directory and file (cache/blogs.json) for storing cached data.

  • Ensuring Cache Availability:
    Uses fs.mkdir with the recursive: true option to create the cache folder if it doesn't exist. \

  • Cache Verification:
    Checks if the cache file already exists using fs.access to avoid unnecessary API calls.

  • Reading Cached Data:
    If available, reads the cache file with "utf-8" encoding to properly parse JSON data.

  • Fetching Fresh Data:
    Calls the API via getAllCaseStudiesForHomePage when no cache is found

  • Writing to Cache:
    Saves the filtered data back to the cache file, ensuring future requests are faster.

Use a CDN for Large Assets

Large assets in your public folder can slow down build times because Astro copies every file—including large images and videos—into the final dist/ directory Additionally, image optimizations and processing increase build duration, making deployments much slower.

To avoid this, offload large assets to a CDN (e.g., Cloudflare, AWS S3, Vercel Storage) , and Use external URLs instead of storing media in the repository.

<!-- Instead of this: -->
<img src="/public/images/large-image.jpg" alt="Large Image" />

<!-- Use this: -->
<img src="https://cdn.example.com/images/large-image.jpg" alt="Large Image" />
Application Modernization Icon

Explore limitless possibilities with AntStack's frontend development capabilities. Empowering your business to achieve your most audacious goals. Build better.

Talk to us

Author(s)

Tags

Your Digital Journey deserves a great story.

Build one with us.

Recommended Blogs

Cookies Icon

These cookies are used to collect information about how you interact with this website and allow us to remember you. We use this information to improve and customize your browsing experience, as well as for analytics.

If you decline, your information won’t be tracked when you visit this website. A single cookie will be used in your browser to remember your preference.

Talk to us