astro-auto-adapter

NPM | GitHub | Licence
Let's you choose Astro Adapters based off of the ASTRO_ADAPTER_MODE
environment variable.
Supported Adapters:
What's New? 🚀
astro-auto-adapter
is now even smarter! Previously, you had to manually set the ASTRO_ADAPTER_MODE
environment variable to choose the right Astro adapter for your project.
Now, we've added some magic to automatically detect the deployment environment you're using.
For example, if you're deploying on Vercel
, the VERCEL
environment variable is set to 1
, and we'll automatically choose the Vercel
adapter for you. Neat, right?
Recent Updates:
- Added SST (Serverless Stack) adapter support for AWS deployments
- Deprecated separate static/edge adapters (now handled by main adapters)
- Improved auto-detection for deployment environments
Dive into the docs to see the magic behind each adapter platform:
Important:
- Only install the adapters you actually use to avoid a large list of adapters you don't use
- This package uses peer dependencies, so adapter versions are managed by your project
- Future adapter updates don't require updating
astro-auto-adapter
Installation
Quick Install:
pnpm astro add astro-auto-adapter
Custom Install:
pnpm install astro-auto-adapter
Then install the specific adapters you need:
pnpm add @astrojs/vercel
pnpm add @astrojs/netlify
pnpm add @astrojs/cloudflare
pnpm add @astrojs/node
pnpm add @deno/astro-adapter
pnpm add astro-sst
Other package managers
npm install astro-auto-adapter @astrojs/vercel
yarn add astro-auto-adapter @astrojs/vercel
Usage
adapter
Function
First, import the necessary types and the adapter
function from the package:
import { adapter, type IAdapterOptions } from "astro-auto-adapter";
Next, call the adapter()
function with the desired adapter type and options:
const astroAdapter = await adapter("netlify", {
netlify: {
builders: true,
},
});
Adapter Options
Here is an overview of the available adapter options:
VercelAdapterOptions
Configuration options for the Vercel adapter.
import type { VercelAdapterOptions } from "astro-auto-adapter";
NodeAdapterOptions
Configuration options for the Node adapter.
import type { NodeAdapterOptions } from "astro-auto-adapter";
CloudflareAdapterOptions
Configuration options for the Cloudflare adapter.
import type { CloudflareAdapterOptions } from "astro-auto-adapter";
DenoAdapterOptions
Configuration options for the Deno adapter.
import type { DenoAdapterOptions } from "astro-auto-adapter";
NetlifyAdapterOptions
Configuration options for the Netlify adapter.
import type { NetlifyAdapterOptions } from "astro-auto-adapter";
SSTAdapterOptions
Configuration options for the SST (Serverless Stack) adapter.
import type { SSTAdapterOptions } from "astro-auto-adapter";
Error Handling
If you try to use an adapter that isn't installed, you'll get a helpful error message:
Error: Package "@astrojs/vercel" is not installed. Please install it with:
pnpm add @astrojs/vercel
Environment Variable
You can use the ASTRO_ADAPTER_MODE
environment variable to set the adapter type instead of providing it directly to the adapter()
function. If the environment variable is not set, the function automatically detects the environment or defaults to the "node" adapter.
export ASTRO_ADAPTER_MODE="netlify"
Default Export
The package also includes a default export that can be used as a shorthand for calling the adapter()
function.
import adapter from "astro-auto-adapter";
const astroAdapter = await adapter("netlify", {
netlify: {
builders: true,
},
});
Examples
Here are some examples of how to use the package with various adapter types and configurations:
Cloudflare
import { adapter } from "astro-auto-adapter";
const options = {
imageService: "cloudflare",
runtime: { mode: "local" }
};
const astroAdapter = await adapter("cloudflare", { cloudflare: options });
Deno
import { adapter } from "astro-auto-adapter";
const options = {
port: 3000,
hostname: "localhost",
};
const astroAdapter = await adapter("deno", { deno: options });
Netlify
import { adapter } from "astro-auto-adapter";
const options = {
builders: true,
edgeMiddleware: true,
binaryMediaTypes: ["application/octet-stream"],
};
const astroAdapter = await adapter("netlify", { netlify: options });
SST (Serverless Stack)
import { adapter } from "astro-auto-adapter";
const options = {
responseMode: "stream",
};
const astroAdapter = await adapter("sst", { sst: options });
Vercel
import { adapter } from "astro-auto-adapter";
const options = {
webAnalytics: { enabled: true },
speedInsights: { enabled: true },
};
const astroAdapter = await adapter("vercel", { vercel: options });
Node
import { adapter } from "astro-auto-adapter";
const options = {
mode: "standalone",
host: "0.0.0.0",
port: 3000,
};
const astroAdapter = await adapter("node", { node: options });
Custom/Third-Party Adapters
You can register custom adapters for platforms not included by default:
import { adapter } from "astro-auto-adapter";
const astroAdapter = await adapter("railway", {
railway: {
region: "us-west",
environmentId: "prod"
},
register: {
railway: async (opts) => {
const { default: railwayAdapter } = await import("@railway/astro-adapter");
return railwayAdapter(opts);
},
"custom-platform": (opts) => {
return {
name: "custom-platform-adapter",
hooks: {
"astro:config:setup": ({ updateConfig }) => {
updateConfig({
output: "server",
});
}
}
};
}
}
});
Type-Safe Custom Adapters
For full TypeScript support with custom adapters:
import { adapter, createTypedAdapter } from "astro-auto-adapter";
import type { AdapterFactory } from "astro-auto-adapter";
interface RailwayOptions {
region: 'us-west' | 'us-east' | 'eu-west';
healthCheckPath?: string;
environmentId?: string;
}
interface CustomPlatformOptions {
apiKey: string;
endpoint: string;
timeout?: number;
}
const railwayAdapter = createTypedAdapter<RailwayOptions>(async (options) => {
const { default: railway } = await import("@railway/astro-adapter");
return railway({
region: options.region,
healthCheckPath: options.healthCheckPath ?? '/health',
environmentId: options.environmentId
});
});
const customAdapter = createTypedAdapter<CustomPlatformOptions>((options) => ({
name: "custom-platform-adapter",
hooks: {
"astro:config:setup": ({ updateConfig }) => {
updateConfig({
output: "server",
vite: {
define: {
'process.env.API_KEY': JSON.stringify(options.apiKey),
'process.env.ENDPOINT': JSON.stringify(options.endpoint)
}
}
});
}
}
}));
const astroAdapter = await adapter("railway", {
railway: {
region: "us-west",
healthCheckPath: "/api/health",
},
register: {
railway: railwayAdapter,
'custom-platform': customAdapter
}
});
Alternative: Direct Type Declaration
You can also use module augmentation for global type safety:
declare module "astro-auto-adapter" {
interface IAdapterOptions {
railway?: {
region: 'us-west' | 'us-east' | 'eu-west';
healthCheckPath?: string;
environmentId?: string;
};
'custom-platform'?: {
apiKey: string;
endpoint: string;
timeout?: number;
};
}
}
const astroAdapter = await adapter("railway", {
railway: {
region: "us-west",
healthCheckPath: "/health"
}
});
Benefits of Type-Safe Custom Adapters:
- ✅ Full IntelliSense - Autocomplete for all adapter options
- ✅ Compile-time validation - Catch configuration errors early
- ✅ Refactoring safety - Rename properties with confidence
- ✅ Documentation integration - JSDoc comments in autocomplete
- ✅ Zero runtime overhead - Types are compile-time only
Type Safety Best Practices:
1. Define Strict Option Types
interface AdapterOptions {
region: 'us-west' | 'us-east' | 'eu-west';
memory: 512 | 1024 | 2048 | 4096;
ssl?: boolean;
}
interface AdapterOptions {
region: string;
memory: number;
}
2. Use JSDoc for Better Developer Experience
interface RailwayOptions {
region: 'us-west' | 'us-east' | 'eu-west';
healthCheckPath?: string;
}
3. Organize Types in Separate Files
export interface RailwayOptions { }
export interface DigitalOceanOptions { }
4. Provide Default Values in Factories
const railwayAdapter = createTypedAdapter<RailwayOptions>(async (options) => {
const config = {
region: 'us-west',
healthCheckPath: '/health',
memory: 1024,
...options
};
const { default: railway } = await import('@railway/astro-adapter');
return railway(config);
});
output
Function
The output
function in astro-auto-adapter
is a smart utility designed to automatically select the appropriate Astro output mode based on the target deployment environment. This function is especially useful when working with different hosting platforms, as it simplifies the process of configuring the correct output mode for Astro projects.
Key Features:
- Automatic Mode Selection: Chooses the correct Astro output mode (static or server) based on the environment.
- Environment Variable Support: Uses
ASTRO_OUTPUT_MODE
to determine the preferred mode if set.
- Fallback to Default Mode: If the environment variable isn't set, the function falls back to "static" by default.
Usage in Astro Projects:
To use the output
function, you need to import it into your Astro project and then call it with appropriate parameters. Here's a general structure of how to use it:
import { output } from 'astro-auto-adapter';
const astroOutputMode = output('deno', 'server');
Parameters:
type
(optional): Type of adapter you're using (e.g., 'vercel', 'netlify', 'sst'). Defaults to the value from the ASTRO_ADAPTER_MODE
environment variable.
mode
(optional): Sets Astro output mode ('static' or 'server'). Defaults to 'static', if the ASTRO_OUTPUT_MODE
environment variable isn't set.
Note: As of Astro v5, hybrid
mode has been deprecated. Both server
and static
modes now support selective rendering using export const prerender = true | false;
on individual pages.
Examples:
1. Using with Vercel:
const outputMode = output('vercel');
2. Using with Netlify:
const outputMode = output('netlify', 'server');
3. Using with SST:
const outputMode = output('sst', 'server');
4. Hybrid Mode (Astro v4 & v5 Compatible):
const outputMode = output('vercel', 'hybrid');
const outputMode = output('vercel', 'server');
5. Selective Rendering (Astro v5 Preferred):
const outputMode = output('vercel', 'server');
export const prerender = true;
export const prerender = false;
6. Default Usage (No Specific Adapter):
const outputMode = output();
Supported Adapters:
- Vercel
- Netlify
- Cloudflare
- Deno
- Node.js
- SST (Serverless Stack)
- Custom adapters via
register
option
Version Compatibility:
- Astro v4: Full support including
hybrid
mode
- Astro v5+: Full support with automatic
hybrid
→ server
conversion
- Backward Compatible: Works seamlessly across version upgrades
Note: Ensure that the necessary environment variables are set appropriately for the output
function to work correctly.
⚠️ Deprecated Features
The following adapter types have been deprecated and consolidated into their main adapters:
netlify-static
→ Use netlify
with output mode static
netlify-edge
→ Use netlify
with appropriate configuration
vercel-static
→ Use vercel
with output mode static
vercel-edge
→ Use vercel
with appropriate configuration
Astro Version Compatibility:
hybrid
output mode → Astro v4: Supported natively, Astro v5+: Auto-converts to server
mode with selective prerendering
Migration Examples:
const adapter = await adapter("vercel-static", { "vercel-static": options });
const adapter = await adapter("vercel", { vercel: options });
const outputMode = output("vercel", "static");
const outputMode = output("vercel", "hybrid");
const outputMode = output("vercel", "server");
Showcase
A couple sites/projects that use astro-auto-adapter
:
- Your site/project here...
Real-World Type-Safe Custom Adapter Example:
export interface RailwayOptions {
region: 'us-west' | 'us-east' | 'eu-west';
healthCheckPath?: string;
environmentId?: string;
memory?: 512 | 1024 | 2048 | 4096;
}
export interface DigitalOceanOptions {
dropletSize: 's-1vcpu-1gb' | 's-2vcpu-2gb' | 's-4vcpu-8gb';
region: 'nyc1' | 'sfo3' | 'fra1';
enableBackups?: boolean;
}
import { defineConfig } from 'astro/config';
import { adapter, output, createTypedAdapter } from 'astro-auto-adapter';
import type { RailwayOptions, DigitalOceanOptions } from './types/adapters';
const railwayAdapter = createTypedAdapter<RailwayOptions>(async (options) => {
const { default: railway } = await import('@railway/astro-adapter');
return railway({
region: options.region,
healthCheckPath: options.healthCheckPath ?? '/health',
environmentId: options.environmentId,
memory: options.memory ?? 1024
});
});
const digitalOceanAdapter = createTypedAdapter<DigitalOceanOptions>(async (options) => {
const { default: digitalOcean } = await import('@digitalocean/astro-adapter');
return digitalOcean({
dropletSize: options.dropletSize,
region: options.region,
enableBackups: options.enableBackups ?? true
});
});
export default defineConfig({
output: output('railway', 'server'),
adapter: await adapter('railway', {
railway: {
region: 'us-west',
healthCheckPath: '/api/health',
environmentId: process.env.RAILWAY_ENVIRONMENT_ID,
memory: 2048
},
register: {
railway: railwayAdapter,
digitalocean: digitalOceanAdapter
}
})
});
import { getEnv } from "astro-auto-adapter";
const adapterType = getEnv("DEPLOYMENT_TARGET") || 'railway';
export default defineConfig({
output: output(adapterType, 'server'),
adapter: await adapter(adapterType, {
railway: {
region: 'us-west',
memory: 1024
},
digitalocean: {
dropletSize: 's-2vcpu-2gb',
region: 'nyc1'
},
register: {
railway: railwayAdapter,
digitalocean: digitalOceanAdapter
}
})
});
Contributing
This project uses pnpm as the package manager.
Install all necessary packages
pnpm install
Then run tests
pnpm test
Build project
pnpm run build
Architecture Notes
This package uses peer dependencies for adapters rather than bundling them directly. This approach:
- ✅ Reduces bundle size (users only install adapters they use)
- ✅ Allows automatic updates to latest adapter versions
- ✅ Prevents version conflicts with user projects
- ✅ Eliminates need for constant package updates
Note: This project uses Conventional Commits standard for commits, so, please format your commits using the rules it sets out.
Licence
See the LICENSE file for license rights and limitations (MIT).