Astro is a modern site builder with web best practices, performance, and DX front-of-mind.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
The experimental Container API allows rendering Astro components in isolation, useful for testing, server-side rendering, and programmatic component rendering outside of the normal Astro build process.
Creates a new container instance for rendering components.
class experimental_AstroContainer {
/**
* Creates a new container instance
*/
static create(
options?: AstroContainerOptions
): Promise<experimental_AstroContainer>;
}
interface AstroContainerOptions {
streaming?: boolean;
renderers?: SSRLoadedRenderer[];
astroConfig?: AstroContainerUserConfig;
manifest?: SSRManifest;
resolve?: (specifier: string) => Promise<string>;
}import { experimental_AstroContainer as AstroContainer } from 'astro/container';
import MyComponent from './MyComponent.astro';
const container = await AstroContainer.create();
const result = await container.renderToString(MyComponent);
console.log(result);Renders a component to an HTML string.
/**
* Renders a component to HTML string
*/
renderToString(
component: AstroComponentFactory,
options?: ContainerRenderOptions
): Promise<string>;
interface ContainerRenderOptions {
slots?: Record<string, any>;
request?: Request;
params?: Record<string, string | undefined>;
locals?: App.Locals;
routeType?: 'page' | 'endpoint';
props?: Props;
partial?: boolean;
}import { experimental_AstroContainer as AstroContainer } from 'astro/container';
import Card from './Card.astro';
import Layout from './Layout.astro';
const container = await AstroContainer.create();
// Basic rendering
const html = await container.renderToString(Card, {
props: { title: 'Hello', content: 'World' },
});
// With slots
const withSlots = await container.renderToString(Layout, {
slots: {
default: '<p>Main content</p>',
sidebar: '<div>Sidebar</div>',
},
});
// With request context
const withRequest = await container.renderToString(Card, {
request: new Request('https://example.com/page'),
params: { slug: 'my-page' },
locals: { user: { id: '123' } },
});Renders a component to a Response object.
/**
* Renders a component to Response object
*/
renderToResponse(
component: AstroComponentFactory,
options?: ContainerRenderOptions
): Promise<Response>;import { experimental_AstroContainer as AstroContainer } from 'astro/container';
import Page from './Page.astro';
const container = await AstroContainer.create();
const response = await container.renderToResponse(Page);
console.log(response.status);
console.log(response.headers.get('content-type'));
const html = await response.text();Adds a server renderer for framework components (React, Vue, Svelte, etc.).
/**
* Adds a server renderer to the container
*/
addServerRenderer(options: AddServerRenderer): void;
type AddServerRenderer =
| {
renderer: NamedSSRLoadedRendererValue;
}
| {
renderer: SSRLoadedRendererValue;
name: string;
};import { experimental_AstroContainer as AstroContainer } from 'astro/container';
import reactRenderer from '@astrojs/react/server.js';
import vueRenderer from '@astrojs/vue/server.js';
import ReactComponent from './ReactComponent.jsx';
const container = await AstroContainer.create();
container.addServerRenderer({ renderer: reactRenderer });
container.addServerRenderer({ renderer: vueRenderer });
const result = await container.renderToString(ReactComponent);Adds a client renderer for components with client:* directives.
/**
* Adds a client renderer for hydration directives
*/
addClientRenderer(options: AddClientRenderer): void;
interface AddClientRenderer {
name: string;
entrypoint: string;
}import { experimental_AstroContainer as AstroContainer } from 'astro/container';
import reactRenderer from '@astrojs/react/server.js';
const container = await AstroContainer.create();
container.addServerRenderer({ renderer: reactRenderer });
container.addClientRenderer({
name: '@astrojs/react',
entrypoint: '@astrojs/react/client.js',
});Inserts a page route for Astro.rewrite support.
/**
* Inserts a page route into the container
*/
insertPageRoute(
route: string,
component: AstroComponentFactory,
params?: Record<string, string | undefined>
): void;import { experimental_AstroContainer as AstroContainer } from 'astro/container';
import BlogPost from './BlogPost.astro';
import ProductPage from './ProductPage.astro';
const container = await AstroContainer.create();
container.insertPageRoute('/blog/[slug]', BlogPost, { slug: 'my-post' });
container.insertPageRoute('/products/[id]', ProductPage);
const result = await container.renderToString(BlogPost, {
request: new Request('https://example.com/blog/my-post'),
params: { slug: 'my-post' },
});Utility function for loading renderers.
/**
* Loads renderers for use in container
*/
function loadRenderers(
renderers: AstroRenderer[]
): Promise<SSRLoadedRenderer[]>;
interface AstroRenderer {
name: string;
serverEntrypoint: string;
clientEntrypoint?: string;
}Common pattern for testing Astro components:
import { describe, it, expect } from 'vitest';
import { experimental_AstroContainer as AstroContainer } from 'astro/container';
import MyComponent from '../src/components/MyComponent.astro';
describe('MyComponent', () => {
it('renders correctly', async () => {
const container = await AstroContainer.create();
const result = await container.renderToString(MyComponent, {
props: {
title: 'Test Title',
content: 'Test Content',
},
});
expect(result).toContain('Test Title');
expect(result).toContain('Test Content');
});
it('handles slots', async () => {
const container = await AstroContainer.create();
const result = await container.renderToString(MyComponent, {
slots: {
default: '<p>Slot content</p>',
},
});
expect(result).toContain('Slot content');
});
});Using container for server-side rendering:
import { experimental_AstroContainer as AstroContainer } from 'astro/container';
import Page from './pages/[slug].astro';
export async function handler(request: Request) {
const url = new URL(request.url);
const slug = url.pathname.split('/').pop();
const container = await AstroContainer.create({
streaming: true,
});
const response = await container.renderToResponse(Page, {
request,
params: { slug },
routeType: 'page',
});
return response;
}interface AstroComponentFactory {
(result: any, props: any, slots: any): AstroFactoryReturnValue | Promise<AstroFactoryReturnValue>;
isAstroComponentFactory?: boolean;
moduleId?: string | undefined;
propagation?: PropagationHint;
}
type AstroFactoryReturnValue = string | Response;
type PropagationHint = 'none' | 'in-tree' | 'self';interface ComponentInstance {
default: AstroComponentFactory;
getStaticPaths?: () => GetStaticPathsResult | Promise<GetStaticPathsResult>;
css?: string[];
partial?: boolean;
prerender?: boolean;
}/**
* Subset of Astro configuration for container API
*/
type AstroContainerUserConfig = Omit<AstroUserConfig, 'integrations' | 'adapter'>;import { experimental_AstroContainer as AstroContainer } from 'astro/container';
const container = await AstroContainer.create({
astroConfig: {
site: 'https://example.com',
base: '/blog',
trailingSlash: 'always',
build: {
format: 'directory'
}
}
});insertPageRoute() if components use Astro.rewrite() or reference other routes.streaming: true for better performance with large components.