New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details
Socket
Book a DemoSign in
Socket

astro-stacks

Package Overview
Dependencies
Maintainers
1
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

astro-stacks

Laravel Blade-style @stack/@push system for Astro SSR

latest
Source
npmnpm
Version
1.1.1
Version published
Weekly downloads
13
225%
Maintainers
1
Weekly downloads
 
Created
Source

astro-stacks

A Laravel Blade-style @stack / @push / @pushOnce system for Astro SSR. Lets deeply nested components push content (scripts, styles, SVG symbols, preconnects, meta tags) to named stacks, which are collected and emitted at designated output points in your layout.

Streaming and Buffering

Important tradeoff: The middleware buffers the full HTML response to replace <!--@stack(name)--> placeholders. This disables streaming for that request.

If a response contains no placeholders, it passes through untouched — no buffering, no overhead.

In practice, this tradeoff is acceptable for most Astro projects: marketing sites and regular websites rarely need streaming, and Astro Islands are not affected since they hydrate on the client via separate fetch requests after the initial HTML is delivered.

The Problem

In Astro SSR, the HTML stream is generated top-to-bottom. A component's frontmatter executes at the moment the renderer reaches that component in the output. This means a <slot /> and all of its children render before any sibling that comes after the slot in the layout.

This creates a problem: how does a deeply nested child component contribute a <link rel="preconnect">, a <script>, or structured data to <head> — which has already been emitted before the child even runs?

astro-stacks solves this with a middleware that buffers the response and replaces <!--@stack(name)--> placeholder comments with the collected stack content after the full page has rendered. Use the <Stack> component to place these placeholders anywhere in your layout.

Installation

bun add astro-stacks

Setup

npx astro add astro-stacks

Or manually add to your Astro config:

// astro.config.mjs
import { defineConfig } from "astro/config";
import astroStacks from "astro-stacks";

export default defineConfig({
  integrations: [astroStacks()],
});

Typed Stack Names

Types are auto-injected by the integration — no manual env.d.ts needed. The integration scans your .astro files for <Stack name="..." /> usage and generates typed stack names, giving you autocomplete on push, pushOnce, get, and has.

You can also declare additional stack names via the stacks config option:

export default defineConfig({
  integrations: [astroStacks({ stacks: ["head", "beforeBodyEnd"] })],
});

Other integrations (or your own code) can augment StackNames via declaration merging:

declare module "astro-stacks" {
  interface StackNames {
    "myCustomStack": true;
  }
}

Layout

Use the <Stack> component to place output points in your layout:

---
import Stack from "astro-stacks/stack.astro";
---

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>My Site</title>
    <Stack name="head" />
  </head>
  <body>
    <slot />
    <Stack name="beforeBodyEnd" />
  </body>
</html>

API Reference

createStackStore()

Creates a new stack store instance. You only need this directly if you're building custom middleware.

import { createStackStore } from "astro-stacks";
const store = createStackStore();

.push(stack, content)

Push a string of HTML content to a named stack.

Astro.locals.stacks.push("head", '<link rel="preconnect" href="https://cdn.example.com">');
ParameterTypeDescription
stackstringThe stack name
contentstringHTML string to append

.pushOnce(stack, key, content)

Push content only if the given key has not already been pushed to this stack.

Astro.locals.stacks.pushOnce(
  "beforeBodyEnd",
  "accordion-js",
  `<script>/* accordion behavior */</script>`,
);
ParameterTypeDescription
stackstringThe stack name
keystringUnique deduplication key
contentstringHTML string to append (skipped if key already seen)

.get(stack)

Returns all content pushed to the named stack, joined with newlines. Returns an empty string if the stack has no items. Does not consume the stack.

const html = store.get("head"); // string

.has(stack)

Returns true if the named stack has any items.

if (store.has("beforeBodyEnd")) { /* ... */ }

renderStacks(html, store)

Replaces all <!--@stack(name)--> placeholders in a string. Low-level — prefer the integration.

import { renderStacks } from "astro-stacks";
const finalHtml = renderStacks(rawHtml, store);

renderStacksResponse(response, store)

Takes a Response and returns a new Response with placeholders replaced. Non-HTML responses pass through untouched. HTML without placeholders passes through untouched.

import { renderStacksResponse } from "astro-stacks";
const response = await renderStacksResponse(await next(), store);

Stack Component

Emits a <!--@stack(name)--> placeholder that the middleware replaces with collected stack content. Works anywhere in your layout.

---
import Stack from "astro-stacks/stack.astro";
---

<Stack name="head" />
PropTypeDescription
namestringThe stack to output

StackStore Type

import type { StackStore } from "astro-stacks";

Usage Example

A deeply nested component that pushes a preconnect to <head> and a script to beforeBodyEnd:

---
// src/components/VideoPlayer.astro
Astro.locals.stacks.push("head", '<link rel="preconnect" href="https://cdn.video.com">');

Astro.locals.stacks.pushOnce(
  "beforeBodyEnd",
  "video-player-js",
  `<script src="/video-player.js" defer></script>`,
);
---

<div data-video-player>
  <slot />
</div>

The preconnect appears in <head> and the script appears at end of <body>, both via <Stack> placeholder replacement. Both work regardless of how deeply the component is nested.

Exports

Export PathContents
astro-stackscreateStackStore, renderStacks, renderStacksResponse, StackStore / StackNames / StackName types, integration default export
astro-stacks/stack.astroStack component
astro-stacks/middlewareMiddleware (auto-registered by integration)

Keywords

astro

FAQs

Package last updated on 01 Mar 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts