<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/how-to-build-an-astro-integration-80rlhli9m" -->

---
title: How to build an Astro integration | daily.dev
description: A step-by-step guide to building an Astro integration package from scratch. Covers creating the integration factory function, using lifecycle hooks like...
canonical: https://daily.dev/posts/how-to-build-an-astro-integration-80rlhli9m
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: How to build an Astro integration | daily.dev
og:description: A step-by-step guide to building an Astro integration package from scratch. Covers creating the integration factory function, using lifecycle hooks like...
og:url: https://daily.dev/posts/how-to-build-an-astro-integration-80rlhli9m
og:image: https://api.daily.dev/og/posts/80rLhLI9m.png
og:image:alt: How to build an Astro integration
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# How to build an Astro integration

**[Flavio Copes](https://daily.dev/sources/flaviocopes)** · 6 min read · 0 upvotes · 0 comments

## Summary

A step-by-step guide to building an Astro integration package from scratch. Covers creating the integration factory function, using lifecycle hooks like `astro:config:setup` and `astro:build:done`, injecting routes and scripts, adding a Vite virtual module for build metadata, conditionally running dev-only code, using Astro's logger, and testing locally with a sibling project. Also covers making the integration compatible with `astro add` and best practices for integration design.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://flaviocopes.com/build-astro-integration>

## Questions this post answers

### How do I add a virtual module to an Astro integration using Vite?

Create a Vite plugin with resolveId and load hooks: resolveId matches a public id like 'virtual:astro-build-info' and returns a resolved id prefixed with a null byte, while load returns the module's source when that resolved id is requested. Register the plugin by calling updateConfig with a vite.plugins array inside the astro:config:setup hook.

_Developers wiring virtual modules into Astro plugins can save this kind of hook-by-hook walkthrough on daily.dev._

### How do I only inject a script during Astro dev mode and not in production builds?

Check the command argument passed to the astro:config:setup hook and call injectScript only when command equals 'dev'. This avoids shipping debug console output, like a build-info console.debug message, on every production page while still allowing the same hook to configure other setup steps like routes and Vite plugins.

_Anyone tuning dev-only versus production behavior in Astro plugins can track these hook patterns on daily.dev._

### How can an Astro integration report information after a production build finishes?

Use the astro:build:done lifecycle hook, which receives dir, pages, and logger arguments. The pages array length and dir.pathname can be logged or used to generate a search index, upload build artifacts, or report output, without depending on undocumented build directories.

_Teams automating post-build reporting in Astro can keep this hook reference handy on daily.dev._

## Similar posts on daily.dev

- [How Astro is built](https://daily.dev/posts/how-astro-is-built-vvxmcldse) · Flavio Copes · 2 upvotes · 0 comments
- [Astro 7.0](https://daily.dev/posts/astro-7-0-2arekjquc) · Astro · 202 upvotes · 14 comments

---

Tags: [#javascript](https://daily.dev/tags/javascript), [#vite](https://daily.dev/tags/vite), [#astro](https://daily.dev/tags/astro), [#web-components](https://daily.dev/tags/web-components)

[View this post on daily.dev](https://daily.dev/posts/how-to-build-an-astro-integration-80rlhli9m)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"How to build an Astro integration","url":"https://daily.dev/posts/how-to-build-an-astro-integration-80rlhli9m","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/how-to-build-an-astro-integration-80rlhli9m"},"datePublished":"2026-07-27T09:50:08.402Z","dateModified":"2026-09-13T19:54:12.553Z","description":"A step-by-step guide to building an Astro integration package from scratch. Covers creating the integration factory function, using lifecycle hooks like...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/907c6c028f107fad7d0379f1571dde35?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/907c6c028f107fad7d0379f1571dde35?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Flavio Copes","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Flavio Copes","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1/logos/1f2dbd275797411bbd37bfdaaf0951a9","url":"https://daily.dev/sources/flaviocopes"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/how-to-build-an-astro-integration-80rlhli9m","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"javascript,vite,astro,web-components","timeRequired":"PT6M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Flavio Copes","item":"https://daily.dev/sources/flaviocopes"},{"@type":"ListItem","position":3,"name":"How to build an Astro integration"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/how-to-build-an-astro-integration-80rlhli9m#faq","mainEntity":[{"@type":"Question","name":"How do I add a virtual module to an Astro integration using Vite?","acceptedAnswer":{"@type":"Answer","text":"Create a Vite plugin with resolveId and load hooks: resolveId matches a public id like 'virtual:astro-build-info' and returns a resolved id prefixed with a null byte, while load returns the module's source when that resolved id is requested. Register the plugin by calling updateConfig with a vite.plugins array inside the astro:config:setup hook. Developers wiring virtual modules into Astro plugins can save this kind of hook-by-hook walkthrough on daily.dev."}},{"@type":"Question","name":"How do I only inject a script during Astro dev mode and not in production builds?","acceptedAnswer":{"@type":"Answer","text":"Check the command argument passed to the astro:config:setup hook and call injectScript only when command equals 'dev'. This avoids shipping debug console output, like a build-info console.debug message, on every production page while still allowing the same hook to configure other setup steps like routes and Vite plugins. Anyone tuning dev-only versus production behavior in Astro plugins can track these hook patterns on daily.dev."}},{"@type":"Question","name":"How can an Astro integration report information after a production build finishes?","acceptedAnswer":{"@type":"Answer","text":"Use the astro:build:done lifecycle hook, which receives dir, pages, and logger arguments. The pages array length and dir.pathname can be logged or used to generate a search index, upload build artifacts, or report output, without depending on undocumented build directories. Teams automating post-build reporting in Astro can keep this hook reference handy on daily.dev."}}]}
```

