Astro is a modern site builder with web best practices, performance, and DX front-of-mind.
npx @tessl/cli install tessl/npm-astro@5.15.0Fast, content-focused web framework. Zero JavaScript by default, selective hydration.
Install: npm install astro | Type: TypeScript
Task type →
├─ Static content → [Configuration](./configuration.md) + [CLI](./cli-and-build.md)
├─ CMS/API data → [Content Collections](./content-collections.md) + [Loaders](./content-loaders.md)
├─ Server rendering → [SSR](./ssr-and-app.md) + [Middleware](./middleware.md)
├─ Multi-language → [i18n](./i18n.md)
└─ Client interaction → [Transitions](./transitions.md) + [Server Actions](./server-actions.md)Input type →
├─ Type-safe server functions → [Server Actions](./server-actions.md) - defineAction()
├─ API endpoints → [SSR](./ssr-and-app.md) - API routes
└─ Auth/validation → [Middleware](./middleware.md) + [Server Actions](./server-actions.md)Source →
├─ Markdown/MDX → [Content Collections](./content-collections.md) - glob loader
├─ JSON/YAML/TOML → [Loaders](./content-loaders.md) - file loader
├─ External API/CMS → [Loaders](./content-loaders.md) - custom loader
└─ Real-time data → [Content Collections](./content-collections.md) - live collectionsAsset →
├─ Images → [Assets](./assets.md) - Image component, getImage()
├─ Fonts → [Configuration](./configuration.md) - font providers
└─ Build → [Configuration](./configuration.md) - build settingsTarget →
├─ Static hosting → output: 'static' in [Configuration](./configuration.md)
├─ Serverless → [Integrations](./integrations.md) - adapters
├─ Edge runtime → [SSR](./ssr-and-app.md) - App class
└─ Custom server → [SSR](./ssr-and-app.md) - NodeApp| Export | APIs | Doc |
|---|---|---|
astro | CLI, programmatic APIs | CLI |
astro/config | defineConfig, image/font services | Configuration |
astro/app | App (SSR runtime) | SSR |
astro/app/node | NodeApp, loadApp, loadManifest | SSR |
astro/loaders | glob, file | Loaders |
astro/zod | Zod (re-export) | Content Collections |
astro/toolbar | defineToolbarApp | Dev Toolbar |
astro/container | experimental_AstroContainer | Container |
astro/env/runtime | env utilities | Environment |
astro/assets/utils | image utilities | Assets |
astro/middleware | createContext, sequence | Middleware |
| Module | APIs | Doc |
|---|---|---|
astro:content | getCollection, getEntry, render | Content Collections |
astro:assets | Image, Picture, Font, getImage | Assets |
astro:actions | defineAction, actions, errors | Server Actions |
astro:middleware | defineMiddleware, sequence | Middleware |
astro:transitions | ClientRouter, slide, fade | Transitions |
astro:transitions/client | navigate, events | Transitions |
astro:i18n | locale URL functions | i18n |
astro:env/client | PUBLIC_* vars | Environment |
astro:env/server | all vars, getSecret | Environment |
astro:prefetch | prefetch | Transitions |
// src/actions/index.ts
import { defineAction } from 'astro:actions';
import { z } from 'astro/zod';
export const server = {
contact: defineAction({
accept: 'form',
input: z.object({ email: z.string().email(), message: z.string() }),
handler: async (input) => {
// Process form data
return { success: true };
}
})
};<form method="POST" action={actions.contact}>
<input type="email" name="email" required />
<textarea name="message" required></textarea>
<button>Send</button>
</form>// src/middleware.ts
import { defineMiddleware, sequence } from 'astro:middleware';
export const onRequest = sequence(
defineMiddleware(async (context, next) => {
if (context.url.pathname.startsWith('/admin')) {
if (!context.cookies.get('session')) return context.redirect('/login');
}
return next();
})
);// src/content/config.ts
import { defineCollection, z } from 'astro:content';
export const collections = {
blog: defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
pubDate: z.date(),
tags: z.array(z.string())
})
})
};
// Usage
import { getCollection } from 'astro:content';
const posts = await getCollection('blog', (p) => !p.data.draft);// Adapter server entry
import { App } from 'astro/app';
const app = new App(manifest);
export default {
async fetch(request) {
return app.render(request, {
clientAddress: request.headers.get('CF-Connecting-IP')
});
}
};// astro.config.mjs
export default defineConfig({
i18n: {
defaultLocale: 'en',
locales: ['en', 'fr', 'es'],
routing: { prefixDefaultLocale: false }
}
});---
import { getRelativeLocaleUrl } from 'astro:i18n';
const frUrl = getRelativeLocaleUrl('fr', '/about');
---output: 'static' → HTML filesoutput: 'server' + adapter → server bundle// src/env.d.ts
declare namespace App {
interface Locals { user?: { id: string } }
}compressHTML: true, assetsPrefix for CDNsecurity: { checkOrigin: true }access: 'secret' for env varsastro sync to generatesrc/pages/):global() for globalclient: directivesclient:*